LCOV - code coverage report
Current view: top level - synthesis/MeasurementEquations/lbfgs - interpolation.cc (source / functions) Hit Total Coverage
Test: ctest_coverage.info Lines: 0 17890 0.0 %
Date: 2023-11-02 14:27:30 Functions: 0 933 0.0 %

          Line data    Source code
       1             : /*************************************************************************
       2             : ALGLIB 3.17.0 (source code generated 2020-12-27)
       3             : Copyright (c) Sergey Bochkanov (ALGLIB project).
       4             : 
       5             : >>> SOURCE LICENSE >>>
       6             : This program is free software; you can redistribute it and/or modify
       7             : it under the terms of the GNU General Public License as published by
       8             : the Free Software Foundation (www.fsf.org); either version 2 of the 
       9             : License, or (at your option) any later version.
      10             : 
      11             : This program is distributed in the hope that it will be useful,
      12             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : GNU General Public License for more details.
      15             : 
      16             : A copy of the GNU General Public License is available at
      17             : http://www.fsf.org/licensing/licenses
      18             : >>> END OF LICENSE >>>
      19             : *************************************************************************/
      20             : #ifdef _MSC_VER
      21             : #define _CRT_SECURE_NO_WARNINGS
      22             : #endif
      23             : #include "stdafx.h"
      24             : #include "interpolation.h"
      25             : 
      26             : // disable some irrelevant warnings
      27             : #if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS)
      28             : #pragma warning(disable:4100)
      29             : #pragma warning(disable:4127)
      30             : #pragma warning(disable:4611)
      31             : #pragma warning(disable:4702)
      32             : #pragma warning(disable:4996)
      33             : #endif
      34             : 
      35             : /////////////////////////////////////////////////////////////////////////
      36             : //
      37             : // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE
      38             : //
      39             : /////////////////////////////////////////////////////////////////////////
      40             : namespace alglib
      41             : {
      42             : 
      43             : #if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD)
      44             : 
      45             : #endif
      46             : 
      47             : #if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD)
      48             : 
      49             : #endif
      50             : 
      51             : #if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD)
      52             : 
      53             : #endif
      54             : 
      55             : #if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD)
      56             : 
      57             : #endif
      58             : 
      59             : #if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD)
      60             : 
      61             : #endif
      62             : 
      63             : #if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD)
      64             : 
      65             : #endif
      66             : 
      67             : #if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD)
      68             : 
      69             : #endif
      70             : 
      71             : #if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD)
      72             : 
      73             : #endif
      74             : 
      75             : #if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD)
      76             : 
      77             : #endif
      78             : 
      79             : #if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD)
      80             : 
      81             : #endif
      82             : 
      83             : #if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD)
      84             : 
      85             : #endif
      86             : 
      87             : #if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD)
      88             : 
      89             : #endif
      90             : 
      91             : #if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD)
      92             : 
      93             : #endif
      94             : 
      95             : #if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD)
      96             : 
      97             : #endif
      98             : 
      99             : #if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD)
     100             : /*************************************************************************
     101             : Buffer  object  which  is  used  to  perform  evaluation  requests  in  the
     102             : multithreaded mode (multiple threads working with same IDW object).
     103             : 
     104             : This object should be created with idwcreatecalcbuffer().
     105             : *************************************************************************/
     106           0 : _idwcalcbuffer_owner::_idwcalcbuffer_owner()
     107             : {
     108             :     jmp_buf _break_jump;
     109             :     alglib_impl::ae_state _state;
     110             :     
     111           0 :     alglib_impl::ae_state_init(&_state);
     112           0 :     if( setjmp(_break_jump) )
     113             :     {
     114           0 :         if( p_struct!=NULL )
     115             :         {
     116           0 :             alglib_impl::_idwcalcbuffer_destroy(p_struct);
     117           0 :             alglib_impl::ae_free(p_struct);
     118             :         }
     119           0 :         p_struct = NULL;
     120             : #if !defined(AE_NO_EXCEPTIONS)
     121           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     122             : #else
     123             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     124             :         return;
     125             : #endif
     126             :     }
     127           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     128           0 :     p_struct = NULL;
     129           0 :     p_struct = (alglib_impl::idwcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwcalcbuffer), &_state);
     130           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwcalcbuffer));
     131           0 :     alglib_impl::_idwcalcbuffer_init(p_struct, &_state, ae_false);
     132           0 :     ae_state_clear(&_state);
     133           0 : }
     134             : 
     135           0 : _idwcalcbuffer_owner::_idwcalcbuffer_owner(const _idwcalcbuffer_owner &rhs)
     136             : {
     137             :     jmp_buf _break_jump;
     138             :     alglib_impl::ae_state _state;
     139             :     
     140           0 :     alglib_impl::ae_state_init(&_state);
     141           0 :     if( setjmp(_break_jump) )
     142             :     {
     143           0 :         if( p_struct!=NULL )
     144             :         {
     145           0 :             alglib_impl::_idwcalcbuffer_destroy(p_struct);
     146           0 :             alglib_impl::ae_free(p_struct);
     147             :         }
     148           0 :         p_struct = NULL;
     149             : #if !defined(AE_NO_EXCEPTIONS)
     150           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     151             : #else
     152             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     153             :         return;
     154             : #endif
     155             :     }
     156           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     157           0 :     p_struct = NULL;
     158           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwcalcbuffer copy constructor failure (source is not initialized)", &_state);
     159           0 :     p_struct = (alglib_impl::idwcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwcalcbuffer), &_state);
     160           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwcalcbuffer));
     161           0 :     alglib_impl::_idwcalcbuffer_init_copy(p_struct, const_cast<alglib_impl::idwcalcbuffer*>(rhs.p_struct), &_state, ae_false);
     162           0 :     ae_state_clear(&_state);
     163           0 : }
     164             : 
     165           0 : _idwcalcbuffer_owner& _idwcalcbuffer_owner::operator=(const _idwcalcbuffer_owner &rhs)
     166             : {
     167           0 :     if( this==&rhs )
     168           0 :         return *this;
     169             :     jmp_buf _break_jump;
     170             :     alglib_impl::ae_state _state;
     171             :     
     172           0 :     alglib_impl::ae_state_init(&_state);
     173           0 :     if( setjmp(_break_jump) )
     174             :     {
     175             : #if !defined(AE_NO_EXCEPTIONS)
     176           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     177             : #else
     178             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     179             :         return *this;
     180             : #endif
     181             :     }
     182           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     183           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwcalcbuffer assignment constructor failure (destination is not initialized)", &_state);
     184           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwcalcbuffer assignment constructor failure (source is not initialized)", &_state);
     185           0 :     alglib_impl::_idwcalcbuffer_destroy(p_struct);
     186           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwcalcbuffer));
     187           0 :     alglib_impl::_idwcalcbuffer_init_copy(p_struct, const_cast<alglib_impl::idwcalcbuffer*>(rhs.p_struct), &_state, ae_false);
     188           0 :     ae_state_clear(&_state);
     189           0 :     return *this;
     190             : }
     191             : 
     192           0 : _idwcalcbuffer_owner::~_idwcalcbuffer_owner()
     193             : {
     194           0 :     if( p_struct!=NULL )
     195             :     {
     196           0 :         alglib_impl::_idwcalcbuffer_destroy(p_struct);
     197           0 :         ae_free(p_struct);
     198             :     }
     199           0 : }
     200             : 
     201           0 : alglib_impl::idwcalcbuffer* _idwcalcbuffer_owner::c_ptr()
     202             : {
     203           0 :     return p_struct;
     204             : }
     205             : 
     206           0 : alglib_impl::idwcalcbuffer* _idwcalcbuffer_owner::c_ptr() const
     207             : {
     208           0 :     return const_cast<alglib_impl::idwcalcbuffer*>(p_struct);
     209             : }
     210           0 : idwcalcbuffer::idwcalcbuffer() : _idwcalcbuffer_owner() 
     211             : {
     212           0 : }
     213             : 
     214           0 : idwcalcbuffer::idwcalcbuffer(const idwcalcbuffer &rhs):_idwcalcbuffer_owner(rhs) 
     215             : {
     216           0 : }
     217             : 
     218           0 : idwcalcbuffer& idwcalcbuffer::operator=(const idwcalcbuffer &rhs)
     219             : {
     220           0 :     if( this==&rhs )
     221           0 :         return *this;
     222           0 :     _idwcalcbuffer_owner::operator=(rhs);
     223           0 :     return *this;
     224             : }
     225             : 
     226           0 : idwcalcbuffer::~idwcalcbuffer()
     227             : {
     228           0 : }
     229             : 
     230             : 
     231             : /*************************************************************************
     232             : IDW (Inverse Distance Weighting) model object.
     233             : *************************************************************************/
     234           0 : _idwmodel_owner::_idwmodel_owner()
     235             : {
     236             :     jmp_buf _break_jump;
     237             :     alglib_impl::ae_state _state;
     238             :     
     239           0 :     alglib_impl::ae_state_init(&_state);
     240           0 :     if( setjmp(_break_jump) )
     241             :     {
     242           0 :         if( p_struct!=NULL )
     243             :         {
     244           0 :             alglib_impl::_idwmodel_destroy(p_struct);
     245           0 :             alglib_impl::ae_free(p_struct);
     246             :         }
     247           0 :         p_struct = NULL;
     248             : #if !defined(AE_NO_EXCEPTIONS)
     249           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     250             : #else
     251             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     252             :         return;
     253             : #endif
     254             :     }
     255           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     256           0 :     p_struct = NULL;
     257           0 :     p_struct = (alglib_impl::idwmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwmodel), &_state);
     258           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwmodel));
     259           0 :     alglib_impl::_idwmodel_init(p_struct, &_state, ae_false);
     260           0 :     ae_state_clear(&_state);
     261           0 : }
     262             : 
     263           0 : _idwmodel_owner::_idwmodel_owner(const _idwmodel_owner &rhs)
     264             : {
     265             :     jmp_buf _break_jump;
     266             :     alglib_impl::ae_state _state;
     267             :     
     268           0 :     alglib_impl::ae_state_init(&_state);
     269           0 :     if( setjmp(_break_jump) )
     270             :     {
     271           0 :         if( p_struct!=NULL )
     272             :         {
     273           0 :             alglib_impl::_idwmodel_destroy(p_struct);
     274           0 :             alglib_impl::ae_free(p_struct);
     275             :         }
     276           0 :         p_struct = NULL;
     277             : #if !defined(AE_NO_EXCEPTIONS)
     278           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     279             : #else
     280             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     281             :         return;
     282             : #endif
     283             :     }
     284           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     285           0 :     p_struct = NULL;
     286           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwmodel copy constructor failure (source is not initialized)", &_state);
     287           0 :     p_struct = (alglib_impl::idwmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwmodel), &_state);
     288           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwmodel));
     289           0 :     alglib_impl::_idwmodel_init_copy(p_struct, const_cast<alglib_impl::idwmodel*>(rhs.p_struct), &_state, ae_false);
     290           0 :     ae_state_clear(&_state);
     291           0 : }
     292             : 
     293           0 : _idwmodel_owner& _idwmodel_owner::operator=(const _idwmodel_owner &rhs)
     294             : {
     295           0 :     if( this==&rhs )
     296           0 :         return *this;
     297             :     jmp_buf _break_jump;
     298             :     alglib_impl::ae_state _state;
     299             :     
     300           0 :     alglib_impl::ae_state_init(&_state);
     301           0 :     if( setjmp(_break_jump) )
     302             :     {
     303             : #if !defined(AE_NO_EXCEPTIONS)
     304           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     305             : #else
     306             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     307             :         return *this;
     308             : #endif
     309             :     }
     310           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     311           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwmodel assignment constructor failure (destination is not initialized)", &_state);
     312           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwmodel assignment constructor failure (source is not initialized)", &_state);
     313           0 :     alglib_impl::_idwmodel_destroy(p_struct);
     314           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwmodel));
     315           0 :     alglib_impl::_idwmodel_init_copy(p_struct, const_cast<alglib_impl::idwmodel*>(rhs.p_struct), &_state, ae_false);
     316           0 :     ae_state_clear(&_state);
     317           0 :     return *this;
     318             : }
     319             : 
     320           0 : _idwmodel_owner::~_idwmodel_owner()
     321             : {
     322           0 :     if( p_struct!=NULL )
     323             :     {
     324           0 :         alglib_impl::_idwmodel_destroy(p_struct);
     325           0 :         ae_free(p_struct);
     326             :     }
     327           0 : }
     328             : 
     329           0 : alglib_impl::idwmodel* _idwmodel_owner::c_ptr()
     330             : {
     331           0 :     return p_struct;
     332             : }
     333             : 
     334           0 : alglib_impl::idwmodel* _idwmodel_owner::c_ptr() const
     335             : {
     336           0 :     return const_cast<alglib_impl::idwmodel*>(p_struct);
     337             : }
     338           0 : idwmodel::idwmodel() : _idwmodel_owner() 
     339             : {
     340           0 : }
     341             : 
     342           0 : idwmodel::idwmodel(const idwmodel &rhs):_idwmodel_owner(rhs) 
     343             : {
     344           0 : }
     345             : 
     346           0 : idwmodel& idwmodel::operator=(const idwmodel &rhs)
     347             : {
     348           0 :     if( this==&rhs )
     349           0 :         return *this;
     350           0 :     _idwmodel_owner::operator=(rhs);
     351           0 :     return *this;
     352             : }
     353             : 
     354           0 : idwmodel::~idwmodel()
     355             : {
     356           0 : }
     357             : 
     358             : 
     359             : /*************************************************************************
     360             : Builder object used to generate IDW (Inverse Distance Weighting) model.
     361             : *************************************************************************/
     362           0 : _idwbuilder_owner::_idwbuilder_owner()
     363             : {
     364             :     jmp_buf _break_jump;
     365             :     alglib_impl::ae_state _state;
     366             :     
     367           0 :     alglib_impl::ae_state_init(&_state);
     368           0 :     if( setjmp(_break_jump) )
     369             :     {
     370           0 :         if( p_struct!=NULL )
     371             :         {
     372           0 :             alglib_impl::_idwbuilder_destroy(p_struct);
     373           0 :             alglib_impl::ae_free(p_struct);
     374             :         }
     375           0 :         p_struct = NULL;
     376             : #if !defined(AE_NO_EXCEPTIONS)
     377           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     378             : #else
     379             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     380             :         return;
     381             : #endif
     382             :     }
     383           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     384           0 :     p_struct = NULL;
     385           0 :     p_struct = (alglib_impl::idwbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwbuilder), &_state);
     386           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwbuilder));
     387           0 :     alglib_impl::_idwbuilder_init(p_struct, &_state, ae_false);
     388           0 :     ae_state_clear(&_state);
     389           0 : }
     390             : 
     391           0 : _idwbuilder_owner::_idwbuilder_owner(const _idwbuilder_owner &rhs)
     392             : {
     393             :     jmp_buf _break_jump;
     394             :     alglib_impl::ae_state _state;
     395             :     
     396           0 :     alglib_impl::ae_state_init(&_state);
     397           0 :     if( setjmp(_break_jump) )
     398             :     {
     399           0 :         if( p_struct!=NULL )
     400             :         {
     401           0 :             alglib_impl::_idwbuilder_destroy(p_struct);
     402           0 :             alglib_impl::ae_free(p_struct);
     403             :         }
     404           0 :         p_struct = NULL;
     405             : #if !defined(AE_NO_EXCEPTIONS)
     406           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     407             : #else
     408             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     409             :         return;
     410             : #endif
     411             :     }
     412           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     413           0 :     p_struct = NULL;
     414           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwbuilder copy constructor failure (source is not initialized)", &_state);
     415           0 :     p_struct = (alglib_impl::idwbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwbuilder), &_state);
     416           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwbuilder));
     417           0 :     alglib_impl::_idwbuilder_init_copy(p_struct, const_cast<alglib_impl::idwbuilder*>(rhs.p_struct), &_state, ae_false);
     418           0 :     ae_state_clear(&_state);
     419           0 : }
     420             : 
     421           0 : _idwbuilder_owner& _idwbuilder_owner::operator=(const _idwbuilder_owner &rhs)
     422             : {
     423           0 :     if( this==&rhs )
     424           0 :         return *this;
     425             :     jmp_buf _break_jump;
     426             :     alglib_impl::ae_state _state;
     427             :     
     428           0 :     alglib_impl::ae_state_init(&_state);
     429           0 :     if( setjmp(_break_jump) )
     430             :     {
     431             : #if !defined(AE_NO_EXCEPTIONS)
     432           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     433             : #else
     434             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     435             :         return *this;
     436             : #endif
     437             :     }
     438           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     439           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwbuilder assignment constructor failure (destination is not initialized)", &_state);
     440           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwbuilder assignment constructor failure (source is not initialized)", &_state);
     441           0 :     alglib_impl::_idwbuilder_destroy(p_struct);
     442           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwbuilder));
     443           0 :     alglib_impl::_idwbuilder_init_copy(p_struct, const_cast<alglib_impl::idwbuilder*>(rhs.p_struct), &_state, ae_false);
     444           0 :     ae_state_clear(&_state);
     445           0 :     return *this;
     446             : }
     447             : 
     448           0 : _idwbuilder_owner::~_idwbuilder_owner()
     449             : {
     450           0 :     if( p_struct!=NULL )
     451             :     {
     452           0 :         alglib_impl::_idwbuilder_destroy(p_struct);
     453           0 :         ae_free(p_struct);
     454             :     }
     455           0 : }
     456             : 
     457           0 : alglib_impl::idwbuilder* _idwbuilder_owner::c_ptr()
     458             : {
     459           0 :     return p_struct;
     460             : }
     461             : 
     462           0 : alglib_impl::idwbuilder* _idwbuilder_owner::c_ptr() const
     463             : {
     464           0 :     return const_cast<alglib_impl::idwbuilder*>(p_struct);
     465             : }
     466           0 : idwbuilder::idwbuilder() : _idwbuilder_owner() 
     467             : {
     468           0 : }
     469             : 
     470           0 : idwbuilder::idwbuilder(const idwbuilder &rhs):_idwbuilder_owner(rhs) 
     471             : {
     472           0 : }
     473             : 
     474           0 : idwbuilder& idwbuilder::operator=(const idwbuilder &rhs)
     475             : {
     476           0 :     if( this==&rhs )
     477           0 :         return *this;
     478           0 :     _idwbuilder_owner::operator=(rhs);
     479           0 :     return *this;
     480             : }
     481             : 
     482           0 : idwbuilder::~idwbuilder()
     483             : {
     484           0 : }
     485             : 
     486             : 
     487             : /*************************************************************************
     488             : IDW fitting report:
     489             :     rmserror        RMS error
     490             :     avgerror        average error
     491             :     maxerror        maximum error
     492             :     r2              coefficient of determination,  R-squared, 1-RSS/TSS
     493             : *************************************************************************/
     494           0 : _idwreport_owner::_idwreport_owner()
     495             : {
     496             :     jmp_buf _break_jump;
     497             :     alglib_impl::ae_state _state;
     498             :     
     499           0 :     alglib_impl::ae_state_init(&_state);
     500           0 :     if( setjmp(_break_jump) )
     501             :     {
     502           0 :         if( p_struct!=NULL )
     503             :         {
     504           0 :             alglib_impl::_idwreport_destroy(p_struct);
     505           0 :             alglib_impl::ae_free(p_struct);
     506             :         }
     507           0 :         p_struct = NULL;
     508             : #if !defined(AE_NO_EXCEPTIONS)
     509           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     510             : #else
     511             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     512             :         return;
     513             : #endif
     514             :     }
     515           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     516           0 :     p_struct = NULL;
     517           0 :     p_struct = (alglib_impl::idwreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwreport), &_state);
     518           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwreport));
     519           0 :     alglib_impl::_idwreport_init(p_struct, &_state, ae_false);
     520           0 :     ae_state_clear(&_state);
     521           0 : }
     522             : 
     523           0 : _idwreport_owner::_idwreport_owner(const _idwreport_owner &rhs)
     524             : {
     525             :     jmp_buf _break_jump;
     526             :     alglib_impl::ae_state _state;
     527             :     
     528           0 :     alglib_impl::ae_state_init(&_state);
     529           0 :     if( setjmp(_break_jump) )
     530             :     {
     531           0 :         if( p_struct!=NULL )
     532             :         {
     533           0 :             alglib_impl::_idwreport_destroy(p_struct);
     534           0 :             alglib_impl::ae_free(p_struct);
     535             :         }
     536           0 :         p_struct = NULL;
     537             : #if !defined(AE_NO_EXCEPTIONS)
     538           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     539             : #else
     540             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     541             :         return;
     542             : #endif
     543             :     }
     544           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     545           0 :     p_struct = NULL;
     546           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwreport copy constructor failure (source is not initialized)", &_state);
     547           0 :     p_struct = (alglib_impl::idwreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwreport), &_state);
     548           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwreport));
     549           0 :     alglib_impl::_idwreport_init_copy(p_struct, const_cast<alglib_impl::idwreport*>(rhs.p_struct), &_state, ae_false);
     550           0 :     ae_state_clear(&_state);
     551           0 : }
     552             : 
     553           0 : _idwreport_owner& _idwreport_owner::operator=(const _idwreport_owner &rhs)
     554             : {
     555           0 :     if( this==&rhs )
     556           0 :         return *this;
     557             :     jmp_buf _break_jump;
     558             :     alglib_impl::ae_state _state;
     559             :     
     560           0 :     alglib_impl::ae_state_init(&_state);
     561           0 :     if( setjmp(_break_jump) )
     562             :     {
     563             : #if !defined(AE_NO_EXCEPTIONS)
     564           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
     565             : #else
     566             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
     567             :         return *this;
     568             : #endif
     569             :     }
     570           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
     571           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwreport assignment constructor failure (destination is not initialized)", &_state);
     572           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwreport assignment constructor failure (source is not initialized)", &_state);
     573           0 :     alglib_impl::_idwreport_destroy(p_struct);
     574           0 :     memset(p_struct, 0, sizeof(alglib_impl::idwreport));
     575           0 :     alglib_impl::_idwreport_init_copy(p_struct, const_cast<alglib_impl::idwreport*>(rhs.p_struct), &_state, ae_false);
     576           0 :     ae_state_clear(&_state);
     577           0 :     return *this;
     578             : }
     579             : 
     580           0 : _idwreport_owner::~_idwreport_owner()
     581             : {
     582           0 :     if( p_struct!=NULL )
     583             :     {
     584           0 :         alglib_impl::_idwreport_destroy(p_struct);
     585           0 :         ae_free(p_struct);
     586             :     }
     587           0 : }
     588             : 
     589           0 : alglib_impl::idwreport* _idwreport_owner::c_ptr()
     590             : {
     591           0 :     return p_struct;
     592             : }
     593             : 
     594           0 : alglib_impl::idwreport* _idwreport_owner::c_ptr() const
     595             : {
     596           0 :     return const_cast<alglib_impl::idwreport*>(p_struct);
     597             : }
     598           0 : idwreport::idwreport() : _idwreport_owner() ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2)
     599             : {
     600           0 : }
     601             : 
     602           0 : idwreport::idwreport(const idwreport &rhs):_idwreport_owner(rhs) ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2)
     603             : {
     604           0 : }
     605             : 
     606           0 : idwreport& idwreport::operator=(const idwreport &rhs)
     607             : {
     608           0 :     if( this==&rhs )
     609           0 :         return *this;
     610           0 :     _idwreport_owner::operator=(rhs);
     611           0 :     return *this;
     612             : }
     613             : 
     614           0 : idwreport::~idwreport()
     615             : {
     616           0 : }
     617             : 
     618             : 
     619             : /*************************************************************************
     620             : This function serializes data structure to string.
     621             : 
     622             : Important properties of s_out:
     623             : * it contains alphanumeric characters, dots, underscores, minus signs
     624             : * these symbols are grouped into words, which are separated by spaces
     625             :   and Windows-style (CR+LF) newlines
     626             : * although  serializer  uses  spaces and CR+LF as separators, you can 
     627             :   replace any separator character by arbitrary combination of spaces,
     628             :   tabs, Windows or Unix newlines. It allows flexible reformatting  of
     629             :   the  string  in  case you want to include it into text or XML file. 
     630             :   But you should not insert separators into the middle of the "words"
     631             :   nor you should change case of letters.
     632             : * s_out can be freely moved between 32-bit and 64-bit systems, little
     633             :   and big endian machines, and so on. You can serialize structure  on
     634             :   32-bit machine and unserialize it on 64-bit one (or vice versa), or
     635             :   serialize  it  on  SPARC  and  unserialize  on  x86.  You  can also 
     636             :   serialize  it  in  C++ version of ALGLIB and unserialize in C# one, 
     637             :   and vice versa.
     638             : *************************************************************************/
     639           0 : void idwserialize(idwmodel &obj, std::string &s_out)
     640             : {
     641             :     jmp_buf _break_jump;
     642             :     alglib_impl::ae_state state;
     643             :     alglib_impl::ae_serializer serializer;
     644             :     alglib_impl::ae_int_t ssize;
     645             : 
     646           0 :     alglib_impl::ae_state_init(&state);
     647           0 :     if( setjmp(_break_jump) )
     648             :     {
     649             : #if !defined(AE_NO_EXCEPTIONS)
     650           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
     651             : #else
     652             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
     653             :         return;
     654             : #endif
     655             :     }
     656           0 :     ae_state_set_break_jump(&state, &_break_jump);
     657           0 :     alglib_impl::ae_serializer_init(&serializer);
     658           0 :     alglib_impl::ae_serializer_alloc_start(&serializer);
     659           0 :     alglib_impl::idwalloc(&serializer, obj.c_ptr(), &state);
     660           0 :     ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer);
     661           0 :     s_out.clear();
     662           0 :     s_out.reserve((size_t)(ssize+1));
     663           0 :     alglib_impl::ae_serializer_sstart_str(&serializer, &s_out);
     664           0 :     alglib_impl::idwserialize(&serializer, obj.c_ptr(), &state);
     665           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
     666           0 :     alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state);
     667           0 :     alglib_impl::ae_serializer_clear(&serializer);
     668           0 :     alglib_impl::ae_state_clear(&state);
     669           0 : }
     670             : /*************************************************************************
     671             : This function unserializes data structure from string.
     672             : *************************************************************************/
     673           0 : void idwunserialize(const std::string &s_in, idwmodel &obj)
     674             : {
     675             :     jmp_buf _break_jump;
     676             :     alglib_impl::ae_state state;
     677             :     alglib_impl::ae_serializer serializer;
     678             : 
     679           0 :     alglib_impl::ae_state_init(&state);
     680           0 :     if( setjmp(_break_jump) )
     681             :     {
     682             : #if !defined(AE_NO_EXCEPTIONS)
     683           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
     684             : #else
     685             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
     686             :         return;
     687             : #endif
     688             :     }
     689           0 :     ae_state_set_break_jump(&state, &_break_jump);
     690           0 :     alglib_impl::ae_serializer_init(&serializer);
     691           0 :     alglib_impl::ae_serializer_ustart_str(&serializer, &s_in);
     692           0 :     alglib_impl::idwunserialize(&serializer, obj.c_ptr(), &state);
     693           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
     694           0 :     alglib_impl::ae_serializer_clear(&serializer);
     695           0 :     alglib_impl::ae_state_clear(&state);
     696           0 : }
     697             : 
     698             : 
     699             : /*************************************************************************
     700             : This function serializes data structure to C++ stream.
     701             : 
     702             : Data stream generated by this function is same as  string  representation
     703             : generated  by  string  version  of  serializer - alphanumeric characters,
     704             : dots, underscores, minus signs, which are grouped into words separated by
     705             : spaces and CR+LF.
     706             : 
     707             : We recommend you to read comments on string version of serializer to find
     708             : out more about serialization of AlGLIB objects.
     709             : *************************************************************************/
     710           0 : void idwserialize(idwmodel &obj, std::ostream &s_out)
     711             : {
     712             :     jmp_buf _break_jump;
     713             :     alglib_impl::ae_state state;
     714             :     alglib_impl::ae_serializer serializer;
     715             : 
     716           0 :     alglib_impl::ae_state_init(&state);
     717           0 :     if( setjmp(_break_jump) )
     718             :     {
     719             : #if !defined(AE_NO_EXCEPTIONS)
     720           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
     721             : #else
     722             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
     723             :         return;
     724             : #endif
     725             :     }
     726           0 :     ae_state_set_break_jump(&state, &_break_jump);
     727           0 :     alglib_impl::ae_serializer_init(&serializer);
     728           0 :     alglib_impl::ae_serializer_alloc_start(&serializer);
     729           0 :     alglib_impl::idwalloc(&serializer, obj.c_ptr(), &state);
     730           0 :     alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask
     731           0 :     alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out);
     732           0 :     alglib_impl::idwserialize(&serializer, obj.c_ptr(), &state);
     733           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
     734           0 :     alglib_impl::ae_serializer_clear(&serializer);
     735           0 :     alglib_impl::ae_state_clear(&state);
     736           0 : }
     737             : /*************************************************************************
     738             : This function unserializes data structure from stream.
     739             : *************************************************************************/
     740           0 : void idwunserialize(const std::istream &s_in, idwmodel &obj)
     741             : {
     742             :     jmp_buf _break_jump;
     743             :     alglib_impl::ae_state state;
     744             :     alglib_impl::ae_serializer serializer;
     745             : 
     746           0 :     alglib_impl::ae_state_init(&state);
     747           0 :     if( setjmp(_break_jump) )
     748             :     {
     749             : #if !defined(AE_NO_EXCEPTIONS)
     750           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
     751             : #else
     752             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
     753             :         return;
     754             : #endif
     755             :     }
     756           0 :     ae_state_set_break_jump(&state, &_break_jump);
     757           0 :     alglib_impl::ae_serializer_init(&serializer);
     758           0 :     alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in);
     759           0 :     alglib_impl::idwunserialize(&serializer, obj.c_ptr(), &state);
     760           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
     761           0 :     alglib_impl::ae_serializer_clear(&serializer);
     762           0 :     alglib_impl::ae_state_clear(&state);
     763           0 : }
     764             : 
     765             : /*************************************************************************
     766             : This function creates buffer  structure  which  can  be  used  to  perform
     767             : parallel  IDW  model  evaluations  (with  one  IDW  model  instance  being
     768             : used from multiple threads, as long as  different  threads  use  different
     769             : instances of buffer).
     770             : 
     771             : This buffer object can be used with  idwtscalcbuf()  function  (here  "ts"
     772             : stands for "thread-safe", "buf" is a suffix which denotes  function  which
     773             : reuses previously allocated output space).
     774             : 
     775             : How to use it:
     776             : * create IDW model structure or load it from file
     777             : * call idwcreatecalcbuffer(), once per thread working with IDW model  (you
     778             :   should call this function only AFTER model initialization, see below for
     779             :   more information)
     780             : * call idwtscalcbuf() from different threads,  with  each  thread  working
     781             :   with its own copy of buffer object.
     782             : 
     783             : INPUT PARAMETERS
     784             :     S           -   IDW model
     785             : 
     786             : OUTPUT PARAMETERS
     787             :     Buf         -   external buffer.
     788             : 
     789             : 
     790             : IMPORTANT: buffer object should be used only with  IDW model object  which
     791             :            was used to initialize buffer. Any attempt to use buffer   with
     792             :            different object is dangerous - you may  get  memory  violation
     793             :            error because sizes of internal arrays do not fit to dimensions
     794             :            of the IDW structure.
     795             : 
     796             : IMPORTANT: you  should  call  this function only for model which was built
     797             :            with model builder (or unserialized from file). Sizes  of  some
     798             :            internal structures are determined only after model  is  built,
     799             :            so buffer object created before model construction  stage  will
     800             :            be useless (and any attempt to use it will result in exception).
     801             : 
     802             :   -- ALGLIB --
     803             :      Copyright 22.10.2018 by Sergey Bochkanov
     804             : *************************************************************************/
     805           0 : void idwcreatecalcbuffer(const idwmodel &s, idwcalcbuffer &buf, const xparams _xparams)
     806             : {
     807             :     jmp_buf _break_jump;
     808             :     alglib_impl::ae_state _alglib_env_state;
     809           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
     810           0 :     if( setjmp(_break_jump) )
     811             :     {
     812             : #if !defined(AE_NO_EXCEPTIONS)
     813           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
     814             : #else
     815             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
     816             :         return;
     817             : #endif
     818             :     }
     819           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
     820           0 :     if( _xparams.flags!=0x0 )
     821           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
     822           0 :     alglib_impl::idwcreatecalcbuffer(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), const_cast<alglib_impl::idwcalcbuffer*>(buf.c_ptr()), &_alglib_env_state);
     823           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
     824           0 :     return;
     825             : }
     826             : 
     827             : /*************************************************************************
     828             : This subroutine creates builder object used  to  generate IDW  model  from
     829             : irregularly sampled (scattered) dataset.  Multidimensional  scalar/vector-
     830             : -valued are supported.
     831             : 
     832             : Builder object is used to fit model to data as follows:
     833             : * builder object is created with idwbuildercreate() function
     834             : * dataset is added with idwbuildersetpoints() function
     835             : * one of the modern IDW algorithms is chosen with either:
     836             :   * idwbuildersetalgomstab()            - Multilayer STABilized algorithm (interpolation)
     837             :   Alternatively, one of the textbook algorithms can be chosen (not recommended):
     838             :   * idwbuildersetalgotextbookshepard()  - textbook Shepard algorithm
     839             :   * idwbuildersetalgotextbookmodshepard()-textbook modified Shepard algorithm
     840             : * finally, model construction is performed with idwfit() function.
     841             : 
     842             :   ! COMMERCIAL EDITION OF ALGLIB:
     843             :   !
     844             :   ! Commercial Edition of ALGLIB includes following important improvements
     845             :   ! of this function:
     846             :   ! * high-performance native backend with same C# interface (C# version)
     847             :   ! * multithreading support (C++ and C# versions)
     848             :   !
     849             :   ! We recommend you to read 'Working with commercial version' section  of
     850             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
     851             :   ! related features provided by commercial edition of ALGLIB.
     852             : 
     853             : INPUT PARAMETERS:
     854             :     NX  -   dimensionality of the argument, NX>=1
     855             :     NY  -   dimensionality of the function being modeled, NY>=1;
     856             :             NY=1 corresponds to classic scalar function, NY>=1 corresponds
     857             :             to vector-valued function.
     858             : 
     859             : OUTPUT PARAMETERS:
     860             :     State-  builder object
     861             : 
     862             :   -- ALGLIB PROJECT --
     863             :      Copyright 22.10.2018 by Bochkanov Sergey
     864             : *************************************************************************/
     865           0 : void idwbuildercreate(const ae_int_t nx, const ae_int_t ny, idwbuilder &state, const xparams _xparams)
     866             : {
     867             :     jmp_buf _break_jump;
     868             :     alglib_impl::ae_state _alglib_env_state;
     869           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
     870           0 :     if( setjmp(_break_jump) )
     871             :     {
     872             : #if !defined(AE_NO_EXCEPTIONS)
     873           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
     874             : #else
     875             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
     876             :         return;
     877             : #endif
     878             :     }
     879           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
     880           0 :     if( _xparams.flags!=0x0 )
     881           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
     882           0 :     alglib_impl::idwbuildercreate(nx, ny, const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), &_alglib_env_state);
     883           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
     884           0 :     return;
     885             : }
     886             : 
     887             : /*************************************************************************
     888             : This function changes number of layers used by IDW-MSTAB algorithm.
     889             : 
     890             : The more layers you have, the finer details can  be  reproduced  with  IDW
     891             : model. The less layers you have, the less memory and CPU time is  consumed
     892             : by the model.
     893             : 
     894             : Memory consumption grows linearly with layers count,  running  time  grows
     895             : sub-linearly.
     896             : 
     897             : The default number of layers is 16, which allows you to reproduce  details
     898             : at distance down to SRad/65536. You will rarely need to change it.
     899             : 
     900             : INPUT PARAMETERS:
     901             :     State   -   builder object
     902             :     NLayers -   NLayers>=1, the number of layers used by the model.
     903             : 
     904             :   -- ALGLIB --
     905             :      Copyright 22.10.2018 by Bochkanov Sergey
     906             : *************************************************************************/
     907           0 : void idwbuildersetnlayers(const idwbuilder &state, const ae_int_t nlayers, const xparams _xparams)
     908             : {
     909             :     jmp_buf _break_jump;
     910             :     alglib_impl::ae_state _alglib_env_state;
     911           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
     912           0 :     if( setjmp(_break_jump) )
     913             :     {
     914             : #if !defined(AE_NO_EXCEPTIONS)
     915           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
     916             : #else
     917             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
     918             :         return;
     919             : #endif
     920             :     }
     921           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
     922           0 :     if( _xparams.flags!=0x0 )
     923           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
     924           0 :     alglib_impl::idwbuildersetnlayers(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), nlayers, &_alglib_env_state);
     925           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
     926           0 :     return;
     927             : }
     928             : 
     929             : /*************************************************************************
     930             : This function adds dataset to the builder object.
     931             : 
     932             : This function overrides results of the previous calls, i.e. multiple calls
     933             : of this function will result in only the last set being added.
     934             : 
     935             : INPUT PARAMETERS:
     936             :     State   -   builder object
     937             :     XY      -   points, array[N,NX+NY]. One row  corresponds to  one point
     938             :                 in the dataset. First NX elements  are  coordinates,  next
     939             :                 NY elements are function values. Array may  be larger than
     940             :                 specified, in  this  case  only leading [N,NX+NY] elements
     941             :                 will be used.
     942             :     N       -   number of points in the dataset, N>=0.
     943             : 
     944             :   -- ALGLIB --
     945             :      Copyright 22.10.2018 by Bochkanov Sergey
     946             : *************************************************************************/
     947           0 : void idwbuildersetpoints(const idwbuilder &state, const real_2d_array &xy, const ae_int_t n, const xparams _xparams)
     948             : {
     949             :     jmp_buf _break_jump;
     950             :     alglib_impl::ae_state _alglib_env_state;
     951           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
     952           0 :     if( setjmp(_break_jump) )
     953             :     {
     954             : #if !defined(AE_NO_EXCEPTIONS)
     955           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
     956             : #else
     957             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
     958             :         return;
     959             : #endif
     960             :     }
     961           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
     962           0 :     if( _xparams.flags!=0x0 )
     963           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
     964           0 :     alglib_impl::idwbuildersetpoints(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, &_alglib_env_state);
     965           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
     966           0 :     return;
     967             : }
     968             : 
     969             : /*************************************************************************
     970             : This function adds dataset to the builder object.
     971             : 
     972             : This function overrides results of the previous calls, i.e. multiple calls
     973             : of this function will result in only the last set being added.
     974             : 
     975             : INPUT PARAMETERS:
     976             :     State   -   builder object
     977             :     XY      -   points, array[N,NX+NY]. One row  corresponds to  one point
     978             :                 in the dataset. First NX elements  are  coordinates,  next
     979             :                 NY elements are function values. Array may  be larger than
     980             :                 specified, in  this  case  only leading [N,NX+NY] elements
     981             :                 will be used.
     982             :     N       -   number of points in the dataset, N>=0.
     983             : 
     984             :   -- ALGLIB --
     985             :      Copyright 22.10.2018 by Bochkanov Sergey
     986             : *************************************************************************/
     987             : #if !defined(AE_NO_EXCEPTIONS)
     988           0 : void idwbuildersetpoints(const idwbuilder &state, const real_2d_array &xy, const xparams _xparams)
     989             : {
     990             :     jmp_buf _break_jump;
     991             :     alglib_impl::ae_state _alglib_env_state;    
     992             :     ae_int_t n;
     993             : 
     994           0 :     n = xy.rows();
     995           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
     996           0 :     if( setjmp(_break_jump) )
     997           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
     998           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
     999           0 :     if( _xparams.flags!=0x0 )
    1000           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1001           0 :     alglib_impl::idwbuildersetpoints(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, &_alglib_env_state);
    1002             : 
    1003           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1004           0 :     return;
    1005             : }
    1006             : #endif
    1007             : 
    1008             : /*************************************************************************
    1009             : This function sets IDW model  construction  algorithm  to  the  Multilayer
    1010             : Stabilized IDW method (IDW-MSTAB), a  latest  incarnation  of  the inverse
    1011             : distance weighting interpolation which fixes shortcomings of  the original
    1012             : and modified Shepard's variants.
    1013             : 
    1014             : The distinctive features of IDW-MSTAB are:
    1015             : 1) exact interpolation  is  pursued  (as  opposed  to  fitting  and  noise
    1016             :    suppression)
    1017             : 2) improved robustness when compared with that of other algorithms:
    1018             :    * MSTAB shows almost no strange  fitting  artifacts  like  ripples  and
    1019             :      sharp spikes (unlike N-dimensional splines and HRBFs)
    1020             :    * MSTAB does not return function values far from the  interval  spanned
    1021             :      by the dataset; say, if all your points have |f|<=1, you  can be sure
    1022             :      that model value won't deviate too much from [-1,+1]
    1023             : 3) good model construction time competing with that of HRBFs  and  bicubic
    1024             :    splines
    1025             : 4) ability to work with any number of dimensions, starting from NX=1
    1026             : 
    1027             : The drawbacks of IDW-MSTAB (and all IDW algorithms in general) are:
    1028             : 1) dependence of the model evaluation time on the search radius
    1029             : 2) bad extrapolation properties, models built by this method  are  usually
    1030             :    conservative in their predictions
    1031             : 
    1032             : Thus, IDW-MSTAB is  a  good  "default"  option  if  you  want  to  perform
    1033             : scattered multidimensional interpolation. Although it has  its  drawbacks,
    1034             : it is easy to use and robust, which makes it a good first step.
    1035             : 
    1036             : 
    1037             : INPUT PARAMETERS:
    1038             :     State   -   builder object
    1039             :     SRad    -   initial search radius, SRad>0 is required. A model  value
    1040             :                 is obtained by "smart" averaging  of  the  dataset  points
    1041             :                 within search radius.
    1042             : 
    1043             : NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
    1044             :         datasets with non-distinct points. In case non-distinct points are
    1045             :         found, an average value for this point will be calculated.
    1046             : 
    1047             : NOTE 2: the memory requirements for model storage are O(NPoints*NLayers).
    1048             :         The model construction needs twice as much memory as model storage.
    1049             : 
    1050             : NOTE 3: by default 16 IDW layers are built which is enough for most cases.
    1051             :         You can change this parameter with idwbuildersetnlayers()  method.
    1052             :         Larger values may be necessary if you need to reproduce  extrafine
    1053             :         details at distances smaller than SRad/65536.  Smaller value   may
    1054             :         be necessary if you have to save memory and  computing  time,  and
    1055             :         ready to sacrifice some model quality.
    1056             : 
    1057             : 
    1058             : ALGORITHM DESCRIPTION
    1059             : 
    1060             : ALGLIB implementation of IDW is somewhat similar to the modified Shepard's
    1061             : method (one with search radius R) but overcomes several of its  drawbacks,
    1062             : namely:
    1063             : 1) a tendency to show stepwise behavior for uniform datasets
    1064             : 2) a tendency to show terrible interpolation properties for highly
    1065             :    nonuniform datasets which often arise in geospatial tasks
    1066             :   (function values are densely sampled across multiple separated
    1067             :   "tracks")
    1068             : 
    1069             : IDW-MSTAB method performs several passes over dataset and builds a sequence
    1070             : of progressively refined IDW models  (layers),  which starts from one with
    1071             : largest search radius SRad  and continues to smaller  search  radii  until
    1072             : required number of  layers  is  built.  Highest  layers  reproduce  global
    1073             : behavior of the target function at larger distances  whilst  lower  layers
    1074             : reproduce fine details at smaller distances.
    1075             : 
    1076             : Each layer is an IDW model built with following modifications:
    1077             : * weights go to zero when distance approach to the current search radius
    1078             : * an additional regularizing term is added to the distance: w=1/(d^2+lambda)
    1079             : * an additional fictional term with unit weight and zero function value is
    1080             :   added in order to promote continuity  properties  at  the  isolated  and
    1081             :   boundary points
    1082             : 
    1083             : By default, 16 layers is built, which is enough for most  cases.  You  can
    1084             : change this parameter with idwbuildersetnlayers() method.
    1085             : 
    1086             :   -- ALGLIB --
    1087             :      Copyright 22.10.2018 by Bochkanov Sergey
    1088             : *************************************************************************/
    1089           0 : void idwbuildersetalgomstab(const idwbuilder &state, const double srad, const xparams _xparams)
    1090             : {
    1091             :     jmp_buf _break_jump;
    1092             :     alglib_impl::ae_state _alglib_env_state;
    1093           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1094           0 :     if( setjmp(_break_jump) )
    1095             :     {
    1096             : #if !defined(AE_NO_EXCEPTIONS)
    1097           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1098             : #else
    1099             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1100             :         return;
    1101             : #endif
    1102             :     }
    1103           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1104           0 :     if( _xparams.flags!=0x0 )
    1105           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1106           0 :     alglib_impl::idwbuildersetalgomstab(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), srad, &_alglib_env_state);
    1107           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1108           0 :     return;
    1109             : }
    1110             : 
    1111             : /*************************************************************************
    1112             : This function sets  IDW  model  construction  algorithm  to  the  textbook
    1113             : Shepard's algorithm with custom (user-specified) power parameter.
    1114             : 
    1115             : IMPORTANT: we do NOT recommend using textbook IDW algorithms because  they
    1116             :            have terrible interpolation properties. Use MSTAB in all cases.
    1117             : 
    1118             : INPUT PARAMETERS:
    1119             :     State   -   builder object
    1120             :     P       -   power parameter, P>0; good value to start with is 2.0
    1121             : 
    1122             : NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
    1123             :         datasets with non-distinct points. In case non-distinct points are
    1124             :         found, an average value for this point will be calculated.
    1125             : 
    1126             :   -- ALGLIB --
    1127             :      Copyright 22.10.2018 by Bochkanov Sergey
    1128             : *************************************************************************/
    1129           0 : void idwbuildersetalgotextbookshepard(const idwbuilder &state, const double p, const xparams _xparams)
    1130             : {
    1131             :     jmp_buf _break_jump;
    1132             :     alglib_impl::ae_state _alglib_env_state;
    1133           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1134           0 :     if( setjmp(_break_jump) )
    1135             :     {
    1136             : #if !defined(AE_NO_EXCEPTIONS)
    1137           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1138             : #else
    1139             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1140             :         return;
    1141             : #endif
    1142             :     }
    1143           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1144           0 :     if( _xparams.flags!=0x0 )
    1145           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1146           0 :     alglib_impl::idwbuildersetalgotextbookshepard(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), p, &_alglib_env_state);
    1147           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1148           0 :     return;
    1149             : }
    1150             : 
    1151             : /*************************************************************************
    1152             : This function sets  IDW  model  construction  algorithm  to the 'textbook'
    1153             : modified Shepard's algorithm with user-specified search radius.
    1154             : 
    1155             : IMPORTANT: we do NOT recommend using textbook IDW algorithms because  they
    1156             :            have terrible interpolation properties. Use MSTAB in all cases.
    1157             : 
    1158             : INPUT PARAMETERS:
    1159             :     State   -   builder object
    1160             :     R       -   search radius
    1161             : 
    1162             : NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
    1163             :         datasets with non-distinct points. In case non-distinct points are
    1164             :         found, an average value for this point will be calculated.
    1165             : 
    1166             :   -- ALGLIB --
    1167             :      Copyright 22.10.2018 by Bochkanov Sergey
    1168             : *************************************************************************/
    1169           0 : void idwbuildersetalgotextbookmodshepard(const idwbuilder &state, const double r, const xparams _xparams)
    1170             : {
    1171             :     jmp_buf _break_jump;
    1172             :     alglib_impl::ae_state _alglib_env_state;
    1173           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1174           0 :     if( setjmp(_break_jump) )
    1175             :     {
    1176             : #if !defined(AE_NO_EXCEPTIONS)
    1177           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1178             : #else
    1179             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1180             :         return;
    1181             : #endif
    1182             :     }
    1183           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1184           0 :     if( _xparams.flags!=0x0 )
    1185           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1186           0 :     alglib_impl::idwbuildersetalgotextbookmodshepard(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), r, &_alglib_env_state);
    1187           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1188           0 :     return;
    1189             : }
    1190             : 
    1191             : /*************************************************************************
    1192             : This function sets prior term (model value at infinity) as  user-specified
    1193             : value.
    1194             : 
    1195             : INPUT PARAMETERS:
    1196             :     S       -   spline builder
    1197             :     V       -   value for user-defined prior
    1198             : 
    1199             : NOTE: for vector-valued models all components of the prior are set to same
    1200             :       user-specified value
    1201             : 
    1202             :   -- ALGLIB --
    1203             :      Copyright 29.10.2018 by Bochkanov Sergey
    1204             : *************************************************************************/
    1205           0 : void idwbuildersetuserterm(const idwbuilder &state, const double v, const xparams _xparams)
    1206             : {
    1207             :     jmp_buf _break_jump;
    1208             :     alglib_impl::ae_state _alglib_env_state;
    1209           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1210           0 :     if( setjmp(_break_jump) )
    1211             :     {
    1212             : #if !defined(AE_NO_EXCEPTIONS)
    1213           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1214             : #else
    1215             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1216             :         return;
    1217             : #endif
    1218             :     }
    1219           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1220           0 :     if( _xparams.flags!=0x0 )
    1221           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1222           0 :     alglib_impl::idwbuildersetuserterm(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), v, &_alglib_env_state);
    1223           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1224           0 :     return;
    1225             : }
    1226             : 
    1227             : /*************************************************************************
    1228             : This function sets constant prior term (model value at infinity).
    1229             : 
    1230             : Constant prior term is determined as mean value over dataset.
    1231             : 
    1232             : INPUT PARAMETERS:
    1233             :     S       -   spline builder
    1234             : 
    1235             :   -- ALGLIB --
    1236             :      Copyright 29.10.2018 by Bochkanov Sergey
    1237             : *************************************************************************/
    1238           0 : void idwbuildersetconstterm(const idwbuilder &state, const xparams _xparams)
    1239             : {
    1240             :     jmp_buf _break_jump;
    1241             :     alglib_impl::ae_state _alglib_env_state;
    1242           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1243           0 :     if( setjmp(_break_jump) )
    1244             :     {
    1245             : #if !defined(AE_NO_EXCEPTIONS)
    1246           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1247             : #else
    1248             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1249             :         return;
    1250             : #endif
    1251             :     }
    1252           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1253           0 :     if( _xparams.flags!=0x0 )
    1254           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1255           0 :     alglib_impl::idwbuildersetconstterm(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), &_alglib_env_state);
    1256           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1257           0 :     return;
    1258             : }
    1259             : 
    1260             : /*************************************************************************
    1261             : This function sets zero prior term (model value at infinity).
    1262             : 
    1263             : INPUT PARAMETERS:
    1264             :     S       -   spline builder
    1265             : 
    1266             :   -- ALGLIB --
    1267             :      Copyright 29.10.2018 by Bochkanov Sergey
    1268             : *************************************************************************/
    1269           0 : void idwbuildersetzeroterm(const idwbuilder &state, const xparams _xparams)
    1270             : {
    1271             :     jmp_buf _break_jump;
    1272             :     alglib_impl::ae_state _alglib_env_state;
    1273           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1274           0 :     if( setjmp(_break_jump) )
    1275             :     {
    1276             : #if !defined(AE_NO_EXCEPTIONS)
    1277           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1278             : #else
    1279             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1280             :         return;
    1281             : #endif
    1282             :     }
    1283           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1284           0 :     if( _xparams.flags!=0x0 )
    1285           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1286           0 :     alglib_impl::idwbuildersetzeroterm(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), &_alglib_env_state);
    1287           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1288           0 :     return;
    1289             : }
    1290             : 
    1291             : /*************************************************************************
    1292             : IDW interpolation: scalar target, 1-dimensional argument
    1293             : 
    1294             : NOTE: this function modifies internal temporaries of the  IDW  model, thus
    1295             :       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
    1296             :       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
    1297             :       thread buffer object.
    1298             : 
    1299             : INPUT PARAMETERS:
    1300             :     S   -   IDW interpolant built with IDW builder
    1301             :     X0  -   argument value
    1302             : 
    1303             : Result:
    1304             :     IDW interpolant S(X0)
    1305             : 
    1306             :   -- ALGLIB --
    1307             :      Copyright 22.10.2018 by Bochkanov Sergey
    1308             : *************************************************************************/
    1309           0 : double idwcalc1(const idwmodel &s, const double x0, const xparams _xparams)
    1310             : {
    1311             :     jmp_buf _break_jump;
    1312             :     alglib_impl::ae_state _alglib_env_state;
    1313           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1314           0 :     if( setjmp(_break_jump) )
    1315             :     {
    1316             : #if !defined(AE_NO_EXCEPTIONS)
    1317           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1318             : #else
    1319             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1320             :         return 0;
    1321             : #endif
    1322             :     }
    1323           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1324           0 :     if( _xparams.flags!=0x0 )
    1325           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1326           0 :     double result = alglib_impl::idwcalc1(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), x0, &_alglib_env_state);
    1327           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1328           0 :     return *(reinterpret_cast<double*>(&result));
    1329             : }
    1330             : 
    1331             : /*************************************************************************
    1332             : IDW interpolation: scalar target, 2-dimensional argument
    1333             : 
    1334             : NOTE: this function modifies internal temporaries of the  IDW  model, thus
    1335             :       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
    1336             :       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
    1337             :       thread buffer object.
    1338             : 
    1339             : INPUT PARAMETERS:
    1340             :     S       -   IDW interpolant built with IDW builder
    1341             :     X0, X1  -   argument value
    1342             : 
    1343             : Result:
    1344             :     IDW interpolant S(X0,X1)
    1345             : 
    1346             :   -- ALGLIB --
    1347             :      Copyright 22.10.2018 by Bochkanov Sergey
    1348             : *************************************************************************/
    1349           0 : double idwcalc2(const idwmodel &s, const double x0, const double x1, const xparams _xparams)
    1350             : {
    1351             :     jmp_buf _break_jump;
    1352             :     alglib_impl::ae_state _alglib_env_state;
    1353           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1354           0 :     if( setjmp(_break_jump) )
    1355             :     {
    1356             : #if !defined(AE_NO_EXCEPTIONS)
    1357           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1358             : #else
    1359             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1360             :         return 0;
    1361             : #endif
    1362             :     }
    1363           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1364           0 :     if( _xparams.flags!=0x0 )
    1365           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1366           0 :     double result = alglib_impl::idwcalc2(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), x0, x1, &_alglib_env_state);
    1367           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1368           0 :     return *(reinterpret_cast<double*>(&result));
    1369             : }
    1370             : 
    1371             : /*************************************************************************
    1372             : IDW interpolation: scalar target, 3-dimensional argument
    1373             : 
    1374             : NOTE: this function modifies internal temporaries of the  IDW  model, thus
    1375             :       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
    1376             :       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
    1377             :       thread buffer object.
    1378             : 
    1379             : INPUT PARAMETERS:
    1380             :     S       -   IDW interpolant built with IDW builder
    1381             :     X0,X1,X2-   argument value
    1382             : 
    1383             : Result:
    1384             :     IDW interpolant S(X0,X1,X2)
    1385             : 
    1386             :   -- ALGLIB --
    1387             :      Copyright 22.10.2018 by Bochkanov Sergey
    1388             : *************************************************************************/
    1389           0 : double idwcalc3(const idwmodel &s, const double x0, const double x1, const double x2, const xparams _xparams)
    1390             : {
    1391             :     jmp_buf _break_jump;
    1392             :     alglib_impl::ae_state _alglib_env_state;
    1393           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1394           0 :     if( setjmp(_break_jump) )
    1395             :     {
    1396             : #if !defined(AE_NO_EXCEPTIONS)
    1397           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1398             : #else
    1399             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1400             :         return 0;
    1401             : #endif
    1402             :     }
    1403           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1404           0 :     if( _xparams.flags!=0x0 )
    1405           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1406           0 :     double result = alglib_impl::idwcalc3(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), x0, x1, x2, &_alglib_env_state);
    1407           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1408           0 :     return *(reinterpret_cast<double*>(&result));
    1409             : }
    1410             : 
    1411             : /*************************************************************************
    1412             : This function calculates values of the IDW model at the given point.
    1413             : 
    1414             : This is general function which can be used for arbitrary NX (dimension  of
    1415             : the space of arguments) and NY (dimension of the function itself). However
    1416             : when  you  have  NY=1  you  may  find more convenient to  use  idwcalc1(),
    1417             : idwcalc2() or idwcalc3().
    1418             : 
    1419             : NOTE: this function modifies internal temporaries of the  IDW  model, thus
    1420             :       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
    1421             :       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
    1422             :       thread buffer object.
    1423             : 
    1424             : INPUT PARAMETERS:
    1425             :     S       -   IDW model
    1426             :     X       -   coordinates, array[NX]. X may have more than NX  elements,
    1427             :                 in this case only leading NX will be used.
    1428             : 
    1429             : OUTPUT PARAMETERS:
    1430             :     Y       -   function value, array[NY]. Y is out-parameter and will  be
    1431             :                 reallocated after call to this function. In case you  want
    1432             :                 to reuse previously allocated Y, you may use idwcalcbuf(),
    1433             :                 which reallocates Y only when it is too small.
    1434             : 
    1435             :   -- ALGLIB --
    1436             :      Copyright 22.10.2018 by Bochkanov Sergey
    1437             : *************************************************************************/
    1438           0 : void idwcalc(const idwmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
    1439             : {
    1440             :     jmp_buf _break_jump;
    1441             :     alglib_impl::ae_state _alglib_env_state;
    1442           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1443           0 :     if( setjmp(_break_jump) )
    1444             :     {
    1445             : #if !defined(AE_NO_EXCEPTIONS)
    1446           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1447             : #else
    1448             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1449             :         return;
    1450             : #endif
    1451             :     }
    1452           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1453           0 :     if( _xparams.flags!=0x0 )
    1454           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1455           0 :     alglib_impl::idwcalc(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), &_alglib_env_state);
    1456           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1457           0 :     return;
    1458             : }
    1459             : 
    1460             : /*************************************************************************
    1461             : This function calculates values of the IDW model at the given point.
    1462             : 
    1463             : Same as idwcalc(), but does not reallocate Y when in is large enough to
    1464             : store function values.
    1465             : 
    1466             : NOTE: this function modifies internal temporaries of the  IDW  model, thus
    1467             :       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
    1468             :       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
    1469             :       thread buffer object.
    1470             : 
    1471             : INPUT PARAMETERS:
    1472             :     S       -   IDW model
    1473             :     X       -   coordinates, array[NX]. X may have more than NX  elements,
    1474             :                 in this case only leading NX will be used.
    1475             :     Y       -   possibly preallocated array
    1476             : 
    1477             : OUTPUT PARAMETERS:
    1478             :     Y       -   function value, array[NY]. Y is not reallocated when it
    1479             :                 is larger than NY.
    1480             : 
    1481             :   -- ALGLIB --
    1482             :      Copyright 22.10.2018 by Bochkanov Sergey
    1483             : *************************************************************************/
    1484           0 : void idwcalcbuf(const idwmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
    1485             : {
    1486             :     jmp_buf _break_jump;
    1487             :     alglib_impl::ae_state _alglib_env_state;
    1488           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1489           0 :     if( setjmp(_break_jump) )
    1490             :     {
    1491             : #if !defined(AE_NO_EXCEPTIONS)
    1492           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1493             : #else
    1494             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1495             :         return;
    1496             : #endif
    1497             :     }
    1498           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1499           0 :     if( _xparams.flags!=0x0 )
    1500           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1501           0 :     alglib_impl::idwcalcbuf(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), &_alglib_env_state);
    1502           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1503           0 :     return;
    1504             : }
    1505             : 
    1506             : /*************************************************************************
    1507             : This function calculates values of the IDW model at the given point, using
    1508             : external  buffer  object  (internal  temporaries  of  IDW  model  are  not
    1509             : modified).
    1510             : 
    1511             : This function allows to use same IDW model object  in  different  threads,
    1512             : assuming  that  different   threads  use different instances of the buffer
    1513             : structure.
    1514             : 
    1515             : INPUT PARAMETERS:
    1516             :     S       -   IDW model, may be shared between different threads
    1517             :     Buf     -   buffer object created for this particular instance of  IDW
    1518             :                 model with idwcreatecalcbuffer().
    1519             :     X       -   coordinates, array[NX]. X may have more than NX  elements,
    1520             :                 in this case only  leading NX will be used.
    1521             :     Y       -   possibly preallocated array
    1522             : 
    1523             : OUTPUT PARAMETERS:
    1524             :     Y       -   function value, array[NY]. Y is not reallocated when it
    1525             :                 is larger than NY.
    1526             : 
    1527             :   -- ALGLIB --
    1528             :      Copyright 13.12.2011 by Bochkanov Sergey
    1529             : *************************************************************************/
    1530           0 : void idwtscalcbuf(const idwmodel &s, const idwcalcbuffer &buf, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
    1531             : {
    1532             :     jmp_buf _break_jump;
    1533             :     alglib_impl::ae_state _alglib_env_state;
    1534           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1535           0 :     if( setjmp(_break_jump) )
    1536             :     {
    1537             : #if !defined(AE_NO_EXCEPTIONS)
    1538           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1539             : #else
    1540             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1541             :         return;
    1542             : #endif
    1543             :     }
    1544           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1545           0 :     if( _xparams.flags!=0x0 )
    1546           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1547           0 :     alglib_impl::idwtscalcbuf(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), const_cast<alglib_impl::idwcalcbuffer*>(buf.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), &_alglib_env_state);
    1548           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1549           0 :     return;
    1550             : }
    1551             : 
    1552             : /*************************************************************************
    1553             : This function fits IDW model to the dataset using current IDW construction
    1554             : algorithm. A model being built and fitting report are returned.
    1555             : 
    1556             : INPUT PARAMETERS:
    1557             :     State   -   builder object
    1558             : 
    1559             : OUTPUT PARAMETERS:
    1560             :     Model   -   an IDW model built with current algorithm
    1561             :     Rep     -   model fitting report, fields of this structure contain
    1562             :                 information about average fitting errors.
    1563             : 
    1564             : NOTE: although IDW-MSTAB algorithm is an  interpolation  method,  i.e.  it
    1565             :       tries to fit the model exactly, it can  handle  datasets  with  non-
    1566             :       distinct points which can not be fit exactly; in such  cases  least-
    1567             :       squares fitting is performed.
    1568             : 
    1569             :   -- ALGLIB --
    1570             :      Copyright 22.10.2018 by Bochkanov Sergey
    1571             : *************************************************************************/
    1572           0 : void idwfit(const idwbuilder &state, idwmodel &model, idwreport &rep, const xparams _xparams)
    1573             : {
    1574             :     jmp_buf _break_jump;
    1575             :     alglib_impl::ae_state _alglib_env_state;
    1576           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1577           0 :     if( setjmp(_break_jump) )
    1578             :     {
    1579             : #if !defined(AE_NO_EXCEPTIONS)
    1580           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1581             : #else
    1582             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1583             :         return;
    1584             : #endif
    1585             :     }
    1586           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1587           0 :     if( _xparams.flags!=0x0 )
    1588           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1589           0 :     alglib_impl::idwfit(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), const_cast<alglib_impl::idwmodel*>(model.c_ptr()), const_cast<alglib_impl::idwreport*>(rep.c_ptr()), &_alglib_env_state);
    1590           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1591           0 :     return;
    1592             : }
    1593             : #endif
    1594             : 
    1595             : #if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD)
    1596             : /*************************************************************************
    1597             : Barycentric interpolant.
    1598             : *************************************************************************/
    1599           0 : _barycentricinterpolant_owner::_barycentricinterpolant_owner()
    1600             : {
    1601             :     jmp_buf _break_jump;
    1602             :     alglib_impl::ae_state _state;
    1603             :     
    1604           0 :     alglib_impl::ae_state_init(&_state);
    1605           0 :     if( setjmp(_break_jump) )
    1606             :     {
    1607           0 :         if( p_struct!=NULL )
    1608             :         {
    1609           0 :             alglib_impl::_barycentricinterpolant_destroy(p_struct);
    1610           0 :             alglib_impl::ae_free(p_struct);
    1611             :         }
    1612           0 :         p_struct = NULL;
    1613             : #if !defined(AE_NO_EXCEPTIONS)
    1614           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    1615             : #else
    1616             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    1617             :         return;
    1618             : #endif
    1619             :     }
    1620           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    1621           0 :     p_struct = NULL;
    1622           0 :     p_struct = (alglib_impl::barycentricinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricinterpolant), &_state);
    1623           0 :     memset(p_struct, 0, sizeof(alglib_impl::barycentricinterpolant));
    1624           0 :     alglib_impl::_barycentricinterpolant_init(p_struct, &_state, ae_false);
    1625           0 :     ae_state_clear(&_state);
    1626           0 : }
    1627             : 
    1628           0 : _barycentricinterpolant_owner::_barycentricinterpolant_owner(const _barycentricinterpolant_owner &rhs)
    1629             : {
    1630             :     jmp_buf _break_jump;
    1631             :     alglib_impl::ae_state _state;
    1632             :     
    1633           0 :     alglib_impl::ae_state_init(&_state);
    1634           0 :     if( setjmp(_break_jump) )
    1635             :     {
    1636           0 :         if( p_struct!=NULL )
    1637             :         {
    1638           0 :             alglib_impl::_barycentricinterpolant_destroy(p_struct);
    1639           0 :             alglib_impl::ae_free(p_struct);
    1640             :         }
    1641           0 :         p_struct = NULL;
    1642             : #if !defined(AE_NO_EXCEPTIONS)
    1643           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    1644             : #else
    1645             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    1646             :         return;
    1647             : #endif
    1648             :     }
    1649           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    1650           0 :     p_struct = NULL;
    1651           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricinterpolant copy constructor failure (source is not initialized)", &_state);
    1652           0 :     p_struct = (alglib_impl::barycentricinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricinterpolant), &_state);
    1653           0 :     memset(p_struct, 0, sizeof(alglib_impl::barycentricinterpolant));
    1654           0 :     alglib_impl::_barycentricinterpolant_init_copy(p_struct, const_cast<alglib_impl::barycentricinterpolant*>(rhs.p_struct), &_state, ae_false);
    1655           0 :     ae_state_clear(&_state);
    1656           0 : }
    1657             : 
    1658           0 : _barycentricinterpolant_owner& _barycentricinterpolant_owner::operator=(const _barycentricinterpolant_owner &rhs)
    1659             : {
    1660           0 :     if( this==&rhs )
    1661           0 :         return *this;
    1662             :     jmp_buf _break_jump;
    1663             :     alglib_impl::ae_state _state;
    1664             :     
    1665           0 :     alglib_impl::ae_state_init(&_state);
    1666           0 :     if( setjmp(_break_jump) )
    1667             :     {
    1668             : #if !defined(AE_NO_EXCEPTIONS)
    1669           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    1670             : #else
    1671             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    1672             :         return *this;
    1673             : #endif
    1674             :     }
    1675           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    1676           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: barycentricinterpolant assignment constructor failure (destination is not initialized)", &_state);
    1677           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricinterpolant assignment constructor failure (source is not initialized)", &_state);
    1678           0 :     alglib_impl::_barycentricinterpolant_destroy(p_struct);
    1679           0 :     memset(p_struct, 0, sizeof(alglib_impl::barycentricinterpolant));
    1680           0 :     alglib_impl::_barycentricinterpolant_init_copy(p_struct, const_cast<alglib_impl::barycentricinterpolant*>(rhs.p_struct), &_state, ae_false);
    1681           0 :     ae_state_clear(&_state);
    1682           0 :     return *this;
    1683             : }
    1684             : 
    1685           0 : _barycentricinterpolant_owner::~_barycentricinterpolant_owner()
    1686             : {
    1687           0 :     if( p_struct!=NULL )
    1688             :     {
    1689           0 :         alglib_impl::_barycentricinterpolant_destroy(p_struct);
    1690           0 :         ae_free(p_struct);
    1691             :     }
    1692           0 : }
    1693             : 
    1694           0 : alglib_impl::barycentricinterpolant* _barycentricinterpolant_owner::c_ptr()
    1695             : {
    1696           0 :     return p_struct;
    1697             : }
    1698             : 
    1699           0 : alglib_impl::barycentricinterpolant* _barycentricinterpolant_owner::c_ptr() const
    1700             : {
    1701           0 :     return const_cast<alglib_impl::barycentricinterpolant*>(p_struct);
    1702             : }
    1703           0 : barycentricinterpolant::barycentricinterpolant() : _barycentricinterpolant_owner() 
    1704             : {
    1705           0 : }
    1706             : 
    1707           0 : barycentricinterpolant::barycentricinterpolant(const barycentricinterpolant &rhs):_barycentricinterpolant_owner(rhs) 
    1708             : {
    1709           0 : }
    1710             : 
    1711           0 : barycentricinterpolant& barycentricinterpolant::operator=(const barycentricinterpolant &rhs)
    1712             : {
    1713           0 :     if( this==&rhs )
    1714           0 :         return *this;
    1715           0 :     _barycentricinterpolant_owner::operator=(rhs);
    1716           0 :     return *this;
    1717             : }
    1718             : 
    1719           0 : barycentricinterpolant::~barycentricinterpolant()
    1720             : {
    1721           0 : }
    1722             : 
    1723             : /*************************************************************************
    1724             : Rational interpolation using barycentric formula
    1725             : 
    1726             : F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))
    1727             : 
    1728             : Input parameters:
    1729             :     B   -   barycentric interpolant built with one of model building
    1730             :             subroutines.
    1731             :     T   -   interpolation point
    1732             : 
    1733             : Result:
    1734             :     barycentric interpolant F(t)
    1735             : 
    1736             :   -- ALGLIB --
    1737             :      Copyright 17.08.2009 by Bochkanov Sergey
    1738             : *************************************************************************/
    1739           0 : double barycentriccalc(const barycentricinterpolant &b, const double t, const xparams _xparams)
    1740             : {
    1741             :     jmp_buf _break_jump;
    1742             :     alglib_impl::ae_state _alglib_env_state;
    1743           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1744           0 :     if( setjmp(_break_jump) )
    1745             :     {
    1746             : #if !defined(AE_NO_EXCEPTIONS)
    1747           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1748             : #else
    1749             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1750             :         return 0;
    1751             : #endif
    1752             :     }
    1753           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1754           0 :     if( _xparams.flags!=0x0 )
    1755           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1756           0 :     double result = alglib_impl::barycentriccalc(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), t, &_alglib_env_state);
    1757           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1758           0 :     return *(reinterpret_cast<double*>(&result));
    1759             : }
    1760             : 
    1761             : /*************************************************************************
    1762             : Differentiation of barycentric interpolant: first derivative.
    1763             : 
    1764             : Algorithm used in this subroutine is very robust and should not fail until
    1765             : provided with values too close to MaxRealNumber  (usually  MaxRealNumber/N
    1766             : or greater will overflow).
    1767             : 
    1768             : INPUT PARAMETERS:
    1769             :     B   -   barycentric interpolant built with one of model building
    1770             :             subroutines.
    1771             :     T   -   interpolation point
    1772             : 
    1773             : OUTPUT PARAMETERS:
    1774             :     F   -   barycentric interpolant at T
    1775             :     DF  -   first derivative
    1776             : 
    1777             : NOTE
    1778             : 
    1779             : 
    1780             :   -- ALGLIB --
    1781             :      Copyright 17.08.2009 by Bochkanov Sergey
    1782             : *************************************************************************/
    1783           0 : void barycentricdiff1(const barycentricinterpolant &b, const double t, double &f, double &df, const xparams _xparams)
    1784             : {
    1785             :     jmp_buf _break_jump;
    1786             :     alglib_impl::ae_state _alglib_env_state;
    1787           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1788           0 :     if( setjmp(_break_jump) )
    1789             :     {
    1790             : #if !defined(AE_NO_EXCEPTIONS)
    1791           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1792             : #else
    1793             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1794             :         return;
    1795             : #endif
    1796             :     }
    1797           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1798           0 :     if( _xparams.flags!=0x0 )
    1799           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1800           0 :     alglib_impl::barycentricdiff1(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), t, &f, &df, &_alglib_env_state);
    1801           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1802           0 :     return;
    1803             : }
    1804             : 
    1805             : /*************************************************************************
    1806             : Differentiation of barycentric interpolant: first/second derivatives.
    1807             : 
    1808             : INPUT PARAMETERS:
    1809             :     B   -   barycentric interpolant built with one of model building
    1810             :             subroutines.
    1811             :     T   -   interpolation point
    1812             : 
    1813             : OUTPUT PARAMETERS:
    1814             :     F   -   barycentric interpolant at T
    1815             :     DF  -   first derivative
    1816             :     D2F -   second derivative
    1817             : 
    1818             : NOTE: this algorithm may fail due to overflow/underflor if  used  on  data
    1819             : whose values are close to MaxRealNumber or MinRealNumber.  Use more robust
    1820             : BarycentricDiff1() subroutine in such cases.
    1821             : 
    1822             : 
    1823             :   -- ALGLIB --
    1824             :      Copyright 17.08.2009 by Bochkanov Sergey
    1825             : *************************************************************************/
    1826           0 : void barycentricdiff2(const barycentricinterpolant &b, const double t, double &f, double &df, double &d2f, const xparams _xparams)
    1827             : {
    1828             :     jmp_buf _break_jump;
    1829             :     alglib_impl::ae_state _alglib_env_state;
    1830           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1831           0 :     if( setjmp(_break_jump) )
    1832             :     {
    1833             : #if !defined(AE_NO_EXCEPTIONS)
    1834           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1835             : #else
    1836             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1837             :         return;
    1838             : #endif
    1839             :     }
    1840           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1841           0 :     if( _xparams.flags!=0x0 )
    1842           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1843           0 :     alglib_impl::barycentricdiff2(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), t, &f, &df, &d2f, &_alglib_env_state);
    1844           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1845           0 :     return;
    1846             : }
    1847             : 
    1848             : /*************************************************************************
    1849             : This subroutine performs linear transformation of the argument.
    1850             : 
    1851             : INPUT PARAMETERS:
    1852             :     B       -   rational interpolant in barycentric form
    1853             :     CA, CB  -   transformation coefficients: x = CA*t + CB
    1854             : 
    1855             : OUTPUT PARAMETERS:
    1856             :     B       -   transformed interpolant with X replaced by T
    1857             : 
    1858             :   -- ALGLIB PROJECT --
    1859             :      Copyright 19.08.2009 by Bochkanov Sergey
    1860             : *************************************************************************/
    1861           0 : void barycentriclintransx(const barycentricinterpolant &b, const double ca, const double cb, const xparams _xparams)
    1862             : {
    1863             :     jmp_buf _break_jump;
    1864             :     alglib_impl::ae_state _alglib_env_state;
    1865           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1866           0 :     if( setjmp(_break_jump) )
    1867             :     {
    1868             : #if !defined(AE_NO_EXCEPTIONS)
    1869           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1870             : #else
    1871             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1872             :         return;
    1873             : #endif
    1874             :     }
    1875           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1876           0 :     if( _xparams.flags!=0x0 )
    1877           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1878           0 :     alglib_impl::barycentriclintransx(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), ca, cb, &_alglib_env_state);
    1879           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1880           0 :     return;
    1881             : }
    1882             : 
    1883             : /*************************************************************************
    1884             : This  subroutine   performs   linear  transformation  of  the  barycentric
    1885             : interpolant.
    1886             : 
    1887             : INPUT PARAMETERS:
    1888             :     B       -   rational interpolant in barycentric form
    1889             :     CA, CB  -   transformation coefficients: B2(x) = CA*B(x) + CB
    1890             : 
    1891             : OUTPUT PARAMETERS:
    1892             :     B       -   transformed interpolant
    1893             : 
    1894             :   -- ALGLIB PROJECT --
    1895             :      Copyright 19.08.2009 by Bochkanov Sergey
    1896             : *************************************************************************/
    1897           0 : void barycentriclintransy(const barycentricinterpolant &b, const double ca, const double cb, const xparams _xparams)
    1898             : {
    1899             :     jmp_buf _break_jump;
    1900             :     alglib_impl::ae_state _alglib_env_state;
    1901           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1902           0 :     if( setjmp(_break_jump) )
    1903             :     {
    1904             : #if !defined(AE_NO_EXCEPTIONS)
    1905           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1906             : #else
    1907             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1908             :         return;
    1909             : #endif
    1910             :     }
    1911           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1912           0 :     if( _xparams.flags!=0x0 )
    1913           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1914           0 :     alglib_impl::barycentriclintransy(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), ca, cb, &_alglib_env_state);
    1915           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1916           0 :     return;
    1917             : }
    1918             : 
    1919             : /*************************************************************************
    1920             : Extracts X/Y/W arrays from rational interpolant
    1921             : 
    1922             : INPUT PARAMETERS:
    1923             :     B   -   barycentric interpolant
    1924             : 
    1925             : OUTPUT PARAMETERS:
    1926             :     N   -   nodes count, N>0
    1927             :     X   -   interpolation nodes, array[0..N-1]
    1928             :     F   -   function values, array[0..N-1]
    1929             :     W   -   barycentric weights, array[0..N-1]
    1930             : 
    1931             :   -- ALGLIB --
    1932             :      Copyright 17.08.2009 by Bochkanov Sergey
    1933             : *************************************************************************/
    1934           0 : void barycentricunpack(const barycentricinterpolant &b, ae_int_t &n, real_1d_array &x, real_1d_array &y, real_1d_array &w, const xparams _xparams)
    1935             : {
    1936             :     jmp_buf _break_jump;
    1937             :     alglib_impl::ae_state _alglib_env_state;
    1938           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1939           0 :     if( setjmp(_break_jump) )
    1940             :     {
    1941             : #if !defined(AE_NO_EXCEPTIONS)
    1942           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1943             : #else
    1944             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1945             :         return;
    1946             : #endif
    1947             :     }
    1948           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1949           0 :     if( _xparams.flags!=0x0 )
    1950           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1951           0 :     alglib_impl::barycentricunpack(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), &n, const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), &_alglib_env_state);
    1952           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1953           0 :     return;
    1954             : }
    1955             : 
    1956             : /*************************************************************************
    1957             : Rational interpolant from X/Y/W arrays
    1958             : 
    1959             : F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))
    1960             : 
    1961             : INPUT PARAMETERS:
    1962             :     X   -   interpolation nodes, array[0..N-1]
    1963             :     F   -   function values, array[0..N-1]
    1964             :     W   -   barycentric weights, array[0..N-1]
    1965             :     N   -   nodes count, N>0
    1966             : 
    1967             : OUTPUT PARAMETERS:
    1968             :     B   -   barycentric interpolant built from (X, Y, W)
    1969             : 
    1970             :   -- ALGLIB --
    1971             :      Copyright 17.08.2009 by Bochkanov Sergey
    1972             : *************************************************************************/
    1973           0 : 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)
    1974             : {
    1975             :     jmp_buf _break_jump;
    1976             :     alglib_impl::ae_state _alglib_env_state;
    1977           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    1978           0 :     if( setjmp(_break_jump) )
    1979             :     {
    1980             : #if !defined(AE_NO_EXCEPTIONS)
    1981           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    1982             : #else
    1983             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    1984             :         return;
    1985             : #endif
    1986             :     }
    1987           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    1988           0 :     if( _xparams.flags!=0x0 )
    1989           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    1990           0 :     alglib_impl::barycentricbuildxyw(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), n, const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), &_alglib_env_state);
    1991           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    1992           0 :     return;
    1993             : }
    1994             : 
    1995             : /*************************************************************************
    1996             : Rational interpolant without poles
    1997             : 
    1998             : The subroutine constructs the rational interpolating function without real
    1999             : poles  (see  'Barycentric rational interpolation with no  poles  and  high
    2000             : rates of approximation', Michael S. Floater. and  Kai  Hormann,  for  more
    2001             : information on this subject).
    2002             : 
    2003             : Input parameters:
    2004             :     X   -   interpolation nodes, array[0..N-1].
    2005             :     Y   -   function values, array[0..N-1].
    2006             :     N   -   number of nodes, N>0.
    2007             :     D   -   order of the interpolation scheme, 0 <= D <= N-1.
    2008             :             D<0 will cause an error.
    2009             :             D>=N it will be replaced with D=N-1.
    2010             :             if you don't know what D to choose, use small value about 3-5.
    2011             : 
    2012             : Output parameters:
    2013             :     B   -   barycentric interpolant.
    2014             : 
    2015             : Note:
    2016             :     this algorithm always succeeds and calculates the weights  with  close
    2017             :     to machine precision.
    2018             : 
    2019             :   -- ALGLIB PROJECT --
    2020             :      Copyright 17.06.2007 by Bochkanov Sergey
    2021             : *************************************************************************/
    2022           0 : 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)
    2023             : {
    2024             :     jmp_buf _break_jump;
    2025             :     alglib_impl::ae_state _alglib_env_state;
    2026           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2027           0 :     if( setjmp(_break_jump) )
    2028             :     {
    2029             : #if !defined(AE_NO_EXCEPTIONS)
    2030           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    2031             : #else
    2032             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    2033             :         return;
    2034             : #endif
    2035             :     }
    2036           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    2037           0 :     if( _xparams.flags!=0x0 )
    2038           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    2039           0 :     alglib_impl::barycentricbuildfloaterhormann(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, d, const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), &_alglib_env_state);
    2040           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    2041           0 :     return;
    2042             : }
    2043             : #endif
    2044             : 
    2045             : #if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD)
    2046             : /*************************************************************************
    2047             : Fits least squares (LS) circle (or NX-dimensional sphere) to data  (a  set
    2048             : of points in NX-dimensional space).
    2049             : 
    2050             : Least squares circle minimizes sum of squared deviations between distances
    2051             : from points to the center and  some  "candidate"  radius,  which  is  also
    2052             : fitted to the data.
    2053             : 
    2054             : INPUT PARAMETERS:
    2055             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
    2056             :                 One row = one point in NX-dimensional space.
    2057             :     NPoints -   dataset size, NPoints>0
    2058             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
    2059             : 
    2060             : OUTPUT PARAMETERS:
    2061             :     CX      -   central point for a sphere
    2062             :     R       -   radius
    2063             : 
    2064             :   -- ALGLIB --
    2065             :      Copyright 07.05.2018 by Bochkanov Sergey
    2066             : *************************************************************************/
    2067           0 : 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)
    2068             : {
    2069             :     jmp_buf _break_jump;
    2070             :     alglib_impl::ae_state _alglib_env_state;
    2071           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2072           0 :     if( setjmp(_break_jump) )
    2073             :     {
    2074             : #if !defined(AE_NO_EXCEPTIONS)
    2075           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    2076             : #else
    2077             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    2078             :         return;
    2079             : #endif
    2080             :     }
    2081           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    2082           0 :     if( _xparams.flags!=0x0 )
    2083           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    2084           0 :     alglib_impl::fitspherels(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), npoints, nx, const_cast<alglib_impl::ae_vector*>(cx.c_ptr()), &r, &_alglib_env_state);
    2085           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    2086           0 :     return;
    2087             : }
    2088             : 
    2089             : /*************************************************************************
    2090             : Fits minimum circumscribed (MC) circle (or NX-dimensional sphere) to  data
    2091             : (a set of points in NX-dimensional space).
    2092             : 
    2093             : INPUT PARAMETERS:
    2094             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
    2095             :                 One row = one point in NX-dimensional space.
    2096             :     NPoints -   dataset size, NPoints>0
    2097             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
    2098             : 
    2099             : OUTPUT PARAMETERS:
    2100             :     CX      -   central point for a sphere
    2101             :     RHi     -   radius
    2102             : 
    2103             : NOTE: this function is an easy-to-use wrapper around more powerful "expert"
    2104             :       function fitspherex().
    2105             : 
    2106             :       This  wrapper  is optimized  for  ease of use and stability - at the
    2107             :       cost of somewhat lower  performance  (we  have  to  use  very  tight
    2108             :       stopping criteria for inner optimizer because we want to  make  sure
    2109             :       that it will converge on any dataset).
    2110             : 
    2111             :       If you are ready to experiment with settings of  "expert"  function,
    2112             :       you can achieve ~2-4x speedup over standard "bulletproof" settings.
    2113             : 
    2114             : 
    2115             :   -- ALGLIB --
    2116             :      Copyright 14.04.2017 by Bochkanov Sergey
    2117             : *************************************************************************/
    2118           0 : 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)
    2119             : {
    2120             :     jmp_buf _break_jump;
    2121             :     alglib_impl::ae_state _alglib_env_state;
    2122           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2123           0 :     if( setjmp(_break_jump) )
    2124             :     {
    2125             : #if !defined(AE_NO_EXCEPTIONS)
    2126           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    2127             : #else
    2128             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    2129             :         return;
    2130             : #endif
    2131             :     }
    2132           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    2133           0 :     if( _xparams.flags!=0x0 )
    2134           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    2135           0 :     alglib_impl::fitspheremc(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), npoints, nx, const_cast<alglib_impl::ae_vector*>(cx.c_ptr()), &rhi, &_alglib_env_state);
    2136           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    2137           0 :     return;
    2138             : }
    2139             : 
    2140             : /*************************************************************************
    2141             : Fits maximum inscribed circle (or NX-dimensional sphere) to data (a set of
    2142             : points in NX-dimensional space).
    2143             : 
    2144             : INPUT PARAMETERS:
    2145             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
    2146             :                 One row = one point in NX-dimensional space.
    2147             :     NPoints -   dataset size, NPoints>0
    2148             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
    2149             : 
    2150             : OUTPUT PARAMETERS:
    2151             :     CX      -   central point for a sphere
    2152             :     RLo     -   radius
    2153             : 
    2154             : NOTE: this function is an easy-to-use wrapper around more powerful "expert"
    2155             :       function fitspherex().
    2156             : 
    2157             :       This  wrapper  is optimized  for  ease of use and stability - at the
    2158             :       cost of somewhat lower  performance  (we  have  to  use  very  tight
    2159             :       stopping criteria for inner optimizer because we want to  make  sure
    2160             :       that it will converge on any dataset).
    2161             : 
    2162             :       If you are ready to experiment with settings of  "expert"  function,
    2163             :       you can achieve ~2-4x speedup over standard "bulletproof" settings.
    2164             : 
    2165             : 
    2166             :   -- ALGLIB --
    2167             :      Copyright 14.04.2017 by Bochkanov Sergey
    2168             : *************************************************************************/
    2169           0 : 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)
    2170             : {
    2171             :     jmp_buf _break_jump;
    2172             :     alglib_impl::ae_state _alglib_env_state;
    2173           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2174           0 :     if( setjmp(_break_jump) )
    2175             :     {
    2176             : #if !defined(AE_NO_EXCEPTIONS)
    2177           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    2178             : #else
    2179             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    2180             :         return;
    2181             : #endif
    2182             :     }
    2183           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    2184           0 :     if( _xparams.flags!=0x0 )
    2185           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    2186           0 :     alglib_impl::fitspheremi(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), npoints, nx, const_cast<alglib_impl::ae_vector*>(cx.c_ptr()), &rlo, &_alglib_env_state);
    2187           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    2188           0 :     return;
    2189             : }
    2190             : 
    2191             : /*************************************************************************
    2192             : Fits minimum zone circle (or NX-dimensional sphere)  to  data  (a  set  of
    2193             : points in NX-dimensional space).
    2194             : 
    2195             : INPUT PARAMETERS:
    2196             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
    2197             :                 One row = one point in NX-dimensional space.
    2198             :     NPoints -   dataset size, NPoints>0
    2199             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
    2200             : 
    2201             : OUTPUT PARAMETERS:
    2202             :     CX      -   central point for a sphere
    2203             :     RLo     -   radius of inscribed circle
    2204             :     RHo     -   radius of circumscribed circle
    2205             : 
    2206             : NOTE: this function is an easy-to-use wrapper around more powerful "expert"
    2207             :       function fitspherex().
    2208             : 
    2209             :       This  wrapper  is optimized  for  ease of use and stability - at the
    2210             :       cost of somewhat lower  performance  (we  have  to  use  very  tight
    2211             :       stopping criteria for inner optimizer because we want to  make  sure
    2212             :       that it will converge on any dataset).
    2213             : 
    2214             :       If you are ready to experiment with settings of  "expert"  function,
    2215             :       you can achieve ~2-4x speedup over standard "bulletproof" settings.
    2216             : 
    2217             : 
    2218             :   -- ALGLIB --
    2219             :      Copyright 14.04.2017 by Bochkanov Sergey
    2220             : *************************************************************************/
    2221           0 : 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)
    2222             : {
    2223             :     jmp_buf _break_jump;
    2224             :     alglib_impl::ae_state _alglib_env_state;
    2225           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2226           0 :     if( setjmp(_break_jump) )
    2227             :     {
    2228             : #if !defined(AE_NO_EXCEPTIONS)
    2229           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    2230             : #else
    2231             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    2232             :         return;
    2233             : #endif
    2234             :     }
    2235           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    2236           0 :     if( _xparams.flags!=0x0 )
    2237           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    2238           0 :     alglib_impl::fitspheremz(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), npoints, nx, const_cast<alglib_impl::ae_vector*>(cx.c_ptr()), &rlo, &rhi, &_alglib_env_state);
    2239           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    2240           0 :     return;
    2241             : }
    2242             : 
    2243             : /*************************************************************************
    2244             : Fitting minimum circumscribed, maximum inscribed or minimum  zone  circles
    2245             : (or NX-dimensional spheres)  to  data  (a  set of points in NX-dimensional
    2246             : space).
    2247             : 
    2248             : This  is  expert  function  which  allows  to  tweak  many  parameters  of
    2249             : underlying nonlinear solver:
    2250             : * stopping criteria for inner iterations
    2251             : * number of outer iterations
    2252             : * penalty coefficient used to handle  nonlinear  constraints  (we  convert
    2253             :   unconstrained nonsmooth optimization problem ivolving max() and/or min()
    2254             :   operations to quadratically constrained smooth one).
    2255             : 
    2256             : You may tweak all these parameters or only some  of  them,  leaving  other
    2257             : ones at their default state - just specify zero  value,  and  solver  will
    2258             : fill it with appropriate default one.
    2259             : 
    2260             : These comments also include some discussion of  approach  used  to  handle
    2261             : such unusual fitting problem,  its  stability,  drawbacks  of  alternative
    2262             : methods, and convergence properties.
    2263             : 
    2264             : INPUT PARAMETERS:
    2265             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
    2266             :                 One row = one point in NX-dimensional space.
    2267             :     NPoints -   dataset size, NPoints>0
    2268             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
    2269             :     ProblemType-used to encode problem type:
    2270             :                 * 0 for least squares circle
    2271             :                 * 1 for minimum circumscribed circle/sphere fitting (MC)
    2272             :                 * 2 for  maximum inscribed circle/sphere fitting (MI)
    2273             :                 * 3 for minimum zone circle fitting (difference between
    2274             :                     Rhi and Rlo is minimized), denoted as MZ
    2275             :     EpsX    -   stopping condition for NLC optimizer:
    2276             :                 * must be non-negative
    2277             :                 * use 0 to choose default value (1.0E-12 is used by default)
    2278             :                 * you may specify larger values, up to 1.0E-6, if you want
    2279             :                   to   speed-up   solver;   NLC   solver  performs several
    2280             :                   preconditioned  outer  iterations,   so   final   result
    2281             :                   typically has precision much better than EpsX.
    2282             :     AULIts  -   number of outer iterations performed by NLC optimizer:
    2283             :                 * must be non-negative
    2284             :                 * use 0 to choose default value (20 is used by default)
    2285             :                 * you may specify values smaller than 20 if you want to
    2286             :                   speed up solver; 10 often results in good combination of
    2287             :                   precision and speed; sometimes you may get good results
    2288             :                   with just 6 outer iterations.
    2289             :                 Ignored for ProblemType=0.
    2290             :     Penalty -   penalty coefficient for NLC optimizer:
    2291             :                 * must be non-negative
    2292             :                 * use 0 to choose default value (1.0E6 in current version)
    2293             :                 * it should be really large, 1.0E6...1.0E7 is a good value
    2294             :                   to start from;
    2295             :                 * generally, default value is good enough
    2296             :                 Ignored for ProblemType=0.
    2297             : 
    2298             : OUTPUT PARAMETERS:
    2299             :     CX      -   central point for a sphere
    2300             :     RLo     -   radius:
    2301             :                 * for ProblemType=2,3, radius of the inscribed sphere
    2302             :                 * for ProblemType=0 - radius of the least squares sphere
    2303             :                 * for ProblemType=1 - zero
    2304             :     RHo     -   radius:
    2305             :                 * for ProblemType=1,3, radius of the circumscribed sphere
    2306             :                 * for ProblemType=0 - radius of the least squares sphere
    2307             :                 * for ProblemType=2 - zero
    2308             : 
    2309             : NOTE: ON THE UNIQUENESS OF SOLUTIONS
    2310             : 
    2311             : ALGLIB provides solution to several related circle fitting  problems:   MC
    2312             : (minimum circumscribed), MI (maximum inscribed)   and   MZ  (minimum zone)
    2313             : fitting, LS (least squares) fitting.
    2314             : 
    2315             : It  is  important  to  note  that  among these problems only MC and LS are
    2316             : convex and have unique solution independently from starting point.
    2317             : 
    2318             : As  for MI,  it  may (or  may  not, depending on dataset properties)  have
    2319             : multiple solutions, and it always  has  one degenerate solution C=infinity
    2320             : which corresponds to infinitely large radius. Thus, there are no guarantees
    2321             : that solution to  MI returned by this solver will be the best one (and  no
    2322             : one can provide you with such guarantee because problem is  NP-hard).  The
    2323             : only guarantee you have is that this solution is locally optimal, i.e.  it
    2324             : can not be improved by infinitesimally small tweaks in the parameters.
    2325             : 
    2326             : It  is  also  possible  to "run away" to infinity when  started  from  bad
    2327             : initial point located outside of point cloud (or when point cloud does not
    2328             : span entire circumference/surface of the sphere).
    2329             : 
    2330             : Finally,  MZ (minimum zone circle) stands somewhere between MC  and  MI in
    2331             : stability. It is somewhat regularized by "circumscribed" term of the merit
    2332             : function; however, solutions to  MZ may be non-unique, and in some unlucky
    2333             : cases it is also possible to "run away to infinity".
    2334             : 
    2335             : 
    2336             : NOTE: ON THE NONLINEARLY CONSTRAINED PROGRAMMING APPROACH
    2337             : 
    2338             : The problem formulation for MC  (minimum circumscribed   circle;  for  the
    2339             : sake of simplicity we omit MZ and MI here) is:
    2340             : 
    2341             :         [     [         ]2 ]
    2342             :     min [ max [ XY[i]-C ]  ]
    2343             :      C  [  i  [         ]  ]
    2344             : 
    2345             : i.e. it is unconstrained nonsmooth optimization problem of finding  "best"
    2346             : central point, with radius R being unambiguously  determined  from  C.  In
    2347             : order to move away from non-smoothness we use following reformulation:
    2348             : 
    2349             :         [   ]                  [         ]2
    2350             :     min [ R ] subject to R>=0, [ XY[i]-C ]  <= R^2
    2351             :     C,R [   ]                  [         ]
    2352             : 
    2353             : i.e. it becomes smooth quadratically constrained optimization problem with
    2354             : linear target function. Such problem statement is 100% equivalent  to  the
    2355             : original nonsmooth one, but much easier  to  approach.  We solve  it  with
    2356             : MinNLC solver provided by ALGLIB.
    2357             : 
    2358             : 
    2359             : NOTE: ON INSTABILITY OF SEQUENTIAL LINEARIZATION APPROACH
    2360             : 
    2361             : ALGLIB  has  nonlinearly  constrained  solver which proved to be stable on
    2362             : such problems. However, some authors proposed to linearize constraints  in
    2363             : the vicinity of current approximation (Ci,Ri) and to get next  approximate
    2364             : solution (Ci+1,Ri+1) as solution to linear programming problem. Obviously,
    2365             : LP problems are easier than nonlinearly constrained ones.
    2366             : 
    2367             : Indeed,  such approach  to   MC/MI/MZ   resulted   in  ~10-20x increase in
    2368             : performance (when compared with NLC solver). However, it turned  out  that
    2369             : in some cases linearized model fails to predict correct direction for next
    2370             : step and tells us that we converged to solution even when we are still 2-4
    2371             : digits of precision away from it.
    2372             : 
    2373             : It is important that it is not failure of LP solver - it is failure of the
    2374             : linear model;  even  when  solved  exactly,  it  fails  to  handle  subtle
    2375             : nonlinearities which arise near the solution. We validated it by comparing
    2376             : results returned by ALGLIB linear solver with that of MATLAB.
    2377             : 
    2378             : In our experiments with linearization:
    2379             : * MC failed most often, at both realistic and synthetic datasets
    2380             : * MI sometimes failed, but sometimes succeeded
    2381             : * MZ often  succeeded; our guess is that presence of two independent  sets
    2382             :   of constraints (one set for Rlo and another one for Rhi) and  two  terms
    2383             :   in the target function (Rlo and Rhi) regularizes task,  so  when  linear
    2384             :   model fails to handle nonlinearities from Rlo, it uses  Rhi  as  a  hint
    2385             :   (and vice versa).
    2386             : 
    2387             : Because linearization approach failed to achieve stable results, we do not
    2388             : include it in ALGLIB.
    2389             : 
    2390             : 
    2391             :   -- ALGLIB --
    2392             :      Copyright 14.04.2017 by Bochkanov Sergey
    2393             : *************************************************************************/
    2394           0 : 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, const double penalty, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams)
    2395             : {
    2396             :     jmp_buf _break_jump;
    2397             :     alglib_impl::ae_state _alglib_env_state;
    2398           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2399           0 :     if( setjmp(_break_jump) )
    2400             :     {
    2401             : #if !defined(AE_NO_EXCEPTIONS)
    2402           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    2403             : #else
    2404             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    2405             :         return;
    2406             : #endif
    2407             :     }
    2408           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    2409           0 :     if( _xparams.flags!=0x0 )
    2410           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    2411           0 :     alglib_impl::fitspherex(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), npoints, nx, problemtype, epsx, aulits, penalty, const_cast<alglib_impl::ae_vector*>(cx.c_ptr()), &rlo, &rhi, &_alglib_env_state);
    2412           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    2413           0 :     return;
    2414             : }
    2415             : #endif
    2416             : 
    2417             : #if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD)
    2418             : 
    2419             : #endif
    2420             : 
    2421             : #if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD)
    2422             : /*************************************************************************
    2423             : 1-dimensional spline interpolant
    2424             : *************************************************************************/
    2425           0 : _spline1dinterpolant_owner::_spline1dinterpolant_owner()
    2426             : {
    2427             :     jmp_buf _break_jump;
    2428             :     alglib_impl::ae_state _state;
    2429             :     
    2430           0 :     alglib_impl::ae_state_init(&_state);
    2431           0 :     if( setjmp(_break_jump) )
    2432             :     {
    2433           0 :         if( p_struct!=NULL )
    2434             :         {
    2435           0 :             alglib_impl::_spline1dinterpolant_destroy(p_struct);
    2436           0 :             alglib_impl::ae_free(p_struct);
    2437             :         }
    2438           0 :         p_struct = NULL;
    2439             : #if !defined(AE_NO_EXCEPTIONS)
    2440           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    2441             : #else
    2442             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    2443             :         return;
    2444             : #endif
    2445             :     }
    2446           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    2447           0 :     p_struct = NULL;
    2448           0 :     p_struct = (alglib_impl::spline1dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dinterpolant), &_state);
    2449           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline1dinterpolant));
    2450           0 :     alglib_impl::_spline1dinterpolant_init(p_struct, &_state, ae_false);
    2451           0 :     ae_state_clear(&_state);
    2452           0 : }
    2453             : 
    2454           0 : _spline1dinterpolant_owner::_spline1dinterpolant_owner(const _spline1dinterpolant_owner &rhs)
    2455             : {
    2456             :     jmp_buf _break_jump;
    2457             :     alglib_impl::ae_state _state;
    2458             :     
    2459           0 :     alglib_impl::ae_state_init(&_state);
    2460           0 :     if( setjmp(_break_jump) )
    2461             :     {
    2462           0 :         if( p_struct!=NULL )
    2463             :         {
    2464           0 :             alglib_impl::_spline1dinterpolant_destroy(p_struct);
    2465           0 :             alglib_impl::ae_free(p_struct);
    2466             :         }
    2467           0 :         p_struct = NULL;
    2468             : #if !defined(AE_NO_EXCEPTIONS)
    2469           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    2470             : #else
    2471             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    2472             :         return;
    2473             : #endif
    2474             :     }
    2475           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    2476           0 :     p_struct = NULL;
    2477           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dinterpolant copy constructor failure (source is not initialized)", &_state);
    2478           0 :     p_struct = (alglib_impl::spline1dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dinterpolant), &_state);
    2479           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline1dinterpolant));
    2480           0 :     alglib_impl::_spline1dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline1dinterpolant*>(rhs.p_struct), &_state, ae_false);
    2481           0 :     ae_state_clear(&_state);
    2482           0 : }
    2483             : 
    2484           0 : _spline1dinterpolant_owner& _spline1dinterpolant_owner::operator=(const _spline1dinterpolant_owner &rhs)
    2485             : {
    2486           0 :     if( this==&rhs )
    2487           0 :         return *this;
    2488             :     jmp_buf _break_jump;
    2489             :     alglib_impl::ae_state _state;
    2490             :     
    2491           0 :     alglib_impl::ae_state_init(&_state);
    2492           0 :     if( setjmp(_break_jump) )
    2493             :     {
    2494             : #if !defined(AE_NO_EXCEPTIONS)
    2495           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    2496             : #else
    2497             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    2498             :         return *this;
    2499             : #endif
    2500             :     }
    2501           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    2502           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline1dinterpolant assignment constructor failure (destination is not initialized)", &_state);
    2503           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dinterpolant assignment constructor failure (source is not initialized)", &_state);
    2504           0 :     alglib_impl::_spline1dinterpolant_destroy(p_struct);
    2505           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline1dinterpolant));
    2506           0 :     alglib_impl::_spline1dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline1dinterpolant*>(rhs.p_struct), &_state, ae_false);
    2507           0 :     ae_state_clear(&_state);
    2508           0 :     return *this;
    2509             : }
    2510             : 
    2511           0 : _spline1dinterpolant_owner::~_spline1dinterpolant_owner()
    2512             : {
    2513           0 :     if( p_struct!=NULL )
    2514             :     {
    2515           0 :         alglib_impl::_spline1dinterpolant_destroy(p_struct);
    2516           0 :         ae_free(p_struct);
    2517             :     }
    2518           0 : }
    2519             : 
    2520           0 : alglib_impl::spline1dinterpolant* _spline1dinterpolant_owner::c_ptr()
    2521             : {
    2522           0 :     return p_struct;
    2523             : }
    2524             : 
    2525           0 : alglib_impl::spline1dinterpolant* _spline1dinterpolant_owner::c_ptr() const
    2526             : {
    2527           0 :     return const_cast<alglib_impl::spline1dinterpolant*>(p_struct);
    2528             : }
    2529           0 : spline1dinterpolant::spline1dinterpolant() : _spline1dinterpolant_owner() 
    2530             : {
    2531           0 : }
    2532             : 
    2533           0 : spline1dinterpolant::spline1dinterpolant(const spline1dinterpolant &rhs):_spline1dinterpolant_owner(rhs) 
    2534             : {
    2535           0 : }
    2536             : 
    2537           0 : spline1dinterpolant& spline1dinterpolant::operator=(const spline1dinterpolant &rhs)
    2538             : {
    2539           0 :     if( this==&rhs )
    2540           0 :         return *this;
    2541           0 :     _spline1dinterpolant_owner::operator=(rhs);
    2542           0 :     return *this;
    2543             : }
    2544             : 
    2545           0 : spline1dinterpolant::~spline1dinterpolant()
    2546             : {
    2547           0 : }
    2548             : 
    2549             : 
    2550             : /*************************************************************************
    2551             : Spline fitting report:
    2552             :     RMSError        RMS error
    2553             :     AvgError        average error
    2554             :     AvgRelError     average relative error (for non-zero Y[I])
    2555             :     MaxError        maximum error
    2556             : 
    2557             : Fields  below are  filled  by   obsolete    functions   (Spline1DFitCubic,
    2558             : Spline1DFitHermite). Modern fitting functions do NOT fill these fields:
    2559             :     TaskRCond       reciprocal of task's condition number
    2560             : *************************************************************************/
    2561           0 : _spline1dfitreport_owner::_spline1dfitreport_owner()
    2562             : {
    2563             :     jmp_buf _break_jump;
    2564             :     alglib_impl::ae_state _state;
    2565             :     
    2566           0 :     alglib_impl::ae_state_init(&_state);
    2567           0 :     if( setjmp(_break_jump) )
    2568             :     {
    2569           0 :         if( p_struct!=NULL )
    2570             :         {
    2571           0 :             alglib_impl::_spline1dfitreport_destroy(p_struct);
    2572           0 :             alglib_impl::ae_free(p_struct);
    2573             :         }
    2574           0 :         p_struct = NULL;
    2575             : #if !defined(AE_NO_EXCEPTIONS)
    2576           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    2577             : #else
    2578             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    2579             :         return;
    2580             : #endif
    2581             :     }
    2582           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    2583           0 :     p_struct = NULL;
    2584           0 :     p_struct = (alglib_impl::spline1dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dfitreport), &_state);
    2585           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline1dfitreport));
    2586           0 :     alglib_impl::_spline1dfitreport_init(p_struct, &_state, ae_false);
    2587           0 :     ae_state_clear(&_state);
    2588           0 : }
    2589             : 
    2590           0 : _spline1dfitreport_owner::_spline1dfitreport_owner(const _spline1dfitreport_owner &rhs)
    2591             : {
    2592             :     jmp_buf _break_jump;
    2593             :     alglib_impl::ae_state _state;
    2594             :     
    2595           0 :     alglib_impl::ae_state_init(&_state);
    2596           0 :     if( setjmp(_break_jump) )
    2597             :     {
    2598           0 :         if( p_struct!=NULL )
    2599             :         {
    2600           0 :             alglib_impl::_spline1dfitreport_destroy(p_struct);
    2601           0 :             alglib_impl::ae_free(p_struct);
    2602             :         }
    2603           0 :         p_struct = NULL;
    2604             : #if !defined(AE_NO_EXCEPTIONS)
    2605           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    2606             : #else
    2607             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    2608             :         return;
    2609             : #endif
    2610             :     }
    2611           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    2612           0 :     p_struct = NULL;
    2613           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dfitreport copy constructor failure (source is not initialized)", &_state);
    2614           0 :     p_struct = (alglib_impl::spline1dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dfitreport), &_state);
    2615           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline1dfitreport));
    2616           0 :     alglib_impl::_spline1dfitreport_init_copy(p_struct, const_cast<alglib_impl::spline1dfitreport*>(rhs.p_struct), &_state, ae_false);
    2617           0 :     ae_state_clear(&_state);
    2618           0 : }
    2619             : 
    2620           0 : _spline1dfitreport_owner& _spline1dfitreport_owner::operator=(const _spline1dfitreport_owner &rhs)
    2621             : {
    2622           0 :     if( this==&rhs )
    2623           0 :         return *this;
    2624             :     jmp_buf _break_jump;
    2625             :     alglib_impl::ae_state _state;
    2626             :     
    2627           0 :     alglib_impl::ae_state_init(&_state);
    2628           0 :     if( setjmp(_break_jump) )
    2629             :     {
    2630             : #if !defined(AE_NO_EXCEPTIONS)
    2631           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    2632             : #else
    2633             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    2634             :         return *this;
    2635             : #endif
    2636             :     }
    2637           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    2638           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline1dfitreport assignment constructor failure (destination is not initialized)", &_state);
    2639           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dfitreport assignment constructor failure (source is not initialized)", &_state);
    2640           0 :     alglib_impl::_spline1dfitreport_destroy(p_struct);
    2641           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline1dfitreport));
    2642           0 :     alglib_impl::_spline1dfitreport_init_copy(p_struct, const_cast<alglib_impl::spline1dfitreport*>(rhs.p_struct), &_state, ae_false);
    2643           0 :     ae_state_clear(&_state);
    2644           0 :     return *this;
    2645             : }
    2646             : 
    2647           0 : _spline1dfitreport_owner::~_spline1dfitreport_owner()
    2648             : {
    2649           0 :     if( p_struct!=NULL )
    2650             :     {
    2651           0 :         alglib_impl::_spline1dfitreport_destroy(p_struct);
    2652           0 :         ae_free(p_struct);
    2653             :     }
    2654           0 : }
    2655             : 
    2656           0 : alglib_impl::spline1dfitreport* _spline1dfitreport_owner::c_ptr()
    2657             : {
    2658           0 :     return p_struct;
    2659             : }
    2660             : 
    2661           0 : alglib_impl::spline1dfitreport* _spline1dfitreport_owner::c_ptr() const
    2662             : {
    2663           0 :     return const_cast<alglib_impl::spline1dfitreport*>(p_struct);
    2664             : }
    2665           0 : spline1dfitreport::spline1dfitreport() : _spline1dfitreport_owner() ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror)
    2666             : {
    2667           0 : }
    2668             : 
    2669           0 : 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)
    2670             : {
    2671           0 : }
    2672             : 
    2673           0 : spline1dfitreport& spline1dfitreport::operator=(const spline1dfitreport &rhs)
    2674             : {
    2675           0 :     if( this==&rhs )
    2676           0 :         return *this;
    2677           0 :     _spline1dfitreport_owner::operator=(rhs);
    2678           0 :     return *this;
    2679             : }
    2680             : 
    2681           0 : spline1dfitreport::~spline1dfitreport()
    2682             : {
    2683           0 : }
    2684             : 
    2685             : /*************************************************************************
    2686             : This subroutine builds linear spline interpolant
    2687             : 
    2688             : INPUT PARAMETERS:
    2689             :     X   -   spline nodes, array[0..N-1]
    2690             :     Y   -   function values, array[0..N-1]
    2691             :     N   -   points count (optional):
    2692             :             * N>=2
    2693             :             * if given, only first N points are used to build spline
    2694             :             * if not given, automatically detected from X/Y sizes
    2695             :               (len(X) must be equal to len(Y))
    2696             : 
    2697             : OUTPUT PARAMETERS:
    2698             :     C   -   spline interpolant
    2699             : 
    2700             : 
    2701             : ORDER OF POINTS
    2702             : 
    2703             : Subroutine automatically sorts points, so caller may pass unsorted array.
    2704             : 
    2705             :   -- ALGLIB PROJECT --
    2706             :      Copyright 24.06.2007 by Bochkanov Sergey
    2707             : *************************************************************************/
    2708           0 : void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams)
    2709             : {
    2710             :     jmp_buf _break_jump;
    2711             :     alglib_impl::ae_state _alglib_env_state;
    2712           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2713           0 :     if( setjmp(_break_jump) )
    2714             :     {
    2715             : #if !defined(AE_NO_EXCEPTIONS)
    2716           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    2717             : #else
    2718             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    2719             :         return;
    2720             : #endif
    2721             :     }
    2722           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    2723           0 :     if( _xparams.flags!=0x0 )
    2724           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    2725           0 :     alglib_impl::spline1dbuildlinear(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    2726           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    2727           0 :     return;
    2728             : }
    2729             : 
    2730             : /*************************************************************************
    2731             : This subroutine builds linear spline interpolant
    2732             : 
    2733             : INPUT PARAMETERS:
    2734             :     X   -   spline nodes, array[0..N-1]
    2735             :     Y   -   function values, array[0..N-1]
    2736             :     N   -   points count (optional):
    2737             :             * N>=2
    2738             :             * if given, only first N points are used to build spline
    2739             :             * if not given, automatically detected from X/Y sizes
    2740             :               (len(X) must be equal to len(Y))
    2741             : 
    2742             : OUTPUT PARAMETERS:
    2743             :     C   -   spline interpolant
    2744             : 
    2745             : 
    2746             : ORDER OF POINTS
    2747             : 
    2748             : Subroutine automatically sorts points, so caller may pass unsorted array.
    2749             : 
    2750             :   -- ALGLIB PROJECT --
    2751             :      Copyright 24.06.2007 by Bochkanov Sergey
    2752             : *************************************************************************/
    2753             : #if !defined(AE_NO_EXCEPTIONS)
    2754           0 : void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams)
    2755             : {
    2756             :     jmp_buf _break_jump;
    2757             :     alglib_impl::ae_state _alglib_env_state;    
    2758             :     ae_int_t n;
    2759           0 :     if( (x.length()!=y.length()))
    2760           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildlinear': looks like one of arguments has wrong size");
    2761           0 :     n = x.length();
    2762           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2763           0 :     if( setjmp(_break_jump) )
    2764           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    2765           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    2766           0 :     if( _xparams.flags!=0x0 )
    2767           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    2768           0 :     alglib_impl::spline1dbuildlinear(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    2769             : 
    2770           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    2771           0 :     return;
    2772             : }
    2773             : #endif
    2774             : 
    2775             : /*************************************************************************
    2776             : This subroutine builds cubic spline interpolant.
    2777             : 
    2778             : INPUT PARAMETERS:
    2779             :     X           -   spline nodes, array[0..N-1].
    2780             :     Y           -   function values, array[0..N-1].
    2781             : 
    2782             : OPTIONAL PARAMETERS:
    2783             :     N           -   points count:
    2784             :                     * N>=2
    2785             :                     * if given, only first N points are used to build spline
    2786             :                     * if not given, automatically detected from X/Y sizes
    2787             :                       (len(X) must be equal to len(Y))
    2788             :     BoundLType  -   boundary condition type for the left boundary
    2789             :     BoundL      -   left boundary condition (first or second derivative,
    2790             :                     depending on the BoundLType)
    2791             :     BoundRType  -   boundary condition type for the right boundary
    2792             :     BoundR      -   right boundary condition (first or second derivative,
    2793             :                     depending on the BoundRType)
    2794             : 
    2795             : OUTPUT PARAMETERS:
    2796             :     C           -   spline interpolant
    2797             : 
    2798             : ORDER OF POINTS
    2799             : 
    2800             : Subroutine automatically sorts points, so caller may pass unsorted array.
    2801             : 
    2802             : SETTING BOUNDARY VALUES:
    2803             : 
    2804             : The BoundLType/BoundRType parameters can have the following values:
    2805             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    2806             :           In this case:
    2807             :           * both BoundLType and BoundRType must be equal to -1.
    2808             :           * BoundL/BoundR are ignored
    2809             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    2810             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    2811             :           (BoundL and/or BoundR are ignored).
    2812             :     *  1, which corresponds to the first derivative boundary condition
    2813             :     *  2, which corresponds to the second derivative boundary condition
    2814             :     *  by default, BoundType=0 is used
    2815             : 
    2816             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    2817             : 
    2818             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    2819             : However, this subroutine doesn't require you to specify equal  values  for
    2820             : the first and last points - it automatically forces them  to  be  equal by
    2821             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    2822             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    2823             : i.e. to make Y[first_point]=Y[last_point].
    2824             : 
    2825             :   -- ALGLIB PROJECT --
    2826             :      Copyright 23.06.2007 by Bochkanov Sergey
    2827             : *************************************************************************/
    2828           0 : 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)
    2829             : {
    2830             :     jmp_buf _break_jump;
    2831             :     alglib_impl::ae_state _alglib_env_state;
    2832           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2833           0 :     if( setjmp(_break_jump) )
    2834             :     {
    2835             : #if !defined(AE_NO_EXCEPTIONS)
    2836           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    2837             : #else
    2838             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    2839             :         return;
    2840             : #endif
    2841             :     }
    2842           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    2843           0 :     if( _xparams.flags!=0x0 )
    2844           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    2845           0 :     alglib_impl::spline1dbuildcubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    2846           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    2847           0 :     return;
    2848             : }
    2849             : 
    2850             : /*************************************************************************
    2851             : This subroutine builds cubic spline interpolant.
    2852             : 
    2853             : INPUT PARAMETERS:
    2854             :     X           -   spline nodes, array[0..N-1].
    2855             :     Y           -   function values, array[0..N-1].
    2856             : 
    2857             : OPTIONAL PARAMETERS:
    2858             :     N           -   points count:
    2859             :                     * N>=2
    2860             :                     * if given, only first N points are used to build spline
    2861             :                     * if not given, automatically detected from X/Y sizes
    2862             :                       (len(X) must be equal to len(Y))
    2863             :     BoundLType  -   boundary condition type for the left boundary
    2864             :     BoundL      -   left boundary condition (first or second derivative,
    2865             :                     depending on the BoundLType)
    2866             :     BoundRType  -   boundary condition type for the right boundary
    2867             :     BoundR      -   right boundary condition (first or second derivative,
    2868             :                     depending on the BoundRType)
    2869             : 
    2870             : OUTPUT PARAMETERS:
    2871             :     C           -   spline interpolant
    2872             : 
    2873             : ORDER OF POINTS
    2874             : 
    2875             : Subroutine automatically sorts points, so caller may pass unsorted array.
    2876             : 
    2877             : SETTING BOUNDARY VALUES:
    2878             : 
    2879             : The BoundLType/BoundRType parameters can have the following values:
    2880             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    2881             :           In this case:
    2882             :           * both BoundLType and BoundRType must be equal to -1.
    2883             :           * BoundL/BoundR are ignored
    2884             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    2885             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    2886             :           (BoundL and/or BoundR are ignored).
    2887             :     *  1, which corresponds to the first derivative boundary condition
    2888             :     *  2, which corresponds to the second derivative boundary condition
    2889             :     *  by default, BoundType=0 is used
    2890             : 
    2891             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    2892             : 
    2893             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    2894             : However, this subroutine doesn't require you to specify equal  values  for
    2895             : the first and last points - it automatically forces them  to  be  equal by
    2896             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    2897             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    2898             : i.e. to make Y[first_point]=Y[last_point].
    2899             : 
    2900             :   -- ALGLIB PROJECT --
    2901             :      Copyright 23.06.2007 by Bochkanov Sergey
    2902             : *************************************************************************/
    2903             : #if !defined(AE_NO_EXCEPTIONS)
    2904           0 : void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams)
    2905             : {
    2906             :     jmp_buf _break_jump;
    2907             :     alglib_impl::ae_state _alglib_env_state;    
    2908             :     ae_int_t n;
    2909             :     ae_int_t boundltype;
    2910             :     double boundl;
    2911             :     ae_int_t boundrtype;
    2912             :     double boundr;
    2913           0 :     if( (x.length()!=y.length()))
    2914           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildcubic': looks like one of arguments has wrong size");
    2915           0 :     n = x.length();
    2916           0 :     boundltype = 0;
    2917           0 :     boundl = 0;
    2918           0 :     boundrtype = 0;
    2919           0 :     boundr = 0;
    2920           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2921           0 :     if( setjmp(_break_jump) )
    2922           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    2923           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    2924           0 :     if( _xparams.flags!=0x0 )
    2925           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    2926           0 :     alglib_impl::spline1dbuildcubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    2927             : 
    2928           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    2929           0 :     return;
    2930             : }
    2931             : #endif
    2932             : 
    2933             : /*************************************************************************
    2934             : This function solves following problem: given table y[] of function values
    2935             : at nodes x[], it calculates and returns table of function derivatives  d[]
    2936             : (calculated at the same nodes x[]).
    2937             : 
    2938             : This function yields same result as Spline1DBuildCubic() call followed  by
    2939             : sequence of Spline1DDiff() calls, but it can be several times faster  when
    2940             : called for ordered X[] and X2[].
    2941             : 
    2942             : INPUT PARAMETERS:
    2943             :     X           -   spline nodes
    2944             :     Y           -   function values
    2945             : 
    2946             : OPTIONAL PARAMETERS:
    2947             :     N           -   points count:
    2948             :                     * N>=2
    2949             :                     * if given, only first N points are used
    2950             :                     * if not given, automatically detected from X/Y sizes
    2951             :                       (len(X) must be equal to len(Y))
    2952             :     BoundLType  -   boundary condition type for the left boundary
    2953             :     BoundL      -   left boundary condition (first or second derivative,
    2954             :                     depending on the BoundLType)
    2955             :     BoundRType  -   boundary condition type for the right boundary
    2956             :     BoundR      -   right boundary condition (first or second derivative,
    2957             :                     depending on the BoundRType)
    2958             : 
    2959             : OUTPUT PARAMETERS:
    2960             :     D           -   derivative values at X[]
    2961             : 
    2962             : ORDER OF POINTS
    2963             : 
    2964             : Subroutine automatically sorts points, so caller may pass unsorted array.
    2965             : Derivative values are correctly reordered on return, so  D[I]  is  always
    2966             : equal to S'(X[I]) independently of points order.
    2967             : 
    2968             : SETTING BOUNDARY VALUES:
    2969             : 
    2970             : The BoundLType/BoundRType parameters can have the following values:
    2971             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    2972             :           In this case:
    2973             :           * both BoundLType and BoundRType must be equal to -1.
    2974             :           * BoundL/BoundR are ignored
    2975             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    2976             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    2977             :           (BoundL and/or BoundR are ignored).
    2978             :     *  1, which corresponds to the first derivative boundary condition
    2979             :     *  2, which corresponds to the second derivative boundary condition
    2980             :     *  by default, BoundType=0 is used
    2981             : 
    2982             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    2983             : 
    2984             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    2985             : However, this subroutine doesn't require you to specify equal  values  for
    2986             : the first and last points - it automatically forces them  to  be  equal by
    2987             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    2988             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    2989             : i.e. to make Y[first_point]=Y[last_point].
    2990             : 
    2991             :   -- ALGLIB PROJECT --
    2992             :      Copyright 03.09.2010 by Bochkanov Sergey
    2993             : *************************************************************************/
    2994           0 : 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)
    2995             : {
    2996             :     jmp_buf _break_jump;
    2997             :     alglib_impl::ae_state _alglib_env_state;
    2998           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    2999           0 :     if( setjmp(_break_jump) )
    3000             :     {
    3001             : #if !defined(AE_NO_EXCEPTIONS)
    3002           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3003             : #else
    3004             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    3005             :         return;
    3006             : #endif
    3007             :     }
    3008           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3009           0 :     if( _xparams.flags!=0x0 )
    3010           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3011           0 :     alglib_impl::spline1dgriddiffcubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::ae_vector*>(d.c_ptr()), &_alglib_env_state);
    3012           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3013           0 :     return;
    3014             : }
    3015             : 
    3016             : /*************************************************************************
    3017             : This function solves following problem: given table y[] of function values
    3018             : at nodes x[], it calculates and returns table of function derivatives  d[]
    3019             : (calculated at the same nodes x[]).
    3020             : 
    3021             : This function yields same result as Spline1DBuildCubic() call followed  by
    3022             : sequence of Spline1DDiff() calls, but it can be several times faster  when
    3023             : called for ordered X[] and X2[].
    3024             : 
    3025             : INPUT PARAMETERS:
    3026             :     X           -   spline nodes
    3027             :     Y           -   function values
    3028             : 
    3029             : OPTIONAL PARAMETERS:
    3030             :     N           -   points count:
    3031             :                     * N>=2
    3032             :                     * if given, only first N points are used
    3033             :                     * if not given, automatically detected from X/Y sizes
    3034             :                       (len(X) must be equal to len(Y))
    3035             :     BoundLType  -   boundary condition type for the left boundary
    3036             :     BoundL      -   left boundary condition (first or second derivative,
    3037             :                     depending on the BoundLType)
    3038             :     BoundRType  -   boundary condition type for the right boundary
    3039             :     BoundR      -   right boundary condition (first or second derivative,
    3040             :                     depending on the BoundRType)
    3041             : 
    3042             : OUTPUT PARAMETERS:
    3043             :     D           -   derivative values at X[]
    3044             : 
    3045             : ORDER OF POINTS
    3046             : 
    3047             : Subroutine automatically sorts points, so caller may pass unsorted array.
    3048             : Derivative values are correctly reordered on return, so  D[I]  is  always
    3049             : equal to S'(X[I]) independently of points order.
    3050             : 
    3051             : SETTING BOUNDARY VALUES:
    3052             : 
    3053             : The BoundLType/BoundRType parameters can have the following values:
    3054             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    3055             :           In this case:
    3056             :           * both BoundLType and BoundRType must be equal to -1.
    3057             :           * BoundL/BoundR are ignored
    3058             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    3059             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    3060             :           (BoundL and/or BoundR are ignored).
    3061             :     *  1, which corresponds to the first derivative boundary condition
    3062             :     *  2, which corresponds to the second derivative boundary condition
    3063             :     *  by default, BoundType=0 is used
    3064             : 
    3065             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3066             : 
    3067             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3068             : However, this subroutine doesn't require you to specify equal  values  for
    3069             : the first and last points - it automatically forces them  to  be  equal by
    3070             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3071             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3072             : i.e. to make Y[first_point]=Y[last_point].
    3073             : 
    3074             :   -- ALGLIB PROJECT --
    3075             :      Copyright 03.09.2010 by Bochkanov Sergey
    3076             : *************************************************************************/
    3077             : #if !defined(AE_NO_EXCEPTIONS)
    3078           0 : void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d, const xparams _xparams)
    3079             : {
    3080             :     jmp_buf _break_jump;
    3081             :     alglib_impl::ae_state _alglib_env_state;    
    3082             :     ae_int_t n;
    3083             :     ae_int_t boundltype;
    3084             :     double boundl;
    3085             :     ae_int_t boundrtype;
    3086             :     double boundr;
    3087           0 :     if( (x.length()!=y.length()))
    3088           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dgriddiffcubic': looks like one of arguments has wrong size");
    3089           0 :     n = x.length();
    3090           0 :     boundltype = 0;
    3091           0 :     boundl = 0;
    3092           0 :     boundrtype = 0;
    3093           0 :     boundr = 0;
    3094           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3095           0 :     if( setjmp(_break_jump) )
    3096           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3097           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3098           0 :     if( _xparams.flags!=0x0 )
    3099           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3100           0 :     alglib_impl::spline1dgriddiffcubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::ae_vector*>(d.c_ptr()), &_alglib_env_state);
    3101             : 
    3102           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3103           0 :     return;
    3104             : }
    3105             : #endif
    3106             : 
    3107             : /*************************************************************************
    3108             : This function solves following problem: given table y[] of function values
    3109             : at  nodes  x[],  it  calculates  and  returns  tables  of first and second
    3110             : function derivatives d1[] and d2[] (calculated at the same nodes x[]).
    3111             : 
    3112             : This function yields same result as Spline1DBuildCubic() call followed  by
    3113             : sequence of Spline1DDiff() calls, but it can be several times faster  when
    3114             : called for ordered X[] and X2[].
    3115             : 
    3116             : INPUT PARAMETERS:
    3117             :     X           -   spline nodes
    3118             :     Y           -   function values
    3119             : 
    3120             : OPTIONAL PARAMETERS:
    3121             :     N           -   points count:
    3122             :                     * N>=2
    3123             :                     * if given, only first N points are used
    3124             :                     * if not given, automatically detected from X/Y sizes
    3125             :                       (len(X) must be equal to len(Y))
    3126             :     BoundLType  -   boundary condition type for the left boundary
    3127             :     BoundL      -   left boundary condition (first or second derivative,
    3128             :                     depending on the BoundLType)
    3129             :     BoundRType  -   boundary condition type for the right boundary
    3130             :     BoundR      -   right boundary condition (first or second derivative,
    3131             :                     depending on the BoundRType)
    3132             : 
    3133             : OUTPUT PARAMETERS:
    3134             :     D1          -   S' values at X[]
    3135             :     D2          -   S'' values at X[]
    3136             : 
    3137             : ORDER OF POINTS
    3138             : 
    3139             : Subroutine automatically sorts points, so caller may pass unsorted array.
    3140             : Derivative values are correctly reordered on return, so  D[I]  is  always
    3141             : equal to S'(X[I]) independently of points order.
    3142             : 
    3143             : SETTING BOUNDARY VALUES:
    3144             : 
    3145             : The BoundLType/BoundRType parameters can have the following values:
    3146             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    3147             :           In this case:
    3148             :           * both BoundLType and BoundRType must be equal to -1.
    3149             :           * BoundL/BoundR are ignored
    3150             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    3151             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    3152             :           (BoundL and/or BoundR are ignored).
    3153             :     *  1, which corresponds to the first derivative boundary condition
    3154             :     *  2, which corresponds to the second derivative boundary condition
    3155             :     *  by default, BoundType=0 is used
    3156             : 
    3157             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3158             : 
    3159             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3160             : However, this subroutine doesn't require you to specify equal  values  for
    3161             : the first and last points - it automatically forces them  to  be  equal by
    3162             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3163             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3164             : i.e. to make Y[first_point]=Y[last_point].
    3165             : 
    3166             :   -- ALGLIB PROJECT --
    3167             :      Copyright 03.09.2010 by Bochkanov Sergey
    3168             : *************************************************************************/
    3169           0 : 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)
    3170             : {
    3171             :     jmp_buf _break_jump;
    3172             :     alglib_impl::ae_state _alglib_env_state;
    3173           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3174           0 :     if( setjmp(_break_jump) )
    3175             :     {
    3176             : #if !defined(AE_NO_EXCEPTIONS)
    3177           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3178             : #else
    3179             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    3180             :         return;
    3181             : #endif
    3182             :     }
    3183           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3184           0 :     if( _xparams.flags!=0x0 )
    3185           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3186           0 :     alglib_impl::spline1dgriddiff2cubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::ae_vector*>(d1.c_ptr()), const_cast<alglib_impl::ae_vector*>(d2.c_ptr()), &_alglib_env_state);
    3187           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3188           0 :     return;
    3189             : }
    3190             : 
    3191             : /*************************************************************************
    3192             : This function solves following problem: given table y[] of function values
    3193             : at  nodes  x[],  it  calculates  and  returns  tables  of first and second
    3194             : function derivatives d1[] and d2[] (calculated at the same nodes x[]).
    3195             : 
    3196             : This function yields same result as Spline1DBuildCubic() call followed  by
    3197             : sequence of Spline1DDiff() calls, but it can be several times faster  when
    3198             : called for ordered X[] and X2[].
    3199             : 
    3200             : INPUT PARAMETERS:
    3201             :     X           -   spline nodes
    3202             :     Y           -   function values
    3203             : 
    3204             : OPTIONAL PARAMETERS:
    3205             :     N           -   points count:
    3206             :                     * N>=2
    3207             :                     * if given, only first N points are used
    3208             :                     * if not given, automatically detected from X/Y sizes
    3209             :                       (len(X) must be equal to len(Y))
    3210             :     BoundLType  -   boundary condition type for the left boundary
    3211             :     BoundL      -   left boundary condition (first or second derivative,
    3212             :                     depending on the BoundLType)
    3213             :     BoundRType  -   boundary condition type for the right boundary
    3214             :     BoundR      -   right boundary condition (first or second derivative,
    3215             :                     depending on the BoundRType)
    3216             : 
    3217             : OUTPUT PARAMETERS:
    3218             :     D1          -   S' values at X[]
    3219             :     D2          -   S'' values at X[]
    3220             : 
    3221             : ORDER OF POINTS
    3222             : 
    3223             : Subroutine automatically sorts points, so caller may pass unsorted array.
    3224             : Derivative values are correctly reordered on return, so  D[I]  is  always
    3225             : equal to S'(X[I]) independently of points order.
    3226             : 
    3227             : SETTING BOUNDARY VALUES:
    3228             : 
    3229             : The BoundLType/BoundRType parameters can have the following values:
    3230             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    3231             :           In this case:
    3232             :           * both BoundLType and BoundRType must be equal to -1.
    3233             :           * BoundL/BoundR are ignored
    3234             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    3235             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    3236             :           (BoundL and/or BoundR are ignored).
    3237             :     *  1, which corresponds to the first derivative boundary condition
    3238             :     *  2, which corresponds to the second derivative boundary condition
    3239             :     *  by default, BoundType=0 is used
    3240             : 
    3241             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3242             : 
    3243             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3244             : However, this subroutine doesn't require you to specify equal  values  for
    3245             : the first and last points - it automatically forces them  to  be  equal by
    3246             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3247             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3248             : i.e. to make Y[first_point]=Y[last_point].
    3249             : 
    3250             :   -- ALGLIB PROJECT --
    3251             :      Copyright 03.09.2010 by Bochkanov Sergey
    3252             : *************************************************************************/
    3253             : #if !defined(AE_NO_EXCEPTIONS)
    3254           0 : void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d1, real_1d_array &d2, const xparams _xparams)
    3255             : {
    3256             :     jmp_buf _break_jump;
    3257             :     alglib_impl::ae_state _alglib_env_state;    
    3258             :     ae_int_t n;
    3259             :     ae_int_t boundltype;
    3260             :     double boundl;
    3261             :     ae_int_t boundrtype;
    3262             :     double boundr;
    3263           0 :     if( (x.length()!=y.length()))
    3264           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dgriddiff2cubic': looks like one of arguments has wrong size");
    3265           0 :     n = x.length();
    3266           0 :     boundltype = 0;
    3267           0 :     boundl = 0;
    3268           0 :     boundrtype = 0;
    3269           0 :     boundr = 0;
    3270           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3271           0 :     if( setjmp(_break_jump) )
    3272           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3273           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3274           0 :     if( _xparams.flags!=0x0 )
    3275           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3276           0 :     alglib_impl::spline1dgriddiff2cubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::ae_vector*>(d1.c_ptr()), const_cast<alglib_impl::ae_vector*>(d2.c_ptr()), &_alglib_env_state);
    3277             : 
    3278           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3279           0 :     return;
    3280             : }
    3281             : #endif
    3282             : 
    3283             : /*************************************************************************
    3284             : This function solves following problem: given table y[] of function values
    3285             : at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
    3286             : function values y2[] (calculated at x2[]).
    3287             : 
    3288             : This function yields same result as Spline1DBuildCubic() call followed  by
    3289             : sequence of Spline1DDiff() calls, but it can be several times faster  when
    3290             : called for ordered X[] and X2[].
    3291             : 
    3292             : INPUT PARAMETERS:
    3293             :     X           -   old spline nodes
    3294             :     Y           -   function values
    3295             :     X2           -  new spline nodes
    3296             : 
    3297             : OPTIONAL PARAMETERS:
    3298             :     N           -   points count:
    3299             :                     * N>=2
    3300             :                     * if given, only first N points from X/Y are used
    3301             :                     * if not given, automatically detected from X/Y sizes
    3302             :                       (len(X) must be equal to len(Y))
    3303             :     BoundLType  -   boundary condition type for the left boundary
    3304             :     BoundL      -   left boundary condition (first or second derivative,
    3305             :                     depending on the BoundLType)
    3306             :     BoundRType  -   boundary condition type for the right boundary
    3307             :     BoundR      -   right boundary condition (first or second derivative,
    3308             :                     depending on the BoundRType)
    3309             :     N2          -   new points count:
    3310             :                     * N2>=2
    3311             :                     * if given, only first N2 points from X2 are used
    3312             :                     * if not given, automatically detected from X2 size
    3313             : 
    3314             : OUTPUT PARAMETERS:
    3315             :     F2          -   function values at X2[]
    3316             : 
    3317             : ORDER OF POINTS
    3318             : 
    3319             : Subroutine automatically sorts points, so caller  may pass unsorted array.
    3320             : Function  values  are correctly reordered on  return, so F2[I]  is  always
    3321             : equal to S(X2[I]) independently of points order.
    3322             : 
    3323             : SETTING BOUNDARY VALUES:
    3324             : 
    3325             : The BoundLType/BoundRType parameters can have the following values:
    3326             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    3327             :           In this case:
    3328             :           * both BoundLType and BoundRType must be equal to -1.
    3329             :           * BoundL/BoundR are ignored
    3330             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    3331             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    3332             :           (BoundL and/or BoundR are ignored).
    3333             :     *  1, which corresponds to the first derivative boundary condition
    3334             :     *  2, which corresponds to the second derivative boundary condition
    3335             :     *  by default, BoundType=0 is used
    3336             : 
    3337             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3338             : 
    3339             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3340             : However, this subroutine doesn't require you to specify equal  values  for
    3341             : the first and last points - it automatically forces them  to  be  equal by
    3342             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3343             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3344             : i.e. to make Y[first_point]=Y[last_point].
    3345             : 
    3346             :   -- ALGLIB PROJECT --
    3347             :      Copyright 03.09.2010 by Bochkanov Sergey
    3348             : *************************************************************************/
    3349           0 : 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)
    3350             : {
    3351             :     jmp_buf _break_jump;
    3352             :     alglib_impl::ae_state _alglib_env_state;
    3353           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3354           0 :     if( setjmp(_break_jump) )
    3355             :     {
    3356             : #if !defined(AE_NO_EXCEPTIONS)
    3357           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3358             : #else
    3359             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    3360             :         return;
    3361             : #endif
    3362             :     }
    3363           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3364           0 :     if( _xparams.flags!=0x0 )
    3365           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3366           0 :     alglib_impl::spline1dconvcubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::ae_vector*>(x2.c_ptr()), n2, const_cast<alglib_impl::ae_vector*>(y2.c_ptr()), &_alglib_env_state);
    3367           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3368           0 :     return;
    3369             : }
    3370             : 
    3371             : /*************************************************************************
    3372             : This function solves following problem: given table y[] of function values
    3373             : at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
    3374             : function values y2[] (calculated at x2[]).
    3375             : 
    3376             : This function yields same result as Spline1DBuildCubic() call followed  by
    3377             : sequence of Spline1DDiff() calls, but it can be several times faster  when
    3378             : called for ordered X[] and X2[].
    3379             : 
    3380             : INPUT PARAMETERS:
    3381             :     X           -   old spline nodes
    3382             :     Y           -   function values
    3383             :     X2           -  new spline nodes
    3384             : 
    3385             : OPTIONAL PARAMETERS:
    3386             :     N           -   points count:
    3387             :                     * N>=2
    3388             :                     * if given, only first N points from X/Y are used
    3389             :                     * if not given, automatically detected from X/Y sizes
    3390             :                       (len(X) must be equal to len(Y))
    3391             :     BoundLType  -   boundary condition type for the left boundary
    3392             :     BoundL      -   left boundary condition (first or second derivative,
    3393             :                     depending on the BoundLType)
    3394             :     BoundRType  -   boundary condition type for the right boundary
    3395             :     BoundR      -   right boundary condition (first or second derivative,
    3396             :                     depending on the BoundRType)
    3397             :     N2          -   new points count:
    3398             :                     * N2>=2
    3399             :                     * if given, only first N2 points from X2 are used
    3400             :                     * if not given, automatically detected from X2 size
    3401             : 
    3402             : OUTPUT PARAMETERS:
    3403             :     F2          -   function values at X2[]
    3404             : 
    3405             : ORDER OF POINTS
    3406             : 
    3407             : Subroutine automatically sorts points, so caller  may pass unsorted array.
    3408             : Function  values  are correctly reordered on  return, so F2[I]  is  always
    3409             : equal to S(X2[I]) independently of points order.
    3410             : 
    3411             : SETTING BOUNDARY VALUES:
    3412             : 
    3413             : The BoundLType/BoundRType parameters can have the following values:
    3414             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    3415             :           In this case:
    3416             :           * both BoundLType and BoundRType must be equal to -1.
    3417             :           * BoundL/BoundR are ignored
    3418             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    3419             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    3420             :           (BoundL and/or BoundR are ignored).
    3421             :     *  1, which corresponds to the first derivative boundary condition
    3422             :     *  2, which corresponds to the second derivative boundary condition
    3423             :     *  by default, BoundType=0 is used
    3424             : 
    3425             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3426             : 
    3427             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3428             : However, this subroutine doesn't require you to specify equal  values  for
    3429             : the first and last points - it automatically forces them  to  be  equal by
    3430             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3431             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3432             : i.e. to make Y[first_point]=Y[last_point].
    3433             : 
    3434             :   -- ALGLIB PROJECT --
    3435             :      Copyright 03.09.2010 by Bochkanov Sergey
    3436             : *************************************************************************/
    3437             : #if !defined(AE_NO_EXCEPTIONS)
    3438           0 : void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, const xparams _xparams)
    3439             : {
    3440             :     jmp_buf _break_jump;
    3441             :     alglib_impl::ae_state _alglib_env_state;    
    3442             :     ae_int_t n;
    3443             :     ae_int_t boundltype;
    3444             :     double boundl;
    3445             :     ae_int_t boundrtype;
    3446             :     double boundr;
    3447             :     ae_int_t n2;
    3448           0 :     if( (x.length()!=y.length()))
    3449           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dconvcubic': looks like one of arguments has wrong size");
    3450           0 :     n = x.length();
    3451           0 :     boundltype = 0;
    3452           0 :     boundl = 0;
    3453           0 :     boundrtype = 0;
    3454           0 :     boundr = 0;
    3455           0 :     n2 = x2.length();
    3456           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3457           0 :     if( setjmp(_break_jump) )
    3458           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3459           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3460           0 :     if( _xparams.flags!=0x0 )
    3461           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3462           0 :     alglib_impl::spline1dconvcubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::ae_vector*>(x2.c_ptr()), n2, const_cast<alglib_impl::ae_vector*>(y2.c_ptr()), &_alglib_env_state);
    3463             : 
    3464           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3465           0 :     return;
    3466             : }
    3467             : #endif
    3468             : 
    3469             : /*************************************************************************
    3470             : This function solves following problem: given table y[] of function values
    3471             : at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
    3472             : function values y2[] and derivatives d2[] (calculated at x2[]).
    3473             : 
    3474             : This function yields same result as Spline1DBuildCubic() call followed  by
    3475             : sequence of Spline1DDiff() calls, but it can be several times faster  when
    3476             : called for ordered X[] and X2[].
    3477             : 
    3478             : INPUT PARAMETERS:
    3479             :     X           -   old spline nodes
    3480             :     Y           -   function values
    3481             :     X2           -  new spline nodes
    3482             : 
    3483             : OPTIONAL PARAMETERS:
    3484             :     N           -   points count:
    3485             :                     * N>=2
    3486             :                     * if given, only first N points from X/Y are used
    3487             :                     * if not given, automatically detected from X/Y sizes
    3488             :                       (len(X) must be equal to len(Y))
    3489             :     BoundLType  -   boundary condition type for the left boundary
    3490             :     BoundL      -   left boundary condition (first or second derivative,
    3491             :                     depending on the BoundLType)
    3492             :     BoundRType  -   boundary condition type for the right boundary
    3493             :     BoundR      -   right boundary condition (first or second derivative,
    3494             :                     depending on the BoundRType)
    3495             :     N2          -   new points count:
    3496             :                     * N2>=2
    3497             :                     * if given, only first N2 points from X2 are used
    3498             :                     * if not given, automatically detected from X2 size
    3499             : 
    3500             : OUTPUT PARAMETERS:
    3501             :     F2          -   function values at X2[]
    3502             :     D2          -   first derivatives at X2[]
    3503             : 
    3504             : ORDER OF POINTS
    3505             : 
    3506             : Subroutine automatically sorts points, so caller  may pass unsorted array.
    3507             : Function  values  are correctly reordered on  return, so F2[I]  is  always
    3508             : equal to S(X2[I]) independently of points order.
    3509             : 
    3510             : SETTING BOUNDARY VALUES:
    3511             : 
    3512             : The BoundLType/BoundRType parameters can have the following values:
    3513             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    3514             :           In this case:
    3515             :           * both BoundLType and BoundRType must be equal to -1.
    3516             :           * BoundL/BoundR are ignored
    3517             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    3518             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    3519             :           (BoundL and/or BoundR are ignored).
    3520             :     *  1, which corresponds to the first derivative boundary condition
    3521             :     *  2, which corresponds to the second derivative boundary condition
    3522             :     *  by default, BoundType=0 is used
    3523             : 
    3524             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3525             : 
    3526             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3527             : However, this subroutine doesn't require you to specify equal  values  for
    3528             : the first and last points - it automatically forces them  to  be  equal by
    3529             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3530             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3531             : i.e. to make Y[first_point]=Y[last_point].
    3532             : 
    3533             :   -- ALGLIB PROJECT --
    3534             :      Copyright 03.09.2010 by Bochkanov Sergey
    3535             : *************************************************************************/
    3536           0 : 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)
    3537             : {
    3538             :     jmp_buf _break_jump;
    3539             :     alglib_impl::ae_state _alglib_env_state;
    3540           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3541           0 :     if( setjmp(_break_jump) )
    3542             :     {
    3543             : #if !defined(AE_NO_EXCEPTIONS)
    3544           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3545             : #else
    3546             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    3547             :         return;
    3548             : #endif
    3549             :     }
    3550           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3551           0 :     if( _xparams.flags!=0x0 )
    3552           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3553           0 :     alglib_impl::spline1dconvdiffcubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::ae_vector*>(x2.c_ptr()), n2, const_cast<alglib_impl::ae_vector*>(y2.c_ptr()), const_cast<alglib_impl::ae_vector*>(d2.c_ptr()), &_alglib_env_state);
    3554           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3555           0 :     return;
    3556             : }
    3557             : 
    3558             : /*************************************************************************
    3559             : This function solves following problem: given table y[] of function values
    3560             : at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
    3561             : function values y2[] and derivatives d2[] (calculated at x2[]).
    3562             : 
    3563             : This function yields same result as Spline1DBuildCubic() call followed  by
    3564             : sequence of Spline1DDiff() calls, but it can be several times faster  when
    3565             : called for ordered X[] and X2[].
    3566             : 
    3567             : INPUT PARAMETERS:
    3568             :     X           -   old spline nodes
    3569             :     Y           -   function values
    3570             :     X2           -  new spline nodes
    3571             : 
    3572             : OPTIONAL PARAMETERS:
    3573             :     N           -   points count:
    3574             :                     * N>=2
    3575             :                     * if given, only first N points from X/Y are used
    3576             :                     * if not given, automatically detected from X/Y sizes
    3577             :                       (len(X) must be equal to len(Y))
    3578             :     BoundLType  -   boundary condition type for the left boundary
    3579             :     BoundL      -   left boundary condition (first or second derivative,
    3580             :                     depending on the BoundLType)
    3581             :     BoundRType  -   boundary condition type for the right boundary
    3582             :     BoundR      -   right boundary condition (first or second derivative,
    3583             :                     depending on the BoundRType)
    3584             :     N2          -   new points count:
    3585             :                     * N2>=2
    3586             :                     * if given, only first N2 points from X2 are used
    3587             :                     * if not given, automatically detected from X2 size
    3588             : 
    3589             : OUTPUT PARAMETERS:
    3590             :     F2          -   function values at X2[]
    3591             :     D2          -   first derivatives at X2[]
    3592             : 
    3593             : ORDER OF POINTS
    3594             : 
    3595             : Subroutine automatically sorts points, so caller  may pass unsorted array.
    3596             : Function  values  are correctly reordered on  return, so F2[I]  is  always
    3597             : equal to S(X2[I]) independently of points order.
    3598             : 
    3599             : SETTING BOUNDARY VALUES:
    3600             : 
    3601             : The BoundLType/BoundRType parameters can have the following values:
    3602             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    3603             :           In this case:
    3604             :           * both BoundLType and BoundRType must be equal to -1.
    3605             :           * BoundL/BoundR are ignored
    3606             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    3607             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    3608             :           (BoundL and/or BoundR are ignored).
    3609             :     *  1, which corresponds to the first derivative boundary condition
    3610             :     *  2, which corresponds to the second derivative boundary condition
    3611             :     *  by default, BoundType=0 is used
    3612             : 
    3613             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3614             : 
    3615             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3616             : However, this subroutine doesn't require you to specify equal  values  for
    3617             : the first and last points - it automatically forces them  to  be  equal by
    3618             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3619             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3620             : i.e. to make Y[first_point]=Y[last_point].
    3621             : 
    3622             :   -- ALGLIB PROJECT --
    3623             :      Copyright 03.09.2010 by Bochkanov Sergey
    3624             : *************************************************************************/
    3625             : #if !defined(AE_NO_EXCEPTIONS)
    3626           0 : 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)
    3627             : {
    3628             :     jmp_buf _break_jump;
    3629             :     alglib_impl::ae_state _alglib_env_state;    
    3630             :     ae_int_t n;
    3631             :     ae_int_t boundltype;
    3632             :     double boundl;
    3633             :     ae_int_t boundrtype;
    3634             :     double boundr;
    3635             :     ae_int_t n2;
    3636           0 :     if( (x.length()!=y.length()))
    3637           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dconvdiffcubic': looks like one of arguments has wrong size");
    3638           0 :     n = x.length();
    3639           0 :     boundltype = 0;
    3640           0 :     boundl = 0;
    3641           0 :     boundrtype = 0;
    3642           0 :     boundr = 0;
    3643           0 :     n2 = x2.length();
    3644           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3645           0 :     if( setjmp(_break_jump) )
    3646           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3647           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3648           0 :     if( _xparams.flags!=0x0 )
    3649           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3650           0 :     alglib_impl::spline1dconvdiffcubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::ae_vector*>(x2.c_ptr()), n2, const_cast<alglib_impl::ae_vector*>(y2.c_ptr()), const_cast<alglib_impl::ae_vector*>(d2.c_ptr()), &_alglib_env_state);
    3651             : 
    3652           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3653           0 :     return;
    3654             : }
    3655             : #endif
    3656             : 
    3657             : /*************************************************************************
    3658             : This function solves following problem: given table y[] of function values
    3659             : at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
    3660             : function  values  y2[],  first  and  second  derivatives  d2[]  and  dd2[]
    3661             : (calculated at x2[]).
    3662             : 
    3663             : This function yields same result as Spline1DBuildCubic() call followed  by
    3664             : sequence of Spline1DDiff() calls, but it can be several times faster  when
    3665             : called for ordered X[] and X2[].
    3666             : 
    3667             : INPUT PARAMETERS:
    3668             :     X           -   old spline nodes
    3669             :     Y           -   function values
    3670             :     X2           -  new spline nodes
    3671             : 
    3672             : OPTIONAL PARAMETERS:
    3673             :     N           -   points count:
    3674             :                     * N>=2
    3675             :                     * if given, only first N points from X/Y are used
    3676             :                     * if not given, automatically detected from X/Y sizes
    3677             :                       (len(X) must be equal to len(Y))
    3678             :     BoundLType  -   boundary condition type for the left boundary
    3679             :     BoundL      -   left boundary condition (first or second derivative,
    3680             :                     depending on the BoundLType)
    3681             :     BoundRType  -   boundary condition type for the right boundary
    3682             :     BoundR      -   right boundary condition (first or second derivative,
    3683             :                     depending on the BoundRType)
    3684             :     N2          -   new points count:
    3685             :                     * N2>=2
    3686             :                     * if given, only first N2 points from X2 are used
    3687             :                     * if not given, automatically detected from X2 size
    3688             : 
    3689             : OUTPUT PARAMETERS:
    3690             :     F2          -   function values at X2[]
    3691             :     D2          -   first derivatives at X2[]
    3692             :     DD2         -   second derivatives at X2[]
    3693             : 
    3694             : ORDER OF POINTS
    3695             : 
    3696             : Subroutine automatically sorts points, so caller  may pass unsorted array.
    3697             : Function  values  are correctly reordered on  return, so F2[I]  is  always
    3698             : equal to S(X2[I]) independently of points order.
    3699             : 
    3700             : SETTING BOUNDARY VALUES:
    3701             : 
    3702             : The BoundLType/BoundRType parameters can have the following values:
    3703             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    3704             :           In this case:
    3705             :           * both BoundLType and BoundRType must be equal to -1.
    3706             :           * BoundL/BoundR are ignored
    3707             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    3708             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    3709             :           (BoundL and/or BoundR are ignored).
    3710             :     *  1, which corresponds to the first derivative boundary condition
    3711             :     *  2, which corresponds to the second derivative boundary condition
    3712             :     *  by default, BoundType=0 is used
    3713             : 
    3714             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3715             : 
    3716             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3717             : However, this subroutine doesn't require you to specify equal  values  for
    3718             : the first and last points - it automatically forces them  to  be  equal by
    3719             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3720             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3721             : i.e. to make Y[first_point]=Y[last_point].
    3722             : 
    3723             :   -- ALGLIB PROJECT --
    3724             :      Copyright 03.09.2010 by Bochkanov Sergey
    3725             : *************************************************************************/
    3726           0 : 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)
    3727             : {
    3728             :     jmp_buf _break_jump;
    3729             :     alglib_impl::ae_state _alglib_env_state;
    3730           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3731           0 :     if( setjmp(_break_jump) )
    3732             :     {
    3733             : #if !defined(AE_NO_EXCEPTIONS)
    3734           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3735             : #else
    3736             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    3737             :         return;
    3738             : #endif
    3739             :     }
    3740           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3741           0 :     if( _xparams.flags!=0x0 )
    3742           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3743           0 :     alglib_impl::spline1dconvdiff2cubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::ae_vector*>(x2.c_ptr()), n2, const_cast<alglib_impl::ae_vector*>(y2.c_ptr()), const_cast<alglib_impl::ae_vector*>(d2.c_ptr()), const_cast<alglib_impl::ae_vector*>(dd2.c_ptr()), &_alglib_env_state);
    3744           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3745           0 :     return;
    3746             : }
    3747             : 
    3748             : /*************************************************************************
    3749             : This function solves following problem: given table y[] of function values
    3750             : at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
    3751             : function  values  y2[],  first  and  second  derivatives  d2[]  and  dd2[]
    3752             : (calculated at x2[]).
    3753             : 
    3754             : This function yields same result as Spline1DBuildCubic() call followed  by
    3755             : sequence of Spline1DDiff() calls, but it can be several times faster  when
    3756             : called for ordered X[] and X2[].
    3757             : 
    3758             : INPUT PARAMETERS:
    3759             :     X           -   old spline nodes
    3760             :     Y           -   function values
    3761             :     X2           -  new spline nodes
    3762             : 
    3763             : OPTIONAL PARAMETERS:
    3764             :     N           -   points count:
    3765             :                     * N>=2
    3766             :                     * if given, only first N points from X/Y are used
    3767             :                     * if not given, automatically detected from X/Y sizes
    3768             :                       (len(X) must be equal to len(Y))
    3769             :     BoundLType  -   boundary condition type for the left boundary
    3770             :     BoundL      -   left boundary condition (first or second derivative,
    3771             :                     depending on the BoundLType)
    3772             :     BoundRType  -   boundary condition type for the right boundary
    3773             :     BoundR      -   right boundary condition (first or second derivative,
    3774             :                     depending on the BoundRType)
    3775             :     N2          -   new points count:
    3776             :                     * N2>=2
    3777             :                     * if given, only first N2 points from X2 are used
    3778             :                     * if not given, automatically detected from X2 size
    3779             : 
    3780             : OUTPUT PARAMETERS:
    3781             :     F2          -   function values at X2[]
    3782             :     D2          -   first derivatives at X2[]
    3783             :     DD2         -   second derivatives at X2[]
    3784             : 
    3785             : ORDER OF POINTS
    3786             : 
    3787             : Subroutine automatically sorts points, so caller  may pass unsorted array.
    3788             : Function  values  are correctly reordered on  return, so F2[I]  is  always
    3789             : equal to S(X2[I]) independently of points order.
    3790             : 
    3791             : SETTING BOUNDARY VALUES:
    3792             : 
    3793             : The BoundLType/BoundRType parameters can have the following values:
    3794             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
    3795             :           In this case:
    3796             :           * both BoundLType and BoundRType must be equal to -1.
    3797             :           * BoundL/BoundR are ignored
    3798             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
    3799             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
    3800             :           (BoundL and/or BoundR are ignored).
    3801             :     *  1, which corresponds to the first derivative boundary condition
    3802             :     *  2, which corresponds to the second derivative boundary condition
    3803             :     *  by default, BoundType=0 is used
    3804             : 
    3805             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3806             : 
    3807             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3808             : However, this subroutine doesn't require you to specify equal  values  for
    3809             : the first and last points - it automatically forces them  to  be  equal by
    3810             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3811             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3812             : i.e. to make Y[first_point]=Y[last_point].
    3813             : 
    3814             :   -- ALGLIB PROJECT --
    3815             :      Copyright 03.09.2010 by Bochkanov Sergey
    3816             : *************************************************************************/
    3817             : #if !defined(AE_NO_EXCEPTIONS)
    3818           0 : 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)
    3819             : {
    3820             :     jmp_buf _break_jump;
    3821             :     alglib_impl::ae_state _alglib_env_state;    
    3822             :     ae_int_t n;
    3823             :     ae_int_t boundltype;
    3824             :     double boundl;
    3825             :     ae_int_t boundrtype;
    3826             :     double boundr;
    3827             :     ae_int_t n2;
    3828           0 :     if( (x.length()!=y.length()))
    3829           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dconvdiff2cubic': looks like one of arguments has wrong size");
    3830           0 :     n = x.length();
    3831           0 :     boundltype = 0;
    3832           0 :     boundl = 0;
    3833           0 :     boundrtype = 0;
    3834           0 :     boundr = 0;
    3835           0 :     n2 = x2.length();
    3836           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3837           0 :     if( setjmp(_break_jump) )
    3838           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3839           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3840           0 :     if( _xparams.flags!=0x0 )
    3841           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3842           0 :     alglib_impl::spline1dconvdiff2cubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundltype, boundl, boundrtype, boundr, const_cast<alglib_impl::ae_vector*>(x2.c_ptr()), n2, const_cast<alglib_impl::ae_vector*>(y2.c_ptr()), const_cast<alglib_impl::ae_vector*>(d2.c_ptr()), const_cast<alglib_impl::ae_vector*>(dd2.c_ptr()), &_alglib_env_state);
    3843             : 
    3844           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3845           0 :     return;
    3846             : }
    3847             : #endif
    3848             : 
    3849             : /*************************************************************************
    3850             : This subroutine builds Catmull-Rom spline interpolant.
    3851             : 
    3852             : INPUT PARAMETERS:
    3853             :     X           -   spline nodes, array[0..N-1].
    3854             :     Y           -   function values, array[0..N-1].
    3855             : 
    3856             : OPTIONAL PARAMETERS:
    3857             :     N           -   points count:
    3858             :                     * N>=2
    3859             :                     * if given, only first N points are used to build spline
    3860             :                     * if not given, automatically detected from X/Y sizes
    3861             :                       (len(X) must be equal to len(Y))
    3862             :     BoundType   -   boundary condition type:
    3863             :                     * -1 for periodic boundary condition
    3864             :                     *  0 for parabolically terminated spline (default)
    3865             :     Tension     -   tension parameter:
    3866             :                     * tension=0   corresponds to classic Catmull-Rom spline (default)
    3867             :                     * 0<tension<1 corresponds to more general form - cardinal spline
    3868             : 
    3869             : OUTPUT PARAMETERS:
    3870             :     C           -   spline interpolant
    3871             : 
    3872             : 
    3873             : ORDER OF POINTS
    3874             : 
    3875             : Subroutine automatically sorts points, so caller may pass unsorted array.
    3876             : 
    3877             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3878             : 
    3879             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3880             : However, this subroutine doesn't require you to specify equal  values  for
    3881             : the first and last points - it automatically forces them  to  be  equal by
    3882             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3883             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3884             : i.e. to make Y[first_point]=Y[last_point].
    3885             : 
    3886             :   -- ALGLIB PROJECT --
    3887             :      Copyright 23.06.2007 by Bochkanov Sergey
    3888             : *************************************************************************/
    3889           0 : void spline1dbuildcatmullrom(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundtype, const double tension, spline1dinterpolant &c, const xparams _xparams)
    3890             : {
    3891             :     jmp_buf _break_jump;
    3892             :     alglib_impl::ae_state _alglib_env_state;
    3893           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3894           0 :     if( setjmp(_break_jump) )
    3895             :     {
    3896             : #if !defined(AE_NO_EXCEPTIONS)
    3897           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3898             : #else
    3899             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    3900             :         return;
    3901             : #endif
    3902             :     }
    3903           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3904           0 :     if( _xparams.flags!=0x0 )
    3905           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3906           0 :     alglib_impl::spline1dbuildcatmullrom(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundtype, tension, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    3907           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3908           0 :     return;
    3909             : }
    3910             : 
    3911             : /*************************************************************************
    3912             : This subroutine builds Catmull-Rom spline interpolant.
    3913             : 
    3914             : INPUT PARAMETERS:
    3915             :     X           -   spline nodes, array[0..N-1].
    3916             :     Y           -   function values, array[0..N-1].
    3917             : 
    3918             : OPTIONAL PARAMETERS:
    3919             :     N           -   points count:
    3920             :                     * N>=2
    3921             :                     * if given, only first N points are used to build spline
    3922             :                     * if not given, automatically detected from X/Y sizes
    3923             :                       (len(X) must be equal to len(Y))
    3924             :     BoundType   -   boundary condition type:
    3925             :                     * -1 for periodic boundary condition
    3926             :                     *  0 for parabolically terminated spline (default)
    3927             :     Tension     -   tension parameter:
    3928             :                     * tension=0   corresponds to classic Catmull-Rom spline (default)
    3929             :                     * 0<tension<1 corresponds to more general form - cardinal spline
    3930             : 
    3931             : OUTPUT PARAMETERS:
    3932             :     C           -   spline interpolant
    3933             : 
    3934             : 
    3935             : ORDER OF POINTS
    3936             : 
    3937             : Subroutine automatically sorts points, so caller may pass unsorted array.
    3938             : 
    3939             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
    3940             : 
    3941             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
    3942             : However, this subroutine doesn't require you to specify equal  values  for
    3943             : the first and last points - it automatically forces them  to  be  equal by
    3944             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
    3945             : Y[last_point]. However it is recommended to pass consistent values of Y[],
    3946             : i.e. to make Y[first_point]=Y[last_point].
    3947             : 
    3948             :   -- ALGLIB PROJECT --
    3949             :      Copyright 23.06.2007 by Bochkanov Sergey
    3950             : *************************************************************************/
    3951             : #if !defined(AE_NO_EXCEPTIONS)
    3952           0 : void spline1dbuildcatmullrom(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams)
    3953             : {
    3954             :     jmp_buf _break_jump;
    3955             :     alglib_impl::ae_state _alglib_env_state;    
    3956             :     ae_int_t n;
    3957             :     ae_int_t boundtype;
    3958             :     double tension;
    3959           0 :     if( (x.length()!=y.length()))
    3960           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildcatmullrom': looks like one of arguments has wrong size");
    3961           0 :     n = x.length();
    3962           0 :     boundtype = 0;
    3963           0 :     tension = 0;
    3964           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    3965           0 :     if( setjmp(_break_jump) )
    3966           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    3967           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    3968           0 :     if( _xparams.flags!=0x0 )
    3969           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    3970           0 :     alglib_impl::spline1dbuildcatmullrom(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, boundtype, tension, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    3971             : 
    3972           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    3973           0 :     return;
    3974             : }
    3975             : #endif
    3976             : 
    3977             : /*************************************************************************
    3978             : This subroutine builds Hermite spline interpolant.
    3979             : 
    3980             : INPUT PARAMETERS:
    3981             :     X           -   spline nodes, array[0..N-1]
    3982             :     Y           -   function values, array[0..N-1]
    3983             :     D           -   derivatives, array[0..N-1]
    3984             :     N           -   points count (optional):
    3985             :                     * N>=2
    3986             :                     * if given, only first N points are used to build spline
    3987             :                     * if not given, automatically detected from X/Y sizes
    3988             :                       (len(X) must be equal to len(Y))
    3989             : 
    3990             : OUTPUT PARAMETERS:
    3991             :     C           -   spline interpolant.
    3992             : 
    3993             : 
    3994             : ORDER OF POINTS
    3995             : 
    3996             : Subroutine automatically sorts points, so caller may pass unsorted array.
    3997             : 
    3998             :   -- ALGLIB PROJECT --
    3999             :      Copyright 23.06.2007 by Bochkanov Sergey
    4000             : *************************************************************************/
    4001           0 : 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)
    4002             : {
    4003             :     jmp_buf _break_jump;
    4004             :     alglib_impl::ae_state _alglib_env_state;
    4005           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4006           0 :     if( setjmp(_break_jump) )
    4007             :     {
    4008             : #if !defined(AE_NO_EXCEPTIONS)
    4009           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4010             : #else
    4011             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4012             :         return;
    4013             : #endif
    4014             :     }
    4015           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4016           0 :     if( _xparams.flags!=0x0 )
    4017           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4018           0 :     alglib_impl::spline1dbuildhermite(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(d.c_ptr()), n, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    4019           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4020           0 :     return;
    4021             : }
    4022             : 
    4023             : /*************************************************************************
    4024             : This subroutine builds Hermite spline interpolant.
    4025             : 
    4026             : INPUT PARAMETERS:
    4027             :     X           -   spline nodes, array[0..N-1]
    4028             :     Y           -   function values, array[0..N-1]
    4029             :     D           -   derivatives, array[0..N-1]
    4030             :     N           -   points count (optional):
    4031             :                     * N>=2
    4032             :                     * if given, only first N points are used to build spline
    4033             :                     * if not given, automatically detected from X/Y sizes
    4034             :                       (len(X) must be equal to len(Y))
    4035             : 
    4036             : OUTPUT PARAMETERS:
    4037             :     C           -   spline interpolant.
    4038             : 
    4039             : 
    4040             : ORDER OF POINTS
    4041             : 
    4042             : Subroutine automatically sorts points, so caller may pass unsorted array.
    4043             : 
    4044             :   -- ALGLIB PROJECT --
    4045             :      Copyright 23.06.2007 by Bochkanov Sergey
    4046             : *************************************************************************/
    4047             : #if !defined(AE_NO_EXCEPTIONS)
    4048           0 : void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, spline1dinterpolant &c, const xparams _xparams)
    4049             : {
    4050             :     jmp_buf _break_jump;
    4051             :     alglib_impl::ae_state _alglib_env_state;    
    4052             :     ae_int_t n;
    4053           0 :     if( (x.length()!=y.length()) || (x.length()!=d.length()))
    4054           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildhermite': looks like one of arguments has wrong size");
    4055           0 :     n = x.length();
    4056           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4057           0 :     if( setjmp(_break_jump) )
    4058           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4059           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4060           0 :     if( _xparams.flags!=0x0 )
    4061           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4062           0 :     alglib_impl::spline1dbuildhermite(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(d.c_ptr()), n, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    4063             : 
    4064           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4065           0 :     return;
    4066             : }
    4067             : #endif
    4068             : 
    4069             : /*************************************************************************
    4070             : This subroutine builds Akima spline interpolant
    4071             : 
    4072             : INPUT PARAMETERS:
    4073             :     X           -   spline nodes, array[0..N-1]
    4074             :     Y           -   function values, array[0..N-1]
    4075             :     N           -   points count (optional):
    4076             :                     * N>=2
    4077             :                     * if given, only first N points are used to build spline
    4078             :                     * if not given, automatically detected from X/Y sizes
    4079             :                       (len(X) must be equal to len(Y))
    4080             : 
    4081             : OUTPUT PARAMETERS:
    4082             :     C           -   spline interpolant
    4083             : 
    4084             : 
    4085             : ORDER OF POINTS
    4086             : 
    4087             : Subroutine automatically sorts points, so caller may pass unsorted array.
    4088             : 
    4089             :   -- ALGLIB PROJECT --
    4090             :      Copyright 24.06.2007 by Bochkanov Sergey
    4091             : *************************************************************************/
    4092           0 : void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams)
    4093             : {
    4094             :     jmp_buf _break_jump;
    4095             :     alglib_impl::ae_state _alglib_env_state;
    4096           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4097           0 :     if( setjmp(_break_jump) )
    4098             :     {
    4099             : #if !defined(AE_NO_EXCEPTIONS)
    4100           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4101             : #else
    4102             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4103             :         return;
    4104             : #endif
    4105             :     }
    4106           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4107           0 :     if( _xparams.flags!=0x0 )
    4108           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4109           0 :     alglib_impl::spline1dbuildakima(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    4110           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4111           0 :     return;
    4112             : }
    4113             : 
    4114             : /*************************************************************************
    4115             : This subroutine builds Akima spline interpolant
    4116             : 
    4117             : INPUT PARAMETERS:
    4118             :     X           -   spline nodes, array[0..N-1]
    4119             :     Y           -   function values, array[0..N-1]
    4120             :     N           -   points count (optional):
    4121             :                     * N>=2
    4122             :                     * if given, only first N points are used to build spline
    4123             :                     * if not given, automatically detected from X/Y sizes
    4124             :                       (len(X) must be equal to len(Y))
    4125             : 
    4126             : OUTPUT PARAMETERS:
    4127             :     C           -   spline interpolant
    4128             : 
    4129             : 
    4130             : ORDER OF POINTS
    4131             : 
    4132             : Subroutine automatically sorts points, so caller may pass unsorted array.
    4133             : 
    4134             :   -- ALGLIB PROJECT --
    4135             :      Copyright 24.06.2007 by Bochkanov Sergey
    4136             : *************************************************************************/
    4137             : #if !defined(AE_NO_EXCEPTIONS)
    4138           0 : void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams)
    4139             : {
    4140             :     jmp_buf _break_jump;
    4141             :     alglib_impl::ae_state _alglib_env_state;    
    4142             :     ae_int_t n;
    4143           0 :     if( (x.length()!=y.length()))
    4144           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildakima': looks like one of arguments has wrong size");
    4145           0 :     n = x.length();
    4146           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4147           0 :     if( setjmp(_break_jump) )
    4148           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4149           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4150           0 :     if( _xparams.flags!=0x0 )
    4151           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4152           0 :     alglib_impl::spline1dbuildakima(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    4153             : 
    4154           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4155           0 :     return;
    4156             : }
    4157             : #endif
    4158             : 
    4159             : /*************************************************************************
    4160             : This subroutine calculates the value of the spline at the given point X.
    4161             : 
    4162             : INPUT PARAMETERS:
    4163             :     C   -   spline interpolant
    4164             :     X   -   point
    4165             : 
    4166             : Result:
    4167             :     S(x)
    4168             : 
    4169             :   -- ALGLIB PROJECT --
    4170             :      Copyright 23.06.2007 by Bochkanov Sergey
    4171             : *************************************************************************/
    4172           0 : double spline1dcalc(const spline1dinterpolant &c, const double x, const xparams _xparams)
    4173             : {
    4174             :     jmp_buf _break_jump;
    4175             :     alglib_impl::ae_state _alglib_env_state;
    4176           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4177           0 :     if( setjmp(_break_jump) )
    4178             :     {
    4179             : #if !defined(AE_NO_EXCEPTIONS)
    4180           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4181             : #else
    4182             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4183             :         return 0;
    4184             : #endif
    4185             :     }
    4186           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4187           0 :     if( _xparams.flags!=0x0 )
    4188           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4189           0 :     double result = alglib_impl::spline1dcalc(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), x, &_alglib_env_state);
    4190           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4191           0 :     return *(reinterpret_cast<double*>(&result));
    4192             : }
    4193             : 
    4194             : /*************************************************************************
    4195             : This subroutine differentiates the spline.
    4196             : 
    4197             : INPUT PARAMETERS:
    4198             :     C   -   spline interpolant.
    4199             :     X   -   point
    4200             : 
    4201             : Result:
    4202             :     S   -   S(x)
    4203             :     DS  -   S'(x)
    4204             :     D2S -   S''(x)
    4205             : 
    4206             :   -- ALGLIB PROJECT --
    4207             :      Copyright 24.06.2007 by Bochkanov Sergey
    4208             : *************************************************************************/
    4209           0 : void spline1ddiff(const spline1dinterpolant &c, const double x, double &s, double &ds, double &d2s, const xparams _xparams)
    4210             : {
    4211             :     jmp_buf _break_jump;
    4212             :     alglib_impl::ae_state _alglib_env_state;
    4213           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4214           0 :     if( setjmp(_break_jump) )
    4215             :     {
    4216             : #if !defined(AE_NO_EXCEPTIONS)
    4217           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4218             : #else
    4219             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4220             :         return;
    4221             : #endif
    4222             :     }
    4223           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4224           0 :     if( _xparams.flags!=0x0 )
    4225           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4226           0 :     alglib_impl::spline1ddiff(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), x, &s, &ds, &d2s, &_alglib_env_state);
    4227           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4228           0 :     return;
    4229             : }
    4230             : 
    4231             : /*************************************************************************
    4232             : This subroutine unpacks the spline into the coefficients table.
    4233             : 
    4234             : INPUT PARAMETERS:
    4235             :     C   -   spline interpolant.
    4236             :     X   -   point
    4237             : 
    4238             : OUTPUT PARAMETERS:
    4239             :     Tbl -   coefficients table, unpacked format, array[0..N-2, 0..5].
    4240             :             For I = 0...N-2:
    4241             :                 Tbl[I,0] = X[i]
    4242             :                 Tbl[I,1] = X[i+1]
    4243             :                 Tbl[I,2] = C0
    4244             :                 Tbl[I,3] = C1
    4245             :                 Tbl[I,4] = C2
    4246             :                 Tbl[I,5] = C3
    4247             :             On [x[i], x[i+1]] spline is equals to:
    4248             :                 S(x) = C0 + C1*t + C2*t^2 + C3*t^3
    4249             :                 t = x-x[i]
    4250             : 
    4251             : NOTE:
    4252             :     You  can rebuild spline with  Spline1DBuildHermite()  function,  which
    4253             :     accepts as inputs function values and derivatives at nodes, which  are
    4254             :     easy to calculate when you have coefficients.
    4255             : 
    4256             :   -- ALGLIB PROJECT --
    4257             :      Copyright 29.06.2007 by Bochkanov Sergey
    4258             : *************************************************************************/
    4259           0 : void spline1dunpack(const spline1dinterpolant &c, ae_int_t &n, real_2d_array &tbl, const xparams _xparams)
    4260             : {
    4261             :     jmp_buf _break_jump;
    4262             :     alglib_impl::ae_state _alglib_env_state;
    4263           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4264           0 :     if( setjmp(_break_jump) )
    4265             :     {
    4266             : #if !defined(AE_NO_EXCEPTIONS)
    4267           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4268             : #else
    4269             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4270             :         return;
    4271             : #endif
    4272             :     }
    4273           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4274           0 :     if( _xparams.flags!=0x0 )
    4275           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4276           0 :     alglib_impl::spline1dunpack(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &n, const_cast<alglib_impl::ae_matrix*>(tbl.c_ptr()), &_alglib_env_state);
    4277           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4278           0 :     return;
    4279             : }
    4280             : 
    4281             : /*************************************************************************
    4282             : This subroutine performs linear transformation of the spline argument.
    4283             : 
    4284             : INPUT PARAMETERS:
    4285             :     C   -   spline interpolant.
    4286             :     A, B-   transformation coefficients: x = A*t + B
    4287             : Result:
    4288             :     C   -   transformed spline
    4289             : 
    4290             :   -- ALGLIB PROJECT --
    4291             :      Copyright 30.06.2007 by Bochkanov Sergey
    4292             : *************************************************************************/
    4293           0 : void spline1dlintransx(const spline1dinterpolant &c, const double a, const double b, const xparams _xparams)
    4294             : {
    4295             :     jmp_buf _break_jump;
    4296             :     alglib_impl::ae_state _alglib_env_state;
    4297           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4298           0 :     if( setjmp(_break_jump) )
    4299             :     {
    4300             : #if !defined(AE_NO_EXCEPTIONS)
    4301           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4302             : #else
    4303             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4304             :         return;
    4305             : #endif
    4306             :     }
    4307           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4308           0 :     if( _xparams.flags!=0x0 )
    4309           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4310           0 :     alglib_impl::spline1dlintransx(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), a, b, &_alglib_env_state);
    4311           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4312           0 :     return;
    4313             : }
    4314             : 
    4315             : /*************************************************************************
    4316             : This subroutine performs linear transformation of the spline.
    4317             : 
    4318             : INPUT PARAMETERS:
    4319             :     C   -   spline interpolant.
    4320             :     A, B-   transformation coefficients: S2(x) = A*S(x) + B
    4321             : Result:
    4322             :     C   -   transformed spline
    4323             : 
    4324             :   -- ALGLIB PROJECT --
    4325             :      Copyright 30.06.2007 by Bochkanov Sergey
    4326             : *************************************************************************/
    4327           0 : void spline1dlintransy(const spline1dinterpolant &c, const double a, const double b, const xparams _xparams)
    4328             : {
    4329             :     jmp_buf _break_jump;
    4330             :     alglib_impl::ae_state _alglib_env_state;
    4331           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4332           0 :     if( setjmp(_break_jump) )
    4333             :     {
    4334             : #if !defined(AE_NO_EXCEPTIONS)
    4335           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4336             : #else
    4337             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4338             :         return;
    4339             : #endif
    4340             :     }
    4341           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4342           0 :     if( _xparams.flags!=0x0 )
    4343           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4344           0 :     alglib_impl::spline1dlintransy(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), a, b, &_alglib_env_state);
    4345           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4346           0 :     return;
    4347             : }
    4348             : 
    4349             : /*************************************************************************
    4350             : This subroutine integrates the spline.
    4351             : 
    4352             : INPUT PARAMETERS:
    4353             :     C   -   spline interpolant.
    4354             :     X   -   right bound of the integration interval [a, x],
    4355             :             here 'a' denotes min(x[])
    4356             : Result:
    4357             :     integral(S(t)dt,a,x)
    4358             : 
    4359             :   -- ALGLIB PROJECT --
    4360             :      Copyright 23.06.2007 by Bochkanov Sergey
    4361             : *************************************************************************/
    4362           0 : double spline1dintegrate(const spline1dinterpolant &c, const double x, const xparams _xparams)
    4363             : {
    4364             :     jmp_buf _break_jump;
    4365             :     alglib_impl::ae_state _alglib_env_state;
    4366           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4367           0 :     if( setjmp(_break_jump) )
    4368             :     {
    4369             : #if !defined(AE_NO_EXCEPTIONS)
    4370           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4371             : #else
    4372             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4373             :         return 0;
    4374             : #endif
    4375             :     }
    4376           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4377           0 :     if( _xparams.flags!=0x0 )
    4378           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4379           0 :     double result = alglib_impl::spline1dintegrate(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), x, &_alglib_env_state);
    4380           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4381           0 :     return *(reinterpret_cast<double*>(&result));
    4382             : }
    4383             : 
    4384             : /*************************************************************************
    4385             : Fitting by smoothing (penalized) cubic spline.
    4386             : 
    4387             : This function approximates N scattered points (some of X[] may be equal to
    4388             : each other) by cubic spline with M  nodes  at  equidistant  grid  spanning
    4389             : interval [min(x,xc),max(x,xc)].
    4390             : 
    4391             : The problem is regularized by adding nonlinearity penalty to  usual  least
    4392             : squares penalty function:
    4393             : 
    4394             :     MERIT_FUNC = F_LS + F_NL
    4395             : 
    4396             : where F_LS is a least squares error  term,  and  F_NL  is  a  nonlinearity
    4397             : penalty which is roughly proportional to LambdaNS*integral{ S''(x)^2*dx }.
    4398             : Algorithm applies automatic renormalization of F_NL  which  makes  penalty
    4399             : term roughly invariant to scaling of X[] and changes in M.
    4400             : 
    4401             : This function is a new edition  of  penalized  regression  spline fitting,
    4402             : a fast and compact one which needs much less resources that  its  previous
    4403             : version: just O(maxMN) memory and O(maxMN*log(maxMN)) time.
    4404             : 
    4405             : NOTE: it is OK to run this function with both M<<N and M>>N;  say,  it  is
    4406             :       possible to process 100 points with 1000-node spline.
    4407             : 
    4408             : INPUT PARAMETERS:
    4409             :     X           -   points, array[0..N-1].
    4410             :     Y           -   function values, array[0..N-1].
    4411             :     N           -   number of points (optional):
    4412             :                     * N>0
    4413             :                     * if given, only first N elements of X/Y are processed
    4414             :                     * if not given, automatically determined from lengths
    4415             :     M           -   number of basis functions ( = number_of_nodes), M>=4.
    4416             :     LambdaNS    -   LambdaNS>=0, regularization  constant  passed by user.
    4417             :                     It penalizes nonlinearity in the regression spline.
    4418             :                     Possible values to start from are 0.00001, 0.1, 1
    4419             : 
    4420             : OUTPUT PARAMETERS:
    4421             :     S   -   spline interpolant.
    4422             :     Rep -   Following fields are set:
    4423             :             * RMSError      rms error on the (X,Y).
    4424             :             * AvgError      average error on the (X,Y).
    4425             :             * AvgRelError   average relative error on the non-zero Y
    4426             :             * MaxError      maximum error
    4427             : 
    4428             :   -- ALGLIB PROJECT --
    4429             :      Copyright 27.08.2019 by Bochkanov Sergey
    4430             : *************************************************************************/
    4431           0 : 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)
    4432             : {
    4433             :     jmp_buf _break_jump;
    4434             :     alglib_impl::ae_state _alglib_env_state;
    4435           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4436           0 :     if( setjmp(_break_jump) )
    4437             :     {
    4438             : #if !defined(AE_NO_EXCEPTIONS)
    4439           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4440             : #else
    4441             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4442             :         return;
    4443             : #endif
    4444             :     }
    4445           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4446           0 :     if( _xparams.flags!=0x0 )
    4447           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4448           0 :     alglib_impl::spline1dfit(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, lambdans, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
    4449           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4450           0 :     return;
    4451             : }
    4452             : 
    4453             : /*************************************************************************
    4454             : Fitting by smoothing (penalized) cubic spline.
    4455             : 
    4456             : This function approximates N scattered points (some of X[] may be equal to
    4457             : each other) by cubic spline with M  nodes  at  equidistant  grid  spanning
    4458             : interval [min(x,xc),max(x,xc)].
    4459             : 
    4460             : The problem is regularized by adding nonlinearity penalty to  usual  least
    4461             : squares penalty function:
    4462             : 
    4463             :     MERIT_FUNC = F_LS + F_NL
    4464             : 
    4465             : where F_LS is a least squares error  term,  and  F_NL  is  a  nonlinearity
    4466             : penalty which is roughly proportional to LambdaNS*integral{ S''(x)^2*dx }.
    4467             : Algorithm applies automatic renormalization of F_NL  which  makes  penalty
    4468             : term roughly invariant to scaling of X[] and changes in M.
    4469             : 
    4470             : This function is a new edition  of  penalized  regression  spline fitting,
    4471             : a fast and compact one which needs much less resources that  its  previous
    4472             : version: just O(maxMN) memory and O(maxMN*log(maxMN)) time.
    4473             : 
    4474             : NOTE: it is OK to run this function with both M<<N and M>>N;  say,  it  is
    4475             :       possible to process 100 points with 1000-node spline.
    4476             : 
    4477             : INPUT PARAMETERS:
    4478             :     X           -   points, array[0..N-1].
    4479             :     Y           -   function values, array[0..N-1].
    4480             :     N           -   number of points (optional):
    4481             :                     * N>0
    4482             :                     * if given, only first N elements of X/Y are processed
    4483             :                     * if not given, automatically determined from lengths
    4484             :     M           -   number of basis functions ( = number_of_nodes), M>=4.
    4485             :     LambdaNS    -   LambdaNS>=0, regularization  constant  passed by user.
    4486             :                     It penalizes nonlinearity in the regression spline.
    4487             :                     Possible values to start from are 0.00001, 0.1, 1
    4488             : 
    4489             : OUTPUT PARAMETERS:
    4490             :     S   -   spline interpolant.
    4491             :     Rep -   Following fields are set:
    4492             :             * RMSError      rms error on the (X,Y).
    4493             :             * AvgError      average error on the (X,Y).
    4494             :             * AvgRelError   average relative error on the non-zero Y
    4495             :             * MaxError      maximum error
    4496             : 
    4497             :   -- ALGLIB PROJECT --
    4498             :      Copyright 27.08.2019 by Bochkanov Sergey
    4499             : *************************************************************************/
    4500             : #if !defined(AE_NO_EXCEPTIONS)
    4501           0 : 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)
    4502             : {
    4503             :     jmp_buf _break_jump;
    4504             :     alglib_impl::ae_state _alglib_env_state;    
    4505             :     ae_int_t n;
    4506           0 :     if( (x.length()!=y.length()))
    4507           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfit': looks like one of arguments has wrong size");
    4508           0 :     n = x.length();
    4509           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4510           0 :     if( setjmp(_break_jump) )
    4511           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4512           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4513           0 :     if( _xparams.flags!=0x0 )
    4514           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4515           0 :     alglib_impl::spline1dfit(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, lambdans, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
    4516             : 
    4517           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4518           0 :     return;
    4519             : }
    4520             : #endif
    4521             : 
    4522             : /*************************************************************************
    4523             : This function builds monotone cubic Hermite interpolant. This interpolant
    4524             : is monotonic in [x(0),x(n-1)] and is constant outside of this interval.
    4525             : 
    4526             : In  case  y[]  form  non-monotonic  sequence,  interpolant  is  piecewise
    4527             : monotonic.  Say, for x=(0,1,2,3,4)  and  y=(0,1,2,1,0)  interpolant  will
    4528             : monotonically grow at [0..2] and monotonically decrease at [2..4].
    4529             : 
    4530             : INPUT PARAMETERS:
    4531             :     X           -   spline nodes, array[0..N-1]. Subroutine automatically
    4532             :                     sorts points, so caller may pass unsorted array.
    4533             :     Y           -   function values, array[0..N-1]
    4534             :     N           -   the number of points(N>=2).
    4535             : 
    4536             : OUTPUT PARAMETERS:
    4537             :     C           -   spline interpolant.
    4538             : 
    4539             :  -- ALGLIB PROJECT --
    4540             :      Copyright 21.06.2012 by Bochkanov Sergey
    4541             : *************************************************************************/
    4542           0 : void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams)
    4543             : {
    4544             :     jmp_buf _break_jump;
    4545             :     alglib_impl::ae_state _alglib_env_state;
    4546           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4547           0 :     if( setjmp(_break_jump) )
    4548             :     {
    4549             : #if !defined(AE_NO_EXCEPTIONS)
    4550           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4551             : #else
    4552             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4553             :         return;
    4554             : #endif
    4555             :     }
    4556           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4557           0 :     if( _xparams.flags!=0x0 )
    4558           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4559           0 :     alglib_impl::spline1dbuildmonotone(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    4560           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4561           0 :     return;
    4562             : }
    4563             : 
    4564             : /*************************************************************************
    4565             : This function builds monotone cubic Hermite interpolant. This interpolant
    4566             : is monotonic in [x(0),x(n-1)] and is constant outside of this interval.
    4567             : 
    4568             : In  case  y[]  form  non-monotonic  sequence,  interpolant  is  piecewise
    4569             : monotonic.  Say, for x=(0,1,2,3,4)  and  y=(0,1,2,1,0)  interpolant  will
    4570             : monotonically grow at [0..2] and monotonically decrease at [2..4].
    4571             : 
    4572             : INPUT PARAMETERS:
    4573             :     X           -   spline nodes, array[0..N-1]. Subroutine automatically
    4574             :                     sorts points, so caller may pass unsorted array.
    4575             :     Y           -   function values, array[0..N-1]
    4576             :     N           -   the number of points(N>=2).
    4577             : 
    4578             : OUTPUT PARAMETERS:
    4579             :     C           -   spline interpolant.
    4580             : 
    4581             :  -- ALGLIB PROJECT --
    4582             :      Copyright 21.06.2012 by Bochkanov Sergey
    4583             : *************************************************************************/
    4584             : #if !defined(AE_NO_EXCEPTIONS)
    4585           0 : void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams)
    4586             : {
    4587             :     jmp_buf _break_jump;
    4588             :     alglib_impl::ae_state _alglib_env_state;    
    4589             :     ae_int_t n;
    4590           0 :     if( (x.length()!=y.length()))
    4591           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildmonotone': looks like one of arguments has wrong size");
    4592           0 :     n = x.length();
    4593           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4594           0 :     if( setjmp(_break_jump) )
    4595           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4596           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4597           0 :     if( _xparams.flags!=0x0 )
    4598           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4599           0 :     alglib_impl::spline1dbuildmonotone(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    4600             : 
    4601           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4602           0 :     return;
    4603             : }
    4604             : #endif
    4605             : #endif
    4606             : 
    4607             : #if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD)
    4608             : /*************************************************************************
    4609             : Parametric spline inteprolant: 2-dimensional curve.
    4610             : 
    4611             : You should not try to access its members directly - use PSpline2XXXXXXXX()
    4612             : functions instead.
    4613             : *************************************************************************/
    4614           0 : _pspline2interpolant_owner::_pspline2interpolant_owner()
    4615             : {
    4616             :     jmp_buf _break_jump;
    4617             :     alglib_impl::ae_state _state;
    4618             :     
    4619           0 :     alglib_impl::ae_state_init(&_state);
    4620           0 :     if( setjmp(_break_jump) )
    4621             :     {
    4622           0 :         if( p_struct!=NULL )
    4623             :         {
    4624           0 :             alglib_impl::_pspline2interpolant_destroy(p_struct);
    4625           0 :             alglib_impl::ae_free(p_struct);
    4626             :         }
    4627           0 :         p_struct = NULL;
    4628             : #if !defined(AE_NO_EXCEPTIONS)
    4629           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    4630             : #else
    4631             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    4632             :         return;
    4633             : #endif
    4634             :     }
    4635           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    4636           0 :     p_struct = NULL;
    4637           0 :     p_struct = (alglib_impl::pspline2interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline2interpolant), &_state);
    4638           0 :     memset(p_struct, 0, sizeof(alglib_impl::pspline2interpolant));
    4639           0 :     alglib_impl::_pspline2interpolant_init(p_struct, &_state, ae_false);
    4640           0 :     ae_state_clear(&_state);
    4641           0 : }
    4642             : 
    4643           0 : _pspline2interpolant_owner::_pspline2interpolant_owner(const _pspline2interpolant_owner &rhs)
    4644             : {
    4645             :     jmp_buf _break_jump;
    4646             :     alglib_impl::ae_state _state;
    4647             :     
    4648           0 :     alglib_impl::ae_state_init(&_state);
    4649           0 :     if( setjmp(_break_jump) )
    4650             :     {
    4651           0 :         if( p_struct!=NULL )
    4652             :         {
    4653           0 :             alglib_impl::_pspline2interpolant_destroy(p_struct);
    4654           0 :             alglib_impl::ae_free(p_struct);
    4655             :         }
    4656           0 :         p_struct = NULL;
    4657             : #if !defined(AE_NO_EXCEPTIONS)
    4658           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    4659             : #else
    4660             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    4661             :         return;
    4662             : #endif
    4663             :     }
    4664           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    4665           0 :     p_struct = NULL;
    4666           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline2interpolant copy constructor failure (source is not initialized)", &_state);
    4667           0 :     p_struct = (alglib_impl::pspline2interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline2interpolant), &_state);
    4668           0 :     memset(p_struct, 0, sizeof(alglib_impl::pspline2interpolant));
    4669           0 :     alglib_impl::_pspline2interpolant_init_copy(p_struct, const_cast<alglib_impl::pspline2interpolant*>(rhs.p_struct), &_state, ae_false);
    4670           0 :     ae_state_clear(&_state);
    4671           0 : }
    4672             : 
    4673           0 : _pspline2interpolant_owner& _pspline2interpolant_owner::operator=(const _pspline2interpolant_owner &rhs)
    4674             : {
    4675           0 :     if( this==&rhs )
    4676           0 :         return *this;
    4677             :     jmp_buf _break_jump;
    4678             :     alglib_impl::ae_state _state;
    4679             :     
    4680           0 :     alglib_impl::ae_state_init(&_state);
    4681           0 :     if( setjmp(_break_jump) )
    4682             :     {
    4683             : #if !defined(AE_NO_EXCEPTIONS)
    4684           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    4685             : #else
    4686             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    4687             :         return *this;
    4688             : #endif
    4689             :     }
    4690           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    4691           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: pspline2interpolant assignment constructor failure (destination is not initialized)", &_state);
    4692           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline2interpolant assignment constructor failure (source is not initialized)", &_state);
    4693           0 :     alglib_impl::_pspline2interpolant_destroy(p_struct);
    4694           0 :     memset(p_struct, 0, sizeof(alglib_impl::pspline2interpolant));
    4695           0 :     alglib_impl::_pspline2interpolant_init_copy(p_struct, const_cast<alglib_impl::pspline2interpolant*>(rhs.p_struct), &_state, ae_false);
    4696           0 :     ae_state_clear(&_state);
    4697           0 :     return *this;
    4698             : }
    4699             : 
    4700           0 : _pspline2interpolant_owner::~_pspline2interpolant_owner()
    4701             : {
    4702           0 :     if( p_struct!=NULL )
    4703             :     {
    4704           0 :         alglib_impl::_pspline2interpolant_destroy(p_struct);
    4705           0 :         ae_free(p_struct);
    4706             :     }
    4707           0 : }
    4708             : 
    4709           0 : alglib_impl::pspline2interpolant* _pspline2interpolant_owner::c_ptr()
    4710             : {
    4711           0 :     return p_struct;
    4712             : }
    4713             : 
    4714           0 : alglib_impl::pspline2interpolant* _pspline2interpolant_owner::c_ptr() const
    4715             : {
    4716           0 :     return const_cast<alglib_impl::pspline2interpolant*>(p_struct);
    4717             : }
    4718           0 : pspline2interpolant::pspline2interpolant() : _pspline2interpolant_owner() 
    4719             : {
    4720           0 : }
    4721             : 
    4722           0 : pspline2interpolant::pspline2interpolant(const pspline2interpolant &rhs):_pspline2interpolant_owner(rhs) 
    4723             : {
    4724           0 : }
    4725             : 
    4726           0 : pspline2interpolant& pspline2interpolant::operator=(const pspline2interpolant &rhs)
    4727             : {
    4728           0 :     if( this==&rhs )
    4729           0 :         return *this;
    4730           0 :     _pspline2interpolant_owner::operator=(rhs);
    4731           0 :     return *this;
    4732             : }
    4733             : 
    4734           0 : pspline2interpolant::~pspline2interpolant()
    4735             : {
    4736           0 : }
    4737             : 
    4738             : 
    4739             : /*************************************************************************
    4740             : Parametric spline inteprolant: 3-dimensional curve.
    4741             : 
    4742             : You should not try to access its members directly - use PSpline3XXXXXXXX()
    4743             : functions instead.
    4744             : *************************************************************************/
    4745           0 : _pspline3interpolant_owner::_pspline3interpolant_owner()
    4746             : {
    4747             :     jmp_buf _break_jump;
    4748             :     alglib_impl::ae_state _state;
    4749             :     
    4750           0 :     alglib_impl::ae_state_init(&_state);
    4751           0 :     if( setjmp(_break_jump) )
    4752             :     {
    4753           0 :         if( p_struct!=NULL )
    4754             :         {
    4755           0 :             alglib_impl::_pspline3interpolant_destroy(p_struct);
    4756           0 :             alglib_impl::ae_free(p_struct);
    4757             :         }
    4758           0 :         p_struct = NULL;
    4759             : #if !defined(AE_NO_EXCEPTIONS)
    4760           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    4761             : #else
    4762             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    4763             :         return;
    4764             : #endif
    4765             :     }
    4766           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    4767           0 :     p_struct = NULL;
    4768           0 :     p_struct = (alglib_impl::pspline3interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline3interpolant), &_state);
    4769           0 :     memset(p_struct, 0, sizeof(alglib_impl::pspline3interpolant));
    4770           0 :     alglib_impl::_pspline3interpolant_init(p_struct, &_state, ae_false);
    4771           0 :     ae_state_clear(&_state);
    4772           0 : }
    4773             : 
    4774           0 : _pspline3interpolant_owner::_pspline3interpolant_owner(const _pspline3interpolant_owner &rhs)
    4775             : {
    4776             :     jmp_buf _break_jump;
    4777             :     alglib_impl::ae_state _state;
    4778             :     
    4779           0 :     alglib_impl::ae_state_init(&_state);
    4780           0 :     if( setjmp(_break_jump) )
    4781             :     {
    4782           0 :         if( p_struct!=NULL )
    4783             :         {
    4784           0 :             alglib_impl::_pspline3interpolant_destroy(p_struct);
    4785           0 :             alglib_impl::ae_free(p_struct);
    4786             :         }
    4787           0 :         p_struct = NULL;
    4788             : #if !defined(AE_NO_EXCEPTIONS)
    4789           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    4790             : #else
    4791             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    4792             :         return;
    4793             : #endif
    4794             :     }
    4795           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    4796           0 :     p_struct = NULL;
    4797           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline3interpolant copy constructor failure (source is not initialized)", &_state);
    4798           0 :     p_struct = (alglib_impl::pspline3interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline3interpolant), &_state);
    4799           0 :     memset(p_struct, 0, sizeof(alglib_impl::pspline3interpolant));
    4800           0 :     alglib_impl::_pspline3interpolant_init_copy(p_struct, const_cast<alglib_impl::pspline3interpolant*>(rhs.p_struct), &_state, ae_false);
    4801           0 :     ae_state_clear(&_state);
    4802           0 : }
    4803             : 
    4804           0 : _pspline3interpolant_owner& _pspline3interpolant_owner::operator=(const _pspline3interpolant_owner &rhs)
    4805             : {
    4806           0 :     if( this==&rhs )
    4807           0 :         return *this;
    4808             :     jmp_buf _break_jump;
    4809             :     alglib_impl::ae_state _state;
    4810             :     
    4811           0 :     alglib_impl::ae_state_init(&_state);
    4812           0 :     if( setjmp(_break_jump) )
    4813             :     {
    4814             : #if !defined(AE_NO_EXCEPTIONS)
    4815           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    4816             : #else
    4817             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    4818             :         return *this;
    4819             : #endif
    4820             :     }
    4821           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    4822           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: pspline3interpolant assignment constructor failure (destination is not initialized)", &_state);
    4823           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline3interpolant assignment constructor failure (source is not initialized)", &_state);
    4824           0 :     alglib_impl::_pspline3interpolant_destroy(p_struct);
    4825           0 :     memset(p_struct, 0, sizeof(alglib_impl::pspline3interpolant));
    4826           0 :     alglib_impl::_pspline3interpolant_init_copy(p_struct, const_cast<alglib_impl::pspline3interpolant*>(rhs.p_struct), &_state, ae_false);
    4827           0 :     ae_state_clear(&_state);
    4828           0 :     return *this;
    4829             : }
    4830             : 
    4831           0 : _pspline3interpolant_owner::~_pspline3interpolant_owner()
    4832             : {
    4833           0 :     if( p_struct!=NULL )
    4834             :     {
    4835           0 :         alglib_impl::_pspline3interpolant_destroy(p_struct);
    4836           0 :         ae_free(p_struct);
    4837             :     }
    4838           0 : }
    4839             : 
    4840           0 : alglib_impl::pspline3interpolant* _pspline3interpolant_owner::c_ptr()
    4841             : {
    4842           0 :     return p_struct;
    4843             : }
    4844             : 
    4845           0 : alglib_impl::pspline3interpolant* _pspline3interpolant_owner::c_ptr() const
    4846             : {
    4847           0 :     return const_cast<alglib_impl::pspline3interpolant*>(p_struct);
    4848             : }
    4849           0 : pspline3interpolant::pspline3interpolant() : _pspline3interpolant_owner() 
    4850             : {
    4851           0 : }
    4852             : 
    4853           0 : pspline3interpolant::pspline3interpolant(const pspline3interpolant &rhs):_pspline3interpolant_owner(rhs) 
    4854             : {
    4855           0 : }
    4856             : 
    4857           0 : pspline3interpolant& pspline3interpolant::operator=(const pspline3interpolant &rhs)
    4858             : {
    4859           0 :     if( this==&rhs )
    4860           0 :         return *this;
    4861           0 :     _pspline3interpolant_owner::operator=(rhs);
    4862           0 :     return *this;
    4863             : }
    4864             : 
    4865           0 : pspline3interpolant::~pspline3interpolant()
    4866             : {
    4867           0 : }
    4868             : 
    4869             : /*************************************************************************
    4870             : This function  builds  non-periodic 2-dimensional parametric spline  which
    4871             : starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]).
    4872             : 
    4873             : INPUT PARAMETERS:
    4874             :     XY  -   points, array[0..N-1,0..1].
    4875             :             XY[I,0:1] corresponds to the Ith point.
    4876             :             Order of points is important!
    4877             :     N   -   points count, N>=5 for Akima splines, N>=2 for other types  of
    4878             :             splines.
    4879             :     ST  -   spline type:
    4880             :             * 0     Akima spline
    4881             :             * 1     parabolically terminated Catmull-Rom spline (Tension=0)
    4882             :             * 2     parabolically terminated cubic spline
    4883             :     PT  -   parameterization type:
    4884             :             * 0     uniform
    4885             :             * 1     chord length
    4886             :             * 2     centripetal
    4887             : 
    4888             : OUTPUT PARAMETERS:
    4889             :     P   -   parametric spline interpolant
    4890             : 
    4891             : 
    4892             : NOTES:
    4893             : * this function  assumes  that  there all consequent points  are distinct.
    4894             :   I.e. (x0,y0)<>(x1,y1),  (x1,y1)<>(x2,y2),  (x2,y2)<>(x3,y3)  and  so on.
    4895             :   However, non-consequent points may coincide, i.e. we can  have  (x0,y0)=
    4896             :   =(x2,y2).
    4897             : 
    4898             :   -- ALGLIB PROJECT --
    4899             :      Copyright 28.05.2010 by Bochkanov Sergey
    4900             : *************************************************************************/
    4901           0 : 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)
    4902             : {
    4903             :     jmp_buf _break_jump;
    4904             :     alglib_impl::ae_state _alglib_env_state;
    4905           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4906           0 :     if( setjmp(_break_jump) )
    4907             :     {
    4908             : #if !defined(AE_NO_EXCEPTIONS)
    4909           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4910             : #else
    4911             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4912             :         return;
    4913             : #endif
    4914             :     }
    4915           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4916           0 :     if( _xparams.flags!=0x0 )
    4917           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4918           0 :     alglib_impl::pspline2build(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, st, pt, const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), &_alglib_env_state);
    4919           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4920           0 :     return;
    4921             : }
    4922             : 
    4923             : /*************************************************************************
    4924             : This function  builds  non-periodic 3-dimensional parametric spline  which
    4925             : starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]).
    4926             : 
    4927             : Same as PSpline2Build() function, but for 3D, so we  won't  duplicate  its
    4928             : description here.
    4929             : 
    4930             :   -- ALGLIB PROJECT --
    4931             :      Copyright 28.05.2010 by Bochkanov Sergey
    4932             : *************************************************************************/
    4933           0 : 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)
    4934             : {
    4935             :     jmp_buf _break_jump;
    4936             :     alglib_impl::ae_state _alglib_env_state;
    4937           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4938           0 :     if( setjmp(_break_jump) )
    4939             :     {
    4940             : #if !defined(AE_NO_EXCEPTIONS)
    4941           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4942             : #else
    4943             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    4944             :         return;
    4945             : #endif
    4946             :     }
    4947           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    4948           0 :     if( _xparams.flags!=0x0 )
    4949           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    4950           0 :     alglib_impl::pspline3build(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, st, pt, const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), &_alglib_env_state);
    4951           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    4952           0 :     return;
    4953             : }
    4954             : 
    4955             : /*************************************************************************
    4956             : This  function  builds  periodic  2-dimensional  parametric  spline  which
    4957             : starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then
    4958             : back to (X[0],Y[0]).
    4959             : 
    4960             : INPUT PARAMETERS:
    4961             :     XY  -   points, array[0..N-1,0..1].
    4962             :             XY[I,0:1] corresponds to the Ith point.
    4963             :             XY[N-1,0:1] must be different from XY[0,0:1].
    4964             :             Order of points is important!
    4965             :     N   -   points count, N>=3 for other types of splines.
    4966             :     ST  -   spline type:
    4967             :             * 1     Catmull-Rom spline (Tension=0) with cyclic boundary conditions
    4968             :             * 2     cubic spline with cyclic boundary conditions
    4969             :     PT  -   parameterization type:
    4970             :             * 0     uniform
    4971             :             * 1     chord length
    4972             :             * 2     centripetal
    4973             : 
    4974             : OUTPUT PARAMETERS:
    4975             :     P   -   parametric spline interpolant
    4976             : 
    4977             : 
    4978             : NOTES:
    4979             : * this function  assumes  that there all consequent points  are  distinct.
    4980             :   I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2),  (x2,y2)<>(x3,y3)  and  so  on.
    4981             :   However, non-consequent points may coincide, i.e. we can  have  (x0,y0)=
    4982             :   =(x2,y2).
    4983             : * last point of sequence is NOT equal to the first  point.  You  shouldn't
    4984             :   make curve "explicitly periodic" by making them equal.
    4985             : 
    4986             :   -- ALGLIB PROJECT --
    4987             :      Copyright 28.05.2010 by Bochkanov Sergey
    4988             : *************************************************************************/
    4989           0 : 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)
    4990             : {
    4991             :     jmp_buf _break_jump;
    4992             :     alglib_impl::ae_state _alglib_env_state;
    4993           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    4994           0 :     if( setjmp(_break_jump) )
    4995             :     {
    4996             : #if !defined(AE_NO_EXCEPTIONS)
    4997           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    4998             : #else
    4999             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5000             :         return;
    5001             : #endif
    5002             :     }
    5003           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5004           0 :     if( _xparams.flags!=0x0 )
    5005           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5006           0 :     alglib_impl::pspline2buildperiodic(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, st, pt, const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), &_alglib_env_state);
    5007           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5008           0 :     return;
    5009             : }
    5010             : 
    5011             : /*************************************************************************
    5012             : This  function  builds  periodic  3-dimensional  parametric  spline  which
    5013             : starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1])
    5014             : and then back to (X[0],Y[0],Z[0]).
    5015             : 
    5016             : Same as PSpline2Build() function, but for 3D, so we  won't  duplicate  its
    5017             : description here.
    5018             : 
    5019             :   -- ALGLIB PROJECT --
    5020             :      Copyright 28.05.2010 by Bochkanov Sergey
    5021             : *************************************************************************/
    5022           0 : 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)
    5023             : {
    5024             :     jmp_buf _break_jump;
    5025             :     alglib_impl::ae_state _alglib_env_state;
    5026           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5027           0 :     if( setjmp(_break_jump) )
    5028             :     {
    5029             : #if !defined(AE_NO_EXCEPTIONS)
    5030           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5031             : #else
    5032             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5033             :         return;
    5034             : #endif
    5035             :     }
    5036           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5037           0 :     if( _xparams.flags!=0x0 )
    5038           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5039           0 :     alglib_impl::pspline3buildperiodic(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, st, pt, const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), &_alglib_env_state);
    5040           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5041           0 :     return;
    5042             : }
    5043             : 
    5044             : /*************************************************************************
    5045             : This function returns vector of parameter values correspoding to points.
    5046             : 
    5047             : I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P)  we
    5048             : have
    5049             :     (X[0],Y[0]) = PSpline2Calc(P,U[0]),
    5050             :     (X[1],Y[1]) = PSpline2Calc(P,U[1]),
    5051             :     (X[2],Y[2]) = PSpline2Calc(P,U[2]),
    5052             :     ...
    5053             : 
    5054             : INPUT PARAMETERS:
    5055             :     P   -   parametric spline interpolant
    5056             : 
    5057             : OUTPUT PARAMETERS:
    5058             :     N   -   array size
    5059             :     T   -   array[0..N-1]
    5060             : 
    5061             : 
    5062             : NOTES:
    5063             : * for non-periodic splines U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]=1
    5064             : * for periodic splines     U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]<1
    5065             : 
    5066             :   -- ALGLIB PROJECT --
    5067             :      Copyright 28.05.2010 by Bochkanov Sergey
    5068             : *************************************************************************/
    5069           0 : void pspline2parametervalues(const pspline2interpolant &p, ae_int_t &n, real_1d_array &t, const xparams _xparams)
    5070             : {
    5071             :     jmp_buf _break_jump;
    5072             :     alglib_impl::ae_state _alglib_env_state;
    5073           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5074           0 :     if( setjmp(_break_jump) )
    5075             :     {
    5076             : #if !defined(AE_NO_EXCEPTIONS)
    5077           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5078             : #else
    5079             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5080             :         return;
    5081             : #endif
    5082             :     }
    5083           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5084           0 :     if( _xparams.flags!=0x0 )
    5085           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5086           0 :     alglib_impl::pspline2parametervalues(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), &n, const_cast<alglib_impl::ae_vector*>(t.c_ptr()), &_alglib_env_state);
    5087           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5088           0 :     return;
    5089             : }
    5090             : 
    5091             : /*************************************************************************
    5092             : This function returns vector of parameter values correspoding to points.
    5093             : 
    5094             : Same as PSpline2ParameterValues(), but for 3D.
    5095             : 
    5096             :   -- ALGLIB PROJECT --
    5097             :      Copyright 28.05.2010 by Bochkanov Sergey
    5098             : *************************************************************************/
    5099           0 : void pspline3parametervalues(const pspline3interpolant &p, ae_int_t &n, real_1d_array &t, const xparams _xparams)
    5100             : {
    5101             :     jmp_buf _break_jump;
    5102             :     alglib_impl::ae_state _alglib_env_state;
    5103           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5104           0 :     if( setjmp(_break_jump) )
    5105             :     {
    5106             : #if !defined(AE_NO_EXCEPTIONS)
    5107           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5108             : #else
    5109             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5110             :         return;
    5111             : #endif
    5112             :     }
    5113           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5114           0 :     if( _xparams.flags!=0x0 )
    5115           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5116           0 :     alglib_impl::pspline3parametervalues(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), &n, const_cast<alglib_impl::ae_vector*>(t.c_ptr()), &_alglib_env_state);
    5117           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5118           0 :     return;
    5119             : }
    5120             : 
    5121             : /*************************************************************************
    5122             : This function  calculates  the value of the parametric spline for a  given
    5123             : value of parameter T
    5124             : 
    5125             : INPUT PARAMETERS:
    5126             :     P   -   parametric spline interpolant
    5127             :     T   -   point:
    5128             :             * T in [0,1] corresponds to interval spanned by points
    5129             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
    5130             :               the curve before the first (after the last) point
    5131             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
    5132             :               by making T=T-floor(T).
    5133             : 
    5134             : OUTPUT PARAMETERS:
    5135             :     X   -   X-position
    5136             :     Y   -   Y-position
    5137             : 
    5138             : 
    5139             :   -- ALGLIB PROJECT --
    5140             :      Copyright 28.05.2010 by Bochkanov Sergey
    5141             : *************************************************************************/
    5142           0 : void pspline2calc(const pspline2interpolant &p, const double t, double &x, double &y, const xparams _xparams)
    5143             : {
    5144             :     jmp_buf _break_jump;
    5145             :     alglib_impl::ae_state _alglib_env_state;
    5146           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5147           0 :     if( setjmp(_break_jump) )
    5148             :     {
    5149             : #if !defined(AE_NO_EXCEPTIONS)
    5150           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5151             : #else
    5152             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5153             :         return;
    5154             : #endif
    5155             :     }
    5156           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5157           0 :     if( _xparams.flags!=0x0 )
    5158           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5159           0 :     alglib_impl::pspline2calc(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), t, &x, &y, &_alglib_env_state);
    5160           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5161           0 :     return;
    5162             : }
    5163             : 
    5164             : /*************************************************************************
    5165             : This function  calculates  the value of the parametric spline for a  given
    5166             : value of parameter T.
    5167             : 
    5168             : INPUT PARAMETERS:
    5169             :     P   -   parametric spline interpolant
    5170             :     T   -   point:
    5171             :             * T in [0,1] corresponds to interval spanned by points
    5172             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
    5173             :               the curve before the first (after the last) point
    5174             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
    5175             :               by making T=T-floor(T).
    5176             : 
    5177             : OUTPUT PARAMETERS:
    5178             :     X   -   X-position
    5179             :     Y   -   Y-position
    5180             :     Z   -   Z-position
    5181             : 
    5182             : 
    5183             :   -- ALGLIB PROJECT --
    5184             :      Copyright 28.05.2010 by Bochkanov Sergey
    5185             : *************************************************************************/
    5186           0 : void pspline3calc(const pspline3interpolant &p, const double t, double &x, double &y, double &z, const xparams _xparams)
    5187             : {
    5188             :     jmp_buf _break_jump;
    5189             :     alglib_impl::ae_state _alglib_env_state;
    5190           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5191           0 :     if( setjmp(_break_jump) )
    5192             :     {
    5193             : #if !defined(AE_NO_EXCEPTIONS)
    5194           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5195             : #else
    5196             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5197             :         return;
    5198             : #endif
    5199             :     }
    5200           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5201           0 :     if( _xparams.flags!=0x0 )
    5202           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5203           0 :     alglib_impl::pspline3calc(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), t, &x, &y, &z, &_alglib_env_state);
    5204           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5205           0 :     return;
    5206             : }
    5207             : 
    5208             : /*************************************************************************
    5209             : This function  calculates  tangent vector for a given value of parameter T
    5210             : 
    5211             : INPUT PARAMETERS:
    5212             :     P   -   parametric spline interpolant
    5213             :     T   -   point:
    5214             :             * T in [0,1] corresponds to interval spanned by points
    5215             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
    5216             :               the curve before the first (after the last) point
    5217             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
    5218             :               by making T=T-floor(T).
    5219             : 
    5220             : OUTPUT PARAMETERS:
    5221             :     X    -   X-component of tangent vector (normalized)
    5222             :     Y    -   Y-component of tangent vector (normalized)
    5223             : 
    5224             : NOTE:
    5225             :     X^2+Y^2 is either 1 (for non-zero tangent vector) or 0.
    5226             : 
    5227             : 
    5228             :   -- ALGLIB PROJECT --
    5229             :      Copyright 28.05.2010 by Bochkanov Sergey
    5230             : *************************************************************************/
    5231           0 : void pspline2tangent(const pspline2interpolant &p, const double t, double &x, double &y, const xparams _xparams)
    5232             : {
    5233             :     jmp_buf _break_jump;
    5234             :     alglib_impl::ae_state _alglib_env_state;
    5235           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5236           0 :     if( setjmp(_break_jump) )
    5237             :     {
    5238             : #if !defined(AE_NO_EXCEPTIONS)
    5239           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5240             : #else
    5241             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5242             :         return;
    5243             : #endif
    5244             :     }
    5245           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5246           0 :     if( _xparams.flags!=0x0 )
    5247           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5248           0 :     alglib_impl::pspline2tangent(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), t, &x, &y, &_alglib_env_state);
    5249           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5250           0 :     return;
    5251             : }
    5252             : 
    5253             : /*************************************************************************
    5254             : This function  calculates  tangent vector for a given value of parameter T
    5255             : 
    5256             : INPUT PARAMETERS:
    5257             :     P   -   parametric spline interpolant
    5258             :     T   -   point:
    5259             :             * T in [0,1] corresponds to interval spanned by points
    5260             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
    5261             :               the curve before the first (after the last) point
    5262             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
    5263             :               by making T=T-floor(T).
    5264             : 
    5265             : OUTPUT PARAMETERS:
    5266             :     X    -   X-component of tangent vector (normalized)
    5267             :     Y    -   Y-component of tangent vector (normalized)
    5268             :     Z    -   Z-component of tangent vector (normalized)
    5269             : 
    5270             : NOTE:
    5271             :     X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0.
    5272             : 
    5273             : 
    5274             :   -- ALGLIB PROJECT --
    5275             :      Copyright 28.05.2010 by Bochkanov Sergey
    5276             : *************************************************************************/
    5277           0 : void pspline3tangent(const pspline3interpolant &p, const double t, double &x, double &y, double &z, const xparams _xparams)
    5278             : {
    5279             :     jmp_buf _break_jump;
    5280             :     alglib_impl::ae_state _alglib_env_state;
    5281           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5282           0 :     if( setjmp(_break_jump) )
    5283             :     {
    5284             : #if !defined(AE_NO_EXCEPTIONS)
    5285           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5286             : #else
    5287             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5288             :         return;
    5289             : #endif
    5290             :     }
    5291           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5292           0 :     if( _xparams.flags!=0x0 )
    5293           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5294           0 :     alglib_impl::pspline3tangent(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), t, &x, &y, &z, &_alglib_env_state);
    5295           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5296           0 :     return;
    5297             : }
    5298             : 
    5299             : /*************************************************************************
    5300             : This function calculates derivative, i.e. it returns (dX/dT,dY/dT).
    5301             : 
    5302             : INPUT PARAMETERS:
    5303             :     P   -   parametric spline interpolant
    5304             :     T   -   point:
    5305             :             * T in [0,1] corresponds to interval spanned by points
    5306             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
    5307             :               the curve before the first (after the last) point
    5308             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
    5309             :               by making T=T-floor(T).
    5310             : 
    5311             : OUTPUT PARAMETERS:
    5312             :     X   -   X-value
    5313             :     DX  -   X-derivative
    5314             :     Y   -   Y-value
    5315             :     DY  -   Y-derivative
    5316             : 
    5317             : 
    5318             :   -- ALGLIB PROJECT --
    5319             :      Copyright 28.05.2010 by Bochkanov Sergey
    5320             : *************************************************************************/
    5321           0 : void pspline2diff(const pspline2interpolant &p, const double t, double &x, double &dx, double &y, double &dy, const xparams _xparams)
    5322             : {
    5323             :     jmp_buf _break_jump;
    5324             :     alglib_impl::ae_state _alglib_env_state;
    5325           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5326           0 :     if( setjmp(_break_jump) )
    5327             :     {
    5328             : #if !defined(AE_NO_EXCEPTIONS)
    5329           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5330             : #else
    5331             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5332             :         return;
    5333             : #endif
    5334             :     }
    5335           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5336           0 :     if( _xparams.flags!=0x0 )
    5337           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5338           0 :     alglib_impl::pspline2diff(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), t, &x, &dx, &y, &dy, &_alglib_env_state);
    5339           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5340           0 :     return;
    5341             : }
    5342             : 
    5343             : /*************************************************************************
    5344             : This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT).
    5345             : 
    5346             : INPUT PARAMETERS:
    5347             :     P   -   parametric spline interpolant
    5348             :     T   -   point:
    5349             :             * T in [0,1] corresponds to interval spanned by points
    5350             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
    5351             :               the curve before the first (after the last) point
    5352             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
    5353             :               by making T=T-floor(T).
    5354             : 
    5355             : OUTPUT PARAMETERS:
    5356             :     X   -   X-value
    5357             :     DX  -   X-derivative
    5358             :     Y   -   Y-value
    5359             :     DY  -   Y-derivative
    5360             :     Z   -   Z-value
    5361             :     DZ  -   Z-derivative
    5362             : 
    5363             : 
    5364             :   -- ALGLIB PROJECT --
    5365             :      Copyright 28.05.2010 by Bochkanov Sergey
    5366             : *************************************************************************/
    5367           0 : void pspline3diff(const pspline3interpolant &p, const double t, double &x, double &dx, double &y, double &dy, double &z, double &dz, const xparams _xparams)
    5368             : {
    5369             :     jmp_buf _break_jump;
    5370             :     alglib_impl::ae_state _alglib_env_state;
    5371           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5372           0 :     if( setjmp(_break_jump) )
    5373             :     {
    5374             : #if !defined(AE_NO_EXCEPTIONS)
    5375           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5376             : #else
    5377             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5378             :         return;
    5379             : #endif
    5380             :     }
    5381           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5382           0 :     if( _xparams.flags!=0x0 )
    5383           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5384           0 :     alglib_impl::pspline3diff(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), t, &x, &dx, &y, &dy, &z, &dz, &_alglib_env_state);
    5385           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5386           0 :     return;
    5387             : }
    5388             : 
    5389             : /*************************************************************************
    5390             : This function calculates first and second derivative with respect to T.
    5391             : 
    5392             : INPUT PARAMETERS:
    5393             :     P   -   parametric spline interpolant
    5394             :     T   -   point:
    5395             :             * T in [0,1] corresponds to interval spanned by points
    5396             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
    5397             :               the curve before the first (after the last) point
    5398             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
    5399             :               by making T=T-floor(T).
    5400             : 
    5401             : OUTPUT PARAMETERS:
    5402             :     X   -   X-value
    5403             :     DX  -   derivative
    5404             :     D2X -   second derivative
    5405             :     Y   -   Y-value
    5406             :     DY  -   derivative
    5407             :     D2Y -   second derivative
    5408             : 
    5409             : 
    5410             :   -- ALGLIB PROJECT --
    5411             :      Copyright 28.05.2010 by Bochkanov Sergey
    5412             : *************************************************************************/
    5413           0 : void pspline2diff2(const pspline2interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, const xparams _xparams)
    5414             : {
    5415             :     jmp_buf _break_jump;
    5416             :     alglib_impl::ae_state _alglib_env_state;
    5417           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5418           0 :     if( setjmp(_break_jump) )
    5419             :     {
    5420             : #if !defined(AE_NO_EXCEPTIONS)
    5421           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5422             : #else
    5423             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5424             :         return;
    5425             : #endif
    5426             :     }
    5427           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5428           0 :     if( _xparams.flags!=0x0 )
    5429           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5430           0 :     alglib_impl::pspline2diff2(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), t, &x, &dx, &d2x, &y, &dy, &d2y, &_alglib_env_state);
    5431           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5432           0 :     return;
    5433             : }
    5434             : 
    5435             : /*************************************************************************
    5436             : This function calculates first and second derivative with respect to T.
    5437             : 
    5438             : INPUT PARAMETERS:
    5439             :     P   -   parametric spline interpolant
    5440             :     T   -   point:
    5441             :             * T in [0,1] corresponds to interval spanned by points
    5442             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
    5443             :               the curve before the first (after the last) point
    5444             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
    5445             :               by making T=T-floor(T).
    5446             : 
    5447             : OUTPUT PARAMETERS:
    5448             :     X   -   X-value
    5449             :     DX  -   derivative
    5450             :     D2X -   second derivative
    5451             :     Y   -   Y-value
    5452             :     DY  -   derivative
    5453             :     D2Y -   second derivative
    5454             :     Z   -   Z-value
    5455             :     DZ  -   derivative
    5456             :     D2Z -   second derivative
    5457             : 
    5458             : 
    5459             :   -- ALGLIB PROJECT --
    5460             :      Copyright 28.05.2010 by Bochkanov Sergey
    5461             : *************************************************************************/
    5462           0 : 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)
    5463             : {
    5464             :     jmp_buf _break_jump;
    5465             :     alglib_impl::ae_state _alglib_env_state;
    5466           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5467           0 :     if( setjmp(_break_jump) )
    5468             :     {
    5469             : #if !defined(AE_NO_EXCEPTIONS)
    5470           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5471             : #else
    5472             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5473             :         return;
    5474             : #endif
    5475             :     }
    5476           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5477           0 :     if( _xparams.flags!=0x0 )
    5478           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5479           0 :     alglib_impl::pspline3diff2(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), t, &x, &dx, &d2x, &y, &dy, &d2y, &z, &dz, &d2z, &_alglib_env_state);
    5480           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5481           0 :     return;
    5482             : }
    5483             : 
    5484             : /*************************************************************************
    5485             : This function  calculates  arc length, i.e. length of  curve  between  t=a
    5486             : and t=b.
    5487             : 
    5488             : INPUT PARAMETERS:
    5489             :     P   -   parametric spline interpolant
    5490             :     A,B -   parameter values corresponding to arc ends:
    5491             :             * B>A will result in positive length returned
    5492             :             * B<A will result in negative length returned
    5493             : 
    5494             : RESULT:
    5495             :     length of arc starting at T=A and ending at T=B.
    5496             : 
    5497             : 
    5498             :   -- ALGLIB PROJECT --
    5499             :      Copyright 30.05.2010 by Bochkanov Sergey
    5500             : *************************************************************************/
    5501           0 : double pspline2arclength(const pspline2interpolant &p, const double a, const double b, const xparams _xparams)
    5502             : {
    5503             :     jmp_buf _break_jump;
    5504             :     alglib_impl::ae_state _alglib_env_state;
    5505           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5506           0 :     if( setjmp(_break_jump) )
    5507             :     {
    5508             : #if !defined(AE_NO_EXCEPTIONS)
    5509           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5510             : #else
    5511             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5512             :         return 0;
    5513             : #endif
    5514             :     }
    5515           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5516           0 :     if( _xparams.flags!=0x0 )
    5517           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5518           0 :     double result = alglib_impl::pspline2arclength(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), a, b, &_alglib_env_state);
    5519           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5520           0 :     return *(reinterpret_cast<double*>(&result));
    5521             : }
    5522             : 
    5523             : /*************************************************************************
    5524             : This function  calculates  arc length, i.e. length of  curve  between  t=a
    5525             : and t=b.
    5526             : 
    5527             : INPUT PARAMETERS:
    5528             :     P   -   parametric spline interpolant
    5529             :     A,B -   parameter values corresponding to arc ends:
    5530             :             * B>A will result in positive length returned
    5531             :             * B<A will result in negative length returned
    5532             : 
    5533             : RESULT:
    5534             :     length of arc starting at T=A and ending at T=B.
    5535             : 
    5536             : 
    5537             :   -- ALGLIB PROJECT --
    5538             :      Copyright 30.05.2010 by Bochkanov Sergey
    5539             : *************************************************************************/
    5540           0 : double pspline3arclength(const pspline3interpolant &p, const double a, const double b, const xparams _xparams)
    5541             : {
    5542             :     jmp_buf _break_jump;
    5543             :     alglib_impl::ae_state _alglib_env_state;
    5544           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5545           0 :     if( setjmp(_break_jump) )
    5546             :     {
    5547             : #if !defined(AE_NO_EXCEPTIONS)
    5548           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5549             : #else
    5550             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5551             :         return 0;
    5552             : #endif
    5553             :     }
    5554           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5555           0 :     if( _xparams.flags!=0x0 )
    5556           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5557           0 :     double result = alglib_impl::pspline3arclength(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), a, b, &_alglib_env_state);
    5558           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5559           0 :     return *(reinterpret_cast<double*>(&result));
    5560             : }
    5561             : 
    5562             : /*************************************************************************
    5563             : This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
    5564             : Peucker algorithm. This  function  performs PARAMETRIC fit, i.e. it can be
    5565             : used to fit curves like circles.
    5566             : 
    5567             : On  input  it  accepts dataset which describes parametric multidimensional
    5568             : curve X(t), with X being vector, and t taking values in [0,N), where N  is
    5569             : a number of points in dataset. As result, it returns reduced  dataset  X2,
    5570             : which can be used to build  parametric  curve  X2(t),  which  approximates
    5571             : X(t) with desired precision (or has specified number of sections).
    5572             : 
    5573             : 
    5574             : INPUT PARAMETERS:
    5575             :     X       -   array of multidimensional points:
    5576             :                 * at least N elements, leading N elements are used if more
    5577             :                   than N elements were specified
    5578             :                 * order of points is IMPORTANT because  it  is  parametric
    5579             :                   fit
    5580             :                 * each row of array is one point which has D coordinates
    5581             :     N       -   number of elements in X
    5582             :     D       -   number of dimensions (elements per row of X)
    5583             :     StopM   -   stopping condition - desired number of sections:
    5584             :                 * at most M sections are generated by this function
    5585             :                 * less than M sections can be generated if we have N<M
    5586             :                   (or some X are non-distinct).
    5587             :                 * zero StopM means that algorithm does not stop after
    5588             :                   achieving some pre-specified section count
    5589             :     StopEps -   stopping condition - desired precision:
    5590             :                 * algorithm stops after error in each section is at most Eps
    5591             :                 * zero Eps means that algorithm does not stop after
    5592             :                   achieving some pre-specified precision
    5593             : 
    5594             : OUTPUT PARAMETERS:
    5595             :     X2      -   array of corner points for piecewise approximation,
    5596             :                 has length NSections+1 or zero (for NSections=0).
    5597             :     Idx2    -   array of indexes (parameter values):
    5598             :                 * has length NSections+1 or zero (for NSections=0).
    5599             :                 * each element of Idx2 corresponds to same-numbered
    5600             :                   element of X2
    5601             :                 * each element of Idx2 is index of  corresponding  element
    5602             :                   of X2 at original array X, i.e. I-th  row  of  X2  is
    5603             :                   Idx2[I]-th row of X.
    5604             :                 * elements of Idx2 can be treated as parameter values
    5605             :                   which should be used when building new parametric curve
    5606             :                 * Idx2[0]=0, Idx2[NSections]=N-1
    5607             :     NSections-  number of sections found by algorithm, NSections<=M,
    5608             :                 NSections can be zero for degenerate datasets
    5609             :                 (N<=1 or all X[] are non-distinct).
    5610             : 
    5611             : NOTE: algorithm stops after:
    5612             :       a) dividing curve into StopM sections
    5613             :       b) achieving required precision StopEps
    5614             :       c) dividing curve into N-1 sections
    5615             :       If both StopM and StopEps are non-zero, algorithm is stopped by  the
    5616             :       FIRST criterion which is satisfied. In case both StopM  and  StopEps
    5617             :       are zero, algorithm stops because of (c).
    5618             : 
    5619             :   -- ALGLIB --
    5620             :      Copyright 02.10.2014 by Bochkanov Sergey
    5621             : *************************************************************************/
    5622           0 : void parametricrdpfixed(const real_2d_array &x, const ae_int_t n, const ae_int_t d, const ae_int_t stopm, const double stopeps, real_2d_array &x2, integer_1d_array &idx2, ae_int_t &nsections, const xparams _xparams)
    5623             : {
    5624             :     jmp_buf _break_jump;
    5625             :     alglib_impl::ae_state _alglib_env_state;
    5626           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5627           0 :     if( setjmp(_break_jump) )
    5628             :     {
    5629             : #if !defined(AE_NO_EXCEPTIONS)
    5630           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5631             : #else
    5632             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5633             :         return;
    5634             : #endif
    5635             :     }
    5636           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5637           0 :     if( _xparams.flags!=0x0 )
    5638           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5639           0 :     alglib_impl::parametricrdpfixed(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), n, d, stopm, stopeps, const_cast<alglib_impl::ae_matrix*>(x2.c_ptr()), const_cast<alglib_impl::ae_vector*>(idx2.c_ptr()), &nsections, &_alglib_env_state);
    5640           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5641           0 :     return;
    5642             : }
    5643             : #endif
    5644             : 
    5645             : #if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD)
    5646             : /*************************************************************************
    5647             : 3-dimensional spline inteprolant
    5648             : *************************************************************************/
    5649           0 : _spline3dinterpolant_owner::_spline3dinterpolant_owner()
    5650             : {
    5651             :     jmp_buf _break_jump;
    5652             :     alglib_impl::ae_state _state;
    5653             :     
    5654           0 :     alglib_impl::ae_state_init(&_state);
    5655           0 :     if( setjmp(_break_jump) )
    5656             :     {
    5657           0 :         if( p_struct!=NULL )
    5658             :         {
    5659           0 :             alglib_impl::_spline3dinterpolant_destroy(p_struct);
    5660           0 :             alglib_impl::ae_free(p_struct);
    5661             :         }
    5662           0 :         p_struct = NULL;
    5663             : #if !defined(AE_NO_EXCEPTIONS)
    5664           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    5665             : #else
    5666             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    5667             :         return;
    5668             : #endif
    5669             :     }
    5670           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    5671           0 :     p_struct = NULL;
    5672           0 :     p_struct = (alglib_impl::spline3dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline3dinterpolant), &_state);
    5673           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline3dinterpolant));
    5674           0 :     alglib_impl::_spline3dinterpolant_init(p_struct, &_state, ae_false);
    5675           0 :     ae_state_clear(&_state);
    5676           0 : }
    5677             : 
    5678           0 : _spline3dinterpolant_owner::_spline3dinterpolant_owner(const _spline3dinterpolant_owner &rhs)
    5679             : {
    5680             :     jmp_buf _break_jump;
    5681             :     alglib_impl::ae_state _state;
    5682             :     
    5683           0 :     alglib_impl::ae_state_init(&_state);
    5684           0 :     if( setjmp(_break_jump) )
    5685             :     {
    5686           0 :         if( p_struct!=NULL )
    5687             :         {
    5688           0 :             alglib_impl::_spline3dinterpolant_destroy(p_struct);
    5689           0 :             alglib_impl::ae_free(p_struct);
    5690             :         }
    5691           0 :         p_struct = NULL;
    5692             : #if !defined(AE_NO_EXCEPTIONS)
    5693           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    5694             : #else
    5695             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    5696             :         return;
    5697             : #endif
    5698             :     }
    5699           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    5700           0 :     p_struct = NULL;
    5701           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline3dinterpolant copy constructor failure (source is not initialized)", &_state);
    5702           0 :     p_struct = (alglib_impl::spline3dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline3dinterpolant), &_state);
    5703           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline3dinterpolant));
    5704           0 :     alglib_impl::_spline3dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline3dinterpolant*>(rhs.p_struct), &_state, ae_false);
    5705           0 :     ae_state_clear(&_state);
    5706           0 : }
    5707             : 
    5708           0 : _spline3dinterpolant_owner& _spline3dinterpolant_owner::operator=(const _spline3dinterpolant_owner &rhs)
    5709             : {
    5710           0 :     if( this==&rhs )
    5711           0 :         return *this;
    5712             :     jmp_buf _break_jump;
    5713             :     alglib_impl::ae_state _state;
    5714             :     
    5715           0 :     alglib_impl::ae_state_init(&_state);
    5716           0 :     if( setjmp(_break_jump) )
    5717             :     {
    5718             : #if !defined(AE_NO_EXCEPTIONS)
    5719           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    5720             : #else
    5721             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    5722             :         return *this;
    5723             : #endif
    5724             :     }
    5725           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    5726           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline3dinterpolant assignment constructor failure (destination is not initialized)", &_state);
    5727           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline3dinterpolant assignment constructor failure (source is not initialized)", &_state);
    5728           0 :     alglib_impl::_spline3dinterpolant_destroy(p_struct);
    5729           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline3dinterpolant));
    5730           0 :     alglib_impl::_spline3dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline3dinterpolant*>(rhs.p_struct), &_state, ae_false);
    5731           0 :     ae_state_clear(&_state);
    5732           0 :     return *this;
    5733             : }
    5734             : 
    5735           0 : _spline3dinterpolant_owner::~_spline3dinterpolant_owner()
    5736             : {
    5737           0 :     if( p_struct!=NULL )
    5738             :     {
    5739           0 :         alglib_impl::_spline3dinterpolant_destroy(p_struct);
    5740           0 :         ae_free(p_struct);
    5741             :     }
    5742           0 : }
    5743             : 
    5744           0 : alglib_impl::spline3dinterpolant* _spline3dinterpolant_owner::c_ptr()
    5745             : {
    5746           0 :     return p_struct;
    5747             : }
    5748             : 
    5749           0 : alglib_impl::spline3dinterpolant* _spline3dinterpolant_owner::c_ptr() const
    5750             : {
    5751           0 :     return const_cast<alglib_impl::spline3dinterpolant*>(p_struct);
    5752             : }
    5753           0 : spline3dinterpolant::spline3dinterpolant() : _spline3dinterpolant_owner() 
    5754             : {
    5755           0 : }
    5756             : 
    5757           0 : spline3dinterpolant::spline3dinterpolant(const spline3dinterpolant &rhs):_spline3dinterpolant_owner(rhs) 
    5758             : {
    5759           0 : }
    5760             : 
    5761           0 : spline3dinterpolant& spline3dinterpolant::operator=(const spline3dinterpolant &rhs)
    5762             : {
    5763           0 :     if( this==&rhs )
    5764           0 :         return *this;
    5765           0 :     _spline3dinterpolant_owner::operator=(rhs);
    5766           0 :     return *this;
    5767             : }
    5768             : 
    5769           0 : spline3dinterpolant::~spline3dinterpolant()
    5770             : {
    5771           0 : }
    5772             : 
    5773             : /*************************************************************************
    5774             : This subroutine calculates the value of the trilinear or tricubic spline at
    5775             : the given point (X,Y,Z).
    5776             : 
    5777             : INPUT PARAMETERS:
    5778             :     C   -   coefficients table.
    5779             :             Built by BuildBilinearSpline or BuildBicubicSpline.
    5780             :     X, Y,
    5781             :     Z   -   point
    5782             : 
    5783             : Result:
    5784             :     S(x,y,z)
    5785             : 
    5786             :   -- ALGLIB PROJECT --
    5787             :      Copyright 26.04.2012 by Bochkanov Sergey
    5788             : *************************************************************************/
    5789           0 : double spline3dcalc(const spline3dinterpolant &c, const double x, const double y, const double z, const xparams _xparams)
    5790             : {
    5791             :     jmp_buf _break_jump;
    5792             :     alglib_impl::ae_state _alglib_env_state;
    5793           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5794           0 :     if( setjmp(_break_jump) )
    5795             :     {
    5796             : #if !defined(AE_NO_EXCEPTIONS)
    5797           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5798             : #else
    5799             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5800             :         return 0;
    5801             : #endif
    5802             :     }
    5803           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5804           0 :     if( _xparams.flags!=0x0 )
    5805           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5806           0 :     double result = alglib_impl::spline3dcalc(const_cast<alglib_impl::spline3dinterpolant*>(c.c_ptr()), x, y, z, &_alglib_env_state);
    5807           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5808           0 :     return *(reinterpret_cast<double*>(&result));
    5809             : }
    5810             : 
    5811             : /*************************************************************************
    5812             : This subroutine performs linear transformation of the spline argument.
    5813             : 
    5814             : INPUT PARAMETERS:
    5815             :     C       -   spline interpolant
    5816             :     AX, BX  -   transformation coefficients: x = A*u + B
    5817             :     AY, BY  -   transformation coefficients: y = A*v + B
    5818             :     AZ, BZ  -   transformation coefficients: z = A*w + B
    5819             : 
    5820             : OUTPUT PARAMETERS:
    5821             :     C   -   transformed spline
    5822             : 
    5823             :   -- ALGLIB PROJECT --
    5824             :      Copyright 26.04.2012 by Bochkanov Sergey
    5825             : *************************************************************************/
    5826           0 : void spline3dlintransxyz(const spline3dinterpolant &c, const double ax, const double bx, const double ay, const double by, const double az, const double bz, const xparams _xparams)
    5827             : {
    5828             :     jmp_buf _break_jump;
    5829             :     alglib_impl::ae_state _alglib_env_state;
    5830           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5831           0 :     if( setjmp(_break_jump) )
    5832             :     {
    5833             : #if !defined(AE_NO_EXCEPTIONS)
    5834           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5835             : #else
    5836             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5837             :         return;
    5838             : #endif
    5839             :     }
    5840           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5841           0 :     if( _xparams.flags!=0x0 )
    5842           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5843           0 :     alglib_impl::spline3dlintransxyz(const_cast<alglib_impl::spline3dinterpolant*>(c.c_ptr()), ax, bx, ay, by, az, bz, &_alglib_env_state);
    5844           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5845           0 :     return;
    5846             : }
    5847             : 
    5848             : /*************************************************************************
    5849             : This subroutine performs linear transformation of the spline.
    5850             : 
    5851             : INPUT PARAMETERS:
    5852             :     C   -   spline interpolant.
    5853             :     A, B-   transformation coefficients: S2(x,y) = A*S(x,y,z) + B
    5854             : 
    5855             : OUTPUT PARAMETERS:
    5856             :     C   -   transformed spline
    5857             : 
    5858             :   -- ALGLIB PROJECT --
    5859             :      Copyright 26.04.2012 by Bochkanov Sergey
    5860             : *************************************************************************/
    5861           0 : void spline3dlintransf(const spline3dinterpolant &c, const double a, const double b, const xparams _xparams)
    5862             : {
    5863             :     jmp_buf _break_jump;
    5864             :     alglib_impl::ae_state _alglib_env_state;
    5865           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5866           0 :     if( setjmp(_break_jump) )
    5867             :     {
    5868             : #if !defined(AE_NO_EXCEPTIONS)
    5869           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5870             : #else
    5871             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5872             :         return;
    5873             : #endif
    5874             :     }
    5875           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5876           0 :     if( _xparams.flags!=0x0 )
    5877           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5878           0 :     alglib_impl::spline3dlintransf(const_cast<alglib_impl::spline3dinterpolant*>(c.c_ptr()), a, b, &_alglib_env_state);
    5879           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5880           0 :     return;
    5881             : }
    5882             : 
    5883             : /*************************************************************************
    5884             : Trilinear spline resampling
    5885             : 
    5886             : INPUT PARAMETERS:
    5887             :     A           -   array[0..OldXCount*OldYCount*OldZCount-1], function
    5888             :                     values at the old grid, :
    5889             :                         A[0]        x=0,y=0,z=0
    5890             :                         A[1]        x=1,y=0,z=0
    5891             :                         A[..]       ...
    5892             :                         A[..]       x=oldxcount-1,y=0,z=0
    5893             :                         A[..]       x=0,y=1,z=0
    5894             :                         A[..]       ...
    5895             :                         ...
    5896             :     OldZCount   -   old Z-count, OldZCount>1
    5897             :     OldYCount   -   old Y-count, OldYCount>1
    5898             :     OldXCount   -   old X-count, OldXCount>1
    5899             :     NewZCount   -   new Z-count, NewZCount>1
    5900             :     NewYCount   -   new Y-count, NewYCount>1
    5901             :     NewXCount   -   new X-count, NewXCount>1
    5902             : 
    5903             : OUTPUT PARAMETERS:
    5904             :     B           -   array[0..NewXCount*NewYCount*NewZCount-1], function
    5905             :                     values at the new grid:
    5906             :                         B[0]        x=0,y=0,z=0
    5907             :                         B[1]        x=1,y=0,z=0
    5908             :                         B[..]       ...
    5909             :                         B[..]       x=newxcount-1,y=0,z=0
    5910             :                         B[..]       x=0,y=1,z=0
    5911             :                         B[..]       ...
    5912             :                         ...
    5913             : 
    5914             :   -- ALGLIB routine --
    5915             :      26.04.2012
    5916             :      Copyright by Bochkanov Sergey
    5917             : *************************************************************************/
    5918           0 : 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)
    5919             : {
    5920             :     jmp_buf _break_jump;
    5921             :     alglib_impl::ae_state _alglib_env_state;
    5922           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5923           0 :     if( setjmp(_break_jump) )
    5924             :     {
    5925             : #if !defined(AE_NO_EXCEPTIONS)
    5926           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5927             : #else
    5928             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5929             :         return;
    5930             : #endif
    5931             :     }
    5932           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5933           0 :     if( _xparams.flags!=0x0 )
    5934           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5935           0 :     alglib_impl::spline3dresampletrilinear(const_cast<alglib_impl::ae_vector*>(a.c_ptr()), oldzcount, oldycount, oldxcount, newzcount, newycount, newxcount, const_cast<alglib_impl::ae_vector*>(b.c_ptr()), &_alglib_env_state);
    5936           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5937           0 :     return;
    5938             : }
    5939             : 
    5940             : /*************************************************************************
    5941             : This subroutine builds trilinear vector-valued spline.
    5942             : 
    5943             : INPUT PARAMETERS:
    5944             :     X   -   spline abscissas,  array[0..N-1]
    5945             :     Y   -   spline ordinates,  array[0..M-1]
    5946             :     Z   -   spline applicates, array[0..L-1]
    5947             :     F   -   function values, array[0..M*N*L*D-1]:
    5948             :             * first D elements store D values at (X[0],Y[0],Z[0])
    5949             :             * next D elements store D values at (X[1],Y[0],Z[0])
    5950             :             * next D elements store D values at (X[2],Y[0],Z[0])
    5951             :             * ...
    5952             :             * next D elements store D values at (X[0],Y[1],Z[0])
    5953             :             * next D elements store D values at (X[1],Y[1],Z[0])
    5954             :             * next D elements store D values at (X[2],Y[1],Z[0])
    5955             :             * ...
    5956             :             * next D elements store D values at (X[0],Y[0],Z[1])
    5957             :             * next D elements store D values at (X[1],Y[0],Z[1])
    5958             :             * next D elements store D values at (X[2],Y[0],Z[1])
    5959             :             * ...
    5960             :             * general form - D function values at (X[i],Y[j]) are stored
    5961             :               at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1].
    5962             :     M,N,
    5963             :     L   -   grid size, M>=2, N>=2, L>=2
    5964             :     D   -   vector dimension, D>=1
    5965             : 
    5966             : OUTPUT PARAMETERS:
    5967             :     C   -   spline interpolant
    5968             : 
    5969             :   -- ALGLIB PROJECT --
    5970             :      Copyright 26.04.2012 by Bochkanov Sergey
    5971             : *************************************************************************/
    5972           0 : 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)
    5973             : {
    5974             :     jmp_buf _break_jump;
    5975             :     alglib_impl::ae_state _alglib_env_state;
    5976           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    5977           0 :     if( setjmp(_break_jump) )
    5978             :     {
    5979             : #if !defined(AE_NO_EXCEPTIONS)
    5980           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    5981             : #else
    5982             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    5983             :         return;
    5984             : #endif
    5985             :     }
    5986           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    5987           0 :     if( _xparams.flags!=0x0 )
    5988           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    5989           0 :     alglib_impl::spline3dbuildtrilinearv(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), m, const_cast<alglib_impl::ae_vector*>(z.c_ptr()), l, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), d, const_cast<alglib_impl::spline3dinterpolant*>(c.c_ptr()), &_alglib_env_state);
    5990           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    5991           0 :     return;
    5992             : }
    5993             : 
    5994             : /*************************************************************************
    5995             : This subroutine calculates bilinear or bicubic vector-valued spline at the
    5996             : given point (X,Y,Z).
    5997             : 
    5998             : INPUT PARAMETERS:
    5999             :     C   -   spline interpolant.
    6000             :     X, Y,
    6001             :     Z   -   point
    6002             :     F   -   output buffer, possibly preallocated array. In case array size
    6003             :             is large enough to store result, it is not reallocated.  Array
    6004             :             which is too short will be reallocated
    6005             : 
    6006             : OUTPUT PARAMETERS:
    6007             :     F   -   array[D] (or larger) which stores function values
    6008             : 
    6009             :   -- ALGLIB PROJECT --
    6010             :      Copyright 26.04.2012 by Bochkanov Sergey
    6011             : *************************************************************************/
    6012           0 : void spline3dcalcvbuf(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f, const xparams _xparams)
    6013             : {
    6014             :     jmp_buf _break_jump;
    6015             :     alglib_impl::ae_state _alglib_env_state;
    6016           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6017           0 :     if( setjmp(_break_jump) )
    6018             :     {
    6019             : #if !defined(AE_NO_EXCEPTIONS)
    6020           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6021             : #else
    6022             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6023             :         return;
    6024             : #endif
    6025             :     }
    6026           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6027           0 :     if( _xparams.flags!=0x0 )
    6028           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6029           0 :     alglib_impl::spline3dcalcvbuf(const_cast<alglib_impl::spline3dinterpolant*>(c.c_ptr()), x, y, z, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), &_alglib_env_state);
    6030           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6031           0 :     return;
    6032             : }
    6033             : 
    6034             : /*************************************************************************
    6035             : This subroutine calculates trilinear or tricubic vector-valued spline at the
    6036             : given point (X,Y,Z).
    6037             : 
    6038             : INPUT PARAMETERS:
    6039             :     C   -   spline interpolant.
    6040             :     X, Y,
    6041             :     Z   -   point
    6042             : 
    6043             : OUTPUT PARAMETERS:
    6044             :     F   -   array[D] which stores function values.  F is out-parameter and
    6045             :             it  is  reallocated  after  call to this function. In case you
    6046             :             want  to    reuse  previously  allocated  F,   you   may   use
    6047             :             Spline2DCalcVBuf(),  which  reallocates  F only when it is too
    6048             :             small.
    6049             : 
    6050             :   -- ALGLIB PROJECT --
    6051             :      Copyright 26.04.2012 by Bochkanov Sergey
    6052             : *************************************************************************/
    6053           0 : void spline3dcalcv(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f, const xparams _xparams)
    6054             : {
    6055             :     jmp_buf _break_jump;
    6056             :     alglib_impl::ae_state _alglib_env_state;
    6057           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6058           0 :     if( setjmp(_break_jump) )
    6059             :     {
    6060             : #if !defined(AE_NO_EXCEPTIONS)
    6061           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6062             : #else
    6063             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6064             :         return;
    6065             : #endif
    6066             :     }
    6067           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6068           0 :     if( _xparams.flags!=0x0 )
    6069           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6070           0 :     alglib_impl::spline3dcalcv(const_cast<alglib_impl::spline3dinterpolant*>(c.c_ptr()), x, y, z, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), &_alglib_env_state);
    6071           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6072           0 :     return;
    6073             : }
    6074             : 
    6075             : /*************************************************************************
    6076             : This subroutine unpacks tri-dimensional spline into the coefficients table
    6077             : 
    6078             : INPUT PARAMETERS:
    6079             :     C   -   spline interpolant.
    6080             : 
    6081             : Result:
    6082             :     N   -   grid size (X)
    6083             :     M   -   grid size (Y)
    6084             :     L   -   grid size (Z)
    6085             :     D   -   number of components
    6086             :     SType-  spline type. Currently, only one spline type is supported:
    6087             :             trilinear spline, as indicated by SType=1.
    6088             :     Tbl -   spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13].
    6089             :             For T=0..D-1 (component index), I = 0...N-2 (x index),
    6090             :             J=0..M-2 (y index), K=0..L-2 (z index):
    6091             :                 Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1),
    6092             : 
    6093             :                 Q-th row stores decomposition for T-th component of the
    6094             :                 vector-valued function
    6095             : 
    6096             :                 Tbl[Q,0] = X[i]
    6097             :                 Tbl[Q,1] = X[i+1]
    6098             :                 Tbl[Q,2] = Y[j]
    6099             :                 Tbl[Q,3] = Y[j+1]
    6100             :                 Tbl[Q,4] = Z[k]
    6101             :                 Tbl[Q,5] = Z[k+1]
    6102             : 
    6103             :                 Tbl[Q,6] = C000
    6104             :                 Tbl[Q,7] = C100
    6105             :                 Tbl[Q,8] = C010
    6106             :                 Tbl[Q,9] = C110
    6107             :                 Tbl[Q,10]= C001
    6108             :                 Tbl[Q,11]= C101
    6109             :                 Tbl[Q,12]= C011
    6110             :                 Tbl[Q,13]= C111
    6111             :             On each grid square spline is equals to:
    6112             :                 S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1)
    6113             :                 t = x-x[j]
    6114             :                 u = y-y[i]
    6115             :                 v = z-z[k]
    6116             : 
    6117             :             NOTE: format of Tbl is given for SType=1. Future versions of
    6118             :                   ALGLIB can use different formats for different values of
    6119             :                   SType.
    6120             : 
    6121             :   -- ALGLIB PROJECT --
    6122             :      Copyright 26.04.2012 by Bochkanov Sergey
    6123             : *************************************************************************/
    6124           0 : 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)
    6125             : {
    6126             :     jmp_buf _break_jump;
    6127             :     alglib_impl::ae_state _alglib_env_state;
    6128           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6129           0 :     if( setjmp(_break_jump) )
    6130             :     {
    6131             : #if !defined(AE_NO_EXCEPTIONS)
    6132           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6133             : #else
    6134             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6135             :         return;
    6136             : #endif
    6137             :     }
    6138           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6139           0 :     if( _xparams.flags!=0x0 )
    6140           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6141           0 :     alglib_impl::spline3dunpackv(const_cast<alglib_impl::spline3dinterpolant*>(c.c_ptr()), &n, &m, &l, &d, &stype, const_cast<alglib_impl::ae_matrix*>(tbl.c_ptr()), &_alglib_env_state);
    6142           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6143           0 :     return;
    6144             : }
    6145             : #endif
    6146             : 
    6147             : #if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD)
    6148             : /*************************************************************************
    6149             : Conversion from barycentric representation to Chebyshev basis.
    6150             : This function has O(N^2) complexity.
    6151             : 
    6152             : INPUT PARAMETERS:
    6153             :     P   -   polynomial in barycentric form
    6154             :     A,B -   base interval for Chebyshev polynomials (see below)
    6155             :             A<>B
    6156             : 
    6157             : OUTPUT PARAMETERS
    6158             :     T   -   coefficients of Chebyshev representation;
    6159             :             P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 },
    6160             :             where Ti - I-th Chebyshev polynomial.
    6161             : 
    6162             : NOTES:
    6163             :     barycentric interpolant passed as P may be either polynomial  obtained
    6164             :     from  polynomial  interpolation/ fitting or rational function which is
    6165             :     NOT polynomial. We can't distinguish between these two cases, and this
    6166             :     algorithm just tries to work assuming that P IS a polynomial.  If not,
    6167             :     algorithm will return results, but they won't have any meaning.
    6168             : 
    6169             :   -- ALGLIB --
    6170             :      Copyright 30.09.2010 by Bochkanov Sergey
    6171             : *************************************************************************/
    6172           0 : void polynomialbar2cheb(const barycentricinterpolant &p, const double a, const double b, real_1d_array &t, const xparams _xparams)
    6173             : {
    6174             :     jmp_buf _break_jump;
    6175             :     alglib_impl::ae_state _alglib_env_state;
    6176           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6177           0 :     if( setjmp(_break_jump) )
    6178             :     {
    6179             : #if !defined(AE_NO_EXCEPTIONS)
    6180           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6181             : #else
    6182             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6183             :         return;
    6184             : #endif
    6185             :     }
    6186           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6187           0 :     if( _xparams.flags!=0x0 )
    6188           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6189           0 :     alglib_impl::polynomialbar2cheb(const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), a, b, const_cast<alglib_impl::ae_vector*>(t.c_ptr()), &_alglib_env_state);
    6190           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6191           0 :     return;
    6192             : }
    6193             : 
    6194             : /*************************************************************************
    6195             : Conversion from Chebyshev basis to barycentric representation.
    6196             : This function has O(N^2) complexity.
    6197             : 
    6198             : INPUT PARAMETERS:
    6199             :     T   -   coefficients of Chebyshev representation;
    6200             :             P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N },
    6201             :             where Ti - I-th Chebyshev polynomial.
    6202             :     N   -   number of coefficients:
    6203             :             * if given, only leading N elements of T are used
    6204             :             * if not given, automatically determined from size of T
    6205             :     A,B -   base interval for Chebyshev polynomials (see above)
    6206             :             A<B
    6207             : 
    6208             : OUTPUT PARAMETERS
    6209             :     P   -   polynomial in barycentric form
    6210             : 
    6211             :   -- ALGLIB --
    6212             :      Copyright 30.09.2010 by Bochkanov Sergey
    6213             : *************************************************************************/
    6214           0 : void polynomialcheb2bar(const real_1d_array &t, const ae_int_t n, const double a, const double b, barycentricinterpolant &p, const xparams _xparams)
    6215             : {
    6216             :     jmp_buf _break_jump;
    6217             :     alglib_impl::ae_state _alglib_env_state;
    6218           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6219           0 :     if( setjmp(_break_jump) )
    6220             :     {
    6221             : #if !defined(AE_NO_EXCEPTIONS)
    6222           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6223             : #else
    6224             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6225             :         return;
    6226             : #endif
    6227             :     }
    6228           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6229           0 :     if( _xparams.flags!=0x0 )
    6230           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6231           0 :     alglib_impl::polynomialcheb2bar(const_cast<alglib_impl::ae_vector*>(t.c_ptr()), n, a, b, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6232           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6233           0 :     return;
    6234             : }
    6235             : 
    6236             : /*************************************************************************
    6237             : Conversion from Chebyshev basis to barycentric representation.
    6238             : This function has O(N^2) complexity.
    6239             : 
    6240             : INPUT PARAMETERS:
    6241             :     T   -   coefficients of Chebyshev representation;
    6242             :             P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N },
    6243             :             where Ti - I-th Chebyshev polynomial.
    6244             :     N   -   number of coefficients:
    6245             :             * if given, only leading N elements of T are used
    6246             :             * if not given, automatically determined from size of T
    6247             :     A,B -   base interval for Chebyshev polynomials (see above)
    6248             :             A<B
    6249             : 
    6250             : OUTPUT PARAMETERS
    6251             :     P   -   polynomial in barycentric form
    6252             : 
    6253             :   -- ALGLIB --
    6254             :      Copyright 30.09.2010 by Bochkanov Sergey
    6255             : *************************************************************************/
    6256             : #if !defined(AE_NO_EXCEPTIONS)
    6257           0 : void polynomialcheb2bar(const real_1d_array &t, const double a, const double b, barycentricinterpolant &p, const xparams _xparams)
    6258             : {
    6259             :     jmp_buf _break_jump;
    6260             :     alglib_impl::ae_state _alglib_env_state;    
    6261             :     ae_int_t n;
    6262             : 
    6263           0 :     n = t.length();
    6264           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6265           0 :     if( setjmp(_break_jump) )
    6266           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6267           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6268           0 :     if( _xparams.flags!=0x0 )
    6269           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6270           0 :     alglib_impl::polynomialcheb2bar(const_cast<alglib_impl::ae_vector*>(t.c_ptr()), n, a, b, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6271             : 
    6272           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6273           0 :     return;
    6274             : }
    6275             : #endif
    6276             : 
    6277             : /*************************************************************************
    6278             : Conversion from barycentric representation to power basis.
    6279             : This function has O(N^2) complexity.
    6280             : 
    6281             : INPUT PARAMETERS:
    6282             :     P   -   polynomial in barycentric form
    6283             :     C   -   offset (see below); 0.0 is used as default value.
    6284             :     S   -   scale (see below);  1.0 is used as default value. S<>0.
    6285             : 
    6286             : OUTPUT PARAMETERS
    6287             :     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
    6288             :     N   -   number of coefficients (polynomial degree plus 1)
    6289             : 
    6290             : NOTES:
    6291             : 1.  this function accepts offset and scale, which can be  set  to  improve
    6292             :     numerical properties of polynomial. For example, if P was obtained  as
    6293             :     result of interpolation on [-1,+1],  you  can  set  C=0  and  S=1  and
    6294             :     represent  P  as sum of 1, x, x^2, x^3 and so on. In most cases you it
    6295             :     is exactly what you need.
    6296             : 
    6297             :     However, if your interpolation model was built on [999,1001], you will
    6298             :     see significant growth of numerical errors when using {1, x, x^2, x^3}
    6299             :     as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3
    6300             :     will be better option. Such representation can be  obtained  by  using
    6301             :     1000.0 as offset C and 1.0 as scale S.
    6302             : 
    6303             : 2.  power basis is ill-conditioned and tricks described above can't  solve
    6304             :     this problem completely. This function  will  return  coefficients  in
    6305             :     any  case,  but  for  N>8  they  will  become unreliable. However, N's
    6306             :     less than 5 are pretty safe.
    6307             : 
    6308             : 3.  barycentric interpolant passed as P may be either polynomial  obtained
    6309             :     from  polynomial  interpolation/ fitting or rational function which is
    6310             :     NOT polynomial. We can't distinguish between these two cases, and this
    6311             :     algorithm just tries to work assuming that P IS a polynomial.  If not,
    6312             :     algorithm will return results, but they won't have any meaning.
    6313             : 
    6314             :   -- ALGLIB --
    6315             :      Copyright 30.09.2010 by Bochkanov Sergey
    6316             : *************************************************************************/
    6317           0 : void polynomialbar2pow(const barycentricinterpolant &p, const double c, const double s, real_1d_array &a, const xparams _xparams)
    6318             : {
    6319             :     jmp_buf _break_jump;
    6320             :     alglib_impl::ae_state _alglib_env_state;
    6321           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6322           0 :     if( setjmp(_break_jump) )
    6323             :     {
    6324             : #if !defined(AE_NO_EXCEPTIONS)
    6325           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6326             : #else
    6327             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6328             :         return;
    6329             : #endif
    6330             :     }
    6331           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6332           0 :     if( _xparams.flags!=0x0 )
    6333           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6334           0 :     alglib_impl::polynomialbar2pow(const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), c, s, const_cast<alglib_impl::ae_vector*>(a.c_ptr()), &_alglib_env_state);
    6335           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6336           0 :     return;
    6337             : }
    6338             : 
    6339             : /*************************************************************************
    6340             : Conversion from barycentric representation to power basis.
    6341             : This function has O(N^2) complexity.
    6342             : 
    6343             : INPUT PARAMETERS:
    6344             :     P   -   polynomial in barycentric form
    6345             :     C   -   offset (see below); 0.0 is used as default value.
    6346             :     S   -   scale (see below);  1.0 is used as default value. S<>0.
    6347             : 
    6348             : OUTPUT PARAMETERS
    6349             :     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
    6350             :     N   -   number of coefficients (polynomial degree plus 1)
    6351             : 
    6352             : NOTES:
    6353             : 1.  this function accepts offset and scale, which can be  set  to  improve
    6354             :     numerical properties of polynomial. For example, if P was obtained  as
    6355             :     result of interpolation on [-1,+1],  you  can  set  C=0  and  S=1  and
    6356             :     represent  P  as sum of 1, x, x^2, x^3 and so on. In most cases you it
    6357             :     is exactly what you need.
    6358             : 
    6359             :     However, if your interpolation model was built on [999,1001], you will
    6360             :     see significant growth of numerical errors when using {1, x, x^2, x^3}
    6361             :     as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3
    6362             :     will be better option. Such representation can be  obtained  by  using
    6363             :     1000.0 as offset C and 1.0 as scale S.
    6364             : 
    6365             : 2.  power basis is ill-conditioned and tricks described above can't  solve
    6366             :     this problem completely. This function  will  return  coefficients  in
    6367             :     any  case,  but  for  N>8  they  will  become unreliable. However, N's
    6368             :     less than 5 are pretty safe.
    6369             : 
    6370             : 3.  barycentric interpolant passed as P may be either polynomial  obtained
    6371             :     from  polynomial  interpolation/ fitting or rational function which is
    6372             :     NOT polynomial. We can't distinguish between these two cases, and this
    6373             :     algorithm just tries to work assuming that P IS a polynomial.  If not,
    6374             :     algorithm will return results, but they won't have any meaning.
    6375             : 
    6376             :   -- ALGLIB --
    6377             :      Copyright 30.09.2010 by Bochkanov Sergey
    6378             : *************************************************************************/
    6379             : #if !defined(AE_NO_EXCEPTIONS)
    6380           0 : void polynomialbar2pow(const barycentricinterpolant &p, real_1d_array &a, const xparams _xparams)
    6381             : {
    6382             :     jmp_buf _break_jump;
    6383             :     alglib_impl::ae_state _alglib_env_state;    
    6384             :     double c;
    6385             :     double s;
    6386             : 
    6387           0 :     c = 0;
    6388           0 :     s = 1;
    6389           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6390           0 :     if( setjmp(_break_jump) )
    6391           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6392           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6393           0 :     if( _xparams.flags!=0x0 )
    6394           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6395           0 :     alglib_impl::polynomialbar2pow(const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), c, s, const_cast<alglib_impl::ae_vector*>(a.c_ptr()), &_alglib_env_state);
    6396             : 
    6397           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6398           0 :     return;
    6399             : }
    6400             : #endif
    6401             : 
    6402             : /*************************************************************************
    6403             : Conversion from power basis to barycentric representation.
    6404             : This function has O(N^2) complexity.
    6405             : 
    6406             : INPUT PARAMETERS:
    6407             :     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
    6408             :     N   -   number of coefficients (polynomial degree plus 1)
    6409             :             * if given, only leading N elements of A are used
    6410             :             * if not given, automatically determined from size of A
    6411             :     C   -   offset (see below); 0.0 is used as default value.
    6412             :     S   -   scale (see below);  1.0 is used as default value. S<>0.
    6413             : 
    6414             : OUTPUT PARAMETERS
    6415             :     P   -   polynomial in barycentric form
    6416             : 
    6417             : 
    6418             : NOTES:
    6419             : 1.  this function accepts offset and scale, which can be  set  to  improve
    6420             :     numerical properties of polynomial. For example, if you interpolate on
    6421             :     [-1,+1],  you  can  set C=0 and S=1 and convert from sum of 1, x, x^2,
    6422             :     x^3 and so on. In most cases you it is exactly what you need.
    6423             : 
    6424             :     However, if your interpolation model was built on [999,1001], you will
    6425             :     see significant growth of numerical errors when using {1, x, x^2, x^3}
    6426             :     as  input  basis.  Converting  from  sum  of  1, (x-1000), (x-1000)^2,
    6427             :     (x-1000)^3 will be better option (you have to specify 1000.0 as offset
    6428             :     C and 1.0 as scale S).
    6429             : 
    6430             : 2.  power basis is ill-conditioned and tricks described above can't  solve
    6431             :     this problem completely. This function  will  return barycentric model
    6432             :     in any case, but for N>8 accuracy well degrade. However, N's less than
    6433             :     5 are pretty safe.
    6434             : 
    6435             :   -- ALGLIB --
    6436             :      Copyright 30.09.2010 by Bochkanov Sergey
    6437             : *************************************************************************/
    6438           0 : void polynomialpow2bar(const real_1d_array &a, const ae_int_t n, const double c, const double s, barycentricinterpolant &p, const xparams _xparams)
    6439             : {
    6440             :     jmp_buf _break_jump;
    6441             :     alglib_impl::ae_state _alglib_env_state;
    6442           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6443           0 :     if( setjmp(_break_jump) )
    6444             :     {
    6445             : #if !defined(AE_NO_EXCEPTIONS)
    6446           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6447             : #else
    6448             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6449             :         return;
    6450             : #endif
    6451             :     }
    6452           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6453           0 :     if( _xparams.flags!=0x0 )
    6454           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6455           0 :     alglib_impl::polynomialpow2bar(const_cast<alglib_impl::ae_vector*>(a.c_ptr()), n, c, s, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6456           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6457           0 :     return;
    6458             : }
    6459             : 
    6460             : /*************************************************************************
    6461             : Conversion from power basis to barycentric representation.
    6462             : This function has O(N^2) complexity.
    6463             : 
    6464             : INPUT PARAMETERS:
    6465             :     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
    6466             :     N   -   number of coefficients (polynomial degree plus 1)
    6467             :             * if given, only leading N elements of A are used
    6468             :             * if not given, automatically determined from size of A
    6469             :     C   -   offset (see below); 0.0 is used as default value.
    6470             :     S   -   scale (see below);  1.0 is used as default value. S<>0.
    6471             : 
    6472             : OUTPUT PARAMETERS
    6473             :     P   -   polynomial in barycentric form
    6474             : 
    6475             : 
    6476             : NOTES:
    6477             : 1.  this function accepts offset and scale, which can be  set  to  improve
    6478             :     numerical properties of polynomial. For example, if you interpolate on
    6479             :     [-1,+1],  you  can  set C=0 and S=1 and convert from sum of 1, x, x^2,
    6480             :     x^3 and so on. In most cases you it is exactly what you need.
    6481             : 
    6482             :     However, if your interpolation model was built on [999,1001], you will
    6483             :     see significant growth of numerical errors when using {1, x, x^2, x^3}
    6484             :     as  input  basis.  Converting  from  sum  of  1, (x-1000), (x-1000)^2,
    6485             :     (x-1000)^3 will be better option (you have to specify 1000.0 as offset
    6486             :     C and 1.0 as scale S).
    6487             : 
    6488             : 2.  power basis is ill-conditioned and tricks described above can't  solve
    6489             :     this problem completely. This function  will  return barycentric model
    6490             :     in any case, but for N>8 accuracy well degrade. However, N's less than
    6491             :     5 are pretty safe.
    6492             : 
    6493             :   -- ALGLIB --
    6494             :      Copyright 30.09.2010 by Bochkanov Sergey
    6495             : *************************************************************************/
    6496             : #if !defined(AE_NO_EXCEPTIONS)
    6497           0 : void polynomialpow2bar(const real_1d_array &a, barycentricinterpolant &p, const xparams _xparams)
    6498             : {
    6499             :     jmp_buf _break_jump;
    6500             :     alglib_impl::ae_state _alglib_env_state;    
    6501             :     ae_int_t n;
    6502             :     double c;
    6503             :     double s;
    6504             : 
    6505           0 :     n = a.length();
    6506           0 :     c = 0;
    6507           0 :     s = 1;
    6508           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6509           0 :     if( setjmp(_break_jump) )
    6510           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6511           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6512           0 :     if( _xparams.flags!=0x0 )
    6513           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6514           0 :     alglib_impl::polynomialpow2bar(const_cast<alglib_impl::ae_vector*>(a.c_ptr()), n, c, s, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6515             : 
    6516           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6517           0 :     return;
    6518             : }
    6519             : #endif
    6520             : 
    6521             : /*************************************************************************
    6522             : Lagrange intepolant: generation of the model on the general grid.
    6523             : This function has O(N^2) complexity.
    6524             : 
    6525             : INPUT PARAMETERS:
    6526             :     X   -   abscissas, array[0..N-1]
    6527             :     Y   -   function values, array[0..N-1]
    6528             :     N   -   number of points, N>=1
    6529             : 
    6530             : OUTPUT PARAMETERS
    6531             :     P   -   barycentric model which represents Lagrange interpolant
    6532             :             (see ratint unit info and BarycentricCalc() description for
    6533             :             more information).
    6534             : 
    6535             :   -- ALGLIB --
    6536             :      Copyright 02.12.2009 by Bochkanov Sergey
    6537             : *************************************************************************/
    6538           0 : void polynomialbuild(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams)
    6539             : {
    6540             :     jmp_buf _break_jump;
    6541             :     alglib_impl::ae_state _alglib_env_state;
    6542           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6543           0 :     if( setjmp(_break_jump) )
    6544             :     {
    6545             : #if !defined(AE_NO_EXCEPTIONS)
    6546           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6547             : #else
    6548             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6549             :         return;
    6550             : #endif
    6551             :     }
    6552           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6553           0 :     if( _xparams.flags!=0x0 )
    6554           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6555           0 :     alglib_impl::polynomialbuild(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6556           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6557           0 :     return;
    6558             : }
    6559             : 
    6560             : /*************************************************************************
    6561             : Lagrange intepolant: generation of the model on the general grid.
    6562             : This function has O(N^2) complexity.
    6563             : 
    6564             : INPUT PARAMETERS:
    6565             :     X   -   abscissas, array[0..N-1]
    6566             :     Y   -   function values, array[0..N-1]
    6567             :     N   -   number of points, N>=1
    6568             : 
    6569             : OUTPUT PARAMETERS
    6570             :     P   -   barycentric model which represents Lagrange interpolant
    6571             :             (see ratint unit info and BarycentricCalc() description for
    6572             :             more information).
    6573             : 
    6574             :   -- ALGLIB --
    6575             :      Copyright 02.12.2009 by Bochkanov Sergey
    6576             : *************************************************************************/
    6577             : #if !defined(AE_NO_EXCEPTIONS)
    6578           0 : void polynomialbuild(const real_1d_array &x, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams)
    6579             : {
    6580             :     jmp_buf _break_jump;
    6581             :     alglib_impl::ae_state _alglib_env_state;    
    6582             :     ae_int_t n;
    6583           0 :     if( (x.length()!=y.length()))
    6584           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialbuild': looks like one of arguments has wrong size");
    6585           0 :     n = x.length();
    6586           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6587           0 :     if( setjmp(_break_jump) )
    6588           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6589           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6590           0 :     if( _xparams.flags!=0x0 )
    6591           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6592           0 :     alglib_impl::polynomialbuild(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6593             : 
    6594           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6595           0 :     return;
    6596             : }
    6597             : #endif
    6598             : 
    6599             : /*************************************************************************
    6600             : Lagrange intepolant: generation of the model on equidistant grid.
    6601             : This function has O(N) complexity.
    6602             : 
    6603             : INPUT PARAMETERS:
    6604             :     A   -   left boundary of [A,B]
    6605             :     B   -   right boundary of [A,B]
    6606             :     Y   -   function values at the nodes, array[0..N-1]
    6607             :     N   -   number of points, N>=1
    6608             :             for N=1 a constant model is constructed.
    6609             : 
    6610             : OUTPUT PARAMETERS
    6611             :     P   -   barycentric model which represents Lagrange interpolant
    6612             :             (see ratint unit info and BarycentricCalc() description for
    6613             :             more information).
    6614             : 
    6615             :   -- ALGLIB --
    6616             :      Copyright 03.12.2009 by Bochkanov Sergey
    6617             : *************************************************************************/
    6618           0 : void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams)
    6619             : {
    6620             :     jmp_buf _break_jump;
    6621             :     alglib_impl::ae_state _alglib_env_state;
    6622           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6623           0 :     if( setjmp(_break_jump) )
    6624             :     {
    6625             : #if !defined(AE_NO_EXCEPTIONS)
    6626           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6627             : #else
    6628             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6629             :         return;
    6630             : #endif
    6631             :     }
    6632           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6633           0 :     if( _xparams.flags!=0x0 )
    6634           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6635           0 :     alglib_impl::polynomialbuildeqdist(a, b, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6636           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6637           0 :     return;
    6638             : }
    6639             : 
    6640             : /*************************************************************************
    6641             : Lagrange intepolant: generation of the model on equidistant grid.
    6642             : This function has O(N) complexity.
    6643             : 
    6644             : INPUT PARAMETERS:
    6645             :     A   -   left boundary of [A,B]
    6646             :     B   -   right boundary of [A,B]
    6647             :     Y   -   function values at the nodes, array[0..N-1]
    6648             :     N   -   number of points, N>=1
    6649             :             for N=1 a constant model is constructed.
    6650             : 
    6651             : OUTPUT PARAMETERS
    6652             :     P   -   barycentric model which represents Lagrange interpolant
    6653             :             (see ratint unit info and BarycentricCalc() description for
    6654             :             more information).
    6655             : 
    6656             :   -- ALGLIB --
    6657             :      Copyright 03.12.2009 by Bochkanov Sergey
    6658             : *************************************************************************/
    6659             : #if !defined(AE_NO_EXCEPTIONS)
    6660           0 : void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams)
    6661             : {
    6662             :     jmp_buf _break_jump;
    6663             :     alglib_impl::ae_state _alglib_env_state;    
    6664             :     ae_int_t n;
    6665             : 
    6666           0 :     n = y.length();
    6667           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6668           0 :     if( setjmp(_break_jump) )
    6669           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6670           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6671           0 :     if( _xparams.flags!=0x0 )
    6672           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6673           0 :     alglib_impl::polynomialbuildeqdist(a, b, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6674             : 
    6675           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6676           0 :     return;
    6677             : }
    6678             : #endif
    6679             : 
    6680             : /*************************************************************************
    6681             : Lagrange intepolant on Chebyshev grid (first kind).
    6682             : This function has O(N) complexity.
    6683             : 
    6684             : INPUT PARAMETERS:
    6685             :     A   -   left boundary of [A,B]
    6686             :     B   -   right boundary of [A,B]
    6687             :     Y   -   function values at the nodes, array[0..N-1],
    6688             :             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)))
    6689             :     N   -   number of points, N>=1
    6690             :             for N=1 a constant model is constructed.
    6691             : 
    6692             : OUTPUT PARAMETERS
    6693             :     P   -   barycentric model which represents Lagrange interpolant
    6694             :             (see ratint unit info and BarycentricCalc() description for
    6695             :             more information).
    6696             : 
    6697             :   -- ALGLIB --
    6698             :      Copyright 03.12.2009 by Bochkanov Sergey
    6699             : *************************************************************************/
    6700           0 : void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams)
    6701             : {
    6702             :     jmp_buf _break_jump;
    6703             :     alglib_impl::ae_state _alglib_env_state;
    6704           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6705           0 :     if( setjmp(_break_jump) )
    6706             :     {
    6707             : #if !defined(AE_NO_EXCEPTIONS)
    6708           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6709             : #else
    6710             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6711             :         return;
    6712             : #endif
    6713             :     }
    6714           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6715           0 :     if( _xparams.flags!=0x0 )
    6716           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6717           0 :     alglib_impl::polynomialbuildcheb1(a, b, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6718           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6719           0 :     return;
    6720             : }
    6721             : 
    6722             : /*************************************************************************
    6723             : Lagrange intepolant on Chebyshev grid (first kind).
    6724             : This function has O(N) complexity.
    6725             : 
    6726             : INPUT PARAMETERS:
    6727             :     A   -   left boundary of [A,B]
    6728             :     B   -   right boundary of [A,B]
    6729             :     Y   -   function values at the nodes, array[0..N-1],
    6730             :             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)))
    6731             :     N   -   number of points, N>=1
    6732             :             for N=1 a constant model is constructed.
    6733             : 
    6734             : OUTPUT PARAMETERS
    6735             :     P   -   barycentric model which represents Lagrange interpolant
    6736             :             (see ratint unit info and BarycentricCalc() description for
    6737             :             more information).
    6738             : 
    6739             :   -- ALGLIB --
    6740             :      Copyright 03.12.2009 by Bochkanov Sergey
    6741             : *************************************************************************/
    6742             : #if !defined(AE_NO_EXCEPTIONS)
    6743           0 : void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams)
    6744             : {
    6745             :     jmp_buf _break_jump;
    6746             :     alglib_impl::ae_state _alglib_env_state;    
    6747             :     ae_int_t n;
    6748             : 
    6749           0 :     n = y.length();
    6750           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6751           0 :     if( setjmp(_break_jump) )
    6752           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6753           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6754           0 :     if( _xparams.flags!=0x0 )
    6755           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6756           0 :     alglib_impl::polynomialbuildcheb1(a, b, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6757             : 
    6758           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6759           0 :     return;
    6760             : }
    6761             : #endif
    6762             : 
    6763             : /*************************************************************************
    6764             : Lagrange intepolant on Chebyshev grid (second kind).
    6765             : This function has O(N) complexity.
    6766             : 
    6767             : INPUT PARAMETERS:
    6768             :     A   -   left boundary of [A,B]
    6769             :     B   -   right boundary of [A,B]
    6770             :     Y   -   function values at the nodes, array[0..N-1],
    6771             :             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)))
    6772             :     N   -   number of points, N>=1
    6773             :             for N=1 a constant model is constructed.
    6774             : 
    6775             : OUTPUT PARAMETERS
    6776             :     P   -   barycentric model which represents Lagrange interpolant
    6777             :             (see ratint unit info and BarycentricCalc() description for
    6778             :             more information).
    6779             : 
    6780             :   -- ALGLIB --
    6781             :      Copyright 03.12.2009 by Bochkanov Sergey
    6782             : *************************************************************************/
    6783           0 : void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams)
    6784             : {
    6785             :     jmp_buf _break_jump;
    6786             :     alglib_impl::ae_state _alglib_env_state;
    6787           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6788           0 :     if( setjmp(_break_jump) )
    6789             :     {
    6790             : #if !defined(AE_NO_EXCEPTIONS)
    6791           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6792             : #else
    6793             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6794             :         return;
    6795             : #endif
    6796             :     }
    6797           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6798           0 :     if( _xparams.flags!=0x0 )
    6799           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6800           0 :     alglib_impl::polynomialbuildcheb2(a, b, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6801           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6802           0 :     return;
    6803             : }
    6804             : 
    6805             : /*************************************************************************
    6806             : Lagrange intepolant on Chebyshev grid (second kind).
    6807             : This function has O(N) complexity.
    6808             : 
    6809             : INPUT PARAMETERS:
    6810             :     A   -   left boundary of [A,B]
    6811             :     B   -   right boundary of [A,B]
    6812             :     Y   -   function values at the nodes, array[0..N-1],
    6813             :             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)))
    6814             :     N   -   number of points, N>=1
    6815             :             for N=1 a constant model is constructed.
    6816             : 
    6817             : OUTPUT PARAMETERS
    6818             :     P   -   barycentric model which represents Lagrange interpolant
    6819             :             (see ratint unit info and BarycentricCalc() description for
    6820             :             more information).
    6821             : 
    6822             :   -- ALGLIB --
    6823             :      Copyright 03.12.2009 by Bochkanov Sergey
    6824             : *************************************************************************/
    6825             : #if !defined(AE_NO_EXCEPTIONS)
    6826           0 : void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams)
    6827             : {
    6828             :     jmp_buf _break_jump;
    6829             :     alglib_impl::ae_state _alglib_env_state;    
    6830             :     ae_int_t n;
    6831             : 
    6832           0 :     n = y.length();
    6833           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6834           0 :     if( setjmp(_break_jump) )
    6835           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6836           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6837           0 :     if( _xparams.flags!=0x0 )
    6838           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6839           0 :     alglib_impl::polynomialbuildcheb2(a, b, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), &_alglib_env_state);
    6840             : 
    6841           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6842           0 :     return;
    6843             : }
    6844             : #endif
    6845             : 
    6846             : /*************************************************************************
    6847             : Fast equidistant polynomial interpolation function with O(N) complexity
    6848             : 
    6849             : INPUT PARAMETERS:
    6850             :     A   -   left boundary of [A,B]
    6851             :     B   -   right boundary of [A,B]
    6852             :     F   -   function values, array[0..N-1]
    6853             :     N   -   number of points on equidistant grid, N>=1
    6854             :             for N=1 a constant model is constructed.
    6855             :     T   -   position where P(x) is calculated
    6856             : 
    6857             : RESULT
    6858             :     value of the Lagrange interpolant at T
    6859             : 
    6860             : IMPORTANT
    6861             :     this function provides fast interface which is not overflow-safe
    6862             :     nor it is very precise.
    6863             :     the best option is to use  PolynomialBuildEqDist()/BarycentricCalc()
    6864             :     subroutines unless you are pretty sure that your data will not result
    6865             :     in overflow.
    6866             : 
    6867             :   -- ALGLIB --
    6868             :      Copyright 02.12.2009 by Bochkanov Sergey
    6869             : *************************************************************************/
    6870           0 : double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams)
    6871             : {
    6872             :     jmp_buf _break_jump;
    6873             :     alglib_impl::ae_state _alglib_env_state;
    6874           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6875           0 :     if( setjmp(_break_jump) )
    6876             :     {
    6877             : #if !defined(AE_NO_EXCEPTIONS)
    6878           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6879             : #else
    6880             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6881             :         return 0;
    6882             : #endif
    6883             :     }
    6884           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6885           0 :     if( _xparams.flags!=0x0 )
    6886           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6887           0 :     double result = alglib_impl::polynomialcalceqdist(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
    6888           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6889           0 :     return *(reinterpret_cast<double*>(&result));
    6890             : }
    6891             : 
    6892             : /*************************************************************************
    6893             : Fast equidistant polynomial interpolation function with O(N) complexity
    6894             : 
    6895             : INPUT PARAMETERS:
    6896             :     A   -   left boundary of [A,B]
    6897             :     B   -   right boundary of [A,B]
    6898             :     F   -   function values, array[0..N-1]
    6899             :     N   -   number of points on equidistant grid, N>=1
    6900             :             for N=1 a constant model is constructed.
    6901             :     T   -   position where P(x) is calculated
    6902             : 
    6903             : RESULT
    6904             :     value of the Lagrange interpolant at T
    6905             : 
    6906             : IMPORTANT
    6907             :     this function provides fast interface which is not overflow-safe
    6908             :     nor it is very precise.
    6909             :     the best option is to use  PolynomialBuildEqDist()/BarycentricCalc()
    6910             :     subroutines unless you are pretty sure that your data will not result
    6911             :     in overflow.
    6912             : 
    6913             :   -- ALGLIB --
    6914             :      Copyright 02.12.2009 by Bochkanov Sergey
    6915             : *************************************************************************/
    6916             : #if !defined(AE_NO_EXCEPTIONS)
    6917           0 : double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams)
    6918             : {
    6919             :     jmp_buf _break_jump;
    6920             :     alglib_impl::ae_state _alglib_env_state;    
    6921             :     ae_int_t n;
    6922             : 
    6923           0 :     n = f.length();
    6924           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6925           0 :     if( setjmp(_break_jump) )
    6926           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6927           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6928           0 :     if( _xparams.flags!=0x0 )
    6929           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6930           0 :     double result = alglib_impl::polynomialcalceqdist(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
    6931             : 
    6932           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6933           0 :     return *(reinterpret_cast<double*>(&result));
    6934             : }
    6935             : #endif
    6936             : 
    6937             : /*************************************************************************
    6938             : Fast polynomial interpolation function on Chebyshev points (first kind)
    6939             : with O(N) complexity.
    6940             : 
    6941             : INPUT PARAMETERS:
    6942             :     A   -   left boundary of [A,B]
    6943             :     B   -   right boundary of [A,B]
    6944             :     F   -   function values, array[0..N-1]
    6945             :     N   -   number of points on Chebyshev grid (first kind),
    6946             :             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))
    6947             :             for N=1 a constant model is constructed.
    6948             :     T   -   position where P(x) is calculated
    6949             : 
    6950             : RESULT
    6951             :     value of the Lagrange interpolant at T
    6952             : 
    6953             : IMPORTANT
    6954             :     this function provides fast interface which is not overflow-safe
    6955             :     nor it is very precise.
    6956             :     the best option is to use  PolIntBuildCheb1()/BarycentricCalc()
    6957             :     subroutines unless you are pretty sure that your data will not result
    6958             :     in overflow.
    6959             : 
    6960             :   -- ALGLIB --
    6961             :      Copyright 02.12.2009 by Bochkanov Sergey
    6962             : *************************************************************************/
    6963           0 : double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams)
    6964             : {
    6965             :     jmp_buf _break_jump;
    6966             :     alglib_impl::ae_state _alglib_env_state;
    6967           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    6968           0 :     if( setjmp(_break_jump) )
    6969             :     {
    6970             : #if !defined(AE_NO_EXCEPTIONS)
    6971           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    6972             : #else
    6973             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    6974             :         return 0;
    6975             : #endif
    6976             :     }
    6977           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    6978           0 :     if( _xparams.flags!=0x0 )
    6979           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    6980           0 :     double result = alglib_impl::polynomialcalccheb1(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
    6981           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    6982           0 :     return *(reinterpret_cast<double*>(&result));
    6983             : }
    6984             : 
    6985             : /*************************************************************************
    6986             : Fast polynomial interpolation function on Chebyshev points (first kind)
    6987             : with O(N) complexity.
    6988             : 
    6989             : INPUT PARAMETERS:
    6990             :     A   -   left boundary of [A,B]
    6991             :     B   -   right boundary of [A,B]
    6992             :     F   -   function values, array[0..N-1]
    6993             :     N   -   number of points on Chebyshev grid (first kind),
    6994             :             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))
    6995             :             for N=1 a constant model is constructed.
    6996             :     T   -   position where P(x) is calculated
    6997             : 
    6998             : RESULT
    6999             :     value of the Lagrange interpolant at T
    7000             : 
    7001             : IMPORTANT
    7002             :     this function provides fast interface which is not overflow-safe
    7003             :     nor it is very precise.
    7004             :     the best option is to use  PolIntBuildCheb1()/BarycentricCalc()
    7005             :     subroutines unless you are pretty sure that your data will not result
    7006             :     in overflow.
    7007             : 
    7008             :   -- ALGLIB --
    7009             :      Copyright 02.12.2009 by Bochkanov Sergey
    7010             : *************************************************************************/
    7011             : #if !defined(AE_NO_EXCEPTIONS)
    7012           0 : double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams)
    7013             : {
    7014             :     jmp_buf _break_jump;
    7015             :     alglib_impl::ae_state _alglib_env_state;    
    7016             :     ae_int_t n;
    7017             : 
    7018           0 :     n = f.length();
    7019           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    7020           0 :     if( setjmp(_break_jump) )
    7021           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    7022           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    7023           0 :     if( _xparams.flags!=0x0 )
    7024           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    7025           0 :     double result = alglib_impl::polynomialcalccheb1(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
    7026             : 
    7027           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    7028           0 :     return *(reinterpret_cast<double*>(&result));
    7029             : }
    7030             : #endif
    7031             : 
    7032             : /*************************************************************************
    7033             : Fast polynomial interpolation function on Chebyshev points (second kind)
    7034             : with O(N) complexity.
    7035             : 
    7036             : INPUT PARAMETERS:
    7037             :     A   -   left boundary of [A,B]
    7038             :     B   -   right boundary of [A,B]
    7039             :     F   -   function values, array[0..N-1]
    7040             :     N   -   number of points on Chebyshev grid (second kind),
    7041             :             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))
    7042             :             for N=1 a constant model is constructed.
    7043             :     T   -   position where P(x) is calculated
    7044             : 
    7045             : RESULT
    7046             :     value of the Lagrange interpolant at T
    7047             : 
    7048             : IMPORTANT
    7049             :     this function provides fast interface which is not overflow-safe
    7050             :     nor it is very precise.
    7051             :     the best option is to use PolIntBuildCheb2()/BarycentricCalc()
    7052             :     subroutines unless you are pretty sure that your data will not result
    7053             :     in overflow.
    7054             : 
    7055             :   -- ALGLIB --
    7056             :      Copyright 02.12.2009 by Bochkanov Sergey
    7057             : *************************************************************************/
    7058           0 : double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams)
    7059             : {
    7060             :     jmp_buf _break_jump;
    7061             :     alglib_impl::ae_state _alglib_env_state;
    7062           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    7063           0 :     if( setjmp(_break_jump) )
    7064             :     {
    7065             : #if !defined(AE_NO_EXCEPTIONS)
    7066           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    7067             : #else
    7068             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    7069             :         return 0;
    7070             : #endif
    7071             :     }
    7072           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    7073           0 :     if( _xparams.flags!=0x0 )
    7074           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    7075           0 :     double result = alglib_impl::polynomialcalccheb2(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
    7076           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    7077           0 :     return *(reinterpret_cast<double*>(&result));
    7078             : }
    7079             : 
    7080             : /*************************************************************************
    7081             : Fast polynomial interpolation function on Chebyshev points (second kind)
    7082             : with O(N) complexity.
    7083             : 
    7084             : INPUT PARAMETERS:
    7085             :     A   -   left boundary of [A,B]
    7086             :     B   -   right boundary of [A,B]
    7087             :     F   -   function values, array[0..N-1]
    7088             :     N   -   number of points on Chebyshev grid (second kind),
    7089             :             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))
    7090             :             for N=1 a constant model is constructed.
    7091             :     T   -   position where P(x) is calculated
    7092             : 
    7093             : RESULT
    7094             :     value of the Lagrange interpolant at T
    7095             : 
    7096             : IMPORTANT
    7097             :     this function provides fast interface which is not overflow-safe
    7098             :     nor it is very precise.
    7099             :     the best option is to use PolIntBuildCheb2()/BarycentricCalc()
    7100             :     subroutines unless you are pretty sure that your data will not result
    7101             :     in overflow.
    7102             : 
    7103             :   -- ALGLIB --
    7104             :      Copyright 02.12.2009 by Bochkanov Sergey
    7105             : *************************************************************************/
    7106             : #if !defined(AE_NO_EXCEPTIONS)
    7107           0 : double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams)
    7108             : {
    7109             :     jmp_buf _break_jump;
    7110             :     alglib_impl::ae_state _alglib_env_state;    
    7111             :     ae_int_t n;
    7112             : 
    7113           0 :     n = f.length();
    7114           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    7115           0 :     if( setjmp(_break_jump) )
    7116           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    7117           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    7118           0 :     if( _xparams.flags!=0x0 )
    7119           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    7120           0 :     double result = alglib_impl::polynomialcalccheb2(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
    7121             : 
    7122           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    7123           0 :     return *(reinterpret_cast<double*>(&result));
    7124             : }
    7125             : #endif
    7126             : #endif
    7127             : 
    7128             : #if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD)
    7129             : /*************************************************************************
    7130             : Polynomial fitting report:
    7131             :     TaskRCond       reciprocal of task's condition number
    7132             :     RMSError        RMS error
    7133             :     AvgError        average error
    7134             :     AvgRelError     average relative error (for non-zero Y[I])
    7135             :     MaxError        maximum error
    7136             : *************************************************************************/
    7137           0 : _polynomialfitreport_owner::_polynomialfitreport_owner()
    7138             : {
    7139             :     jmp_buf _break_jump;
    7140             :     alglib_impl::ae_state _state;
    7141             :     
    7142           0 :     alglib_impl::ae_state_init(&_state);
    7143           0 :     if( setjmp(_break_jump) )
    7144             :     {
    7145           0 :         if( p_struct!=NULL )
    7146             :         {
    7147           0 :             alglib_impl::_polynomialfitreport_destroy(p_struct);
    7148           0 :             alglib_impl::ae_free(p_struct);
    7149             :         }
    7150           0 :         p_struct = NULL;
    7151             : #if !defined(AE_NO_EXCEPTIONS)
    7152           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7153             : #else
    7154             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7155             :         return;
    7156             : #endif
    7157             :     }
    7158           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7159           0 :     p_struct = NULL;
    7160           0 :     p_struct = (alglib_impl::polynomialfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialfitreport), &_state);
    7161           0 :     memset(p_struct, 0, sizeof(alglib_impl::polynomialfitreport));
    7162           0 :     alglib_impl::_polynomialfitreport_init(p_struct, &_state, ae_false);
    7163           0 :     ae_state_clear(&_state);
    7164           0 : }
    7165             : 
    7166           0 : _polynomialfitreport_owner::_polynomialfitreport_owner(const _polynomialfitreport_owner &rhs)
    7167             : {
    7168             :     jmp_buf _break_jump;
    7169             :     alglib_impl::ae_state _state;
    7170             :     
    7171           0 :     alglib_impl::ae_state_init(&_state);
    7172           0 :     if( setjmp(_break_jump) )
    7173             :     {
    7174           0 :         if( p_struct!=NULL )
    7175             :         {
    7176           0 :             alglib_impl::_polynomialfitreport_destroy(p_struct);
    7177           0 :             alglib_impl::ae_free(p_struct);
    7178             :         }
    7179           0 :         p_struct = NULL;
    7180             : #if !defined(AE_NO_EXCEPTIONS)
    7181           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7182             : #else
    7183             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7184             :         return;
    7185             : #endif
    7186             :     }
    7187           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7188           0 :     p_struct = NULL;
    7189           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: polynomialfitreport copy constructor failure (source is not initialized)", &_state);
    7190           0 :     p_struct = (alglib_impl::polynomialfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialfitreport), &_state);
    7191           0 :     memset(p_struct, 0, sizeof(alglib_impl::polynomialfitreport));
    7192           0 :     alglib_impl::_polynomialfitreport_init_copy(p_struct, const_cast<alglib_impl::polynomialfitreport*>(rhs.p_struct), &_state, ae_false);
    7193           0 :     ae_state_clear(&_state);
    7194           0 : }
    7195             : 
    7196           0 : _polynomialfitreport_owner& _polynomialfitreport_owner::operator=(const _polynomialfitreport_owner &rhs)
    7197             : {
    7198           0 :     if( this==&rhs )
    7199           0 :         return *this;
    7200             :     jmp_buf _break_jump;
    7201             :     alglib_impl::ae_state _state;
    7202             :     
    7203           0 :     alglib_impl::ae_state_init(&_state);
    7204           0 :     if( setjmp(_break_jump) )
    7205             :     {
    7206             : #if !defined(AE_NO_EXCEPTIONS)
    7207           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7208             : #else
    7209             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7210             :         return *this;
    7211             : #endif
    7212             :     }
    7213           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7214           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: polynomialfitreport assignment constructor failure (destination is not initialized)", &_state);
    7215           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: polynomialfitreport assignment constructor failure (source is not initialized)", &_state);
    7216           0 :     alglib_impl::_polynomialfitreport_destroy(p_struct);
    7217           0 :     memset(p_struct, 0, sizeof(alglib_impl::polynomialfitreport));
    7218           0 :     alglib_impl::_polynomialfitreport_init_copy(p_struct, const_cast<alglib_impl::polynomialfitreport*>(rhs.p_struct), &_state, ae_false);
    7219           0 :     ae_state_clear(&_state);
    7220           0 :     return *this;
    7221             : }
    7222             : 
    7223           0 : _polynomialfitreport_owner::~_polynomialfitreport_owner()
    7224             : {
    7225           0 :     if( p_struct!=NULL )
    7226             :     {
    7227           0 :         alglib_impl::_polynomialfitreport_destroy(p_struct);
    7228           0 :         ae_free(p_struct);
    7229             :     }
    7230           0 : }
    7231             : 
    7232           0 : alglib_impl::polynomialfitreport* _polynomialfitreport_owner::c_ptr()
    7233             : {
    7234           0 :     return p_struct;
    7235             : }
    7236             : 
    7237           0 : alglib_impl::polynomialfitreport* _polynomialfitreport_owner::c_ptr() const
    7238             : {
    7239           0 :     return const_cast<alglib_impl::polynomialfitreport*>(p_struct);
    7240             : }
    7241           0 : polynomialfitreport::polynomialfitreport() : _polynomialfitreport_owner() ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror)
    7242             : {
    7243           0 : }
    7244             : 
    7245           0 : 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)
    7246             : {
    7247           0 : }
    7248             : 
    7249           0 : polynomialfitreport& polynomialfitreport::operator=(const polynomialfitreport &rhs)
    7250             : {
    7251           0 :     if( this==&rhs )
    7252           0 :         return *this;
    7253           0 :     _polynomialfitreport_owner::operator=(rhs);
    7254           0 :     return *this;
    7255             : }
    7256             : 
    7257           0 : polynomialfitreport::~polynomialfitreport()
    7258             : {
    7259           0 : }
    7260             : 
    7261             : 
    7262             : /*************************************************************************
    7263             : Barycentric fitting report:
    7264             :     RMSError        RMS error
    7265             :     AvgError        average error
    7266             :     AvgRelError     average relative error (for non-zero Y[I])
    7267             :     MaxError        maximum error
    7268             :     TaskRCond       reciprocal of task's condition number
    7269             : *************************************************************************/
    7270           0 : _barycentricfitreport_owner::_barycentricfitreport_owner()
    7271             : {
    7272             :     jmp_buf _break_jump;
    7273             :     alglib_impl::ae_state _state;
    7274             :     
    7275           0 :     alglib_impl::ae_state_init(&_state);
    7276           0 :     if( setjmp(_break_jump) )
    7277             :     {
    7278           0 :         if( p_struct!=NULL )
    7279             :         {
    7280           0 :             alglib_impl::_barycentricfitreport_destroy(p_struct);
    7281           0 :             alglib_impl::ae_free(p_struct);
    7282             :         }
    7283           0 :         p_struct = NULL;
    7284             : #if !defined(AE_NO_EXCEPTIONS)
    7285           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7286             : #else
    7287             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7288             :         return;
    7289             : #endif
    7290             :     }
    7291           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7292           0 :     p_struct = NULL;
    7293           0 :     p_struct = (alglib_impl::barycentricfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricfitreport), &_state);
    7294           0 :     memset(p_struct, 0, sizeof(alglib_impl::barycentricfitreport));
    7295           0 :     alglib_impl::_barycentricfitreport_init(p_struct, &_state, ae_false);
    7296           0 :     ae_state_clear(&_state);
    7297           0 : }
    7298             : 
    7299           0 : _barycentricfitreport_owner::_barycentricfitreport_owner(const _barycentricfitreport_owner &rhs)
    7300             : {
    7301             :     jmp_buf _break_jump;
    7302             :     alglib_impl::ae_state _state;
    7303             :     
    7304           0 :     alglib_impl::ae_state_init(&_state);
    7305           0 :     if( setjmp(_break_jump) )
    7306             :     {
    7307           0 :         if( p_struct!=NULL )
    7308             :         {
    7309           0 :             alglib_impl::_barycentricfitreport_destroy(p_struct);
    7310           0 :             alglib_impl::ae_free(p_struct);
    7311             :         }
    7312           0 :         p_struct = NULL;
    7313             : #if !defined(AE_NO_EXCEPTIONS)
    7314           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7315             : #else
    7316             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7317             :         return;
    7318             : #endif
    7319             :     }
    7320           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7321           0 :     p_struct = NULL;
    7322           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricfitreport copy constructor failure (source is not initialized)", &_state);
    7323           0 :     p_struct = (alglib_impl::barycentricfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricfitreport), &_state);
    7324           0 :     memset(p_struct, 0, sizeof(alglib_impl::barycentricfitreport));
    7325           0 :     alglib_impl::_barycentricfitreport_init_copy(p_struct, const_cast<alglib_impl::barycentricfitreport*>(rhs.p_struct), &_state, ae_false);
    7326           0 :     ae_state_clear(&_state);
    7327           0 : }
    7328             : 
    7329           0 : _barycentricfitreport_owner& _barycentricfitreport_owner::operator=(const _barycentricfitreport_owner &rhs)
    7330             : {
    7331           0 :     if( this==&rhs )
    7332           0 :         return *this;
    7333             :     jmp_buf _break_jump;
    7334             :     alglib_impl::ae_state _state;
    7335             :     
    7336           0 :     alglib_impl::ae_state_init(&_state);
    7337           0 :     if( setjmp(_break_jump) )
    7338             :     {
    7339             : #if !defined(AE_NO_EXCEPTIONS)
    7340           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7341             : #else
    7342             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7343             :         return *this;
    7344             : #endif
    7345             :     }
    7346           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7347           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: barycentricfitreport assignment constructor failure (destination is not initialized)", &_state);
    7348           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricfitreport assignment constructor failure (source is not initialized)", &_state);
    7349           0 :     alglib_impl::_barycentricfitreport_destroy(p_struct);
    7350           0 :     memset(p_struct, 0, sizeof(alglib_impl::barycentricfitreport));
    7351           0 :     alglib_impl::_barycentricfitreport_init_copy(p_struct, const_cast<alglib_impl::barycentricfitreport*>(rhs.p_struct), &_state, ae_false);
    7352           0 :     ae_state_clear(&_state);
    7353           0 :     return *this;
    7354             : }
    7355             : 
    7356           0 : _barycentricfitreport_owner::~_barycentricfitreport_owner()
    7357             : {
    7358           0 :     if( p_struct!=NULL )
    7359             :     {
    7360           0 :         alglib_impl::_barycentricfitreport_destroy(p_struct);
    7361           0 :         ae_free(p_struct);
    7362             :     }
    7363           0 : }
    7364             : 
    7365           0 : alglib_impl::barycentricfitreport* _barycentricfitreport_owner::c_ptr()
    7366             : {
    7367           0 :     return p_struct;
    7368             : }
    7369             : 
    7370           0 : alglib_impl::barycentricfitreport* _barycentricfitreport_owner::c_ptr() const
    7371             : {
    7372           0 :     return const_cast<alglib_impl::barycentricfitreport*>(p_struct);
    7373             : }
    7374           0 : 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)
    7375             : {
    7376           0 : }
    7377             : 
    7378           0 : 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)
    7379             : {
    7380           0 : }
    7381             : 
    7382           0 : barycentricfitreport& barycentricfitreport::operator=(const barycentricfitreport &rhs)
    7383             : {
    7384           0 :     if( this==&rhs )
    7385           0 :         return *this;
    7386           0 :     _barycentricfitreport_owner::operator=(rhs);
    7387           0 :     return *this;
    7388             : }
    7389             : 
    7390           0 : barycentricfitreport::~barycentricfitreport()
    7391             : {
    7392           0 : }
    7393             : 
    7394             : 
    7395             : /*************************************************************************
    7396             : Least squares fitting report. This structure contains informational fields
    7397             : which are set by fitting functions provided by this unit.
    7398             : 
    7399             : Different functions initialize different sets of  fields,  so  you  should
    7400             : read documentation on specific function you used in order  to  know  which
    7401             : fields are initialized.
    7402             : 
    7403             :     TaskRCond       reciprocal of task's condition number
    7404             :     IterationsCount number of internal iterations
    7405             : 
    7406             :     VarIdx          if user-supplied gradient contains errors  which  were
    7407             :                     detected by nonlinear fitter, this  field  is  set  to
    7408             :                     index  of  the  first  component  of gradient which is
    7409             :                     suspected to be spoiled by bugs.
    7410             : 
    7411             :     RMSError        RMS error
    7412             :     AvgError        average error
    7413             :     AvgRelError     average relative error (for non-zero Y[I])
    7414             :     MaxError        maximum error
    7415             : 
    7416             :     WRMSError       weighted RMS error
    7417             : 
    7418             :     CovPar          covariance matrix for parameters, filled by some solvers
    7419             :     ErrPar          vector of errors in parameters, filled by some solvers
    7420             :     ErrCurve        vector of fit errors -  variability  of  the  best-fit
    7421             :                     curve, filled by some solvers.
    7422             :     Noise           vector of per-point noise estimates, filled by
    7423             :                     some solvers.
    7424             :     R2              coefficient of determination (non-weighted, non-adjusted),
    7425             :                     filled by some solvers.
    7426             : *************************************************************************/
    7427           0 : _lsfitreport_owner::_lsfitreport_owner()
    7428             : {
    7429             :     jmp_buf _break_jump;
    7430             :     alglib_impl::ae_state _state;
    7431             :     
    7432           0 :     alglib_impl::ae_state_init(&_state);
    7433           0 :     if( setjmp(_break_jump) )
    7434             :     {
    7435           0 :         if( p_struct!=NULL )
    7436             :         {
    7437           0 :             alglib_impl::_lsfitreport_destroy(p_struct);
    7438           0 :             alglib_impl::ae_free(p_struct);
    7439             :         }
    7440           0 :         p_struct = NULL;
    7441             : #if !defined(AE_NO_EXCEPTIONS)
    7442           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7443             : #else
    7444             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7445             :         return;
    7446             : #endif
    7447             :     }
    7448           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7449           0 :     p_struct = NULL;
    7450           0 :     p_struct = (alglib_impl::lsfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitreport), &_state);
    7451           0 :     memset(p_struct, 0, sizeof(alglib_impl::lsfitreport));
    7452           0 :     alglib_impl::_lsfitreport_init(p_struct, &_state, ae_false);
    7453           0 :     ae_state_clear(&_state);
    7454           0 : }
    7455             : 
    7456           0 : _lsfitreport_owner::_lsfitreport_owner(const _lsfitreport_owner &rhs)
    7457             : {
    7458             :     jmp_buf _break_jump;
    7459             :     alglib_impl::ae_state _state;
    7460             :     
    7461           0 :     alglib_impl::ae_state_init(&_state);
    7462           0 :     if( setjmp(_break_jump) )
    7463             :     {
    7464           0 :         if( p_struct!=NULL )
    7465             :         {
    7466           0 :             alglib_impl::_lsfitreport_destroy(p_struct);
    7467           0 :             alglib_impl::ae_free(p_struct);
    7468             :         }
    7469           0 :         p_struct = NULL;
    7470             : #if !defined(AE_NO_EXCEPTIONS)
    7471           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7472             : #else
    7473             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7474             :         return;
    7475             : #endif
    7476             :     }
    7477           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7478           0 :     p_struct = NULL;
    7479           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitreport copy constructor failure (source is not initialized)", &_state);
    7480           0 :     p_struct = (alglib_impl::lsfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitreport), &_state);
    7481           0 :     memset(p_struct, 0, sizeof(alglib_impl::lsfitreport));
    7482           0 :     alglib_impl::_lsfitreport_init_copy(p_struct, const_cast<alglib_impl::lsfitreport*>(rhs.p_struct), &_state, ae_false);
    7483           0 :     ae_state_clear(&_state);
    7484           0 : }
    7485             : 
    7486           0 : _lsfitreport_owner& _lsfitreport_owner::operator=(const _lsfitreport_owner &rhs)
    7487             : {
    7488           0 :     if( this==&rhs )
    7489           0 :         return *this;
    7490             :     jmp_buf _break_jump;
    7491             :     alglib_impl::ae_state _state;
    7492             :     
    7493           0 :     alglib_impl::ae_state_init(&_state);
    7494           0 :     if( setjmp(_break_jump) )
    7495             :     {
    7496             : #if !defined(AE_NO_EXCEPTIONS)
    7497           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7498             : #else
    7499             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7500             :         return *this;
    7501             : #endif
    7502             :     }
    7503           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7504           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: lsfitreport assignment constructor failure (destination is not initialized)", &_state);
    7505           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitreport assignment constructor failure (source is not initialized)", &_state);
    7506           0 :     alglib_impl::_lsfitreport_destroy(p_struct);
    7507           0 :     memset(p_struct, 0, sizeof(alglib_impl::lsfitreport));
    7508           0 :     alglib_impl::_lsfitreport_init_copy(p_struct, const_cast<alglib_impl::lsfitreport*>(rhs.p_struct), &_state, ae_false);
    7509           0 :     ae_state_clear(&_state);
    7510           0 :     return *this;
    7511             : }
    7512             : 
    7513           0 : _lsfitreport_owner::~_lsfitreport_owner()
    7514             : {
    7515           0 :     if( p_struct!=NULL )
    7516             :     {
    7517           0 :         alglib_impl::_lsfitreport_destroy(p_struct);
    7518           0 :         ae_free(p_struct);
    7519             :     }
    7520           0 : }
    7521             : 
    7522           0 : alglib_impl::lsfitreport* _lsfitreport_owner::c_ptr()
    7523             : {
    7524           0 :     return p_struct;
    7525             : }
    7526             : 
    7527           0 : alglib_impl::lsfitreport* _lsfitreport_owner::c_ptr() const
    7528             : {
    7529           0 :     return const_cast<alglib_impl::lsfitreport*>(p_struct);
    7530             : }
    7531           0 : 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)
    7532             : {
    7533           0 : }
    7534             : 
    7535           0 : 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)
    7536             : {
    7537           0 : }
    7538             : 
    7539           0 : lsfitreport& lsfitreport::operator=(const lsfitreport &rhs)
    7540             : {
    7541           0 :     if( this==&rhs )
    7542           0 :         return *this;
    7543           0 :     _lsfitreport_owner::operator=(rhs);
    7544           0 :     return *this;
    7545             : }
    7546             : 
    7547           0 : lsfitreport::~lsfitreport()
    7548             : {
    7549           0 : }
    7550             : 
    7551             : 
    7552             : /*************************************************************************
    7553             : Nonlinear fitter.
    7554             : 
    7555             : You should use ALGLIB functions to work with fitter.
    7556             : Never try to access its fields directly!
    7557             : *************************************************************************/
    7558           0 : _lsfitstate_owner::_lsfitstate_owner()
    7559             : {
    7560             :     jmp_buf _break_jump;
    7561             :     alglib_impl::ae_state _state;
    7562             :     
    7563           0 :     alglib_impl::ae_state_init(&_state);
    7564           0 :     if( setjmp(_break_jump) )
    7565             :     {
    7566           0 :         if( p_struct!=NULL )
    7567             :         {
    7568           0 :             alglib_impl::_lsfitstate_destroy(p_struct);
    7569           0 :             alglib_impl::ae_free(p_struct);
    7570             :         }
    7571           0 :         p_struct = NULL;
    7572             : #if !defined(AE_NO_EXCEPTIONS)
    7573           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7574             : #else
    7575             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7576             :         return;
    7577             : #endif
    7578             :     }
    7579           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7580           0 :     p_struct = NULL;
    7581           0 :     p_struct = (alglib_impl::lsfitstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitstate), &_state);
    7582           0 :     memset(p_struct, 0, sizeof(alglib_impl::lsfitstate));
    7583           0 :     alglib_impl::_lsfitstate_init(p_struct, &_state, ae_false);
    7584           0 :     ae_state_clear(&_state);
    7585           0 : }
    7586             : 
    7587           0 : _lsfitstate_owner::_lsfitstate_owner(const _lsfitstate_owner &rhs)
    7588             : {
    7589             :     jmp_buf _break_jump;
    7590             :     alglib_impl::ae_state _state;
    7591             :     
    7592           0 :     alglib_impl::ae_state_init(&_state);
    7593           0 :     if( setjmp(_break_jump) )
    7594             :     {
    7595           0 :         if( p_struct!=NULL )
    7596             :         {
    7597           0 :             alglib_impl::_lsfitstate_destroy(p_struct);
    7598           0 :             alglib_impl::ae_free(p_struct);
    7599             :         }
    7600           0 :         p_struct = NULL;
    7601             : #if !defined(AE_NO_EXCEPTIONS)
    7602           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7603             : #else
    7604             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7605             :         return;
    7606             : #endif
    7607             :     }
    7608           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7609           0 :     p_struct = NULL;
    7610           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitstate copy constructor failure (source is not initialized)", &_state);
    7611           0 :     p_struct = (alglib_impl::lsfitstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitstate), &_state);
    7612           0 :     memset(p_struct, 0, sizeof(alglib_impl::lsfitstate));
    7613           0 :     alglib_impl::_lsfitstate_init_copy(p_struct, const_cast<alglib_impl::lsfitstate*>(rhs.p_struct), &_state, ae_false);
    7614           0 :     ae_state_clear(&_state);
    7615           0 : }
    7616             : 
    7617           0 : _lsfitstate_owner& _lsfitstate_owner::operator=(const _lsfitstate_owner &rhs)
    7618             : {
    7619           0 :     if( this==&rhs )
    7620           0 :         return *this;
    7621             :     jmp_buf _break_jump;
    7622             :     alglib_impl::ae_state _state;
    7623             :     
    7624           0 :     alglib_impl::ae_state_init(&_state);
    7625           0 :     if( setjmp(_break_jump) )
    7626             :     {
    7627             : #if !defined(AE_NO_EXCEPTIONS)
    7628           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
    7629             : #else
    7630             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
    7631             :         return *this;
    7632             : #endif
    7633             :     }
    7634           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
    7635           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: lsfitstate assignment constructor failure (destination is not initialized)", &_state);
    7636           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitstate assignment constructor failure (source is not initialized)", &_state);
    7637           0 :     alglib_impl::_lsfitstate_destroy(p_struct);
    7638           0 :     memset(p_struct, 0, sizeof(alglib_impl::lsfitstate));
    7639           0 :     alglib_impl::_lsfitstate_init_copy(p_struct, const_cast<alglib_impl::lsfitstate*>(rhs.p_struct), &_state, ae_false);
    7640           0 :     ae_state_clear(&_state);
    7641           0 :     return *this;
    7642             : }
    7643             : 
    7644           0 : _lsfitstate_owner::~_lsfitstate_owner()
    7645             : {
    7646           0 :     if( p_struct!=NULL )
    7647             :     {
    7648           0 :         alglib_impl::_lsfitstate_destroy(p_struct);
    7649           0 :         ae_free(p_struct);
    7650             :     }
    7651           0 : }
    7652             : 
    7653           0 : alglib_impl::lsfitstate* _lsfitstate_owner::c_ptr()
    7654             : {
    7655           0 :     return p_struct;
    7656             : }
    7657             : 
    7658           0 : alglib_impl::lsfitstate* _lsfitstate_owner::c_ptr() const
    7659             : {
    7660           0 :     return const_cast<alglib_impl::lsfitstate*>(p_struct);
    7661             : }
    7662           0 : 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)
    7663             : {
    7664           0 : }
    7665             : 
    7666           0 : 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)
    7667             : {
    7668           0 : }
    7669             : 
    7670           0 : lsfitstate& lsfitstate::operator=(const lsfitstate &rhs)
    7671             : {
    7672           0 :     if( this==&rhs )
    7673           0 :         return *this;
    7674           0 :     _lsfitstate_owner::operator=(rhs);
    7675           0 :     return *this;
    7676             : }
    7677             : 
    7678           0 : lsfitstate::~lsfitstate()
    7679             : {
    7680           0 : }
    7681             : 
    7682             : /*************************************************************************
    7683             : This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
    7684             : Peucker algorithm, which stops after generating specified number of linear
    7685             : sections.
    7686             : 
    7687             : IMPORTANT:
    7688             : * it does NOT perform least-squares fitting; it  builds  curve,  but  this
    7689             :   curve does not minimize some least squares metric.  See  description  of
    7690             :   RDP algorithm (say, in Wikipedia) for more details on WHAT is performed.
    7691             : * this function does NOT work with parametric curves  (i.e.  curves  which
    7692             :   can be represented as {X(t),Y(t)}. It works with curves   which  can  be
    7693             :   represented as Y(X). Thus,  it  is  impossible  to  model  figures  like
    7694             :   circles  with  this  functions.
    7695             :   If  you  want  to  work  with  parametric   curves,   you   should   use
    7696             :   ParametricRDPFixed() function provided  by  "Parametric"  subpackage  of
    7697             :   "Interpolation" package.
    7698             : 
    7699             : INPUT PARAMETERS:
    7700             :     X       -   array of X-coordinates:
    7701             :                 * at least N elements
    7702             :                 * can be unordered (points are automatically sorted)
    7703             :                 * this function may accept non-distinct X (see below for
    7704             :                   more information on handling of such inputs)
    7705             :     Y       -   array of Y-coordinates:
    7706             :                 * at least N elements
    7707             :     N       -   number of elements in X/Y
    7708             :     M       -   desired number of sections:
    7709             :                 * at most M sections are generated by this function
    7710             :                 * less than M sections can be generated if we have N<M
    7711             :                   (or some X are non-distinct).
    7712             : 
    7713             : OUTPUT PARAMETERS:
    7714             :     X2      -   X-values of corner points for piecewise approximation,
    7715             :                 has length NSections+1 or zero (for NSections=0).
    7716             :     Y2      -   Y-values of corner points,
    7717             :                 has length NSections+1 or zero (for NSections=0).
    7718             :     NSections-  number of sections found by algorithm, NSections<=M,
    7719             :                 NSections can be zero for degenerate datasets
    7720             :                 (N<=1 or all X[] are non-distinct).
    7721             : 
    7722             : NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is  a  first  point  of
    7723             :       curve, (X2[NSection-1],Y2[NSection-1]) is the last point.
    7724             : 
    7725             :   -- ALGLIB --
    7726             :      Copyright 02.10.2014 by Bochkanov Sergey
    7727             : *************************************************************************/
    7728           0 : void lstfitpiecewiselinearrdpfixed(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, real_1d_array &x2, real_1d_array &y2, ae_int_t &nsections, const xparams _xparams)
    7729             : {
    7730             :     jmp_buf _break_jump;
    7731             :     alglib_impl::ae_state _alglib_env_state;
    7732           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    7733           0 :     if( setjmp(_break_jump) )
    7734             :     {
    7735             : #if !defined(AE_NO_EXCEPTIONS)
    7736           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    7737             : #else
    7738             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    7739             :         return;
    7740             : #endif
    7741             :     }
    7742           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    7743           0 :     if( _xparams.flags!=0x0 )
    7744           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    7745           0 :     alglib_impl::lstfitpiecewiselinearrdpfixed(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, const_cast<alglib_impl::ae_vector*>(x2.c_ptr()), const_cast<alglib_impl::ae_vector*>(y2.c_ptr()), &nsections, &_alglib_env_state);
    7746           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    7747           0 :     return;
    7748             : }
    7749             : 
    7750             : /*************************************************************************
    7751             : This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
    7752             : Peucker algorithm, which stops after achieving desired precision.
    7753             : 
    7754             : IMPORTANT:
    7755             : * it performs non-least-squares fitting; it builds curve, but  this  curve
    7756             :   does not minimize some least squares  metric.  See  description  of  RDP
    7757             :   algorithm (say, in Wikipedia) for more details on WHAT is performed.
    7758             : * this function does NOT work with parametric curves  (i.e.  curves  which
    7759             :   can be represented as {X(t),Y(t)}. It works with curves   which  can  be
    7760             :   represented as Y(X). Thus, it is impossible to model figures like circles
    7761             :   with this functions.
    7762             :   If  you  want  to  work  with  parametric   curves,   you   should   use
    7763             :   ParametricRDPFixed() function provided  by  "Parametric"  subpackage  of
    7764             :   "Interpolation" package.
    7765             : 
    7766             : INPUT PARAMETERS:
    7767             :     X       -   array of X-coordinates:
    7768             :                 * at least N elements
    7769             :                 * can be unordered (points are automatically sorted)
    7770             :                 * this function may accept non-distinct X (see below for
    7771             :                   more information on handling of such inputs)
    7772             :     Y       -   array of Y-coordinates:
    7773             :                 * at least N elements
    7774             :     N       -   number of elements in X/Y
    7775             :     Eps     -   positive number, desired precision.
    7776             : 
    7777             : 
    7778             : OUTPUT PARAMETERS:
    7779             :     X2      -   X-values of corner points for piecewise approximation,
    7780             :                 has length NSections+1 or zero (for NSections=0).
    7781             :     Y2      -   Y-values of corner points,
    7782             :                 has length NSections+1 or zero (for NSections=0).
    7783             :     NSections-  number of sections found by algorithm,
    7784             :                 NSections can be zero for degenerate datasets
    7785             :                 (N<=1 or all X[] are non-distinct).
    7786             : 
    7787             : NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is  a  first  point  of
    7788             :       curve, (X2[NSection-1],Y2[NSection-1]) is the last point.
    7789             : 
    7790             :   -- ALGLIB --
    7791             :      Copyright 02.10.2014 by Bochkanov Sergey
    7792             : *************************************************************************/
    7793           0 : void lstfitpiecewiselinearrdp(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double eps, real_1d_array &x2, real_1d_array &y2, ae_int_t &nsections, const xparams _xparams)
    7794             : {
    7795             :     jmp_buf _break_jump;
    7796             :     alglib_impl::ae_state _alglib_env_state;
    7797           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    7798           0 :     if( setjmp(_break_jump) )
    7799             :     {
    7800             : #if !defined(AE_NO_EXCEPTIONS)
    7801           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    7802             : #else
    7803             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    7804             :         return;
    7805             : #endif
    7806             :     }
    7807           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    7808           0 :     if( _xparams.flags!=0x0 )
    7809           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    7810           0 :     alglib_impl::lstfitpiecewiselinearrdp(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, eps, const_cast<alglib_impl::ae_vector*>(x2.c_ptr()), const_cast<alglib_impl::ae_vector*>(y2.c_ptr()), &nsections, &_alglib_env_state);
    7811           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    7812           0 :     return;
    7813             : }
    7814             : 
    7815             : /*************************************************************************
    7816             : Fitting by polynomials in barycentric form. This function provides  simple
    7817             : unterface for unconstrained unweighted fitting. See  PolynomialFitWC()  if
    7818             : you need constrained fitting.
    7819             : 
    7820             : Task is linear, so linear least squares solver is used. Complexity of this
    7821             : computational scheme is O(N*M^2), mostly dominated by least squares solver
    7822             : 
    7823             : SEE ALSO:
    7824             :     PolynomialFitWC()
    7825             : 
    7826             : NOTES:
    7827             :     you can convert P from barycentric form  to  the  power  or  Chebyshev
    7828             :     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
    7829             :     POLINT subpackage.
    7830             : 
    7831             :   ! COMMERCIAL EDITION OF ALGLIB:
    7832             :   !
    7833             :   ! Commercial Edition of ALGLIB includes following important improvements
    7834             :   ! of this function:
    7835             :   ! * high-performance native backend with same C# interface (C# version)
    7836             :   ! * multithreading support (C++ and C# versions)
    7837             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    7838             :   !   (C++ and C# versions, x86/x64 platform)
    7839             :   !
    7840             :   ! We recommend you to read 'Working with commercial version' section  of
    7841             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    7842             :   ! related features provided by commercial edition of ALGLIB.
    7843             : 
    7844             : INPUT PARAMETERS:
    7845             :     X   -   points, array[0..N-1].
    7846             :     Y   -   function values, array[0..N-1].
    7847             :     N   -   number of points, N>0
    7848             :             * if given, only leading N elements of X/Y are used
    7849             :             * if not given, automatically determined from sizes of X/Y
    7850             :     M   -   number of basis functions (= polynomial_degree + 1), M>=1
    7851             : 
    7852             : OUTPUT PARAMETERS:
    7853             :     Info-   same format as in LSFitLinearW() subroutine:
    7854             :             * Info>0    task is solved
    7855             :             * Info<=0   an error occured:
    7856             :                         -4 means inconvergence of internal SVD
    7857             :     P   -   interpolant in barycentric form.
    7858             :     Rep -   report, same format as in LSFitLinearW() subroutine.
    7859             :             Following fields are set:
    7860             :             * RMSError      rms error on the (X,Y).
    7861             :             * AvgError      average error on the (X,Y).
    7862             :             * AvgRelError   average relative error on the non-zero Y
    7863             :             * MaxError      maximum error
    7864             :                             NON-WEIGHTED ERRORS ARE CALCULATED
    7865             : 
    7866             :   -- ALGLIB PROJECT --
    7867             :      Copyright 10.12.2009 by Bochkanov Sergey
    7868             : *************************************************************************/
    7869           0 : 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, const xparams _xparams)
    7870             : {
    7871             :     jmp_buf _break_jump;
    7872             :     alglib_impl::ae_state _alglib_env_state;
    7873           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    7874           0 :     if( setjmp(_break_jump) )
    7875             :     {
    7876             : #if !defined(AE_NO_EXCEPTIONS)
    7877           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    7878             : #else
    7879             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    7880             :         return;
    7881             : #endif
    7882             :     }
    7883           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    7884           0 :     if( _xparams.flags!=0x0 )
    7885           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    7886           0 :     alglib_impl::polynomialfit(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, &info, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), const_cast<alglib_impl::polynomialfitreport*>(rep.c_ptr()), &_alglib_env_state);
    7887           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    7888           0 :     return;
    7889             : }
    7890             : 
    7891             : /*************************************************************************
    7892             : Fitting by polynomials in barycentric form. This function provides  simple
    7893             : unterface for unconstrained unweighted fitting. See  PolynomialFitWC()  if
    7894             : you need constrained fitting.
    7895             : 
    7896             : Task is linear, so linear least squares solver is used. Complexity of this
    7897             : computational scheme is O(N*M^2), mostly dominated by least squares solver
    7898             : 
    7899             : SEE ALSO:
    7900             :     PolynomialFitWC()
    7901             : 
    7902             : NOTES:
    7903             :     you can convert P from barycentric form  to  the  power  or  Chebyshev
    7904             :     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
    7905             :     POLINT subpackage.
    7906             : 
    7907             :   ! COMMERCIAL EDITION OF ALGLIB:
    7908             :   !
    7909             :   ! Commercial Edition of ALGLIB includes following important improvements
    7910             :   ! of this function:
    7911             :   ! * high-performance native backend with same C# interface (C# version)
    7912             :   ! * multithreading support (C++ and C# versions)
    7913             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    7914             :   !   (C++ and C# versions, x86/x64 platform)
    7915             :   !
    7916             :   ! We recommend you to read 'Working with commercial version' section  of
    7917             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    7918             :   ! related features provided by commercial edition of ALGLIB.
    7919             : 
    7920             : INPUT PARAMETERS:
    7921             :     X   -   points, array[0..N-1].
    7922             :     Y   -   function values, array[0..N-1].
    7923             :     N   -   number of points, N>0
    7924             :             * if given, only leading N elements of X/Y are used
    7925             :             * if not given, automatically determined from sizes of X/Y
    7926             :     M   -   number of basis functions (= polynomial_degree + 1), M>=1
    7927             : 
    7928             : OUTPUT PARAMETERS:
    7929             :     Info-   same format as in LSFitLinearW() subroutine:
    7930             :             * Info>0    task is solved
    7931             :             * Info<=0   an error occured:
    7932             :                         -4 means inconvergence of internal SVD
    7933             :     P   -   interpolant in barycentric form.
    7934             :     Rep -   report, same format as in LSFitLinearW() subroutine.
    7935             :             Following fields are set:
    7936             :             * RMSError      rms error on the (X,Y).
    7937             :             * AvgError      average error on the (X,Y).
    7938             :             * AvgRelError   average relative error on the non-zero Y
    7939             :             * MaxError      maximum error
    7940             :                             NON-WEIGHTED ERRORS ARE CALCULATED
    7941             : 
    7942             :   -- ALGLIB PROJECT --
    7943             :      Copyright 10.12.2009 by Bochkanov Sergey
    7944             : *************************************************************************/
    7945             : #if !defined(AE_NO_EXCEPTIONS)
    7946           0 : 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, const xparams _xparams)
    7947             : {
    7948             :     jmp_buf _break_jump;
    7949             :     alglib_impl::ae_state _alglib_env_state;    
    7950             :     ae_int_t n;
    7951           0 :     if( (x.length()!=y.length()))
    7952           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialfit': looks like one of arguments has wrong size");
    7953           0 :     n = x.length();
    7954           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    7955           0 :     if( setjmp(_break_jump) )
    7956           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    7957           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    7958           0 :     if( _xparams.flags!=0x0 )
    7959           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    7960           0 :     alglib_impl::polynomialfit(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, &info, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), const_cast<alglib_impl::polynomialfitreport*>(rep.c_ptr()), &_alglib_env_state);
    7961             : 
    7962           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    7963           0 :     return;
    7964             : }
    7965             : #endif
    7966             : 
    7967             : /*************************************************************************
    7968             : Weighted  fitting by polynomials in barycentric form, with constraints  on
    7969             : function values or first derivatives.
    7970             : 
    7971             : Small regularizing term is used when solving constrained tasks (to improve
    7972             : stability).
    7973             : 
    7974             : Task is linear, so linear least squares solver is used. Complexity of this
    7975             : computational scheme is O(N*M^2), mostly dominated by least squares solver
    7976             : 
    7977             : SEE ALSO:
    7978             :     PolynomialFit()
    7979             : 
    7980             : NOTES:
    7981             :     you can convert P from barycentric form  to  the  power  or  Chebyshev
    7982             :     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
    7983             :     POLINT subpackage.
    7984             : 
    7985             :   ! COMMERCIAL EDITION OF ALGLIB:
    7986             :   !
    7987             :   ! Commercial Edition of ALGLIB includes following important improvements
    7988             :   ! of this function:
    7989             :   ! * high-performance native backend with same C# interface (C# version)
    7990             :   ! * multithreading support (C++ and C# versions)
    7991             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    7992             :   !   (C++ and C# versions, x86/x64 platform)
    7993             :   !
    7994             :   ! We recommend you to read 'Working with commercial version' section  of
    7995             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    7996             :   ! related features provided by commercial edition of ALGLIB.
    7997             : 
    7998             : INPUT PARAMETERS:
    7999             :     X   -   points, array[0..N-1].
    8000             :     Y   -   function values, array[0..N-1].
    8001             :     W   -   weights, array[0..N-1]
    8002             :             Each summand in square  sum  of  approximation deviations from
    8003             :             given  values  is  multiplied  by  the square of corresponding
    8004             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
    8005             :             task.
    8006             :     N   -   number of points, N>0.
    8007             :             * if given, only leading N elements of X/Y/W are used
    8008             :             * if not given, automatically determined from sizes of X/Y/W
    8009             :     XC  -   points where polynomial values/derivatives are constrained,
    8010             :             array[0..K-1].
    8011             :     YC  -   values of constraints, array[0..K-1]
    8012             :     DC  -   array[0..K-1], types of constraints:
    8013             :             * DC[i]=0   means that P(XC[i])=YC[i]
    8014             :             * DC[i]=1   means that P'(XC[i])=YC[i]
    8015             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
    8016             :     K   -   number of constraints, 0<=K<M.
    8017             :             K=0 means no constraints (XC/YC/DC are not used in such cases)
    8018             :     M   -   number of basis functions (= polynomial_degree + 1), M>=1
    8019             : 
    8020             : OUTPUT PARAMETERS:
    8021             :     Info-   same format as in LSFitLinearW() subroutine:
    8022             :             * Info>0    task is solved
    8023             :             * Info<=0   an error occured:
    8024             :                         -4 means inconvergence of internal SVD
    8025             :                         -3 means inconsistent constraints
    8026             :     P   -   interpolant in barycentric form.
    8027             :     Rep -   report, same format as in LSFitLinearW() subroutine.
    8028             :             Following fields are set:
    8029             :             * RMSError      rms error on the (X,Y).
    8030             :             * AvgError      average error on the (X,Y).
    8031             :             * AvgRelError   average relative error on the non-zero Y
    8032             :             * MaxError      maximum error
    8033             :                             NON-WEIGHTED ERRORS ARE CALCULATED
    8034             : 
    8035             : IMPORTANT:
    8036             :     this subroitine doesn't calculate task's condition number for K<>0.
    8037             : 
    8038             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
    8039             : 
    8040             : Setting constraints can lead  to undesired  results,  like ill-conditioned
    8041             : behavior, or inconsistency being detected. From the other side,  it allows
    8042             : us to improve quality of the fit. Here we summarize  our  experience  with
    8043             : constrained regression splines:
    8044             : * even simple constraints can be inconsistent, see  Wikipedia  article  on
    8045             :   this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation
    8046             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
    8047             :   constraints will be consistent
    8048             : * in the general case, consistency of constraints is NOT GUARANTEED.
    8049             : * in the one special cases, however, we can  guarantee  consistency.  This
    8050             :   case  is:  M>1  and constraints on the function values (NOT DERIVATIVES)
    8051             : 
    8052             : Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
    8053             : can't solve your task without them. Anything beyond  special  cases  given
    8054             : above is not guaranteed and may result in inconsistency.
    8055             : 
    8056             :   -- ALGLIB PROJECT --
    8057             :      Copyright 10.12.2009 by Bochkanov Sergey
    8058             : *************************************************************************/
    8059           0 : 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, const xparams _xparams)
    8060             : {
    8061             :     jmp_buf _break_jump;
    8062             :     alglib_impl::ae_state _alglib_env_state;
    8063           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    8064           0 :     if( setjmp(_break_jump) )
    8065             :     {
    8066             : #if !defined(AE_NO_EXCEPTIONS)
    8067           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    8068             : #else
    8069             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    8070             :         return;
    8071             : #endif
    8072             :     }
    8073           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    8074           0 :     if( _xparams.flags!=0x0 )
    8075           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    8076           0 :     alglib_impl::polynomialfitwc(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(xc.c_ptr()), const_cast<alglib_impl::ae_vector*>(yc.c_ptr()), const_cast<alglib_impl::ae_vector*>(dc.c_ptr()), k, m, &info, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), const_cast<alglib_impl::polynomialfitreport*>(rep.c_ptr()), &_alglib_env_state);
    8077           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    8078           0 :     return;
    8079             : }
    8080             : 
    8081             : /*************************************************************************
    8082             : Weighted  fitting by polynomials in barycentric form, with constraints  on
    8083             : function values or first derivatives.
    8084             : 
    8085             : Small regularizing term is used when solving constrained tasks (to improve
    8086             : stability).
    8087             : 
    8088             : Task is linear, so linear least squares solver is used. Complexity of this
    8089             : computational scheme is O(N*M^2), mostly dominated by least squares solver
    8090             : 
    8091             : SEE ALSO:
    8092             :     PolynomialFit()
    8093             : 
    8094             : NOTES:
    8095             :     you can convert P from barycentric form  to  the  power  or  Chebyshev
    8096             :     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
    8097             :     POLINT subpackage.
    8098             : 
    8099             :   ! COMMERCIAL EDITION OF ALGLIB:
    8100             :   !
    8101             :   ! Commercial Edition of ALGLIB includes following important improvements
    8102             :   ! of this function:
    8103             :   ! * high-performance native backend with same C# interface (C# version)
    8104             :   ! * multithreading support (C++ and C# versions)
    8105             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    8106             :   !   (C++ and C# versions, x86/x64 platform)
    8107             :   !
    8108             :   ! We recommend you to read 'Working with commercial version' section  of
    8109             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    8110             :   ! related features provided by commercial edition of ALGLIB.
    8111             : 
    8112             : INPUT PARAMETERS:
    8113             :     X   -   points, array[0..N-1].
    8114             :     Y   -   function values, array[0..N-1].
    8115             :     W   -   weights, array[0..N-1]
    8116             :             Each summand in square  sum  of  approximation deviations from
    8117             :             given  values  is  multiplied  by  the square of corresponding
    8118             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
    8119             :             task.
    8120             :     N   -   number of points, N>0.
    8121             :             * if given, only leading N elements of X/Y/W are used
    8122             :             * if not given, automatically determined from sizes of X/Y/W
    8123             :     XC  -   points where polynomial values/derivatives are constrained,
    8124             :             array[0..K-1].
    8125             :     YC  -   values of constraints, array[0..K-1]
    8126             :     DC  -   array[0..K-1], types of constraints:
    8127             :             * DC[i]=0   means that P(XC[i])=YC[i]
    8128             :             * DC[i]=1   means that P'(XC[i])=YC[i]
    8129             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
    8130             :     K   -   number of constraints, 0<=K<M.
    8131             :             K=0 means no constraints (XC/YC/DC are not used in such cases)
    8132             :     M   -   number of basis functions (= polynomial_degree + 1), M>=1
    8133             : 
    8134             : OUTPUT PARAMETERS:
    8135             :     Info-   same format as in LSFitLinearW() subroutine:
    8136             :             * Info>0    task is solved
    8137             :             * Info<=0   an error occured:
    8138             :                         -4 means inconvergence of internal SVD
    8139             :                         -3 means inconsistent constraints
    8140             :     P   -   interpolant in barycentric form.
    8141             :     Rep -   report, same format as in LSFitLinearW() subroutine.
    8142             :             Following fields are set:
    8143             :             * RMSError      rms error on the (X,Y).
    8144             :             * AvgError      average error on the (X,Y).
    8145             :             * AvgRelError   average relative error on the non-zero Y
    8146             :             * MaxError      maximum error
    8147             :                             NON-WEIGHTED ERRORS ARE CALCULATED
    8148             : 
    8149             : IMPORTANT:
    8150             :     this subroitine doesn't calculate task's condition number for K<>0.
    8151             : 
    8152             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
    8153             : 
    8154             : Setting constraints can lead  to undesired  results,  like ill-conditioned
    8155             : behavior, or inconsistency being detected. From the other side,  it allows
    8156             : us to improve quality of the fit. Here we summarize  our  experience  with
    8157             : constrained regression splines:
    8158             : * even simple constraints can be inconsistent, see  Wikipedia  article  on
    8159             :   this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation
    8160             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
    8161             :   constraints will be consistent
    8162             : * in the general case, consistency of constraints is NOT GUARANTEED.
    8163             : * in the one special cases, however, we can  guarantee  consistency.  This
    8164             :   case  is:  M>1  and constraints on the function values (NOT DERIVATIVES)
    8165             : 
    8166             : Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
    8167             : can't solve your task without them. Anything beyond  special  cases  given
    8168             : above is not guaranteed and may result in inconsistency.
    8169             : 
    8170             :   -- ALGLIB PROJECT --
    8171             :      Copyright 10.12.2009 by Bochkanov Sergey
    8172             : *************************************************************************/
    8173             : #if !defined(AE_NO_EXCEPTIONS)
    8174           0 : 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, const xparams _xparams)
    8175             : {
    8176             :     jmp_buf _break_jump;
    8177             :     alglib_impl::ae_state _alglib_env_state;    
    8178             :     ae_int_t n;
    8179             :     ae_int_t k;
    8180           0 :     if( (x.length()!=y.length()) || (x.length()!=w.length()))
    8181           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size");
    8182           0 :     if( (xc.length()!=yc.length()) || (xc.length()!=dc.length()))
    8183           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size");
    8184           0 :     n = x.length();
    8185           0 :     k = xc.length();
    8186           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    8187           0 :     if( setjmp(_break_jump) )
    8188           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    8189           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    8190           0 :     if( _xparams.flags!=0x0 )
    8191           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    8192           0 :     alglib_impl::polynomialfitwc(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(xc.c_ptr()), const_cast<alglib_impl::ae_vector*>(yc.c_ptr()), const_cast<alglib_impl::ae_vector*>(dc.c_ptr()), k, m, &info, const_cast<alglib_impl::barycentricinterpolant*>(p.c_ptr()), const_cast<alglib_impl::polynomialfitreport*>(rep.c_ptr()), &_alglib_env_state);
    8193             : 
    8194           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    8195           0 :     return;
    8196             : }
    8197             : #endif
    8198             : 
    8199             : /*************************************************************************
    8200             : This function calculates value of four-parameter logistic (4PL)  model  at
    8201             : specified point X. 4PL model has following form:
    8202             : 
    8203             :     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
    8204             : 
    8205             : INPUT PARAMETERS:
    8206             :     X       -   current point, X>=0:
    8207             :                 * zero X is correctly handled even for B<=0
    8208             :                 * negative X results in exception.
    8209             :     A, B, C, D- parameters of 4PL model:
    8210             :                 * A is unconstrained
    8211             :                 * B is unconstrained; zero or negative values are handled
    8212             :                   correctly.
    8213             :                 * C>0, non-positive value results in exception
    8214             :                 * D is unconstrained
    8215             : 
    8216             : RESULT:
    8217             :     model value at X
    8218             : 
    8219             : NOTE: if B=0, denominator is assumed to be equal to 2.0 even  for  zero  X
    8220             :       (strictly speaking, 0^0 is undefined).
    8221             : 
    8222             : NOTE: this function also throws exception  if  all  input  parameters  are
    8223             :       correct, but overflow was detected during calculations.
    8224             : 
    8225             : NOTE: this function performs a lot of checks;  if  you  need  really  high
    8226             :       performance, consider evaluating model  yourself,  without  checking
    8227             :       for degenerate cases.
    8228             : 
    8229             : 
    8230             :   -- ALGLIB PROJECT --
    8231             :      Copyright 14.05.2014 by Bochkanov Sergey
    8232             : *************************************************************************/
    8233           0 : double logisticcalc4(const double x, const double a, const double b, const double c, const double d, const xparams _xparams)
    8234             : {
    8235             :     jmp_buf _break_jump;
    8236             :     alglib_impl::ae_state _alglib_env_state;
    8237           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    8238           0 :     if( setjmp(_break_jump) )
    8239             :     {
    8240             : #if !defined(AE_NO_EXCEPTIONS)
    8241           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    8242             : #else
    8243             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    8244             :         return 0;
    8245             : #endif
    8246             :     }
    8247           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    8248           0 :     if( _xparams.flags!=0x0 )
    8249           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    8250           0 :     double result = alglib_impl::logisticcalc4(x, a, b, c, d, &_alglib_env_state);
    8251           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    8252           0 :     return *(reinterpret_cast<double*>(&result));
    8253             : }
    8254             : 
    8255             : /*************************************************************************
    8256             : This function calculates value of five-parameter logistic (5PL)  model  at
    8257             : specified point X. 5PL model has following form:
    8258             : 
    8259             :     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
    8260             : 
    8261             : INPUT PARAMETERS:
    8262             :     X       -   current point, X>=0:
    8263             :                 * zero X is correctly handled even for B<=0
    8264             :                 * negative X results in exception.
    8265             :     A, B, C, D, G- parameters of 5PL model:
    8266             :                 * A is unconstrained
    8267             :                 * B is unconstrained; zero or negative values are handled
    8268             :                   correctly.
    8269             :                 * C>0, non-positive value results in exception
    8270             :                 * D is unconstrained
    8271             :                 * G>0, non-positive value results in exception
    8272             : 
    8273             : RESULT:
    8274             :     model value at X
    8275             : 
    8276             : NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even  for
    8277             :       zero X (strictly speaking, 0^0 is undefined).
    8278             : 
    8279             : NOTE: this function also throws exception  if  all  input  parameters  are
    8280             :       correct, but overflow was detected during calculations.
    8281             : 
    8282             : NOTE: this function performs a lot of checks;  if  you  need  really  high
    8283             :       performance, consider evaluating model  yourself,  without  checking
    8284             :       for degenerate cases.
    8285             : 
    8286             : 
    8287             :   -- ALGLIB PROJECT --
    8288             :      Copyright 14.05.2014 by Bochkanov Sergey
    8289             : *************************************************************************/
    8290           0 : double logisticcalc5(const double x, const double a, const double b, const double c, const double d, const double g, const xparams _xparams)
    8291             : {
    8292             :     jmp_buf _break_jump;
    8293             :     alglib_impl::ae_state _alglib_env_state;
    8294           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    8295           0 :     if( setjmp(_break_jump) )
    8296             :     {
    8297             : #if !defined(AE_NO_EXCEPTIONS)
    8298           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    8299             : #else
    8300             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    8301             :         return 0;
    8302             : #endif
    8303             :     }
    8304           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    8305           0 :     if( _xparams.flags!=0x0 )
    8306           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    8307           0 :     double result = alglib_impl::logisticcalc5(x, a, b, c, d, g, &_alglib_env_state);
    8308           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    8309           0 :     return *(reinterpret_cast<double*>(&result));
    8310             : }
    8311             : 
    8312             : /*************************************************************************
    8313             : This function fits four-parameter logistic (4PL) model  to  data  provided
    8314             : by user. 4PL model has following form:
    8315             : 
    8316             :     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
    8317             : 
    8318             : Here:
    8319             :     * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL)
    8320             :     * B>=0
    8321             :     * C>0
    8322             : 
    8323             : IMPORTANT: output of this function is constrained in  such  way that  B>0.
    8324             :            Because 4PL model is symmetric with respect to B, there  is  no
    8325             :            need to explore  B<0.  Constraining  B  makes  algorithm easier
    8326             :            to stabilize and debug.
    8327             :            Users  who  for  some  reason  prefer to work with negative B's
    8328             :            should transform output themselves (swap A and D, replace B  by
    8329             :            -B).
    8330             : 
    8331             : 4PL fitting is implemented as follows:
    8332             : * we perform small number of restarts from random locations which helps to
    8333             :   solve problem of bad local extrema. Locations are only partially  random
    8334             :   - we use input data to determine good  initial  guess,  but  we  include
    8335             :   controlled amount of randomness.
    8336             : * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
    8337             :   parameters B and C - it allows us to find good  initial  guess  for  the
    8338             :   second stage without risk of running into "flat spot".
    8339             : * second  Levenberg-Marquardt  round  is   performed   without   excessive
    8340             :   constraints. Results from the previous round are used as initial guess.
    8341             : * after fitting is done, we compare results with best values found so far,
    8342             :   rewrite "best solution" if needed, and move to next random location.
    8343             : 
    8344             : Overall algorithm is very stable and is not prone to  bad  local  extrema.
    8345             : Furthermore, it automatically scales when input data have  very  large  or
    8346             : very small range.
    8347             : 
    8348             : INPUT PARAMETERS:
    8349             :     X       -   array[N], stores X-values.
    8350             :                 MUST include only non-negative numbers  (but  may  include
    8351             :                 zero values). Can be unsorted.
    8352             :     Y       -   array[N], values to fit.
    8353             :     N       -   number of points. If N is less than  length  of  X/Y, only
    8354             :                 leading N elements are used.
    8355             : 
    8356             : OUTPUT PARAMETERS:
    8357             :     A, B, C, D- parameters of 4PL model
    8358             :     Rep     -   fitting report. This structure has many fields,  but  ONLY
    8359             :                 ONES LISTED BELOW ARE SET:
    8360             :                 * Rep.IterationsCount - number of iterations performed
    8361             :                 * Rep.RMSError - root-mean-square error
    8362             :                 * Rep.AvgError - average absolute error
    8363             :                 * Rep.AvgRelError - average relative error (calculated for
    8364             :                   non-zero Y-values)
    8365             :                 * Rep.MaxError - maximum absolute error
    8366             :                 * Rep.R2 - coefficient of determination,  R-squared.  This
    8367             :                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
    8368             :                   of nonlinear  regression  there  are  multiple  ways  to
    8369             :                   define R2, each of them giving different results).
    8370             : 
    8371             : NOTE: for stability reasons the B parameter is restricted by [1/1000,1000]
    8372             :       range. It prevents  algorithm from making trial steps  deep into the
    8373             :       area of bad parameters.
    8374             : 
    8375             : NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
    8376             :       LogisticCalc4() function.
    8377             : 
    8378             : NOTE: if you need better control over fitting process than provided by this
    8379             :       function, you may use LogisticFit45X().
    8380             : 
    8381             : NOTE: step is automatically scaled according to scale of parameters  being
    8382             :       fitted before we compare its length with EpsX. Thus,  this  function
    8383             :       can be used to fit data with very small or very large values without
    8384             :       changing EpsX.
    8385             : 
    8386             : 
    8387             :   -- ALGLIB PROJECT --
    8388             :      Copyright 14.02.2014 by Bochkanov Sergey
    8389             : *************************************************************************/
    8390           0 : 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)
    8391             : {
    8392             :     jmp_buf _break_jump;
    8393             :     alglib_impl::ae_state _alglib_env_state;
    8394           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    8395           0 :     if( setjmp(_break_jump) )
    8396             :     {
    8397             : #if !defined(AE_NO_EXCEPTIONS)
    8398           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    8399             : #else
    8400             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    8401             :         return;
    8402             : #endif
    8403             :     }
    8404           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    8405           0 :     if( _xparams.flags!=0x0 )
    8406           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    8407           0 :     alglib_impl::logisticfit4(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, &a, &b, &c, &d, const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
    8408           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    8409           0 :     return;
    8410             : }
    8411             : 
    8412             : /*************************************************************************
    8413             : This function fits four-parameter logistic (4PL) model  to  data  provided
    8414             : by user, with optional constraints on parameters A and D.  4PL  model  has
    8415             : following form:
    8416             : 
    8417             :     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
    8418             : 
    8419             : Here:
    8420             :     * A, D - with optional equality constraints
    8421             :     * B>=0
    8422             :     * C>0
    8423             : 
    8424             : IMPORTANT: output of this function is constrained in  such  way that  B>0.
    8425             :            Because 4PL model is symmetric with respect to B, there  is  no
    8426             :            need to explore  B<0.  Constraining  B  makes  algorithm easier
    8427             :            to stabilize and debug.
    8428             :            Users  who  for  some  reason  prefer to work with negative B's
    8429             :            should transform output themselves (swap A and D, replace B  by
    8430             :            -B).
    8431             : 
    8432             : 4PL fitting is implemented as follows:
    8433             : * we perform small number of restarts from random locations which helps to
    8434             :   solve problem of bad local extrema. Locations are only partially  random
    8435             :   - we use input data to determine good  initial  guess,  but  we  include
    8436             :   controlled amount of randomness.
    8437             : * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
    8438             :   parameters B and C - it allows us to find good  initial  guess  for  the
    8439             :   second stage without risk of running into "flat spot".
    8440             : * second  Levenberg-Marquardt  round  is   performed   without   excessive
    8441             :   constraints. Results from the previous round are used as initial guess.
    8442             : * after fitting is done, we compare results with best values found so far,
    8443             :   rewrite "best solution" if needed, and move to next random location.
    8444             : 
    8445             : Overall algorithm is very stable and is not prone to  bad  local  extrema.
    8446             : Furthermore, it automatically scales when input data have  very  large  or
    8447             : very small range.
    8448             : 
    8449             : INPUT PARAMETERS:
    8450             :     X       -   array[N], stores X-values.
    8451             :                 MUST include only non-negative numbers  (but  may  include
    8452             :                 zero values). Can be unsorted.
    8453             :     Y       -   array[N], values to fit.
    8454             :     N       -   number of points. If N is less than  length  of  X/Y, only
    8455             :                 leading N elements are used.
    8456             :     CnstrLeft-  optional equality constraint for model value at the   left
    8457             :                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
    8458             :                 not need constraint on the model value at X=0 (in C++  you
    8459             :                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
    8460             :                 Double.NaN).
    8461             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
    8462             :                 information about constraints.
    8463             :     CnstrRight- optional equality constraint for model value at X=infinity.
    8464             :                 Specify NAN (Not-a-Number) if you do not  need  constraint
    8465             :                 on the model value (in C++  you can pass alglib::fp_nan as
    8466             :                 parameter, in  C# it will  be Double.NaN).
    8467             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
    8468             :                 information about constraints.
    8469             : 
    8470             : OUTPUT PARAMETERS:
    8471             :     A, B, C, D- parameters of 4PL model
    8472             :     Rep     -   fitting report. This structure has many fields,  but  ONLY
    8473             :                 ONES LISTED BELOW ARE SET:
    8474             :                 * Rep.IterationsCount - number of iterations performed
    8475             :                 * Rep.RMSError - root-mean-square error
    8476             :                 * Rep.AvgError - average absolute error
    8477             :                 * Rep.AvgRelError - average relative error (calculated for
    8478             :                   non-zero Y-values)
    8479             :                 * Rep.MaxError - maximum absolute error
    8480             :                 * Rep.R2 - coefficient of determination,  R-squared.  This
    8481             :                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
    8482             :                   of nonlinear  regression  there  are  multiple  ways  to
    8483             :                   define R2, each of them giving different results).
    8484             : 
    8485             : NOTE: for stability reasons the B parameter is restricted by [1/1000,1000]
    8486             :       range. It prevents  algorithm from making trial steps  deep into the
    8487             :       area of bad parameters.
    8488             : 
    8489             : NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
    8490             :       LogisticCalc4() function.
    8491             : 
    8492             : NOTE: if you need better control over fitting process than provided by this
    8493             :       function, you may use LogisticFit45X().
    8494             : 
    8495             : NOTE: step is automatically scaled according to scale of parameters  being
    8496             :       fitted before we compare its length with EpsX. Thus,  this  function
    8497             :       can be used to fit data with very small or very large values without
    8498             :       changing EpsX.
    8499             : 
    8500             : EQUALITY CONSTRAINTS ON PARAMETERS
    8501             : 
    8502             : 4PL/5PL solver supports equality constraints on model values at  the  left
    8503             : boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
    8504             : completely optional and you can specify both of them, only  one  -  or  no
    8505             : constraints at all.
    8506             : 
    8507             : Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
    8508             : fitting), and CnstrRight contains right  one.  For  4PL,  left  constraint
    8509             : ALWAYS corresponds to parameter A, and right one is ALWAYS  constraint  on
    8510             : D. That's because 4PL model is normalized in such way that B>=0.
    8511             : 
    8512             : 
    8513             :   -- ALGLIB PROJECT --
    8514             :      Copyright 14.02.2014 by Bochkanov Sergey
    8515             : *************************************************************************/
    8516           0 : 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)
    8517             : {
    8518             :     jmp_buf _break_jump;
    8519             :     alglib_impl::ae_state _alglib_env_state;
    8520           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    8521           0 :     if( setjmp(_break_jump) )
    8522             :     {
    8523             : #if !defined(AE_NO_EXCEPTIONS)
    8524           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    8525             : #else
    8526             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    8527             :         return;
    8528             : #endif
    8529             :     }
    8530           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    8531           0 :     if( _xparams.flags!=0x0 )
    8532           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    8533           0 :     alglib_impl::logisticfit4ec(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, cnstrleft, cnstrright, &a, &b, &c, &d, const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
    8534           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    8535           0 :     return;
    8536             : }
    8537             : 
    8538             : /*************************************************************************
    8539             : This function fits five-parameter logistic (5PL) model  to  data  provided
    8540             : by user. 5PL model has following form:
    8541             : 
    8542             :     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
    8543             : 
    8544             : Here:
    8545             :     * A, D - unconstrained
    8546             :     * B - unconstrained
    8547             :     * C>0
    8548             :     * G>0
    8549             : 
    8550             : IMPORTANT: unlike in  4PL  fitting,  output  of  this  function   is   NOT
    8551             :            constrained in  such  way that B is guaranteed to be  positive.
    8552             :            Furthermore,  unlike  4PL,  5PL  model  is  NOT  symmetric with
    8553             :            respect to B, so you can NOT transform model to equivalent one,
    8554             :            with B having desired sign (>0 or <0).
    8555             : 
    8556             : 5PL fitting is implemented as follows:
    8557             : * we perform small number of restarts from random locations which helps to
    8558             :   solve problem of bad local extrema. Locations are only partially  random
    8559             :   - we use input data to determine good  initial  guess,  but  we  include
    8560             :   controlled amount of randomness.
    8561             : * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
    8562             :   parameters B and C - it allows us to find good  initial  guess  for  the
    8563             :   second stage without risk of running into "flat spot".  Parameter  G  is
    8564             :   fixed at G=1.
    8565             : * second  Levenberg-Marquardt  round  is   performed   without   excessive
    8566             :   constraints on B and C, but with G still equal to 1.  Results  from  the
    8567             :   previous round are used as initial guess.
    8568             : * third Levenberg-Marquardt round relaxes constraints on G  and  tries  two
    8569             :   different models - one with B>0 and one with B<0.
    8570             : * after fitting is done, we compare results with best values found so far,
    8571             :   rewrite "best solution" if needed, and move to next random location.
    8572             : 
    8573             : Overall algorithm is very stable and is not prone to  bad  local  extrema.
    8574             : Furthermore, it automatically scales when input data have  very  large  or
    8575             : very small range.
    8576             : 
    8577             : INPUT PARAMETERS:
    8578             :     X       -   array[N], stores X-values.
    8579             :                 MUST include only non-negative numbers  (but  may  include
    8580             :                 zero values). Can be unsorted.
    8581             :     Y       -   array[N], values to fit.
    8582             :     N       -   number of points. If N is less than  length  of  X/Y, only
    8583             :                 leading N elements are used.
    8584             : 
    8585             : OUTPUT PARAMETERS:
    8586             :     A,B,C,D,G-  parameters of 5PL model
    8587             :     Rep     -   fitting report. This structure has many fields,  but  ONLY
    8588             :                 ONES LISTED BELOW ARE SET:
    8589             :                 * Rep.IterationsCount - number of iterations performed
    8590             :                 * Rep.RMSError - root-mean-square error
    8591             :                 * Rep.AvgError - average absolute error
    8592             :                 * Rep.AvgRelError - average relative error (calculated for
    8593             :                   non-zero Y-values)
    8594             :                 * Rep.MaxError - maximum absolute error
    8595             :                 * Rep.R2 - coefficient of determination,  R-squared.  This
    8596             :                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
    8597             :                   of nonlinear  regression  there  are  multiple  ways  to
    8598             :                   define R2, each of them giving different results).
    8599             : 
    8600             : NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
    8601             :       range, and G is restricted by [1/10,10] range. It prevents algorithm
    8602             :       from making trial steps deep into the area of bad parameters.
    8603             : 
    8604             : NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
    8605             :       LogisticCalc5() function.
    8606             : 
    8607             : NOTE: if you need better control over fitting process than provided by this
    8608             :       function, you may use LogisticFit45X().
    8609             : 
    8610             : NOTE: step is automatically scaled according to scale of parameters  being
    8611             :       fitted before we compare its length with EpsX. Thus,  this  function
    8612             :       can be used to fit data with very small or very large values without
    8613             :       changing EpsX.
    8614             : 
    8615             : 
    8616             :   -- ALGLIB PROJECT --
    8617             :      Copyright 14.02.2014 by Bochkanov Sergey
    8618             : *************************************************************************/
    8619           0 : 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)
    8620             : {
    8621             :     jmp_buf _break_jump;
    8622             :     alglib_impl::ae_state _alglib_env_state;
    8623           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    8624           0 :     if( setjmp(_break_jump) )
    8625             :     {
    8626             : #if !defined(AE_NO_EXCEPTIONS)
    8627           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    8628             : #else
    8629             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    8630             :         return;
    8631             : #endif
    8632             :     }
    8633           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    8634           0 :     if( _xparams.flags!=0x0 )
    8635           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    8636           0 :     alglib_impl::logisticfit5(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, &a, &b, &c, &d, &g, const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
    8637           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    8638           0 :     return;
    8639             : }
    8640             : 
    8641             : /*************************************************************************
    8642             : This function fits five-parameter logistic (5PL) model  to  data  provided
    8643             : by user, subject to optional equality constraints on parameters A  and  D.
    8644             : 5PL model has following form:
    8645             : 
    8646             :     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
    8647             : 
    8648             : Here:
    8649             :     * A, D - with optional equality constraints
    8650             :     * B - unconstrained
    8651             :     * C>0
    8652             :     * G>0
    8653             : 
    8654             : IMPORTANT: unlike in  4PL  fitting,  output  of  this  function   is   NOT
    8655             :            constrained in  such  way that B is guaranteed to be  positive.
    8656             :            Furthermore,  unlike  4PL,  5PL  model  is  NOT  symmetric with
    8657             :            respect to B, so you can NOT transform model to equivalent one,
    8658             :            with B having desired sign (>0 or <0).
    8659             : 
    8660             : 5PL fitting is implemented as follows:
    8661             : * we perform small number of restarts from random locations which helps to
    8662             :   solve problem of bad local extrema. Locations are only partially  random
    8663             :   - we use input data to determine good  initial  guess,  but  we  include
    8664             :   controlled amount of randomness.
    8665             : * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
    8666             :   parameters B and C - it allows us to find good  initial  guess  for  the
    8667             :   second stage without risk of running into "flat spot".  Parameter  G  is
    8668             :   fixed at G=1.
    8669             : * second  Levenberg-Marquardt  round  is   performed   without   excessive
    8670             :   constraints on B and C, but with G still equal to 1.  Results  from  the
    8671             :   previous round are used as initial guess.
    8672             : * third Levenberg-Marquardt round relaxes constraints on G  and  tries  two
    8673             :   different models - one with B>0 and one with B<0.
    8674             : * after fitting is done, we compare results with best values found so far,
    8675             :   rewrite "best solution" if needed, and move to next random location.
    8676             : 
    8677             : Overall algorithm is very stable and is not prone to  bad  local  extrema.
    8678             : Furthermore, it automatically scales when input data have  very  large  or
    8679             : very small range.
    8680             : 
    8681             : INPUT PARAMETERS:
    8682             :     X       -   array[N], stores X-values.
    8683             :                 MUST include only non-negative numbers  (but  may  include
    8684             :                 zero values). Can be unsorted.
    8685             :     Y       -   array[N], values to fit.
    8686             :     N       -   number of points. If N is less than  length  of  X/Y, only
    8687             :                 leading N elements are used.
    8688             :     CnstrLeft-  optional equality constraint for model value at the   left
    8689             :                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
    8690             :                 not need constraint on the model value at X=0 (in C++  you
    8691             :                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
    8692             :                 Double.NaN).
    8693             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
    8694             :                 information about constraints.
    8695             :     CnstrRight- optional equality constraint for model value at X=infinity.
    8696             :                 Specify NAN (Not-a-Number) if you do not  need  constraint
    8697             :                 on the model value (in C++  you can pass alglib::fp_nan as
    8698             :                 parameter, in  C# it will  be Double.NaN).
    8699             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
    8700             :                 information about constraints.
    8701             : 
    8702             : OUTPUT PARAMETERS:
    8703             :     A,B,C,D,G-  parameters of 5PL model
    8704             :     Rep     -   fitting report. This structure has many fields,  but  ONLY
    8705             :                 ONES LISTED BELOW ARE SET:
    8706             :                 * Rep.IterationsCount - number of iterations performed
    8707             :                 * Rep.RMSError - root-mean-square error
    8708             :                 * Rep.AvgError - average absolute error
    8709             :                 * Rep.AvgRelError - average relative error (calculated for
    8710             :                   non-zero Y-values)
    8711             :                 * Rep.MaxError - maximum absolute error
    8712             :                 * Rep.R2 - coefficient of determination,  R-squared.  This
    8713             :                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
    8714             :                   of nonlinear  regression  there  are  multiple  ways  to
    8715             :                   define R2, each of them giving different results).
    8716             : 
    8717             : NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
    8718             :       range, and G is restricted by [1/10,10] range. It prevents algorithm
    8719             :       from making trial steps deep into the area of bad parameters.
    8720             : 
    8721             : NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
    8722             :       LogisticCalc5() function.
    8723             : 
    8724             : NOTE: if you need better control over fitting process than provided by this
    8725             :       function, you may use LogisticFit45X().
    8726             : 
    8727             : NOTE: step is automatically scaled according to scale of parameters  being
    8728             :       fitted before we compare its length with EpsX. Thus,  this  function
    8729             :       can be used to fit data with very small or very large values without
    8730             :       changing EpsX.
    8731             : 
    8732             : EQUALITY CONSTRAINTS ON PARAMETERS
    8733             : 
    8734             : 5PL solver supports equality constraints on model  values  at   the   left
    8735             : boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
    8736             : completely optional and you can specify both of them, only  one  -  or  no
    8737             : constraints at all.
    8738             : 
    8739             : Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
    8740             : fitting), and CnstrRight contains right  one.
    8741             : 
    8742             : Unlike 4PL one, 5PL model is NOT symmetric with respect to  change in sign
    8743             : of B. Thus, negative B's are possible, and left constraint  may  constrain
    8744             : parameter A (for positive B's)  -  or  parameter  D  (for  negative  B's).
    8745             : Similarly changes meaning of right constraint.
    8746             : 
    8747             : You do not have to decide what parameter to  constrain  -  algorithm  will
    8748             : automatically determine correct parameters as fitting progresses. However,
    8749             : question highlighted above is important when you interpret fitting results.
    8750             : 
    8751             : 
    8752             :   -- ALGLIB PROJECT --
    8753             :      Copyright 14.02.2014 by Bochkanov Sergey
    8754             : *************************************************************************/
    8755           0 : 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)
    8756             : {
    8757             :     jmp_buf _break_jump;
    8758             :     alglib_impl::ae_state _alglib_env_state;
    8759           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    8760           0 :     if( setjmp(_break_jump) )
    8761             :     {
    8762             : #if !defined(AE_NO_EXCEPTIONS)
    8763           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    8764             : #else
    8765             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    8766             :         return;
    8767             : #endif
    8768             :     }
    8769           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    8770           0 :     if( _xparams.flags!=0x0 )
    8771           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    8772           0 :     alglib_impl::logisticfit5ec(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, cnstrleft, cnstrright, &a, &b, &c, &d, &g, const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
    8773           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    8774           0 :     return;
    8775             : }
    8776             : 
    8777             : /*************************************************************************
    8778             : This is "expert" 4PL/5PL fitting function, which can be used if  you  need
    8779             : better control over fitting process than provided  by  LogisticFit4()  or
    8780             : LogisticFit5().
    8781             : 
    8782             : This function fits model of the form
    8783             : 
    8784             :     F(x|A,B,C,D)   = D+(A-D)/(1+Power(x/C,B))           (4PL model)
    8785             : 
    8786             : or
    8787             : 
    8788             :     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)    (5PL model)
    8789             : 
    8790             : Here:
    8791             :     * A, D - unconstrained
    8792             :     * B>=0 for 4PL, unconstrained for 5PL
    8793             :     * C>0
    8794             :     * G>0 (if present)
    8795             : 
    8796             : INPUT PARAMETERS:
    8797             :     X       -   array[N], stores X-values.
    8798             :                 MUST include only non-negative numbers  (but  may  include
    8799             :                 zero values). Can be unsorted.
    8800             :     Y       -   array[N], values to fit.
    8801             :     N       -   number of points. If N is less than  length  of  X/Y, only
    8802             :                 leading N elements are used.
    8803             :     CnstrLeft-  optional equality constraint for model value at the   left
    8804             :                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
    8805             :                 not need constraint on the model value at X=0 (in C++  you
    8806             :                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
    8807             :                 Double.NaN).
    8808             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
    8809             :                 information about constraints.
    8810             :     CnstrRight- optional equality constraint for model value at X=infinity.
    8811             :                 Specify NAN (Not-a-Number) if you do not  need  constraint
    8812             :                 on the model value (in C++  you can pass alglib::fp_nan as
    8813             :                 parameter, in  C# it will  be Double.NaN).
    8814             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
    8815             :                 information about constraints.
    8816             :     Is4PL   -   whether 4PL or 5PL models are fitted
    8817             :     LambdaV -   regularization coefficient, LambdaV>=0.
    8818             :                 Set it to zero unless you know what you are doing.
    8819             :     EpsX    -   stopping condition (step size), EpsX>=0.
    8820             :                 Zero value means that small step is automatically chosen.
    8821             :                 See notes below for more information.
    8822             :     RsCnt   -   number of repeated restarts from  random  points.  4PL/5PL
    8823             :                 models are prone to problem of bad local extrema. Utilizing
    8824             :                 multiple random restarts allows  us  to  improve algorithm
    8825             :                 convergence.
    8826             :                 RsCnt>=0.
    8827             :                 Zero value means that function automatically choose  small
    8828             :                 amount of restarts (recommended).
    8829             : 
    8830             : OUTPUT PARAMETERS:
    8831             :     A, B, C, D- parameters of 4PL model
    8832             :     G       -   parameter of 5PL model; for Is4PL=True, G=1 is returned.
    8833             :     Rep     -   fitting report. This structure has many fields,  but  ONLY
    8834             :                 ONES LISTED BELOW ARE SET:
    8835             :                 * Rep.IterationsCount - number of iterations performed
    8836             :                 * Rep.RMSError - root-mean-square error
    8837             :                 * Rep.AvgError - average absolute error
    8838             :                 * Rep.AvgRelError - average relative error (calculated for
    8839             :                   non-zero Y-values)
    8840             :                 * Rep.MaxError - maximum absolute error
    8841             :                 * Rep.R2 - coefficient of determination,  R-squared.  This
    8842             :                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
    8843             :                   of nonlinear  regression  there  are  multiple  ways  to
    8844             :                   define R2, each of them giving different results).
    8845             : 
    8846             : NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
    8847             :       range, and G is restricted by [1/10,10] range. It prevents algorithm
    8848             :       from making trial steps deep into the area of bad parameters.
    8849             : 
    8850             : NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
    8851             :       LogisticCalc5() function.
    8852             : 
    8853             : NOTE: step is automatically scaled according to scale of parameters  being
    8854             :       fitted before we compare its length with EpsX. Thus,  this  function
    8855             :       can be used to fit data with very small or very large values without
    8856             :       changing EpsX.
    8857             : 
    8858             : EQUALITY CONSTRAINTS ON PARAMETERS
    8859             : 
    8860             : 4PL/5PL solver supports equality constraints on model values at  the  left
    8861             : boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
    8862             : completely optional and you can specify both of them, only  one  -  or  no
    8863             : constraints at all.
    8864             : 
    8865             : Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
    8866             : fitting), and CnstrRight contains right  one.  For  4PL,  left  constraint
    8867             : ALWAYS corresponds to parameter A, and right one is ALWAYS  constraint  on
    8868             : D. That's because 4PL model is normalized in such way that B>=0.
    8869             : 
    8870             : For 5PL model things are different. Unlike  4PL  one,  5PL  model  is  NOT
    8871             : symmetric with respect to  change  in  sign  of  B. Thus, negative B's are
    8872             : possible, and left constraint may constrain parameter A (for positive B's)
    8873             : - or parameter D (for negative B's). Similarly changes  meaning  of  right
    8874             : constraint.
    8875             : 
    8876             : You do not have to decide what parameter to  constrain  -  algorithm  will
    8877             : automatically determine correct parameters as fitting progresses. However,
    8878             : question highlighted above is important when you interpret fitting results.
    8879             : 
    8880             : 
    8881             :   -- ALGLIB PROJECT --
    8882             :      Copyright 14.02.2014 by Bochkanov Sergey
    8883             : *************************************************************************/
    8884           0 : 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)
    8885             : {
    8886             :     jmp_buf _break_jump;
    8887             :     alglib_impl::ae_state _alglib_env_state;
    8888           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    8889           0 :     if( setjmp(_break_jump) )
    8890             :     {
    8891             : #if !defined(AE_NO_EXCEPTIONS)
    8892           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    8893             : #else
    8894             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    8895             :         return;
    8896             : #endif
    8897             :     }
    8898           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    8899           0 :     if( _xparams.flags!=0x0 )
    8900           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    8901           0 :     alglib_impl::logisticfit45x(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, cnstrleft, cnstrright, is4pl, lambdav, epsx, rscnt, &a, &b, &c, &d, &g, const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
    8902           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    8903           0 :     return;
    8904             : }
    8905             : 
    8906             : /*************************************************************************
    8907             : Weghted rational least  squares  fitting  using  Floater-Hormann  rational
    8908             : functions  with  optimal  D  chosen  from  [0,9],  with  constraints   and
    8909             : individual weights.
    8910             : 
    8911             : Equidistant  grid  with M node on [min(x),max(x)]  is  used to build basis
    8912             : functions. Different values of D are tried, optimal D (least WEIGHTED root
    8913             : mean square error) is chosen.  Task  is  linear,  so  linear least squares
    8914             : solver  is  used.  Complexity  of  this  computational  scheme is O(N*M^2)
    8915             : (mostly dominated by the least squares solver).
    8916             : 
    8917             : SEE ALSO
    8918             : * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual
    8919             :   weights and constraints.
    8920             : 
    8921             :   ! COMMERCIAL EDITION OF ALGLIB:
    8922             :   !
    8923             :   ! Commercial Edition of ALGLIB includes following important improvements
    8924             :   ! of this function:
    8925             :   ! * high-performance native backend with same C# interface (C# version)
    8926             :   ! * multithreading support (C++ and C# versions)
    8927             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    8928             :   !   (C++ and C# versions, x86/x64 platform)
    8929             :   !
    8930             :   ! We recommend you to read 'Working with commercial version' section  of
    8931             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    8932             :   ! related features provided by commercial edition of ALGLIB.
    8933             : 
    8934             : INPUT PARAMETERS:
    8935             :     X   -   points, array[0..N-1].
    8936             :     Y   -   function values, array[0..N-1].
    8937             :     W   -   weights, array[0..N-1]
    8938             :             Each summand in square  sum  of  approximation deviations from
    8939             :             given  values  is  multiplied  by  the square of corresponding
    8940             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
    8941             :             task.
    8942             :     N   -   number of points, N>0.
    8943             :     XC  -   points where function values/derivatives are constrained,
    8944             :             array[0..K-1].
    8945             :     YC  -   values of constraints, array[0..K-1]
    8946             :     DC  -   array[0..K-1], types of constraints:
    8947             :             * DC[i]=0   means that S(XC[i])=YC[i]
    8948             :             * DC[i]=1   means that S'(XC[i])=YC[i]
    8949             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
    8950             :     K   -   number of constraints, 0<=K<M.
    8951             :             K=0 means no constraints (XC/YC/DC are not used in such cases)
    8952             :     M   -   number of basis functions ( = number_of_nodes), M>=2.
    8953             : 
    8954             : OUTPUT PARAMETERS:
    8955             :     Info-   same format as in LSFitLinearWC() subroutine.
    8956             :             * Info>0    task is solved
    8957             :             * Info<=0   an error occured:
    8958             :                         -4 means inconvergence of internal SVD
    8959             :                         -3 means inconsistent constraints
    8960             :                         -1 means another errors in parameters passed
    8961             :                            (N<=0, for example)
    8962             :     B   -   barycentric interpolant.
    8963             :     Rep -   report, same format as in LSFitLinearWC() subroutine.
    8964             :             Following fields are set:
    8965             :             * DBest         best value of the D parameter
    8966             :             * RMSError      rms error on the (X,Y).
    8967             :             * AvgError      average error on the (X,Y).
    8968             :             * AvgRelError   average relative error on the non-zero Y
    8969             :             * MaxError      maximum error
    8970             :                             NON-WEIGHTED ERRORS ARE CALCULATED
    8971             : 
    8972             : IMPORTANT:
    8973             :     this subroutine doesn't calculate task's condition number for K<>0.
    8974             : 
    8975             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
    8976             : 
    8977             : Setting constraints can lead  to undesired  results,  like ill-conditioned
    8978             : behavior, or inconsistency being detected. From the other side,  it allows
    8979             : us to improve quality of the fit. Here we summarize  our  experience  with
    8980             : constrained barycentric interpolants:
    8981             : * excessive  constraints  can  be  inconsistent.   Floater-Hormann   basis
    8982             :   functions aren't as flexible as splines (although they are very smooth).
    8983             : * the more evenly constraints are spread across [min(x),max(x)],  the more
    8984             :   chances that they will be consistent
    8985             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
    8986             :   constraints will be consistent
    8987             : * in the general case, consistency of constraints IS NOT GUARANTEED.
    8988             : * in the several special cases, however, we CAN guarantee consistency.
    8989             : * one of this cases is constraints on the function  VALUES at the interval
    8990             :   boundaries. Note that consustency of the  constraints  on  the  function
    8991             :   DERIVATIVES is NOT guaranteed (you can use in such cases  cubic  splines
    8992             :   which are more flexible).
    8993             : * another  special  case  is ONE constraint on the function value (OR, but
    8994             :   not AND, derivative) anywhere in the interval
    8995             : 
    8996             : Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
    8997             : can't solve your task without them. Anything beyond  special  cases  given
    8998             : above is not guaranteed and may result in inconsistency.
    8999             : 
    9000             :   -- ALGLIB PROJECT --
    9001             :      Copyright 18.08.2009 by Bochkanov Sergey
    9002             : *************************************************************************/
    9003           0 : 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, const xparams _xparams)
    9004             : {
    9005             :     jmp_buf _break_jump;
    9006             :     alglib_impl::ae_state _alglib_env_state;
    9007           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9008           0 :     if( setjmp(_break_jump) )
    9009             :     {
    9010             : #if !defined(AE_NO_EXCEPTIONS)
    9011           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9012             : #else
    9013             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    9014             :         return;
    9015             : #endif
    9016             :     }
    9017           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9018           0 :     if( _xparams.flags!=0x0 )
    9019           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9020           0 :     alglib_impl::barycentricfitfloaterhormannwc(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(xc.c_ptr()), const_cast<alglib_impl::ae_vector*>(yc.c_ptr()), const_cast<alglib_impl::ae_vector*>(dc.c_ptr()), k, m, &info, const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), const_cast<alglib_impl::barycentricfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9021           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9022           0 :     return;
    9023             : }
    9024             : 
    9025             : /*************************************************************************
    9026             : Rational least squares fitting using  Floater-Hormann  rational  functions
    9027             : with optimal D chosen from [0,9].
    9028             : 
    9029             : Equidistant  grid  with M node on [min(x),max(x)]  is  used to build basis
    9030             : functions. Different values of D are tried, optimal  D  (least  root  mean
    9031             : square error) is chosen.  Task  is  linear, so linear least squares solver
    9032             : is used. Complexity  of  this  computational  scheme is  O(N*M^2)  (mostly
    9033             : dominated by the least squares solver).
    9034             : 
    9035             :   ! COMMERCIAL EDITION OF ALGLIB:
    9036             :   !
    9037             :   ! Commercial Edition of ALGLIB includes following important improvements
    9038             :   ! of this function:
    9039             :   ! * high-performance native backend with same C# interface (C# version)
    9040             :   ! * multithreading support (C++ and C# versions)
    9041             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9042             :   !   (C++ and C# versions, x86/x64 platform)
    9043             :   !
    9044             :   ! We recommend you to read 'Working with commercial version' section  of
    9045             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9046             :   ! related features provided by commercial edition of ALGLIB.
    9047             : 
    9048             : INPUT PARAMETERS:
    9049             :     X   -   points, array[0..N-1].
    9050             :     Y   -   function values, array[0..N-1].
    9051             :     N   -   number of points, N>0.
    9052             :     M   -   number of basis functions ( = number_of_nodes), M>=2.
    9053             : 
    9054             : OUTPUT PARAMETERS:
    9055             :     Info-   same format as in LSFitLinearWC() subroutine.
    9056             :             * Info>0    task is solved
    9057             :             * Info<=0   an error occured:
    9058             :                         -4 means inconvergence of internal SVD
    9059             :                         -3 means inconsistent constraints
    9060             :     B   -   barycentric interpolant.
    9061             :     Rep -   report, same format as in LSFitLinearWC() subroutine.
    9062             :             Following fields are set:
    9063             :             * DBest         best value of the D parameter
    9064             :             * RMSError      rms error on the (X,Y).
    9065             :             * AvgError      average error on the (X,Y).
    9066             :             * AvgRelError   average relative error on the non-zero Y
    9067             :             * MaxError      maximum error
    9068             :                             NON-WEIGHTED ERRORS ARE CALCULATED
    9069             : 
    9070             :   -- ALGLIB PROJECT --
    9071             :      Copyright 18.08.2009 by Bochkanov Sergey
    9072             : *************************************************************************/
    9073           0 : 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, const xparams _xparams)
    9074             : {
    9075             :     jmp_buf _break_jump;
    9076             :     alglib_impl::ae_state _alglib_env_state;
    9077           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9078           0 :     if( setjmp(_break_jump) )
    9079             :     {
    9080             : #if !defined(AE_NO_EXCEPTIONS)
    9081           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9082             : #else
    9083             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    9084             :         return;
    9085             : #endif
    9086             :     }
    9087           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9088           0 :     if( _xparams.flags!=0x0 )
    9089           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9090           0 :     alglib_impl::barycentricfitfloaterhormann(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, &info, const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), const_cast<alglib_impl::barycentricfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9091           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9092           0 :     return;
    9093             : }
    9094             : 
    9095             : /*************************************************************************
    9096             : Weighted fitting by cubic  spline,  with constraints on function values or
    9097             : derivatives.
    9098             : 
    9099             : Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is  used to build
    9100             : basis functions. Basis functions are cubic splines with continuous  second
    9101             : derivatives  and  non-fixed first  derivatives  at  interval  ends.  Small
    9102             : regularizing term is used  when  solving  constrained  tasks  (to  improve
    9103             : stability).
    9104             : 
    9105             : Task is linear, so linear least squares solver is used. Complexity of this
    9106             : computational scheme is O(N*M^2), mostly dominated by least squares solver
    9107             : 
    9108             : SEE ALSO
    9109             :     Spline1DFitHermiteWC()  -   fitting by Hermite splines (more flexible,
    9110             :                                 less smooth)
    9111             :     Spline1DFitCubic()      -   "lightweight" fitting  by  cubic  splines,
    9112             :                                 without invididual weights and constraints
    9113             : 
    9114             :   ! COMMERCIAL EDITION OF ALGLIB:
    9115             :   !
    9116             :   ! Commercial Edition of ALGLIB includes following important improvements
    9117             :   ! of this function:
    9118             :   ! * high-performance native backend with same C# interface (C# version)
    9119             :   ! * multithreading support (C++ and C# versions)
    9120             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9121             :   !   (C++ and C# versions, x86/x64 platform)
    9122             :   !
    9123             :   ! We recommend you to read 'Working with commercial version' section  of
    9124             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9125             :   ! related features provided by commercial edition of ALGLIB.
    9126             : 
    9127             : INPUT PARAMETERS:
    9128             :     X   -   points, array[0..N-1].
    9129             :     Y   -   function values, array[0..N-1].
    9130             :     W   -   weights, array[0..N-1]
    9131             :             Each summand in square  sum  of  approximation deviations from
    9132             :             given  values  is  multiplied  by  the square of corresponding
    9133             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
    9134             :             task.
    9135             :     N   -   number of points (optional):
    9136             :             * N>0
    9137             :             * if given, only first N elements of X/Y/W are processed
    9138             :             * if not given, automatically determined from X/Y/W sizes
    9139             :     XC  -   points where spline values/derivatives are constrained,
    9140             :             array[0..K-1].
    9141             :     YC  -   values of constraints, array[0..K-1]
    9142             :     DC  -   array[0..K-1], types of constraints:
    9143             :             * DC[i]=0   means that S(XC[i])=YC[i]
    9144             :             * DC[i]=1   means that S'(XC[i])=YC[i]
    9145             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
    9146             :     K   -   number of constraints (optional):
    9147             :             * 0<=K<M.
    9148             :             * K=0 means no constraints (XC/YC/DC are not used)
    9149             :             * if given, only first K elements of XC/YC/DC are used
    9150             :             * if not given, automatically determined from XC/YC/DC
    9151             :     M   -   number of basis functions ( = number_of_nodes+2), M>=4.
    9152             : 
    9153             : OUTPUT PARAMETERS:
    9154             :     Info-   same format as in LSFitLinearWC() subroutine.
    9155             :             * Info>0    task is solved
    9156             :             * Info<=0   an error occured:
    9157             :                         -4 means inconvergence of internal SVD
    9158             :                         -3 means inconsistent constraints
    9159             :     S   -   spline interpolant.
    9160             :     Rep -   report, same format as in LSFitLinearWC() subroutine.
    9161             :             Following fields are set:
    9162             :             * RMSError      rms error on the (X,Y).
    9163             :             * AvgError      average error on the (X,Y).
    9164             :             * AvgRelError   average relative error on the non-zero Y
    9165             :             * MaxError      maximum error
    9166             :                             NON-WEIGHTED ERRORS ARE CALCULATED
    9167             : 
    9168             : IMPORTANT:
    9169             :     this subroitine doesn't calculate task's condition number for K<>0.
    9170             : 
    9171             : 
    9172             : ORDER OF POINTS
    9173             : 
    9174             : Subroutine automatically sorts points, so caller may pass unsorted array.
    9175             : 
    9176             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
    9177             : 
    9178             : Setting constraints can lead  to undesired  results,  like ill-conditioned
    9179             : behavior, or inconsistency being detected. From the other side,  it allows
    9180             : us to improve quality of the fit. Here we summarize  our  experience  with
    9181             : constrained regression splines:
    9182             : * excessive constraints can be inconsistent. Splines are  piecewise  cubic
    9183             :   functions, and it is easy to create an example, where  large  number  of
    9184             :   constraints  concentrated  in  small  area will result in inconsistency.
    9185             :   Just because spline is not flexible enough to satisfy all of  them.  And
    9186             :   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
    9187             :   consistent.
    9188             : * the more evenly constraints are spread across [min(x),max(x)],  the more
    9189             :   chances that they will be consistent
    9190             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
    9191             :   constraints will be consistent
    9192             : * in the general case, consistency of constraints IS NOT GUARANTEED.
    9193             : * in the several special cases, however, we CAN guarantee consistency.
    9194             : * one of this cases is constraints  on  the  function  values  AND/OR  its
    9195             :   derivatives at the interval boundaries.
    9196             : * another  special  case  is ONE constraint on the function value (OR, but
    9197             :   not AND, derivative) anywhere in the interval
    9198             : 
    9199             : Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
    9200             : can't solve your task without them. Anything beyond  special  cases  given
    9201             : above is not guaranteed and may result in inconsistency.
    9202             : 
    9203             : 
    9204             :   -- ALGLIB PROJECT --
    9205             :      Copyright 18.08.2009 by Bochkanov Sergey
    9206             : *************************************************************************/
    9207           0 : 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, const xparams _xparams)
    9208             : {
    9209             :     jmp_buf _break_jump;
    9210             :     alglib_impl::ae_state _alglib_env_state;
    9211           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9212           0 :     if( setjmp(_break_jump) )
    9213             :     {
    9214             : #if !defined(AE_NO_EXCEPTIONS)
    9215           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9216             : #else
    9217             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    9218             :         return;
    9219             : #endif
    9220             :     }
    9221           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9222           0 :     if( _xparams.flags!=0x0 )
    9223           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9224           0 :     alglib_impl::spline1dfitcubicwc(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(xc.c_ptr()), const_cast<alglib_impl::ae_vector*>(yc.c_ptr()), const_cast<alglib_impl::ae_vector*>(dc.c_ptr()), k, m, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9225           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9226           0 :     return;
    9227             : }
    9228             : 
    9229             : /*************************************************************************
    9230             : Weighted fitting by cubic  spline,  with constraints on function values or
    9231             : derivatives.
    9232             : 
    9233             : Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is  used to build
    9234             : basis functions. Basis functions are cubic splines with continuous  second
    9235             : derivatives  and  non-fixed first  derivatives  at  interval  ends.  Small
    9236             : regularizing term is used  when  solving  constrained  tasks  (to  improve
    9237             : stability).
    9238             : 
    9239             : Task is linear, so linear least squares solver is used. Complexity of this
    9240             : computational scheme is O(N*M^2), mostly dominated by least squares solver
    9241             : 
    9242             : SEE ALSO
    9243             :     Spline1DFitHermiteWC()  -   fitting by Hermite splines (more flexible,
    9244             :                                 less smooth)
    9245             :     Spline1DFitCubic()      -   "lightweight" fitting  by  cubic  splines,
    9246             :                                 without invididual weights and constraints
    9247             : 
    9248             :   ! COMMERCIAL EDITION OF ALGLIB:
    9249             :   !
    9250             :   ! Commercial Edition of ALGLIB includes following important improvements
    9251             :   ! of this function:
    9252             :   ! * high-performance native backend with same C# interface (C# version)
    9253             :   ! * multithreading support (C++ and C# versions)
    9254             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9255             :   !   (C++ and C# versions, x86/x64 platform)
    9256             :   !
    9257             :   ! We recommend you to read 'Working with commercial version' section  of
    9258             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9259             :   ! related features provided by commercial edition of ALGLIB.
    9260             : 
    9261             : INPUT PARAMETERS:
    9262             :     X   -   points, array[0..N-1].
    9263             :     Y   -   function values, array[0..N-1].
    9264             :     W   -   weights, array[0..N-1]
    9265             :             Each summand in square  sum  of  approximation deviations from
    9266             :             given  values  is  multiplied  by  the square of corresponding
    9267             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
    9268             :             task.
    9269             :     N   -   number of points (optional):
    9270             :             * N>0
    9271             :             * if given, only first N elements of X/Y/W are processed
    9272             :             * if not given, automatically determined from X/Y/W sizes
    9273             :     XC  -   points where spline values/derivatives are constrained,
    9274             :             array[0..K-1].
    9275             :     YC  -   values of constraints, array[0..K-1]
    9276             :     DC  -   array[0..K-1], types of constraints:
    9277             :             * DC[i]=0   means that S(XC[i])=YC[i]
    9278             :             * DC[i]=1   means that S'(XC[i])=YC[i]
    9279             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
    9280             :     K   -   number of constraints (optional):
    9281             :             * 0<=K<M.
    9282             :             * K=0 means no constraints (XC/YC/DC are not used)
    9283             :             * if given, only first K elements of XC/YC/DC are used
    9284             :             * if not given, automatically determined from XC/YC/DC
    9285             :     M   -   number of basis functions ( = number_of_nodes+2), M>=4.
    9286             : 
    9287             : OUTPUT PARAMETERS:
    9288             :     Info-   same format as in LSFitLinearWC() subroutine.
    9289             :             * Info>0    task is solved
    9290             :             * Info<=0   an error occured:
    9291             :                         -4 means inconvergence of internal SVD
    9292             :                         -3 means inconsistent constraints
    9293             :     S   -   spline interpolant.
    9294             :     Rep -   report, same format as in LSFitLinearWC() subroutine.
    9295             :             Following fields are set:
    9296             :             * RMSError      rms error on the (X,Y).
    9297             :             * AvgError      average error on the (X,Y).
    9298             :             * AvgRelError   average relative error on the non-zero Y
    9299             :             * MaxError      maximum error
    9300             :                             NON-WEIGHTED ERRORS ARE CALCULATED
    9301             : 
    9302             : IMPORTANT:
    9303             :     this subroitine doesn't calculate task's condition number for K<>0.
    9304             : 
    9305             : 
    9306             : ORDER OF POINTS
    9307             : 
    9308             : Subroutine automatically sorts points, so caller may pass unsorted array.
    9309             : 
    9310             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
    9311             : 
    9312             : Setting constraints can lead  to undesired  results,  like ill-conditioned
    9313             : behavior, or inconsistency being detected. From the other side,  it allows
    9314             : us to improve quality of the fit. Here we summarize  our  experience  with
    9315             : constrained regression splines:
    9316             : * excessive constraints can be inconsistent. Splines are  piecewise  cubic
    9317             :   functions, and it is easy to create an example, where  large  number  of
    9318             :   constraints  concentrated  in  small  area will result in inconsistency.
    9319             :   Just because spline is not flexible enough to satisfy all of  them.  And
    9320             :   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
    9321             :   consistent.
    9322             : * the more evenly constraints are spread across [min(x),max(x)],  the more
    9323             :   chances that they will be consistent
    9324             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
    9325             :   constraints will be consistent
    9326             : * in the general case, consistency of constraints IS NOT GUARANTEED.
    9327             : * in the several special cases, however, we CAN guarantee consistency.
    9328             : * one of this cases is constraints  on  the  function  values  AND/OR  its
    9329             :   derivatives at the interval boundaries.
    9330             : * another  special  case  is ONE constraint on the function value (OR, but
    9331             :   not AND, derivative) anywhere in the interval
    9332             : 
    9333             : Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
    9334             : can't solve your task without them. Anything beyond  special  cases  given
    9335             : above is not guaranteed and may result in inconsistency.
    9336             : 
    9337             : 
    9338             :   -- ALGLIB PROJECT --
    9339             :      Copyright 18.08.2009 by Bochkanov Sergey
    9340             : *************************************************************************/
    9341             : #if !defined(AE_NO_EXCEPTIONS)
    9342           0 : 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, const xparams _xparams)
    9343             : {
    9344             :     jmp_buf _break_jump;
    9345             :     alglib_impl::ae_state _alglib_env_state;    
    9346             :     ae_int_t n;
    9347             :     ae_int_t k;
    9348           0 :     if( (x.length()!=y.length()) || (x.length()!=w.length()))
    9349           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size");
    9350           0 :     if( (xc.length()!=yc.length()) || (xc.length()!=dc.length()))
    9351           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size");
    9352           0 :     n = x.length();
    9353           0 :     k = xc.length();
    9354           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9355           0 :     if( setjmp(_break_jump) )
    9356           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9357           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9358           0 :     if( _xparams.flags!=0x0 )
    9359           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9360           0 :     alglib_impl::spline1dfitcubicwc(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(xc.c_ptr()), const_cast<alglib_impl::ae_vector*>(yc.c_ptr()), const_cast<alglib_impl::ae_vector*>(dc.c_ptr()), k, m, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9361             : 
    9362           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9363           0 :     return;
    9364             : }
    9365             : #endif
    9366             : 
    9367             : /*************************************************************************
    9368             : Weighted  fitting  by Hermite spline,  with constraints on function values
    9369             : or first derivatives.
    9370             : 
    9371             : Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is  used  to  build
    9372             : basis functions. Basis functions are Hermite splines.  Small  regularizing
    9373             : term is used when solving constrained tasks (to improve stability).
    9374             : 
    9375             : Task is linear, so linear least squares solver is used. Complexity of this
    9376             : computational scheme is O(N*M^2), mostly dominated by least squares solver
    9377             : 
    9378             : SEE ALSO
    9379             :     Spline1DFitCubicWC()    -   fitting by Cubic splines (less flexible,
    9380             :                                 more smooth)
    9381             :     Spline1DFitHermite()    -   "lightweight" Hermite fitting, without
    9382             :                                 invididual weights and constraints
    9383             : 
    9384             :   ! COMMERCIAL EDITION OF ALGLIB:
    9385             :   !
    9386             :   ! Commercial Edition of ALGLIB includes following important improvements
    9387             :   ! of this function:
    9388             :   ! * high-performance native backend with same C# interface (C# version)
    9389             :   ! * multithreading support (C++ and C# versions)
    9390             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9391             :   !   (C++ and C# versions, x86/x64 platform)
    9392             :   !
    9393             :   ! We recommend you to read 'Working with commercial version' section  of
    9394             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9395             :   ! related features provided by commercial edition of ALGLIB.
    9396             : 
    9397             : INPUT PARAMETERS:
    9398             :     X   -   points, array[0..N-1].
    9399             :     Y   -   function values, array[0..N-1].
    9400             :     W   -   weights, array[0..N-1]
    9401             :             Each summand in square  sum  of  approximation deviations from
    9402             :             given  values  is  multiplied  by  the square of corresponding
    9403             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
    9404             :             task.
    9405             :     N   -   number of points (optional):
    9406             :             * N>0
    9407             :             * if given, only first N elements of X/Y/W are processed
    9408             :             * if not given, automatically determined from X/Y/W sizes
    9409             :     XC  -   points where spline values/derivatives are constrained,
    9410             :             array[0..K-1].
    9411             :     YC  -   values of constraints, array[0..K-1]
    9412             :     DC  -   array[0..K-1], types of constraints:
    9413             :             * DC[i]=0   means that S(XC[i])=YC[i]
    9414             :             * DC[i]=1   means that S'(XC[i])=YC[i]
    9415             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
    9416             :     K   -   number of constraints (optional):
    9417             :             * 0<=K<M.
    9418             :             * K=0 means no constraints (XC/YC/DC are not used)
    9419             :             * if given, only first K elements of XC/YC/DC are used
    9420             :             * if not given, automatically determined from XC/YC/DC
    9421             :     M   -   number of basis functions (= 2 * number of nodes),
    9422             :             M>=4,
    9423             :             M IS EVEN!
    9424             : 
    9425             : OUTPUT PARAMETERS:
    9426             :     Info-   same format as in LSFitLinearW() subroutine:
    9427             :             * Info>0    task is solved
    9428             :             * Info<=0   an error occured:
    9429             :                         -4 means inconvergence of internal SVD
    9430             :                         -3 means inconsistent constraints
    9431             :                         -2 means odd M was passed (which is not supported)
    9432             :                         -1 means another errors in parameters passed
    9433             :                            (N<=0, for example)
    9434             :     S   -   spline interpolant.
    9435             :     Rep -   report, same format as in LSFitLinearW() subroutine.
    9436             :             Following fields are set:
    9437             :             * RMSError      rms error on the (X,Y).
    9438             :             * AvgError      average error on the (X,Y).
    9439             :             * AvgRelError   average relative error on the non-zero Y
    9440             :             * MaxError      maximum error
    9441             :                             NON-WEIGHTED ERRORS ARE CALCULATED
    9442             : 
    9443             : IMPORTANT:
    9444             :     this subroitine doesn't calculate task's condition number for K<>0.
    9445             : 
    9446             : IMPORTANT:
    9447             :     this subroitine supports only even M's
    9448             : 
    9449             : 
    9450             : ORDER OF POINTS
    9451             : 
    9452             : Subroutine automatically sorts points, so caller may pass unsorted array.
    9453             : 
    9454             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
    9455             : 
    9456             : Setting constraints can lead  to undesired  results,  like ill-conditioned
    9457             : behavior, or inconsistency being detected. From the other side,  it allows
    9458             : us to improve quality of the fit. Here we summarize  our  experience  with
    9459             : constrained regression splines:
    9460             : * excessive constraints can be inconsistent. Splines are  piecewise  cubic
    9461             :   functions, and it is easy to create an example, where  large  number  of
    9462             :   constraints  concentrated  in  small  area will result in inconsistency.
    9463             :   Just because spline is not flexible enough to satisfy all of  them.  And
    9464             :   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
    9465             :   consistent.
    9466             : * the more evenly constraints are spread across [min(x),max(x)],  the more
    9467             :   chances that they will be consistent
    9468             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
    9469             :   constraints will be consistent
    9470             : * in the general case, consistency of constraints is NOT GUARANTEED.
    9471             : * in the several special cases, however, we can guarantee consistency.
    9472             : * one of this cases is  M>=4  and   constraints  on   the  function  value
    9473             :   (AND/OR its derivative) at the interval boundaries.
    9474             : * another special case is M>=4  and  ONE  constraint on the function value
    9475             :   (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)]
    9476             : 
    9477             : Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
    9478             : can't solve your task without them. Anything beyond  special  cases  given
    9479             : above is not guaranteed and may result in inconsistency.
    9480             : 
    9481             :   -- ALGLIB PROJECT --
    9482             :      Copyright 18.08.2009 by Bochkanov Sergey
    9483             : *************************************************************************/
    9484           0 : 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, const xparams _xparams)
    9485             : {
    9486             :     jmp_buf _break_jump;
    9487             :     alglib_impl::ae_state _alglib_env_state;
    9488           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9489           0 :     if( setjmp(_break_jump) )
    9490             :     {
    9491             : #if !defined(AE_NO_EXCEPTIONS)
    9492           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9493             : #else
    9494             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    9495             :         return;
    9496             : #endif
    9497             :     }
    9498           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9499           0 :     if( _xparams.flags!=0x0 )
    9500           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9501           0 :     alglib_impl::spline1dfithermitewc(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(xc.c_ptr()), const_cast<alglib_impl::ae_vector*>(yc.c_ptr()), const_cast<alglib_impl::ae_vector*>(dc.c_ptr()), k, m, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9502           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9503           0 :     return;
    9504             : }
    9505             : 
    9506             : /*************************************************************************
    9507             : Weighted  fitting  by Hermite spline,  with constraints on function values
    9508             : or first derivatives.
    9509             : 
    9510             : Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is  used  to  build
    9511             : basis functions. Basis functions are Hermite splines.  Small  regularizing
    9512             : term is used when solving constrained tasks (to improve stability).
    9513             : 
    9514             : Task is linear, so linear least squares solver is used. Complexity of this
    9515             : computational scheme is O(N*M^2), mostly dominated by least squares solver
    9516             : 
    9517             : SEE ALSO
    9518             :     Spline1DFitCubicWC()    -   fitting by Cubic splines (less flexible,
    9519             :                                 more smooth)
    9520             :     Spline1DFitHermite()    -   "lightweight" Hermite fitting, without
    9521             :                                 invididual weights and constraints
    9522             : 
    9523             :   ! COMMERCIAL EDITION OF ALGLIB:
    9524             :   !
    9525             :   ! Commercial Edition of ALGLIB includes following important improvements
    9526             :   ! of this function:
    9527             :   ! * high-performance native backend with same C# interface (C# version)
    9528             :   ! * multithreading support (C++ and C# versions)
    9529             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9530             :   !   (C++ and C# versions, x86/x64 platform)
    9531             :   !
    9532             :   ! We recommend you to read 'Working with commercial version' section  of
    9533             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9534             :   ! related features provided by commercial edition of ALGLIB.
    9535             : 
    9536             : INPUT PARAMETERS:
    9537             :     X   -   points, array[0..N-1].
    9538             :     Y   -   function values, array[0..N-1].
    9539             :     W   -   weights, array[0..N-1]
    9540             :             Each summand in square  sum  of  approximation deviations from
    9541             :             given  values  is  multiplied  by  the square of corresponding
    9542             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
    9543             :             task.
    9544             :     N   -   number of points (optional):
    9545             :             * N>0
    9546             :             * if given, only first N elements of X/Y/W are processed
    9547             :             * if not given, automatically determined from X/Y/W sizes
    9548             :     XC  -   points where spline values/derivatives are constrained,
    9549             :             array[0..K-1].
    9550             :     YC  -   values of constraints, array[0..K-1]
    9551             :     DC  -   array[0..K-1], types of constraints:
    9552             :             * DC[i]=0   means that S(XC[i])=YC[i]
    9553             :             * DC[i]=1   means that S'(XC[i])=YC[i]
    9554             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
    9555             :     K   -   number of constraints (optional):
    9556             :             * 0<=K<M.
    9557             :             * K=0 means no constraints (XC/YC/DC are not used)
    9558             :             * if given, only first K elements of XC/YC/DC are used
    9559             :             * if not given, automatically determined from XC/YC/DC
    9560             :     M   -   number of basis functions (= 2 * number of nodes),
    9561             :             M>=4,
    9562             :             M IS EVEN!
    9563             : 
    9564             : OUTPUT PARAMETERS:
    9565             :     Info-   same format as in LSFitLinearW() subroutine:
    9566             :             * Info>0    task is solved
    9567             :             * Info<=0   an error occured:
    9568             :                         -4 means inconvergence of internal SVD
    9569             :                         -3 means inconsistent constraints
    9570             :                         -2 means odd M was passed (which is not supported)
    9571             :                         -1 means another errors in parameters passed
    9572             :                            (N<=0, for example)
    9573             :     S   -   spline interpolant.
    9574             :     Rep -   report, same format as in LSFitLinearW() subroutine.
    9575             :             Following fields are set:
    9576             :             * RMSError      rms error on the (X,Y).
    9577             :             * AvgError      average error on the (X,Y).
    9578             :             * AvgRelError   average relative error on the non-zero Y
    9579             :             * MaxError      maximum error
    9580             :                             NON-WEIGHTED ERRORS ARE CALCULATED
    9581             : 
    9582             : IMPORTANT:
    9583             :     this subroitine doesn't calculate task's condition number for K<>0.
    9584             : 
    9585             : IMPORTANT:
    9586             :     this subroitine supports only even M's
    9587             : 
    9588             : 
    9589             : ORDER OF POINTS
    9590             : 
    9591             : Subroutine automatically sorts points, so caller may pass unsorted array.
    9592             : 
    9593             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
    9594             : 
    9595             : Setting constraints can lead  to undesired  results,  like ill-conditioned
    9596             : behavior, or inconsistency being detected. From the other side,  it allows
    9597             : us to improve quality of the fit. Here we summarize  our  experience  with
    9598             : constrained regression splines:
    9599             : * excessive constraints can be inconsistent. Splines are  piecewise  cubic
    9600             :   functions, and it is easy to create an example, where  large  number  of
    9601             :   constraints  concentrated  in  small  area will result in inconsistency.
    9602             :   Just because spline is not flexible enough to satisfy all of  them.  And
    9603             :   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
    9604             :   consistent.
    9605             : * the more evenly constraints are spread across [min(x),max(x)],  the more
    9606             :   chances that they will be consistent
    9607             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
    9608             :   constraints will be consistent
    9609             : * in the general case, consistency of constraints is NOT GUARANTEED.
    9610             : * in the several special cases, however, we can guarantee consistency.
    9611             : * one of this cases is  M>=4  and   constraints  on   the  function  value
    9612             :   (AND/OR its derivative) at the interval boundaries.
    9613             : * another special case is M>=4  and  ONE  constraint on the function value
    9614             :   (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)]
    9615             : 
    9616             : Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
    9617             : can't solve your task without them. Anything beyond  special  cases  given
    9618             : above is not guaranteed and may result in inconsistency.
    9619             : 
    9620             :   -- ALGLIB PROJECT --
    9621             :      Copyright 18.08.2009 by Bochkanov Sergey
    9622             : *************************************************************************/
    9623             : #if !defined(AE_NO_EXCEPTIONS)
    9624           0 : 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, const xparams _xparams)
    9625             : {
    9626             :     jmp_buf _break_jump;
    9627             :     alglib_impl::ae_state _alglib_env_state;    
    9628             :     ae_int_t n;
    9629             :     ae_int_t k;
    9630           0 :     if( (x.length()!=y.length()) || (x.length()!=w.length()))
    9631           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size");
    9632           0 :     if( (xc.length()!=yc.length()) || (xc.length()!=dc.length()))
    9633           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size");
    9634           0 :     n = x.length();
    9635           0 :     k = xc.length();
    9636           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9637           0 :     if( setjmp(_break_jump) )
    9638           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9639           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9640           0 :     if( _xparams.flags!=0x0 )
    9641           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9642           0 :     alglib_impl::spline1dfithermitewc(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(xc.c_ptr()), const_cast<alglib_impl::ae_vector*>(yc.c_ptr()), const_cast<alglib_impl::ae_vector*>(dc.c_ptr()), k, m, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9643             : 
    9644           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9645           0 :     return;
    9646             : }
    9647             : #endif
    9648             : 
    9649             : /*************************************************************************
    9650             : Least squares fitting by cubic spline.
    9651             : 
    9652             : This subroutine is "lightweight" alternative for more complex and feature-
    9653             : rich Spline1DFitCubicWC().  See  Spline1DFitCubicWC() for more information
    9654             : about subroutine parameters (we don't duplicate it here because of length)
    9655             : 
    9656             :   ! COMMERCIAL EDITION OF ALGLIB:
    9657             :   !
    9658             :   ! Commercial Edition of ALGLIB includes following important improvements
    9659             :   ! of this function:
    9660             :   ! * high-performance native backend with same C# interface (C# version)
    9661             :   ! * multithreading support (C++ and C# versions)
    9662             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9663             :   !   (C++ and C# versions, x86/x64 platform)
    9664             :   !
    9665             :   ! We recommend you to read 'Working with commercial version' section  of
    9666             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9667             :   ! related features provided by commercial edition of ALGLIB.
    9668             : 
    9669             :   -- ALGLIB PROJECT --
    9670             :      Copyright 18.08.2009 by Bochkanov Sergey
    9671             : *************************************************************************/
    9672           0 : 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, const xparams _xparams)
    9673             : {
    9674             :     jmp_buf _break_jump;
    9675             :     alglib_impl::ae_state _alglib_env_state;
    9676           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9677           0 :     if( setjmp(_break_jump) )
    9678             :     {
    9679             : #if !defined(AE_NO_EXCEPTIONS)
    9680           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9681             : #else
    9682             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    9683             :         return;
    9684             : #endif
    9685             :     }
    9686           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9687           0 :     if( _xparams.flags!=0x0 )
    9688           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9689           0 :     alglib_impl::spline1dfitcubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9690           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9691           0 :     return;
    9692             : }
    9693             : 
    9694             : /*************************************************************************
    9695             : Least squares fitting by cubic spline.
    9696             : 
    9697             : This subroutine is "lightweight" alternative for more complex and feature-
    9698             : rich Spline1DFitCubicWC().  See  Spline1DFitCubicWC() for more information
    9699             : about subroutine parameters (we don't duplicate it here because of length)
    9700             : 
    9701             :   ! COMMERCIAL EDITION OF ALGLIB:
    9702             :   !
    9703             :   ! Commercial Edition of ALGLIB includes following important improvements
    9704             :   ! of this function:
    9705             :   ! * high-performance native backend with same C# interface (C# version)
    9706             :   ! * multithreading support (C++ and C# versions)
    9707             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9708             :   !   (C++ and C# versions, x86/x64 platform)
    9709             :   !
    9710             :   ! We recommend you to read 'Working with commercial version' section  of
    9711             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9712             :   ! related features provided by commercial edition of ALGLIB.
    9713             : 
    9714             :   -- ALGLIB PROJECT --
    9715             :      Copyright 18.08.2009 by Bochkanov Sergey
    9716             : *************************************************************************/
    9717             : #if !defined(AE_NO_EXCEPTIONS)
    9718           0 : 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, const xparams _xparams)
    9719             : {
    9720             :     jmp_buf _break_jump;
    9721             :     alglib_impl::ae_state _alglib_env_state;    
    9722             :     ae_int_t n;
    9723           0 :     if( (x.length()!=y.length()))
    9724           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitcubic': looks like one of arguments has wrong size");
    9725           0 :     n = x.length();
    9726           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9727           0 :     if( setjmp(_break_jump) )
    9728           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9729           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9730           0 :     if( _xparams.flags!=0x0 )
    9731           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9732           0 :     alglib_impl::spline1dfitcubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9733             : 
    9734           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9735           0 :     return;
    9736             : }
    9737             : #endif
    9738             : 
    9739             : /*************************************************************************
    9740             : Least squares fitting by Hermite spline.
    9741             : 
    9742             : This subroutine is "lightweight" alternative for more complex and feature-
    9743             : rich Spline1DFitHermiteWC().  See Spline1DFitHermiteWC()  description  for
    9744             : more information about subroutine parameters (we don't duplicate  it  here
    9745             : because of length).
    9746             : 
    9747             :   ! COMMERCIAL EDITION OF ALGLIB:
    9748             :   !
    9749             :   ! Commercial Edition of ALGLIB includes following important improvements
    9750             :   ! of this function:
    9751             :   ! * high-performance native backend with same C# interface (C# version)
    9752             :   ! * multithreading support (C++ and C# versions)
    9753             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9754             :   !   (C++ and C# versions, x86/x64 platform)
    9755             :   !
    9756             :   ! We recommend you to read 'Working with commercial version' section  of
    9757             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9758             :   ! related features provided by commercial edition of ALGLIB.
    9759             : 
    9760             :   -- ALGLIB PROJECT --
    9761             :      Copyright 18.08.2009 by Bochkanov Sergey
    9762             : *************************************************************************/
    9763           0 : 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, const xparams _xparams)
    9764             : {
    9765             :     jmp_buf _break_jump;
    9766             :     alglib_impl::ae_state _alglib_env_state;
    9767           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9768           0 :     if( setjmp(_break_jump) )
    9769             :     {
    9770             : #if !defined(AE_NO_EXCEPTIONS)
    9771           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9772             : #else
    9773             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    9774             :         return;
    9775             : #endif
    9776             :     }
    9777           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9778           0 :     if( _xparams.flags!=0x0 )
    9779           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9780           0 :     alglib_impl::spline1dfithermite(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9781           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9782           0 :     return;
    9783             : }
    9784             : 
    9785             : /*************************************************************************
    9786             : Least squares fitting by Hermite spline.
    9787             : 
    9788             : This subroutine is "lightweight" alternative for more complex and feature-
    9789             : rich Spline1DFitHermiteWC().  See Spline1DFitHermiteWC()  description  for
    9790             : more information about subroutine parameters (we don't duplicate  it  here
    9791             : because of length).
    9792             : 
    9793             :   ! COMMERCIAL EDITION OF ALGLIB:
    9794             :   !
    9795             :   ! Commercial Edition of ALGLIB includes following important improvements
    9796             :   ! of this function:
    9797             :   ! * high-performance native backend with same C# interface (C# version)
    9798             :   ! * multithreading support (C++ and C# versions)
    9799             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9800             :   !   (C++ and C# versions, x86/x64 platform)
    9801             :   !
    9802             :   ! We recommend you to read 'Working with commercial version' section  of
    9803             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9804             :   ! related features provided by commercial edition of ALGLIB.
    9805             : 
    9806             :   -- ALGLIB PROJECT --
    9807             :      Copyright 18.08.2009 by Bochkanov Sergey
    9808             : *************************************************************************/
    9809             : #if !defined(AE_NO_EXCEPTIONS)
    9810           0 : 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, const xparams _xparams)
    9811             : {
    9812             :     jmp_buf _break_jump;
    9813             :     alglib_impl::ae_state _alglib_env_state;    
    9814             :     ae_int_t n;
    9815           0 :     if( (x.length()!=y.length()))
    9816           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfithermite': looks like one of arguments has wrong size");
    9817           0 :     n = x.length();
    9818           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9819           0 :     if( setjmp(_break_jump) )
    9820           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9821           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9822           0 :     if( _xparams.flags!=0x0 )
    9823           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9824           0 :     alglib_impl::spline1dfithermite(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9825             : 
    9826           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9827           0 :     return;
    9828             : }
    9829             : #endif
    9830             : 
    9831             : /*************************************************************************
    9832             : Weighted linear least squares fitting.
    9833             : 
    9834             : QR decomposition is used to reduce task to MxM, then triangular solver  or
    9835             : SVD-based solver is used depending on condition number of the  system.  It
    9836             : allows to maximize speed and retain decent accuracy.
    9837             : 
    9838             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
    9839             :            convenient to use PolynomialFit() function. This function gives
    9840             :            best  results  on  polynomial  problems  and  solves  numerical
    9841             :            stability  issues  which  arise  when   you   fit   high-degree
    9842             :            polynomials to your data.
    9843             : 
    9844             :   ! COMMERCIAL EDITION OF ALGLIB:
    9845             :   !
    9846             :   ! Commercial Edition of ALGLIB includes following important improvements
    9847             :   ! of this function:
    9848             :   ! * high-performance native backend with same C# interface (C# version)
    9849             :   ! * multithreading support (C++ and C# versions)
    9850             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9851             :   !   (C++ and C# versions, x86/x64 platform)
    9852             :   !
    9853             :   ! We recommend you to read 'Working with commercial version' section  of
    9854             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9855             :   ! related features provided by commercial edition of ALGLIB.
    9856             : 
    9857             : INPUT PARAMETERS:
    9858             :     Y       -   array[0..N-1] Function values in  N  points.
    9859             :     W       -   array[0..N-1]  Weights  corresponding to function  values.
    9860             :                 Each summand in square  sum  of  approximation  deviations
    9861             :                 from  given  values  is  multiplied  by  the   square   of
    9862             :                 corresponding weight.
    9863             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
    9864             :                 FMatrix[I, J] - value of J-th basis function in I-th point.
    9865             :     N       -   number of points used. N>=1.
    9866             :     M       -   number of basis functions, M>=1.
    9867             : 
    9868             : OUTPUT PARAMETERS:
    9869             :     Info    -   error code:
    9870             :                 * -4    internal SVD decomposition subroutine failed (very
    9871             :                         rare and for degenerate systems only)
    9872             :                 * -1    incorrect N/M were specified
    9873             :                 *  1    task is solved
    9874             :     C       -   decomposition coefficients, array[0..M-1]
    9875             :     Rep     -   fitting report. Following fields are set:
    9876             :                 * Rep.TaskRCond     reciprocal of condition number
    9877             :                 * R2                non-adjusted coefficient of determination
    9878             :                                     (non-weighted)
    9879             :                 * RMSError          rms error on the (X,Y).
    9880             :                 * AvgError          average error on the (X,Y).
    9881             :                 * AvgRelError       average relative error on the non-zero Y
    9882             :                 * MaxError          maximum error
    9883             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
    9884             : 
    9885             : ERRORS IN PARAMETERS
    9886             : 
    9887             : This  solver  also  calculates different kinds of errors in parameters and
    9888             : fills corresponding fields of report:
    9889             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
    9890             : * Rep.ErrPar        errors in parameters, array[K],
    9891             :                     errpar = sqrt(diag(CovPar))
    9892             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
    9893             :                     best-fit curve from "ideal" best-fit curve built  with
    9894             :                     infinite number of samples, array[N].
    9895             :                     errcurve = sqrt(diag(F*CovPar*F')),
    9896             :                     where F is functions matrix.
    9897             : * Rep.Noise         vector of per-point estimates of noise, array[N]
    9898             : 
    9899             : NOTE:       noise in the data is estimated as follows:
    9900             :             * for fitting without user-supplied  weights  all  points  are
    9901             :               assumed to have same level of noise, which is estimated from
    9902             :               the data
    9903             :             * for fitting with user-supplied weights we assume that  noise
    9904             :               level in I-th point is inversely proportional to Ith weight.
    9905             :               Coefficient of proportionality is estimated from the data.
    9906             : 
    9907             : NOTE:       we apply small amount of regularization when we invert squared
    9908             :             Jacobian and calculate covariance matrix. It  guarantees  that
    9909             :             algorithm won't divide by zero  during  inversion,  but  skews
    9910             :             error estimates a bit (fractional error is about 10^-9).
    9911             : 
    9912             :             However, we believe that this difference is insignificant  for
    9913             :             all practical purposes except for the situation when you  want
    9914             :             to compare ALGLIB results with "reference"  implementation  up
    9915             :             to the last significant digit.
    9916             : 
    9917             : NOTE:       covariance matrix is estimated using  correction  for  degrees
    9918             :             of freedom (covariances are divided by N-M instead of dividing
    9919             :             by N).
    9920             : 
    9921             :   -- ALGLIB --
    9922             :      Copyright 17.08.2009 by Bochkanov Sergey
    9923             : *************************************************************************/
    9924           0 : 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, const xparams _xparams)
    9925             : {
    9926             :     jmp_buf _break_jump;
    9927             :     alglib_impl::ae_state _alglib_env_state;
    9928           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
    9929           0 :     if( setjmp(_break_jump) )
    9930             :     {
    9931             : #if !defined(AE_NO_EXCEPTIONS)
    9932           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
    9933             : #else
    9934             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
    9935             :         return;
    9936             : #endif
    9937             :     }
    9938           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
    9939           0 :     if( _xparams.flags!=0x0 )
    9940           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
    9941           0 :     alglib_impl::lsfitlinearw(const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), const_cast<alglib_impl::ae_matrix*>(fmatrix.c_ptr()), n, m, &info, const_cast<alglib_impl::ae_vector*>(c.c_ptr()), const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
    9942           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
    9943           0 :     return;
    9944             : }
    9945             : 
    9946             : /*************************************************************************
    9947             : Weighted linear least squares fitting.
    9948             : 
    9949             : QR decomposition is used to reduce task to MxM, then triangular solver  or
    9950             : SVD-based solver is used depending on condition number of the  system.  It
    9951             : allows to maximize speed and retain decent accuracy.
    9952             : 
    9953             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
    9954             :            convenient to use PolynomialFit() function. This function gives
    9955             :            best  results  on  polynomial  problems  and  solves  numerical
    9956             :            stability  issues  which  arise  when   you   fit   high-degree
    9957             :            polynomials to your data.
    9958             : 
    9959             :   ! COMMERCIAL EDITION OF ALGLIB:
    9960             :   !
    9961             :   ! Commercial Edition of ALGLIB includes following important improvements
    9962             :   ! of this function:
    9963             :   ! * high-performance native backend with same C# interface (C# version)
    9964             :   ! * multithreading support (C++ and C# versions)
    9965             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
    9966             :   !   (C++ and C# versions, x86/x64 platform)
    9967             :   !
    9968             :   ! We recommend you to read 'Working with commercial version' section  of
    9969             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
    9970             :   ! related features provided by commercial edition of ALGLIB.
    9971             : 
    9972             : INPUT PARAMETERS:
    9973             :     Y       -   array[0..N-1] Function values in  N  points.
    9974             :     W       -   array[0..N-1]  Weights  corresponding to function  values.
    9975             :                 Each summand in square  sum  of  approximation  deviations
    9976             :                 from  given  values  is  multiplied  by  the   square   of
    9977             :                 corresponding weight.
    9978             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
    9979             :                 FMatrix[I, J] - value of J-th basis function in I-th point.
    9980             :     N       -   number of points used. N>=1.
    9981             :     M       -   number of basis functions, M>=1.
    9982             : 
    9983             : OUTPUT PARAMETERS:
    9984             :     Info    -   error code:
    9985             :                 * -4    internal SVD decomposition subroutine failed (very
    9986             :                         rare and for degenerate systems only)
    9987             :                 * -1    incorrect N/M were specified
    9988             :                 *  1    task is solved
    9989             :     C       -   decomposition coefficients, array[0..M-1]
    9990             :     Rep     -   fitting report. Following fields are set:
    9991             :                 * Rep.TaskRCond     reciprocal of condition number
    9992             :                 * R2                non-adjusted coefficient of determination
    9993             :                                     (non-weighted)
    9994             :                 * RMSError          rms error on the (X,Y).
    9995             :                 * AvgError          average error on the (X,Y).
    9996             :                 * AvgRelError       average relative error on the non-zero Y
    9997             :                 * MaxError          maximum error
    9998             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
    9999             : 
   10000             : ERRORS IN PARAMETERS
   10001             : 
   10002             : This  solver  also  calculates different kinds of errors in parameters and
   10003             : fills corresponding fields of report:
   10004             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   10005             : * Rep.ErrPar        errors in parameters, array[K],
   10006             :                     errpar = sqrt(diag(CovPar))
   10007             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   10008             :                     best-fit curve from "ideal" best-fit curve built  with
   10009             :                     infinite number of samples, array[N].
   10010             :                     errcurve = sqrt(diag(F*CovPar*F')),
   10011             :                     where F is functions matrix.
   10012             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   10013             : 
   10014             : NOTE:       noise in the data is estimated as follows:
   10015             :             * for fitting without user-supplied  weights  all  points  are
   10016             :               assumed to have same level of noise, which is estimated from
   10017             :               the data
   10018             :             * for fitting with user-supplied weights we assume that  noise
   10019             :               level in I-th point is inversely proportional to Ith weight.
   10020             :               Coefficient of proportionality is estimated from the data.
   10021             : 
   10022             : NOTE:       we apply small amount of regularization when we invert squared
   10023             :             Jacobian and calculate covariance matrix. It  guarantees  that
   10024             :             algorithm won't divide by zero  during  inversion,  but  skews
   10025             :             error estimates a bit (fractional error is about 10^-9).
   10026             : 
   10027             :             However, we believe that this difference is insignificant  for
   10028             :             all practical purposes except for the situation when you  want
   10029             :             to compare ALGLIB results with "reference"  implementation  up
   10030             :             to the last significant digit.
   10031             : 
   10032             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   10033             :             of freedom (covariances are divided by N-M instead of dividing
   10034             :             by N).
   10035             : 
   10036             :   -- ALGLIB --
   10037             :      Copyright 17.08.2009 by Bochkanov Sergey
   10038             : *************************************************************************/
   10039             : #if !defined(AE_NO_EXCEPTIONS)
   10040           0 : 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, const xparams _xparams)
   10041             : {
   10042             :     jmp_buf _break_jump;
   10043             :     alglib_impl::ae_state _alglib_env_state;    
   10044             :     ae_int_t n;
   10045             :     ae_int_t m;
   10046           0 :     if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows()))
   10047           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearw': looks like one of arguments has wrong size");
   10048           0 :     n = y.length();
   10049           0 :     m = fmatrix.cols();
   10050           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   10051           0 :     if( setjmp(_break_jump) )
   10052           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   10053           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   10054           0 :     if( _xparams.flags!=0x0 )
   10055           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   10056           0 :     alglib_impl::lsfitlinearw(const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), const_cast<alglib_impl::ae_matrix*>(fmatrix.c_ptr()), n, m, &info, const_cast<alglib_impl::ae_vector*>(c.c_ptr()), const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
   10057             : 
   10058           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   10059           0 :     return;
   10060             : }
   10061             : #endif
   10062             : 
   10063             : /*************************************************************************
   10064             : Weighted constained linear least squares fitting.
   10065             : 
   10066             : This  is  variation  of LSFitLinearW(), which searchs for min|A*x=b| given
   10067             : that  K  additional  constaints  C*x=bc are satisfied. It reduces original
   10068             : task to modified one: min|B*y-d| WITHOUT constraints,  then LSFitLinearW()
   10069             : is called.
   10070             : 
   10071             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
   10072             :            convenient to use PolynomialFit() function. This function gives
   10073             :            best  results  on  polynomial  problems  and  solves  numerical
   10074             :            stability  issues  which  arise  when   you   fit   high-degree
   10075             :            polynomials to your data.
   10076             : 
   10077             :   ! COMMERCIAL EDITION OF ALGLIB:
   10078             :   !
   10079             :   ! Commercial Edition of ALGLIB includes following important improvements
   10080             :   ! of this function:
   10081             :   ! * high-performance native backend with same C# interface (C# version)
   10082             :   ! * multithreading support (C++ and C# versions)
   10083             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   10084             :   !   (C++ and C# versions, x86/x64 platform)
   10085             :   !
   10086             :   ! We recommend you to read 'Working with commercial version' section  of
   10087             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   10088             :   ! related features provided by commercial edition of ALGLIB.
   10089             : 
   10090             : INPUT PARAMETERS:
   10091             :     Y       -   array[0..N-1] Function values in  N  points.
   10092             :     W       -   array[0..N-1]  Weights  corresponding to function  values.
   10093             :                 Each summand in square  sum  of  approximation  deviations
   10094             :                 from  given  values  is  multiplied  by  the   square   of
   10095             :                 corresponding weight.
   10096             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
   10097             :                 FMatrix[I,J] - value of J-th basis function in I-th point.
   10098             :     CMatrix -   a table of constaints, array[0..K-1,0..M].
   10099             :                 I-th row of CMatrix corresponds to I-th linear constraint:
   10100             :                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
   10101             :     N       -   number of points used. N>=1.
   10102             :     M       -   number of basis functions, M>=1.
   10103             :     K       -   number of constraints, 0 <= K < M
   10104             :                 K=0 corresponds to absence of constraints.
   10105             : 
   10106             : OUTPUT PARAMETERS:
   10107             :     Info    -   error code:
   10108             :                 * -4    internal SVD decomposition subroutine failed (very
   10109             :                         rare and for degenerate systems only)
   10110             :                 * -3    either   too   many  constraints  (M   or   more),
   10111             :                         degenerate  constraints   (some   constraints  are
   10112             :                         repetead twice) or inconsistent  constraints  were
   10113             :                         specified.
   10114             :                 *  1    task is solved
   10115             :     C       -   decomposition coefficients, array[0..M-1]
   10116             :     Rep     -   fitting report. Following fields are set:
   10117             :                 * R2                non-adjusted coefficient of determination
   10118             :                                     (non-weighted)
   10119             :                 * RMSError          rms error on the (X,Y).
   10120             :                 * AvgError          average error on the (X,Y).
   10121             :                 * AvgRelError       average relative error on the non-zero Y
   10122             :                 * MaxError          maximum error
   10123             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   10124             : 
   10125             : IMPORTANT:
   10126             :     this subroitine doesn't calculate task's condition number for K<>0.
   10127             : 
   10128             : ERRORS IN PARAMETERS
   10129             : 
   10130             : This  solver  also  calculates different kinds of errors in parameters and
   10131             : fills corresponding fields of report:
   10132             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   10133             : * Rep.ErrPar        errors in parameters, array[K],
   10134             :                     errpar = sqrt(diag(CovPar))
   10135             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   10136             :                     best-fit curve from "ideal" best-fit curve built  with
   10137             :                     infinite number of samples, array[N].
   10138             :                     errcurve = sqrt(diag(F*CovPar*F')),
   10139             :                     where F is functions matrix.
   10140             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   10141             : 
   10142             : IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
   10143             :             account boundary/linear constraints! Presence  of  constraints
   10144             :             changes distribution of errors, but there is no  easy  way  to
   10145             :             account for constraints when you calculate covariance matrix.
   10146             : 
   10147             : NOTE:       noise in the data is estimated as follows:
   10148             :             * for fitting without user-supplied  weights  all  points  are
   10149             :               assumed to have same level of noise, which is estimated from
   10150             :               the data
   10151             :             * for fitting with user-supplied weights we assume that  noise
   10152             :               level in I-th point is inversely proportional to Ith weight.
   10153             :               Coefficient of proportionality is estimated from the data.
   10154             : 
   10155             : NOTE:       we apply small amount of regularization when we invert squared
   10156             :             Jacobian and calculate covariance matrix. It  guarantees  that
   10157             :             algorithm won't divide by zero  during  inversion,  but  skews
   10158             :             error estimates a bit (fractional error is about 10^-9).
   10159             : 
   10160             :             However, we believe that this difference is insignificant  for
   10161             :             all practical purposes except for the situation when you  want
   10162             :             to compare ALGLIB results with "reference"  implementation  up
   10163             :             to the last significant digit.
   10164             : 
   10165             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   10166             :             of freedom (covariances are divided by N-M instead of dividing
   10167             :             by N).
   10168             : 
   10169             :   -- ALGLIB --
   10170             :      Copyright 07.09.2009 by Bochkanov Sergey
   10171             : *************************************************************************/
   10172           0 : 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, const xparams _xparams)
   10173             : {
   10174             :     jmp_buf _break_jump;
   10175             :     alglib_impl::ae_state _alglib_env_state;
   10176           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   10177           0 :     if( setjmp(_break_jump) )
   10178             :     {
   10179             : #if !defined(AE_NO_EXCEPTIONS)
   10180           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   10181             : #else
   10182             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   10183             :         return;
   10184             : #endif
   10185             :     }
   10186           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   10187           0 :     if( _xparams.flags!=0x0 )
   10188           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   10189           0 :     alglib_impl::lsfitlinearwc(const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), const_cast<alglib_impl::ae_matrix*>(fmatrix.c_ptr()), const_cast<alglib_impl::ae_matrix*>(cmatrix.c_ptr()), n, m, k, &info, const_cast<alglib_impl::ae_vector*>(c.c_ptr()), const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
   10190           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   10191           0 :     return;
   10192             : }
   10193             : 
   10194             : /*************************************************************************
   10195             : Weighted constained linear least squares fitting.
   10196             : 
   10197             : This  is  variation  of LSFitLinearW(), which searchs for min|A*x=b| given
   10198             : that  K  additional  constaints  C*x=bc are satisfied. It reduces original
   10199             : task to modified one: min|B*y-d| WITHOUT constraints,  then LSFitLinearW()
   10200             : is called.
   10201             : 
   10202             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
   10203             :            convenient to use PolynomialFit() function. This function gives
   10204             :            best  results  on  polynomial  problems  and  solves  numerical
   10205             :            stability  issues  which  arise  when   you   fit   high-degree
   10206             :            polynomials to your data.
   10207             : 
   10208             :   ! COMMERCIAL EDITION OF ALGLIB:
   10209             :   !
   10210             :   ! Commercial Edition of ALGLIB includes following important improvements
   10211             :   ! of this function:
   10212             :   ! * high-performance native backend with same C# interface (C# version)
   10213             :   ! * multithreading support (C++ and C# versions)
   10214             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   10215             :   !   (C++ and C# versions, x86/x64 platform)
   10216             :   !
   10217             :   ! We recommend you to read 'Working with commercial version' section  of
   10218             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   10219             :   ! related features provided by commercial edition of ALGLIB.
   10220             : 
   10221             : INPUT PARAMETERS:
   10222             :     Y       -   array[0..N-1] Function values in  N  points.
   10223             :     W       -   array[0..N-1]  Weights  corresponding to function  values.
   10224             :                 Each summand in square  sum  of  approximation  deviations
   10225             :                 from  given  values  is  multiplied  by  the   square   of
   10226             :                 corresponding weight.
   10227             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
   10228             :                 FMatrix[I,J] - value of J-th basis function in I-th point.
   10229             :     CMatrix -   a table of constaints, array[0..K-1,0..M].
   10230             :                 I-th row of CMatrix corresponds to I-th linear constraint:
   10231             :                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
   10232             :     N       -   number of points used. N>=1.
   10233             :     M       -   number of basis functions, M>=1.
   10234             :     K       -   number of constraints, 0 <= K < M
   10235             :                 K=0 corresponds to absence of constraints.
   10236             : 
   10237             : OUTPUT PARAMETERS:
   10238             :     Info    -   error code:
   10239             :                 * -4    internal SVD decomposition subroutine failed (very
   10240             :                         rare and for degenerate systems only)
   10241             :                 * -3    either   too   many  constraints  (M   or   more),
   10242             :                         degenerate  constraints   (some   constraints  are
   10243             :                         repetead twice) or inconsistent  constraints  were
   10244             :                         specified.
   10245             :                 *  1    task is solved
   10246             :     C       -   decomposition coefficients, array[0..M-1]
   10247             :     Rep     -   fitting report. Following fields are set:
   10248             :                 * R2                non-adjusted coefficient of determination
   10249             :                                     (non-weighted)
   10250             :                 * RMSError          rms error on the (X,Y).
   10251             :                 * AvgError          average error on the (X,Y).
   10252             :                 * AvgRelError       average relative error on the non-zero Y
   10253             :                 * MaxError          maximum error
   10254             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   10255             : 
   10256             : IMPORTANT:
   10257             :     this subroitine doesn't calculate task's condition number for K<>0.
   10258             : 
   10259             : ERRORS IN PARAMETERS
   10260             : 
   10261             : This  solver  also  calculates different kinds of errors in parameters and
   10262             : fills corresponding fields of report:
   10263             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   10264             : * Rep.ErrPar        errors in parameters, array[K],
   10265             :                     errpar = sqrt(diag(CovPar))
   10266             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   10267             :                     best-fit curve from "ideal" best-fit curve built  with
   10268             :                     infinite number of samples, array[N].
   10269             :                     errcurve = sqrt(diag(F*CovPar*F')),
   10270             :                     where F is functions matrix.
   10271             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   10272             : 
   10273             : IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
   10274             :             account boundary/linear constraints! Presence  of  constraints
   10275             :             changes distribution of errors, but there is no  easy  way  to
   10276             :             account for constraints when you calculate covariance matrix.
   10277             : 
   10278             : NOTE:       noise in the data is estimated as follows:
   10279             :             * for fitting without user-supplied  weights  all  points  are
   10280             :               assumed to have same level of noise, which is estimated from
   10281             :               the data
   10282             :             * for fitting with user-supplied weights we assume that  noise
   10283             :               level in I-th point is inversely proportional to Ith weight.
   10284             :               Coefficient of proportionality is estimated from the data.
   10285             : 
   10286             : NOTE:       we apply small amount of regularization when we invert squared
   10287             :             Jacobian and calculate covariance matrix. It  guarantees  that
   10288             :             algorithm won't divide by zero  during  inversion,  but  skews
   10289             :             error estimates a bit (fractional error is about 10^-9).
   10290             : 
   10291             :             However, we believe that this difference is insignificant  for
   10292             :             all practical purposes except for the situation when you  want
   10293             :             to compare ALGLIB results with "reference"  implementation  up
   10294             :             to the last significant digit.
   10295             : 
   10296             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   10297             :             of freedom (covariances are divided by N-M instead of dividing
   10298             :             by N).
   10299             : 
   10300             :   -- ALGLIB --
   10301             :      Copyright 07.09.2009 by Bochkanov Sergey
   10302             : *************************************************************************/
   10303             : #if !defined(AE_NO_EXCEPTIONS)
   10304           0 : 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, const xparams _xparams)
   10305             : {
   10306             :     jmp_buf _break_jump;
   10307             :     alglib_impl::ae_state _alglib_env_state;    
   10308             :     ae_int_t n;
   10309             :     ae_int_t m;
   10310             :     ae_int_t k;
   10311           0 :     if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows()))
   10312           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size");
   10313           0 :     if( (fmatrix.cols()!=cmatrix.cols()-1))
   10314           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size");
   10315           0 :     n = y.length();
   10316           0 :     m = fmatrix.cols();
   10317           0 :     k = cmatrix.rows();
   10318           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   10319           0 :     if( setjmp(_break_jump) )
   10320           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   10321           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   10322           0 :     if( _xparams.flags!=0x0 )
   10323           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   10324           0 :     alglib_impl::lsfitlinearwc(const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), const_cast<alglib_impl::ae_matrix*>(fmatrix.c_ptr()), const_cast<alglib_impl::ae_matrix*>(cmatrix.c_ptr()), n, m, k, &info, const_cast<alglib_impl::ae_vector*>(c.c_ptr()), const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
   10325             : 
   10326           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   10327           0 :     return;
   10328             : }
   10329             : #endif
   10330             : 
   10331             : /*************************************************************************
   10332             : Linear least squares fitting.
   10333             : 
   10334             : QR decomposition is used to reduce task to MxM, then triangular solver  or
   10335             : SVD-based solver is used depending on condition number of the  system.  It
   10336             : allows to maximize speed and retain decent accuracy.
   10337             : 
   10338             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
   10339             :            convenient to use PolynomialFit() function. This function gives
   10340             :            best  results  on  polynomial  problems  and  solves  numerical
   10341             :            stability  issues  which  arise  when   you   fit   high-degree
   10342             :            polynomials to your data.
   10343             : 
   10344             :   ! COMMERCIAL EDITION OF ALGLIB:
   10345             :   !
   10346             :   ! Commercial Edition of ALGLIB includes following important improvements
   10347             :   ! of this function:
   10348             :   ! * high-performance native backend with same C# interface (C# version)
   10349             :   ! * multithreading support (C++ and C# versions)
   10350             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   10351             :   !   (C++ and C# versions, x86/x64 platform)
   10352             :   !
   10353             :   ! We recommend you to read 'Working with commercial version' section  of
   10354             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   10355             :   ! related features provided by commercial edition of ALGLIB.
   10356             : 
   10357             : INPUT PARAMETERS:
   10358             :     Y       -   array[0..N-1] Function values in  N  points.
   10359             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
   10360             :                 FMatrix[I, J] - value of J-th basis function in I-th point.
   10361             :     N       -   number of points used. N>=1.
   10362             :     M       -   number of basis functions, M>=1.
   10363             : 
   10364             : OUTPUT PARAMETERS:
   10365             :     Info    -   error code:
   10366             :                 * -4    internal SVD decomposition subroutine failed (very
   10367             :                         rare and for degenerate systems only)
   10368             :                 *  1    task is solved
   10369             :     C       -   decomposition coefficients, array[0..M-1]
   10370             :     Rep     -   fitting report. Following fields are set:
   10371             :                 * Rep.TaskRCond     reciprocal of condition number
   10372             :                 * R2                non-adjusted coefficient of determination
   10373             :                                     (non-weighted)
   10374             :                 * RMSError          rms error on the (X,Y).
   10375             :                 * AvgError          average error on the (X,Y).
   10376             :                 * AvgRelError       average relative error on the non-zero Y
   10377             :                 * MaxError          maximum error
   10378             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   10379             : 
   10380             : ERRORS IN PARAMETERS
   10381             : 
   10382             : This  solver  also  calculates different kinds of errors in parameters and
   10383             : fills corresponding fields of report:
   10384             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   10385             : * Rep.ErrPar        errors in parameters, array[K],
   10386             :                     errpar = sqrt(diag(CovPar))
   10387             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   10388             :                     best-fit curve from "ideal" best-fit curve built  with
   10389             :                     infinite number of samples, array[N].
   10390             :                     errcurve = sqrt(diag(F*CovPar*F')),
   10391             :                     where F is functions matrix.
   10392             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   10393             : 
   10394             : NOTE:       noise in the data is estimated as follows:
   10395             :             * for fitting without user-supplied  weights  all  points  are
   10396             :               assumed to have same level of noise, which is estimated from
   10397             :               the data
   10398             :             * for fitting with user-supplied weights we assume that  noise
   10399             :               level in I-th point is inversely proportional to Ith weight.
   10400             :               Coefficient of proportionality is estimated from the data.
   10401             : 
   10402             : NOTE:       we apply small amount of regularization when we invert squared
   10403             :             Jacobian and calculate covariance matrix. It  guarantees  that
   10404             :             algorithm won't divide by zero  during  inversion,  but  skews
   10405             :             error estimates a bit (fractional error is about 10^-9).
   10406             : 
   10407             :             However, we believe that this difference is insignificant  for
   10408             :             all practical purposes except for the situation when you  want
   10409             :             to compare ALGLIB results with "reference"  implementation  up
   10410             :             to the last significant digit.
   10411             : 
   10412             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   10413             :             of freedom (covariances are divided by N-M instead of dividing
   10414             :             by N).
   10415             : 
   10416             :   -- ALGLIB --
   10417             :      Copyright 17.08.2009 by Bochkanov Sergey
   10418             : *************************************************************************/
   10419           0 : 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, const xparams _xparams)
   10420             : {
   10421             :     jmp_buf _break_jump;
   10422             :     alglib_impl::ae_state _alglib_env_state;
   10423           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   10424           0 :     if( setjmp(_break_jump) )
   10425             :     {
   10426             : #if !defined(AE_NO_EXCEPTIONS)
   10427           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   10428             : #else
   10429             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   10430             :         return;
   10431             : #endif
   10432             :     }
   10433           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   10434           0 :     if( _xparams.flags!=0x0 )
   10435           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   10436           0 :     alglib_impl::lsfitlinear(const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_matrix*>(fmatrix.c_ptr()), n, m, &info, const_cast<alglib_impl::ae_vector*>(c.c_ptr()), const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
   10437           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   10438           0 :     return;
   10439             : }
   10440             : 
   10441             : /*************************************************************************
   10442             : Linear least squares fitting.
   10443             : 
   10444             : QR decomposition is used to reduce task to MxM, then triangular solver  or
   10445             : SVD-based solver is used depending on condition number of the  system.  It
   10446             : allows to maximize speed and retain decent accuracy.
   10447             : 
   10448             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
   10449             :            convenient to use PolynomialFit() function. This function gives
   10450             :            best  results  on  polynomial  problems  and  solves  numerical
   10451             :            stability  issues  which  arise  when   you   fit   high-degree
   10452             :            polynomials to your data.
   10453             : 
   10454             :   ! COMMERCIAL EDITION OF ALGLIB:
   10455             :   !
   10456             :   ! Commercial Edition of ALGLIB includes following important improvements
   10457             :   ! of this function:
   10458             :   ! * high-performance native backend with same C# interface (C# version)
   10459             :   ! * multithreading support (C++ and C# versions)
   10460             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   10461             :   !   (C++ and C# versions, x86/x64 platform)
   10462             :   !
   10463             :   ! We recommend you to read 'Working with commercial version' section  of
   10464             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   10465             :   ! related features provided by commercial edition of ALGLIB.
   10466             : 
   10467             : INPUT PARAMETERS:
   10468             :     Y       -   array[0..N-1] Function values in  N  points.
   10469             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
   10470             :                 FMatrix[I, J] - value of J-th basis function in I-th point.
   10471             :     N       -   number of points used. N>=1.
   10472             :     M       -   number of basis functions, M>=1.
   10473             : 
   10474             : OUTPUT PARAMETERS:
   10475             :     Info    -   error code:
   10476             :                 * -4    internal SVD decomposition subroutine failed (very
   10477             :                         rare and for degenerate systems only)
   10478             :                 *  1    task is solved
   10479             :     C       -   decomposition coefficients, array[0..M-1]
   10480             :     Rep     -   fitting report. Following fields are set:
   10481             :                 * Rep.TaskRCond     reciprocal of condition number
   10482             :                 * R2                non-adjusted coefficient of determination
   10483             :                                     (non-weighted)
   10484             :                 * RMSError          rms error on the (X,Y).
   10485             :                 * AvgError          average error on the (X,Y).
   10486             :                 * AvgRelError       average relative error on the non-zero Y
   10487             :                 * MaxError          maximum error
   10488             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   10489             : 
   10490             : ERRORS IN PARAMETERS
   10491             : 
   10492             : This  solver  also  calculates different kinds of errors in parameters and
   10493             : fills corresponding fields of report:
   10494             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   10495             : * Rep.ErrPar        errors in parameters, array[K],
   10496             :                     errpar = sqrt(diag(CovPar))
   10497             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   10498             :                     best-fit curve from "ideal" best-fit curve built  with
   10499             :                     infinite number of samples, array[N].
   10500             :                     errcurve = sqrt(diag(F*CovPar*F')),
   10501             :                     where F is functions matrix.
   10502             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   10503             : 
   10504             : NOTE:       noise in the data is estimated as follows:
   10505             :             * for fitting without user-supplied  weights  all  points  are
   10506             :               assumed to have same level of noise, which is estimated from
   10507             :               the data
   10508             :             * for fitting with user-supplied weights we assume that  noise
   10509             :               level in I-th point is inversely proportional to Ith weight.
   10510             :               Coefficient of proportionality is estimated from the data.
   10511             : 
   10512             : NOTE:       we apply small amount of regularization when we invert squared
   10513             :             Jacobian and calculate covariance matrix. It  guarantees  that
   10514             :             algorithm won't divide by zero  during  inversion,  but  skews
   10515             :             error estimates a bit (fractional error is about 10^-9).
   10516             : 
   10517             :             However, we believe that this difference is insignificant  for
   10518             :             all practical purposes except for the situation when you  want
   10519             :             to compare ALGLIB results with "reference"  implementation  up
   10520             :             to the last significant digit.
   10521             : 
   10522             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   10523             :             of freedom (covariances are divided by N-M instead of dividing
   10524             :             by N).
   10525             : 
   10526             :   -- ALGLIB --
   10527             :      Copyright 17.08.2009 by Bochkanov Sergey
   10528             : *************************************************************************/
   10529             : #if !defined(AE_NO_EXCEPTIONS)
   10530           0 : void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep, const xparams _xparams)
   10531             : {
   10532             :     jmp_buf _break_jump;
   10533             :     alglib_impl::ae_state _alglib_env_state;    
   10534             :     ae_int_t n;
   10535             :     ae_int_t m;
   10536           0 :     if( (y.length()!=fmatrix.rows()))
   10537           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinear': looks like one of arguments has wrong size");
   10538           0 :     n = y.length();
   10539           0 :     m = fmatrix.cols();
   10540           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   10541           0 :     if( setjmp(_break_jump) )
   10542           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   10543           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   10544           0 :     if( _xparams.flags!=0x0 )
   10545           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   10546           0 :     alglib_impl::lsfitlinear(const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_matrix*>(fmatrix.c_ptr()), n, m, &info, const_cast<alglib_impl::ae_vector*>(c.c_ptr()), const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
   10547             : 
   10548           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   10549           0 :     return;
   10550             : }
   10551             : #endif
   10552             : 
   10553             : /*************************************************************************
   10554             : Constained linear least squares fitting.
   10555             : 
   10556             : This  is  variation  of LSFitLinear(),  which searchs for min|A*x=b| given
   10557             : that  K  additional  constaints  C*x=bc are satisfied. It reduces original
   10558             : task to modified one: min|B*y-d| WITHOUT constraints,  then  LSFitLinear()
   10559             : is called.
   10560             : 
   10561             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
   10562             :            convenient to use PolynomialFit() function. This function gives
   10563             :            best  results  on  polynomial  problems  and  solves  numerical
   10564             :            stability  issues  which  arise  when   you   fit   high-degree
   10565             :            polynomials to your data.
   10566             : 
   10567             :   ! COMMERCIAL EDITION OF ALGLIB:
   10568             :   !
   10569             :   ! Commercial Edition of ALGLIB includes following important improvements
   10570             :   ! of this function:
   10571             :   ! * high-performance native backend with same C# interface (C# version)
   10572             :   ! * multithreading support (C++ and C# versions)
   10573             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   10574             :   !   (C++ and C# versions, x86/x64 platform)
   10575             :   !
   10576             :   ! We recommend you to read 'Working with commercial version' section  of
   10577             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   10578             :   ! related features provided by commercial edition of ALGLIB.
   10579             : 
   10580             : INPUT PARAMETERS:
   10581             :     Y       -   array[0..N-1] Function values in  N  points.
   10582             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
   10583             :                 FMatrix[I,J] - value of J-th basis function in I-th point.
   10584             :     CMatrix -   a table of constaints, array[0..K-1,0..M].
   10585             :                 I-th row of CMatrix corresponds to I-th linear constraint:
   10586             :                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
   10587             :     N       -   number of points used. N>=1.
   10588             :     M       -   number of basis functions, M>=1.
   10589             :     K       -   number of constraints, 0 <= K < M
   10590             :                 K=0 corresponds to absence of constraints.
   10591             : 
   10592             : OUTPUT PARAMETERS:
   10593             :     Info    -   error code:
   10594             :                 * -4    internal SVD decomposition subroutine failed (very
   10595             :                         rare and for degenerate systems only)
   10596             :                 * -3    either   too   many  constraints  (M   or   more),
   10597             :                         degenerate  constraints   (some   constraints  are
   10598             :                         repetead twice) or inconsistent  constraints  were
   10599             :                         specified.
   10600             :                 *  1    task is solved
   10601             :     C       -   decomposition coefficients, array[0..M-1]
   10602             :     Rep     -   fitting report. Following fields are set:
   10603             :                 * R2                non-adjusted coefficient of determination
   10604             :                                     (non-weighted)
   10605             :                 * RMSError          rms error on the (X,Y).
   10606             :                 * AvgError          average error on the (X,Y).
   10607             :                 * AvgRelError       average relative error on the non-zero Y
   10608             :                 * MaxError          maximum error
   10609             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   10610             : 
   10611             : IMPORTANT:
   10612             :     this subroitine doesn't calculate task's condition number for K<>0.
   10613             : 
   10614             : ERRORS IN PARAMETERS
   10615             : 
   10616             : This  solver  also  calculates different kinds of errors in parameters and
   10617             : fills corresponding fields of report:
   10618             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   10619             : * Rep.ErrPar        errors in parameters, array[K],
   10620             :                     errpar = sqrt(diag(CovPar))
   10621             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   10622             :                     best-fit curve from "ideal" best-fit curve built  with
   10623             :                     infinite number of samples, array[N].
   10624             :                     errcurve = sqrt(diag(F*CovPar*F')),
   10625             :                     where F is functions matrix.
   10626             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   10627             : 
   10628             : IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
   10629             :             account boundary/linear constraints! Presence  of  constraints
   10630             :             changes distribution of errors, but there is no  easy  way  to
   10631             :             account for constraints when you calculate covariance matrix.
   10632             : 
   10633             : NOTE:       noise in the data is estimated as follows:
   10634             :             * for fitting without user-supplied  weights  all  points  are
   10635             :               assumed to have same level of noise, which is estimated from
   10636             :               the data
   10637             :             * for fitting with user-supplied weights we assume that  noise
   10638             :               level in I-th point is inversely proportional to Ith weight.
   10639             :               Coefficient of proportionality is estimated from the data.
   10640             : 
   10641             : NOTE:       we apply small amount of regularization when we invert squared
   10642             :             Jacobian and calculate covariance matrix. It  guarantees  that
   10643             :             algorithm won't divide by zero  during  inversion,  but  skews
   10644             :             error estimates a bit (fractional error is about 10^-9).
   10645             : 
   10646             :             However, we believe that this difference is insignificant  for
   10647             :             all practical purposes except for the situation when you  want
   10648             :             to compare ALGLIB results with "reference"  implementation  up
   10649             :             to the last significant digit.
   10650             : 
   10651             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   10652             :             of freedom (covariances are divided by N-M instead of dividing
   10653             :             by N).
   10654             : 
   10655             :   -- ALGLIB --
   10656             :      Copyright 07.09.2009 by Bochkanov Sergey
   10657             : *************************************************************************/
   10658           0 : 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, const xparams _xparams)
   10659             : {
   10660             :     jmp_buf _break_jump;
   10661             :     alglib_impl::ae_state _alglib_env_state;
   10662           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   10663           0 :     if( setjmp(_break_jump) )
   10664             :     {
   10665             : #if !defined(AE_NO_EXCEPTIONS)
   10666           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   10667             : #else
   10668             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   10669             :         return;
   10670             : #endif
   10671             :     }
   10672           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   10673           0 :     if( _xparams.flags!=0x0 )
   10674           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   10675           0 :     alglib_impl::lsfitlinearc(const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_matrix*>(fmatrix.c_ptr()), const_cast<alglib_impl::ae_matrix*>(cmatrix.c_ptr()), n, m, k, &info, const_cast<alglib_impl::ae_vector*>(c.c_ptr()), const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
   10676           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   10677           0 :     return;
   10678             : }
   10679             : 
   10680             : /*************************************************************************
   10681             : Constained linear least squares fitting.
   10682             : 
   10683             : This  is  variation  of LSFitLinear(),  which searchs for min|A*x=b| given
   10684             : that  K  additional  constaints  C*x=bc are satisfied. It reduces original
   10685             : task to modified one: min|B*y-d| WITHOUT constraints,  then  LSFitLinear()
   10686             : is called.
   10687             : 
   10688             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
   10689             :            convenient to use PolynomialFit() function. This function gives
   10690             :            best  results  on  polynomial  problems  and  solves  numerical
   10691             :            stability  issues  which  arise  when   you   fit   high-degree
   10692             :            polynomials to your data.
   10693             : 
   10694             :   ! COMMERCIAL EDITION OF ALGLIB:
   10695             :   !
   10696             :   ! Commercial Edition of ALGLIB includes following important improvements
   10697             :   ! of this function:
   10698             :   ! * high-performance native backend with same C# interface (C# version)
   10699             :   ! * multithreading support (C++ and C# versions)
   10700             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   10701             :   !   (C++ and C# versions, x86/x64 platform)
   10702             :   !
   10703             :   ! We recommend you to read 'Working with commercial version' section  of
   10704             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   10705             :   ! related features provided by commercial edition of ALGLIB.
   10706             : 
   10707             : INPUT PARAMETERS:
   10708             :     Y       -   array[0..N-1] Function values in  N  points.
   10709             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
   10710             :                 FMatrix[I,J] - value of J-th basis function in I-th point.
   10711             :     CMatrix -   a table of constaints, array[0..K-1,0..M].
   10712             :                 I-th row of CMatrix corresponds to I-th linear constraint:
   10713             :                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
   10714             :     N       -   number of points used. N>=1.
   10715             :     M       -   number of basis functions, M>=1.
   10716             :     K       -   number of constraints, 0 <= K < M
   10717             :                 K=0 corresponds to absence of constraints.
   10718             : 
   10719             : OUTPUT PARAMETERS:
   10720             :     Info    -   error code:
   10721             :                 * -4    internal SVD decomposition subroutine failed (very
   10722             :                         rare and for degenerate systems only)
   10723             :                 * -3    either   too   many  constraints  (M   or   more),
   10724             :                         degenerate  constraints   (some   constraints  are
   10725             :                         repetead twice) or inconsistent  constraints  were
   10726             :                         specified.
   10727             :                 *  1    task is solved
   10728             :     C       -   decomposition coefficients, array[0..M-1]
   10729             :     Rep     -   fitting report. Following fields are set:
   10730             :                 * R2                non-adjusted coefficient of determination
   10731             :                                     (non-weighted)
   10732             :                 * RMSError          rms error on the (X,Y).
   10733             :                 * AvgError          average error on the (X,Y).
   10734             :                 * AvgRelError       average relative error on the non-zero Y
   10735             :                 * MaxError          maximum error
   10736             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   10737             : 
   10738             : IMPORTANT:
   10739             :     this subroitine doesn't calculate task's condition number for K<>0.
   10740             : 
   10741             : ERRORS IN PARAMETERS
   10742             : 
   10743             : This  solver  also  calculates different kinds of errors in parameters and
   10744             : fills corresponding fields of report:
   10745             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   10746             : * Rep.ErrPar        errors in parameters, array[K],
   10747             :                     errpar = sqrt(diag(CovPar))
   10748             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   10749             :                     best-fit curve from "ideal" best-fit curve built  with
   10750             :                     infinite number of samples, array[N].
   10751             :                     errcurve = sqrt(diag(F*CovPar*F')),
   10752             :                     where F is functions matrix.
   10753             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   10754             : 
   10755             : IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
   10756             :             account boundary/linear constraints! Presence  of  constraints
   10757             :             changes distribution of errors, but there is no  easy  way  to
   10758             :             account for constraints when you calculate covariance matrix.
   10759             : 
   10760             : NOTE:       noise in the data is estimated as follows:
   10761             :             * for fitting without user-supplied  weights  all  points  are
   10762             :               assumed to have same level of noise, which is estimated from
   10763             :               the data
   10764             :             * for fitting with user-supplied weights we assume that  noise
   10765             :               level in I-th point is inversely proportional to Ith weight.
   10766             :               Coefficient of proportionality is estimated from the data.
   10767             : 
   10768             : NOTE:       we apply small amount of regularization when we invert squared
   10769             :             Jacobian and calculate covariance matrix. It  guarantees  that
   10770             :             algorithm won't divide by zero  during  inversion,  but  skews
   10771             :             error estimates a bit (fractional error is about 10^-9).
   10772             : 
   10773             :             However, we believe that this difference is insignificant  for
   10774             :             all practical purposes except for the situation when you  want
   10775             :             to compare ALGLIB results with "reference"  implementation  up
   10776             :             to the last significant digit.
   10777             : 
   10778             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   10779             :             of freedom (covariances are divided by N-M instead of dividing
   10780             :             by N).
   10781             : 
   10782             :   -- ALGLIB --
   10783             :      Copyright 07.09.2009 by Bochkanov Sergey
   10784             : *************************************************************************/
   10785             : #if !defined(AE_NO_EXCEPTIONS)
   10786           0 : 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, const xparams _xparams)
   10787             : {
   10788             :     jmp_buf _break_jump;
   10789             :     alglib_impl::ae_state _alglib_env_state;    
   10790             :     ae_int_t n;
   10791             :     ae_int_t m;
   10792             :     ae_int_t k;
   10793           0 :     if( (y.length()!=fmatrix.rows()))
   10794           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size");
   10795           0 :     if( (fmatrix.cols()!=cmatrix.cols()-1))
   10796           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size");
   10797           0 :     n = y.length();
   10798           0 :     m = fmatrix.cols();
   10799           0 :     k = cmatrix.rows();
   10800           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   10801           0 :     if( setjmp(_break_jump) )
   10802           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   10803           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   10804           0 :     if( _xparams.flags!=0x0 )
   10805           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   10806           0 :     alglib_impl::lsfitlinearc(const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_matrix*>(fmatrix.c_ptr()), const_cast<alglib_impl::ae_matrix*>(cmatrix.c_ptr()), n, m, k, &info, const_cast<alglib_impl::ae_vector*>(c.c_ptr()), const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
   10807             : 
   10808           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   10809           0 :     return;
   10810             : }
   10811             : #endif
   10812             : 
   10813             : /*************************************************************************
   10814             : Weighted nonlinear least squares fitting using function values only.
   10815             : 
   10816             : Combination of numerical differentiation and secant updates is used to
   10817             : obtain function Jacobian.
   10818             : 
   10819             : Nonlinear task min(F(c)) is solved, where
   10820             : 
   10821             :     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
   10822             : 
   10823             :     * N is a number of points,
   10824             :     * M is a dimension of a space points belong to,
   10825             :     * K is a dimension of a space of parameters being fitted,
   10826             :     * w is an N-dimensional vector of weight coefficients,
   10827             :     * x is a set of N points, each of them is an M-dimensional vector,
   10828             :     * c is a K-dimensional vector of parameters being fitted
   10829             : 
   10830             : This subroutine uses only f(c,x[i]).
   10831             : 
   10832             : INPUT PARAMETERS:
   10833             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   10834             :     Y       -   array[0..N-1], function values.
   10835             :     W       -   weights, array[0..N-1]
   10836             :     C       -   array[0..K-1], initial approximation to the solution,
   10837             :     N       -   number of points, N>1
   10838             :     M       -   dimension of space
   10839             :     K       -   number of parameters being fitted
   10840             :     DiffStep-   numerical differentiation step;
   10841             :                 should not be very small or large;
   10842             :                 large = loss of accuracy
   10843             :                 small = growth of round-off errors
   10844             : 
   10845             : OUTPUT PARAMETERS:
   10846             :     State   -   structure which stores algorithm state
   10847             : 
   10848             :   -- ALGLIB --
   10849             :      Copyright 18.10.2008 by Bochkanov Sergey
   10850             : *************************************************************************/
   10851           0 : 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)
   10852             : {
   10853             :     jmp_buf _break_jump;
   10854             :     alglib_impl::ae_state _alglib_env_state;
   10855           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   10856           0 :     if( setjmp(_break_jump) )
   10857             :     {
   10858             : #if !defined(AE_NO_EXCEPTIONS)
   10859           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   10860             : #else
   10861             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   10862             :         return;
   10863             : #endif
   10864             :     }
   10865           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   10866           0 :     if( _xparams.flags!=0x0 )
   10867           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   10868           0 :     alglib_impl::lsfitcreatewf(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, diffstep, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   10869           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   10870           0 :     return;
   10871             : }
   10872             : 
   10873             : /*************************************************************************
   10874             : Weighted nonlinear least squares fitting using function values only.
   10875             : 
   10876             : Combination of numerical differentiation and secant updates is used to
   10877             : obtain function Jacobian.
   10878             : 
   10879             : Nonlinear task min(F(c)) is solved, where
   10880             : 
   10881             :     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
   10882             : 
   10883             :     * N is a number of points,
   10884             :     * M is a dimension of a space points belong to,
   10885             :     * K is a dimension of a space of parameters being fitted,
   10886             :     * w is an N-dimensional vector of weight coefficients,
   10887             :     * x is a set of N points, each of them is an M-dimensional vector,
   10888             :     * c is a K-dimensional vector of parameters being fitted
   10889             : 
   10890             : This subroutine uses only f(c,x[i]).
   10891             : 
   10892             : INPUT PARAMETERS:
   10893             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   10894             :     Y       -   array[0..N-1], function values.
   10895             :     W       -   weights, array[0..N-1]
   10896             :     C       -   array[0..K-1], initial approximation to the solution,
   10897             :     N       -   number of points, N>1
   10898             :     M       -   dimension of space
   10899             :     K       -   number of parameters being fitted
   10900             :     DiffStep-   numerical differentiation step;
   10901             :                 should not be very small or large;
   10902             :                 large = loss of accuracy
   10903             :                 small = growth of round-off errors
   10904             : 
   10905             : OUTPUT PARAMETERS:
   10906             :     State   -   structure which stores algorithm state
   10907             : 
   10908             :   -- ALGLIB --
   10909             :      Copyright 18.10.2008 by Bochkanov Sergey
   10910             : *************************************************************************/
   10911             : #if !defined(AE_NO_EXCEPTIONS)
   10912           0 : 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)
   10913             : {
   10914             :     jmp_buf _break_jump;
   10915             :     alglib_impl::ae_state _alglib_env_state;    
   10916             :     ae_int_t n;
   10917             :     ae_int_t m;
   10918             :     ae_int_t k;
   10919           0 :     if( (x.rows()!=y.length()) || (x.rows()!=w.length()))
   10920           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatewf': looks like one of arguments has wrong size");
   10921           0 :     n = x.rows();
   10922           0 :     m = x.cols();
   10923           0 :     k = c.length();
   10924           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   10925           0 :     if( setjmp(_break_jump) )
   10926           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   10927           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   10928           0 :     if( _xparams.flags!=0x0 )
   10929           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   10930           0 :     alglib_impl::lsfitcreatewf(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, diffstep, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   10931             : 
   10932           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   10933           0 :     return;
   10934             : }
   10935             : #endif
   10936             : 
   10937             : /*************************************************************************
   10938             : Nonlinear least squares fitting using function values only.
   10939             : 
   10940             : Combination of numerical differentiation and secant updates is used to
   10941             : obtain function Jacobian.
   10942             : 
   10943             : Nonlinear task min(F(c)) is solved, where
   10944             : 
   10945             :     F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2,
   10946             : 
   10947             :     * N is a number of points,
   10948             :     * M is a dimension of a space points belong to,
   10949             :     * K is a dimension of a space of parameters being fitted,
   10950             :     * w is an N-dimensional vector of weight coefficients,
   10951             :     * x is a set of N points, each of them is an M-dimensional vector,
   10952             :     * c is a K-dimensional vector of parameters being fitted
   10953             : 
   10954             : This subroutine uses only f(c,x[i]).
   10955             : 
   10956             : INPUT PARAMETERS:
   10957             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   10958             :     Y       -   array[0..N-1], function values.
   10959             :     C       -   array[0..K-1], initial approximation to the solution,
   10960             :     N       -   number of points, N>1
   10961             :     M       -   dimension of space
   10962             :     K       -   number of parameters being fitted
   10963             :     DiffStep-   numerical differentiation step;
   10964             :                 should not be very small or large;
   10965             :                 large = loss of accuracy
   10966             :                 small = growth of round-off errors
   10967             : 
   10968             : OUTPUT PARAMETERS:
   10969             :     State   -   structure which stores algorithm state
   10970             : 
   10971             :   -- ALGLIB --
   10972             :      Copyright 18.10.2008 by Bochkanov Sergey
   10973             : *************************************************************************/
   10974           0 : 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)
   10975             : {
   10976             :     jmp_buf _break_jump;
   10977             :     alglib_impl::ae_state _alglib_env_state;
   10978           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   10979           0 :     if( setjmp(_break_jump) )
   10980             :     {
   10981             : #if !defined(AE_NO_EXCEPTIONS)
   10982           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   10983             : #else
   10984             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   10985             :         return;
   10986             : #endif
   10987             :     }
   10988           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   10989           0 :     if( _xparams.flags!=0x0 )
   10990           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   10991           0 :     alglib_impl::lsfitcreatef(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, diffstep, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   10992           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   10993           0 :     return;
   10994             : }
   10995             : 
   10996             : /*************************************************************************
   10997             : Nonlinear least squares fitting using function values only.
   10998             : 
   10999             : Combination of numerical differentiation and secant updates is used to
   11000             : obtain function Jacobian.
   11001             : 
   11002             : Nonlinear task min(F(c)) is solved, where
   11003             : 
   11004             :     F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2,
   11005             : 
   11006             :     * N is a number of points,
   11007             :     * M is a dimension of a space points belong to,
   11008             :     * K is a dimension of a space of parameters being fitted,
   11009             :     * w is an N-dimensional vector of weight coefficients,
   11010             :     * x is a set of N points, each of them is an M-dimensional vector,
   11011             :     * c is a K-dimensional vector of parameters being fitted
   11012             : 
   11013             : This subroutine uses only f(c,x[i]).
   11014             : 
   11015             : INPUT PARAMETERS:
   11016             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   11017             :     Y       -   array[0..N-1], function values.
   11018             :     C       -   array[0..K-1], initial approximation to the solution,
   11019             :     N       -   number of points, N>1
   11020             :     M       -   dimension of space
   11021             :     K       -   number of parameters being fitted
   11022             :     DiffStep-   numerical differentiation step;
   11023             :                 should not be very small or large;
   11024             :                 large = loss of accuracy
   11025             :                 small = growth of round-off errors
   11026             : 
   11027             : OUTPUT PARAMETERS:
   11028             :     State   -   structure which stores algorithm state
   11029             : 
   11030             :   -- ALGLIB --
   11031             :      Copyright 18.10.2008 by Bochkanov Sergey
   11032             : *************************************************************************/
   11033             : #if !defined(AE_NO_EXCEPTIONS)
   11034           0 : 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)
   11035             : {
   11036             :     jmp_buf _break_jump;
   11037             :     alglib_impl::ae_state _alglib_env_state;    
   11038             :     ae_int_t n;
   11039             :     ae_int_t m;
   11040             :     ae_int_t k;
   11041           0 :     if( (x.rows()!=y.length()))
   11042           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatef': looks like one of arguments has wrong size");
   11043           0 :     n = x.rows();
   11044           0 :     m = x.cols();
   11045           0 :     k = c.length();
   11046           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11047           0 :     if( setjmp(_break_jump) )
   11048           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11049           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11050           0 :     if( _xparams.flags!=0x0 )
   11051           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11052           0 :     alglib_impl::lsfitcreatef(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, diffstep, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   11053             : 
   11054           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11055           0 :     return;
   11056             : }
   11057             : #endif
   11058             : 
   11059             : /*************************************************************************
   11060             : Weighted nonlinear least squares fitting using gradient only.
   11061             : 
   11062             : Nonlinear task min(F(c)) is solved, where
   11063             : 
   11064             :     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
   11065             : 
   11066             :     * N is a number of points,
   11067             :     * M is a dimension of a space points belong to,
   11068             :     * K is a dimension of a space of parameters being fitted,
   11069             :     * w is an N-dimensional vector of weight coefficients,
   11070             :     * x is a set of N points, each of them is an M-dimensional vector,
   11071             :     * c is a K-dimensional vector of parameters being fitted
   11072             : 
   11073             : This subroutine uses only f(c,x[i]) and its gradient.
   11074             : 
   11075             : INPUT PARAMETERS:
   11076             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   11077             :     Y       -   array[0..N-1], function values.
   11078             :     W       -   weights, array[0..N-1]
   11079             :     C       -   array[0..K-1], initial approximation to the solution,
   11080             :     N       -   number of points, N>1
   11081             :     M       -   dimension of space
   11082             :     K       -   number of parameters being fitted
   11083             :     CheapFG -   boolean flag, which is:
   11084             :                 * True  if both function and gradient calculation complexity
   11085             :                         are less than O(M^2).  An improved  algorithm  can
   11086             :                         be  used  which corresponds  to  FGJ  scheme  from
   11087             :                         MINLM unit.
   11088             :                 * False otherwise.
   11089             :                         Standard Jacibian-bases  Levenberg-Marquardt  algo
   11090             :                         will be used (FJ scheme).
   11091             : 
   11092             : OUTPUT PARAMETERS:
   11093             :     State   -   structure which stores algorithm state
   11094             : 
   11095             : See also:
   11096             :     LSFitResults
   11097             :     LSFitCreateFG (fitting without weights)
   11098             :     LSFitCreateWFGH (fitting using Hessian)
   11099             :     LSFitCreateFGH (fitting using Hessian, without weights)
   11100             : 
   11101             :   -- ALGLIB --
   11102             :      Copyright 17.08.2009 by Bochkanov Sergey
   11103             : *************************************************************************/
   11104           0 : 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, const xparams _xparams)
   11105             : {
   11106             :     jmp_buf _break_jump;
   11107             :     alglib_impl::ae_state _alglib_env_state;
   11108           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11109           0 :     if( setjmp(_break_jump) )
   11110             :     {
   11111             : #if !defined(AE_NO_EXCEPTIONS)
   11112           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11113             : #else
   11114             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11115             :         return;
   11116             : #endif
   11117             :     }
   11118           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11119           0 :     if( _xparams.flags!=0x0 )
   11120           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11121           0 :     alglib_impl::lsfitcreatewfg(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, cheapfg, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   11122           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11123           0 :     return;
   11124             : }
   11125             : 
   11126             : /*************************************************************************
   11127             : Weighted nonlinear least squares fitting using gradient only.
   11128             : 
   11129             : Nonlinear task min(F(c)) is solved, where
   11130             : 
   11131             :     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
   11132             : 
   11133             :     * N is a number of points,
   11134             :     * M is a dimension of a space points belong to,
   11135             :     * K is a dimension of a space of parameters being fitted,
   11136             :     * w is an N-dimensional vector of weight coefficients,
   11137             :     * x is a set of N points, each of them is an M-dimensional vector,
   11138             :     * c is a K-dimensional vector of parameters being fitted
   11139             : 
   11140             : This subroutine uses only f(c,x[i]) and its gradient.
   11141             : 
   11142             : INPUT PARAMETERS:
   11143             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   11144             :     Y       -   array[0..N-1], function values.
   11145             :     W       -   weights, array[0..N-1]
   11146             :     C       -   array[0..K-1], initial approximation to the solution,
   11147             :     N       -   number of points, N>1
   11148             :     M       -   dimension of space
   11149             :     K       -   number of parameters being fitted
   11150             :     CheapFG -   boolean flag, which is:
   11151             :                 * True  if both function and gradient calculation complexity
   11152             :                         are less than O(M^2).  An improved  algorithm  can
   11153             :                         be  used  which corresponds  to  FGJ  scheme  from
   11154             :                         MINLM unit.
   11155             :                 * False otherwise.
   11156             :                         Standard Jacibian-bases  Levenberg-Marquardt  algo
   11157             :                         will be used (FJ scheme).
   11158             : 
   11159             : OUTPUT PARAMETERS:
   11160             :     State   -   structure which stores algorithm state
   11161             : 
   11162             : See also:
   11163             :     LSFitResults
   11164             :     LSFitCreateFG (fitting without weights)
   11165             :     LSFitCreateWFGH (fitting using Hessian)
   11166             :     LSFitCreateFGH (fitting using Hessian, without weights)
   11167             : 
   11168             :   -- ALGLIB --
   11169             :      Copyright 17.08.2009 by Bochkanov Sergey
   11170             : *************************************************************************/
   11171             : #if !defined(AE_NO_EXCEPTIONS)
   11172           0 : 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, const xparams _xparams)
   11173             : {
   11174             :     jmp_buf _break_jump;
   11175             :     alglib_impl::ae_state _alglib_env_state;    
   11176             :     ae_int_t n;
   11177             :     ae_int_t m;
   11178             :     ae_int_t k;
   11179           0 :     if( (x.rows()!=y.length()) || (x.rows()!=w.length()))
   11180           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatewfg': looks like one of arguments has wrong size");
   11181           0 :     n = x.rows();
   11182           0 :     m = x.cols();
   11183           0 :     k = c.length();
   11184           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11185           0 :     if( setjmp(_break_jump) )
   11186           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11187           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11188           0 :     if( _xparams.flags!=0x0 )
   11189           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11190           0 :     alglib_impl::lsfitcreatewfg(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, cheapfg, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   11191             : 
   11192           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11193           0 :     return;
   11194             : }
   11195             : #endif
   11196             : 
   11197             : /*************************************************************************
   11198             : Nonlinear least squares fitting using gradient only, without individual
   11199             : weights.
   11200             : 
   11201             : Nonlinear task min(F(c)) is solved, where
   11202             : 
   11203             :     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
   11204             : 
   11205             :     * N is a number of points,
   11206             :     * M is a dimension of a space points belong to,
   11207             :     * K is a dimension of a space of parameters being fitted,
   11208             :     * x is a set of N points, each of them is an M-dimensional vector,
   11209             :     * c is a K-dimensional vector of parameters being fitted
   11210             : 
   11211             : This subroutine uses only f(c,x[i]) and its gradient.
   11212             : 
   11213             : INPUT PARAMETERS:
   11214             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   11215             :     Y       -   array[0..N-1], function values.
   11216             :     C       -   array[0..K-1], initial approximation to the solution,
   11217             :     N       -   number of points, N>1
   11218             :     M       -   dimension of space
   11219             :     K       -   number of parameters being fitted
   11220             :     CheapFG -   boolean flag, which is:
   11221             :                 * True  if both function and gradient calculation complexity
   11222             :                         are less than O(M^2).  An improved  algorithm  can
   11223             :                         be  used  which corresponds  to  FGJ  scheme  from
   11224             :                         MINLM unit.
   11225             :                 * False otherwise.
   11226             :                         Standard Jacibian-bases  Levenberg-Marquardt  algo
   11227             :                         will be used (FJ scheme).
   11228             : 
   11229             : OUTPUT PARAMETERS:
   11230             :     State   -   structure which stores algorithm state
   11231             : 
   11232             :   -- ALGLIB --
   11233             :      Copyright 17.08.2009 by Bochkanov Sergey
   11234             : *************************************************************************/
   11235           0 : 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, const xparams _xparams)
   11236             : {
   11237             :     jmp_buf _break_jump;
   11238             :     alglib_impl::ae_state _alglib_env_state;
   11239           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11240           0 :     if( setjmp(_break_jump) )
   11241             :     {
   11242             : #if !defined(AE_NO_EXCEPTIONS)
   11243           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11244             : #else
   11245             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11246             :         return;
   11247             : #endif
   11248             :     }
   11249           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11250           0 :     if( _xparams.flags!=0x0 )
   11251           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11252           0 :     alglib_impl::lsfitcreatefg(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, cheapfg, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   11253           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11254           0 :     return;
   11255             : }
   11256             : 
   11257             : /*************************************************************************
   11258             : Nonlinear least squares fitting using gradient only, without individual
   11259             : weights.
   11260             : 
   11261             : Nonlinear task min(F(c)) is solved, where
   11262             : 
   11263             :     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
   11264             : 
   11265             :     * N is a number of points,
   11266             :     * M is a dimension of a space points belong to,
   11267             :     * K is a dimension of a space of parameters being fitted,
   11268             :     * x is a set of N points, each of them is an M-dimensional vector,
   11269             :     * c is a K-dimensional vector of parameters being fitted
   11270             : 
   11271             : This subroutine uses only f(c,x[i]) and its gradient.
   11272             : 
   11273             : INPUT PARAMETERS:
   11274             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   11275             :     Y       -   array[0..N-1], function values.
   11276             :     C       -   array[0..K-1], initial approximation to the solution,
   11277             :     N       -   number of points, N>1
   11278             :     M       -   dimension of space
   11279             :     K       -   number of parameters being fitted
   11280             :     CheapFG -   boolean flag, which is:
   11281             :                 * True  if both function and gradient calculation complexity
   11282             :                         are less than O(M^2).  An improved  algorithm  can
   11283             :                         be  used  which corresponds  to  FGJ  scheme  from
   11284             :                         MINLM unit.
   11285             :                 * False otherwise.
   11286             :                         Standard Jacibian-bases  Levenberg-Marquardt  algo
   11287             :                         will be used (FJ scheme).
   11288             : 
   11289             : OUTPUT PARAMETERS:
   11290             :     State   -   structure which stores algorithm state
   11291             : 
   11292             :   -- ALGLIB --
   11293             :      Copyright 17.08.2009 by Bochkanov Sergey
   11294             : *************************************************************************/
   11295             : #if !defined(AE_NO_EXCEPTIONS)
   11296           0 : void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const bool cheapfg, lsfitstate &state, const xparams _xparams)
   11297             : {
   11298             :     jmp_buf _break_jump;
   11299             :     alglib_impl::ae_state _alglib_env_state;    
   11300             :     ae_int_t n;
   11301             :     ae_int_t m;
   11302             :     ae_int_t k;
   11303           0 :     if( (x.rows()!=y.length()))
   11304           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatefg': looks like one of arguments has wrong size");
   11305           0 :     n = x.rows();
   11306           0 :     m = x.cols();
   11307           0 :     k = c.length();
   11308           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11309           0 :     if( setjmp(_break_jump) )
   11310           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11311           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11312           0 :     if( _xparams.flags!=0x0 )
   11313           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11314           0 :     alglib_impl::lsfitcreatefg(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, cheapfg, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   11315             : 
   11316           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11317           0 :     return;
   11318             : }
   11319             : #endif
   11320             : 
   11321             : /*************************************************************************
   11322             : Weighted nonlinear least squares fitting using gradient/Hessian.
   11323             : 
   11324             : Nonlinear task min(F(c)) is solved, where
   11325             : 
   11326             :     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
   11327             : 
   11328             :     * N is a number of points,
   11329             :     * M is a dimension of a space points belong to,
   11330             :     * K is a dimension of a space of parameters being fitted,
   11331             :     * w is an N-dimensional vector of weight coefficients,
   11332             :     * x is a set of N points, each of them is an M-dimensional vector,
   11333             :     * c is a K-dimensional vector of parameters being fitted
   11334             : 
   11335             : This subroutine uses f(c,x[i]), its gradient and its Hessian.
   11336             : 
   11337             : INPUT PARAMETERS:
   11338             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   11339             :     Y       -   array[0..N-1], function values.
   11340             :     W       -   weights, array[0..N-1]
   11341             :     C       -   array[0..K-1], initial approximation to the solution,
   11342             :     N       -   number of points, N>1
   11343             :     M       -   dimension of space
   11344             :     K       -   number of parameters being fitted
   11345             : 
   11346             : OUTPUT PARAMETERS:
   11347             :     State   -   structure which stores algorithm state
   11348             : 
   11349             :   -- ALGLIB --
   11350             :      Copyright 17.08.2009 by Bochkanov Sergey
   11351             : *************************************************************************/
   11352           0 : 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, const xparams _xparams)
   11353             : {
   11354             :     jmp_buf _break_jump;
   11355             :     alglib_impl::ae_state _alglib_env_state;
   11356           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11357           0 :     if( setjmp(_break_jump) )
   11358             :     {
   11359             : #if !defined(AE_NO_EXCEPTIONS)
   11360           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11361             : #else
   11362             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11363             :         return;
   11364             : #endif
   11365             :     }
   11366           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11367           0 :     if( _xparams.flags!=0x0 )
   11368           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11369           0 :     alglib_impl::lsfitcreatewfgh(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   11370           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11371           0 :     return;
   11372             : }
   11373             : 
   11374             : /*************************************************************************
   11375             : Weighted nonlinear least squares fitting using gradient/Hessian.
   11376             : 
   11377             : Nonlinear task min(F(c)) is solved, where
   11378             : 
   11379             :     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
   11380             : 
   11381             :     * N is a number of points,
   11382             :     * M is a dimension of a space points belong to,
   11383             :     * K is a dimension of a space of parameters being fitted,
   11384             :     * w is an N-dimensional vector of weight coefficients,
   11385             :     * x is a set of N points, each of them is an M-dimensional vector,
   11386             :     * c is a K-dimensional vector of parameters being fitted
   11387             : 
   11388             : This subroutine uses f(c,x[i]), its gradient and its Hessian.
   11389             : 
   11390             : INPUT PARAMETERS:
   11391             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   11392             :     Y       -   array[0..N-1], function values.
   11393             :     W       -   weights, array[0..N-1]
   11394             :     C       -   array[0..K-1], initial approximation to the solution,
   11395             :     N       -   number of points, N>1
   11396             :     M       -   dimension of space
   11397             :     K       -   number of parameters being fitted
   11398             : 
   11399             : OUTPUT PARAMETERS:
   11400             :     State   -   structure which stores algorithm state
   11401             : 
   11402             :   -- ALGLIB --
   11403             :      Copyright 17.08.2009 by Bochkanov Sergey
   11404             : *************************************************************************/
   11405             : #if !defined(AE_NO_EXCEPTIONS)
   11406           0 : void lsfitcreatewfgh(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)
   11407             : {
   11408             :     jmp_buf _break_jump;
   11409             :     alglib_impl::ae_state _alglib_env_state;    
   11410             :     ae_int_t n;
   11411             :     ae_int_t m;
   11412             :     ae_int_t k;
   11413           0 :     if( (x.rows()!=y.length()) || (x.rows()!=w.length()))
   11414           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatewfgh': looks like one of arguments has wrong size");
   11415           0 :     n = x.rows();
   11416           0 :     m = x.cols();
   11417           0 :     k = c.length();
   11418           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11419           0 :     if( setjmp(_break_jump) )
   11420           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11421           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11422           0 :     if( _xparams.flags!=0x0 )
   11423           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11424           0 :     alglib_impl::lsfitcreatewfgh(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   11425             : 
   11426           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11427           0 :     return;
   11428             : }
   11429             : #endif
   11430             : 
   11431             : /*************************************************************************
   11432             : Nonlinear least squares fitting using gradient/Hessian, without individial
   11433             : weights.
   11434             : 
   11435             : Nonlinear task min(F(c)) is solved, where
   11436             : 
   11437             :     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
   11438             : 
   11439             :     * N is a number of points,
   11440             :     * M is a dimension of a space points belong to,
   11441             :     * K is a dimension of a space of parameters being fitted,
   11442             :     * x is a set of N points, each of them is an M-dimensional vector,
   11443             :     * c is a K-dimensional vector of parameters being fitted
   11444             : 
   11445             : This subroutine uses f(c,x[i]), its gradient and its Hessian.
   11446             : 
   11447             : INPUT PARAMETERS:
   11448             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   11449             :     Y       -   array[0..N-1], function values.
   11450             :     C       -   array[0..K-1], initial approximation to the solution,
   11451             :     N       -   number of points, N>1
   11452             :     M       -   dimension of space
   11453             :     K       -   number of parameters being fitted
   11454             : 
   11455             : OUTPUT PARAMETERS:
   11456             :     State   -   structure which stores algorithm state
   11457             : 
   11458             : 
   11459             :   -- ALGLIB --
   11460             :      Copyright 17.08.2009 by Bochkanov Sergey
   11461             : *************************************************************************/
   11462           0 : 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, const xparams _xparams)
   11463             : {
   11464             :     jmp_buf _break_jump;
   11465             :     alglib_impl::ae_state _alglib_env_state;
   11466           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11467           0 :     if( setjmp(_break_jump) )
   11468             :     {
   11469             : #if !defined(AE_NO_EXCEPTIONS)
   11470           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11471             : #else
   11472             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11473             :         return;
   11474             : #endif
   11475             :     }
   11476           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11477           0 :     if( _xparams.flags!=0x0 )
   11478           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11479           0 :     alglib_impl::lsfitcreatefgh(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   11480           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11481           0 :     return;
   11482             : }
   11483             : 
   11484             : /*************************************************************************
   11485             : Nonlinear least squares fitting using gradient/Hessian, without individial
   11486             : weights.
   11487             : 
   11488             : Nonlinear task min(F(c)) is solved, where
   11489             : 
   11490             :     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
   11491             : 
   11492             :     * N is a number of points,
   11493             :     * M is a dimension of a space points belong to,
   11494             :     * K is a dimension of a space of parameters being fitted,
   11495             :     * x is a set of N points, each of them is an M-dimensional vector,
   11496             :     * c is a K-dimensional vector of parameters being fitted
   11497             : 
   11498             : This subroutine uses f(c,x[i]), its gradient and its Hessian.
   11499             : 
   11500             : INPUT PARAMETERS:
   11501             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   11502             :     Y       -   array[0..N-1], function values.
   11503             :     C       -   array[0..K-1], initial approximation to the solution,
   11504             :     N       -   number of points, N>1
   11505             :     M       -   dimension of space
   11506             :     K       -   number of parameters being fitted
   11507             : 
   11508             : OUTPUT PARAMETERS:
   11509             :     State   -   structure which stores algorithm state
   11510             : 
   11511             : 
   11512             :   -- ALGLIB --
   11513             :      Copyright 17.08.2009 by Bochkanov Sergey
   11514             : *************************************************************************/
   11515             : #if !defined(AE_NO_EXCEPTIONS)
   11516           0 : void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, lsfitstate &state, const xparams _xparams)
   11517             : {
   11518             :     jmp_buf _break_jump;
   11519             :     alglib_impl::ae_state _alglib_env_state;    
   11520             :     ae_int_t n;
   11521             :     ae_int_t m;
   11522             :     ae_int_t k;
   11523           0 :     if( (x.rows()!=y.length()))
   11524           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatefgh': looks like one of arguments has wrong size");
   11525           0 :     n = x.rows();
   11526           0 :     m = x.cols();
   11527           0 :     k = c.length();
   11528           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11529           0 :     if( setjmp(_break_jump) )
   11530           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11531           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11532           0 :     if( _xparams.flags!=0x0 )
   11533           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11534           0 :     alglib_impl::lsfitcreatefgh(const_cast<alglib_impl::ae_matrix*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(c.c_ptr()), n, m, k, const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   11535             : 
   11536           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11537           0 :     return;
   11538             : }
   11539             : #endif
   11540             : 
   11541             : /*************************************************************************
   11542             : Stopping conditions for nonlinear least squares fitting.
   11543             : 
   11544             : INPUT PARAMETERS:
   11545             :     State   -   structure which stores algorithm state
   11546             :     EpsX    -   >=0
   11547             :                 The subroutine finishes its work if  on  k+1-th  iteration
   11548             :                 the condition |v|<=EpsX is fulfilled, where:
   11549             :                 * |.| means Euclidian norm
   11550             :                 * v - scaled step vector, v[i]=dx[i]/s[i]
   11551             :                 * dx - ste pvector, dx=X(k+1)-X(k)
   11552             :                 * s - scaling coefficients set by LSFitSetScale()
   11553             :     MaxIts  -   maximum number of iterations. If MaxIts=0, the  number  of
   11554             :                 iterations   is    unlimited.   Only   Levenberg-Marquardt
   11555             :                 iterations  are  counted  (L-BFGS/CG  iterations  are  NOT
   11556             :                 counted because their cost is very low compared to that of
   11557             :                 LM).
   11558             : 
   11559             : NOTE
   11560             : 
   11561             : Passing EpsX=0  and  MaxIts=0  (simultaneously)  will  lead  to  automatic
   11562             : stopping criterion selection (according to the scheme used by MINLM unit).
   11563             : 
   11564             : 
   11565             :   -- ALGLIB --
   11566             :      Copyright 17.08.2009 by Bochkanov Sergey
   11567             : *************************************************************************/
   11568           0 : void lsfitsetcond(const lsfitstate &state, const double epsx, const ae_int_t maxits, const xparams _xparams)
   11569             : {
   11570             :     jmp_buf _break_jump;
   11571             :     alglib_impl::ae_state _alglib_env_state;
   11572           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11573           0 :     if( setjmp(_break_jump) )
   11574             :     {
   11575             : #if !defined(AE_NO_EXCEPTIONS)
   11576           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11577             : #else
   11578             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11579             :         return;
   11580             : #endif
   11581             :     }
   11582           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11583           0 :     if( _xparams.flags!=0x0 )
   11584           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11585           0 :     alglib_impl::lsfitsetcond(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), epsx, maxits, &_alglib_env_state);
   11586           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11587           0 :     return;
   11588             : }
   11589             : 
   11590             : /*************************************************************************
   11591             : This function sets maximum step length
   11592             : 
   11593             : INPUT PARAMETERS:
   11594             :     State   -   structure which stores algorithm state
   11595             :     StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
   11596             :                 want to limit step length.
   11597             : 
   11598             : Use this subroutine when you optimize target function which contains exp()
   11599             : or  other  fast  growing  functions,  and optimization algorithm makes too
   11600             : large  steps  which  leads  to overflow. This function allows us to reject
   11601             : steps  that  are  too  large  (and  therefore  expose  us  to the possible
   11602             : overflow) without actually calculating function value at the x+stp*d.
   11603             : 
   11604             : NOTE: non-zero StpMax leads to moderate  performance  degradation  because
   11605             : intermediate  step  of  preconditioned L-BFGS optimization is incompatible
   11606             : with limits on step size.
   11607             : 
   11608             :   -- ALGLIB --
   11609             :      Copyright 02.04.2010 by Bochkanov Sergey
   11610             : *************************************************************************/
   11611           0 : void lsfitsetstpmax(const lsfitstate &state, const double stpmax, const xparams _xparams)
   11612             : {
   11613             :     jmp_buf _break_jump;
   11614             :     alglib_impl::ae_state _alglib_env_state;
   11615           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11616           0 :     if( setjmp(_break_jump) )
   11617             :     {
   11618             : #if !defined(AE_NO_EXCEPTIONS)
   11619           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11620             : #else
   11621             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11622             :         return;
   11623             : #endif
   11624             :     }
   11625           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11626           0 :     if( _xparams.flags!=0x0 )
   11627           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11628           0 :     alglib_impl::lsfitsetstpmax(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), stpmax, &_alglib_env_state);
   11629           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11630           0 :     return;
   11631             : }
   11632             : 
   11633             : /*************************************************************************
   11634             : This function turns on/off reporting.
   11635             : 
   11636             : INPUT PARAMETERS:
   11637             :     State   -   structure which stores algorithm state
   11638             :     NeedXRep-   whether iteration reports are needed or not
   11639             : 
   11640             : When reports are needed, State.C (current parameters) and State.F (current
   11641             : value of fitting function) are reported.
   11642             : 
   11643             : 
   11644             :   -- ALGLIB --
   11645             :      Copyright 15.08.2010 by Bochkanov Sergey
   11646             : *************************************************************************/
   11647           0 : void lsfitsetxrep(const lsfitstate &state, const bool needxrep, const xparams _xparams)
   11648             : {
   11649             :     jmp_buf _break_jump;
   11650             :     alglib_impl::ae_state _alglib_env_state;
   11651           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11652           0 :     if( setjmp(_break_jump) )
   11653             :     {
   11654             : #if !defined(AE_NO_EXCEPTIONS)
   11655           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11656             : #else
   11657             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11658             :         return;
   11659             : #endif
   11660             :     }
   11661           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11662           0 :     if( _xparams.flags!=0x0 )
   11663           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11664           0 :     alglib_impl::lsfitsetxrep(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), needxrep, &_alglib_env_state);
   11665           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11666           0 :     return;
   11667             : }
   11668             : 
   11669             : /*************************************************************************
   11670             : This function sets scaling coefficients for underlying optimizer.
   11671             : 
   11672             : ALGLIB optimizers use scaling matrices to test stopping  conditions  (step
   11673             : size and gradient are scaled before comparison with tolerances).  Scale of
   11674             : the I-th variable is a translation invariant measure of:
   11675             : a) "how large" the variable is
   11676             : b) how large the step should be to make significant changes in the function
   11677             : 
   11678             : Generally, scale is NOT considered to be a form of preconditioner.  But LM
   11679             : optimizer is unique in that it uses scaling matrix both  in  the  stopping
   11680             : condition tests and as Marquardt damping factor.
   11681             : 
   11682             : Proper scaling is very important for the algorithm performance. It is less
   11683             : important for the quality of results, but still has some influence (it  is
   11684             : easier  to  converge  when  variables  are  properly  scaled, so premature
   11685             : stopping is possible when very badly scalled variables are  combined  with
   11686             : relaxed stopping conditions).
   11687             : 
   11688             : INPUT PARAMETERS:
   11689             :     State   -   structure stores algorithm state
   11690             :     S       -   array[N], non-zero scaling coefficients
   11691             :                 S[i] may be negative, sign doesn't matter.
   11692             : 
   11693             :   -- ALGLIB --
   11694             :      Copyright 14.01.2011 by Bochkanov Sergey
   11695             : *************************************************************************/
   11696           0 : void lsfitsetscale(const lsfitstate &state, const real_1d_array &s, const xparams _xparams)
   11697             : {
   11698             :     jmp_buf _break_jump;
   11699             :     alglib_impl::ae_state _alglib_env_state;
   11700           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11701           0 :     if( setjmp(_break_jump) )
   11702             :     {
   11703             : #if !defined(AE_NO_EXCEPTIONS)
   11704           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11705             : #else
   11706             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11707             :         return;
   11708             : #endif
   11709             :     }
   11710           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11711           0 :     if( _xparams.flags!=0x0 )
   11712           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11713           0 :     alglib_impl::lsfitsetscale(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(s.c_ptr()), &_alglib_env_state);
   11714           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11715           0 :     return;
   11716             : }
   11717             : 
   11718             : /*************************************************************************
   11719             : This function sets boundary constraints for underlying optimizer
   11720             : 
   11721             : Boundary constraints are inactive by default (after initial creation).
   11722             : They are preserved until explicitly turned off with another SetBC() call.
   11723             : 
   11724             : INPUT PARAMETERS:
   11725             :     State   -   structure stores algorithm state
   11726             :     BndL    -   lower bounds, array[K].
   11727             :                 If some (all) variables are unbounded, you may specify
   11728             :                 very small number or -INF (latter is recommended because
   11729             :                 it will allow solver to use better algorithm).
   11730             :     BndU    -   upper bounds, array[K].
   11731             :                 If some (all) variables are unbounded, you may specify
   11732             :                 very large number or +INF (latter is recommended because
   11733             :                 it will allow solver to use better algorithm).
   11734             : 
   11735             : NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th
   11736             : variable will be "frozen" at X[i]=BndL[i]=BndU[i].
   11737             : 
   11738             : NOTE 2: unlike other constrained optimization algorithms, this solver  has
   11739             : following useful properties:
   11740             : * bound constraints are always satisfied exactly
   11741             : * function is evaluated only INSIDE area specified by bound constraints
   11742             : 
   11743             :   -- ALGLIB --
   11744             :      Copyright 14.01.2011 by Bochkanov Sergey
   11745             : *************************************************************************/
   11746           0 : void lsfitsetbc(const lsfitstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams)
   11747             : {
   11748             :     jmp_buf _break_jump;
   11749             :     alglib_impl::ae_state _alglib_env_state;
   11750           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11751           0 :     if( setjmp(_break_jump) )
   11752             :     {
   11753             : #if !defined(AE_NO_EXCEPTIONS)
   11754           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11755             : #else
   11756             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11757             :         return;
   11758             : #endif
   11759             :     }
   11760           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11761           0 :     if( _xparams.flags!=0x0 )
   11762           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11763           0 :     alglib_impl::lsfitsetbc(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndl.c_ptr()), const_cast<alglib_impl::ae_vector*>(bndu.c_ptr()), &_alglib_env_state);
   11764           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11765           0 :     return;
   11766             : }
   11767             : 
   11768             : /*************************************************************************
   11769             : This function sets linear constraints for underlying optimizer
   11770             : 
   11771             : Linear constraints are inactive by default (after initial creation).
   11772             : They are preserved until explicitly turned off with another SetLC() call.
   11773             : 
   11774             : INPUT PARAMETERS:
   11775             :     State   -   structure stores algorithm state
   11776             :     C       -   linear constraints, array[K,N+1].
   11777             :                 Each row of C represents one constraint, either equality
   11778             :                 or inequality (see below):
   11779             :                 * first N elements correspond to coefficients,
   11780             :                 * last element corresponds to the right part.
   11781             :                 All elements of C (including right part) must be finite.
   11782             :     CT      -   type of constraints, array[K]:
   11783             :                 * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1]
   11784             :                 * if CT[i]=0, then I-th constraint is C[i,*]*x  = C[i,n+1]
   11785             :                 * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1]
   11786             :     K       -   number of equality/inequality constraints, K>=0:
   11787             :                 * if given, only leading K elements of C/CT are used
   11788             :                 * if not given, automatically determined from sizes of C/CT
   11789             : 
   11790             : IMPORTANT: if you have linear constraints, it is strongly  recommended  to
   11791             :            set scale of variables with lsfitsetscale(). QP solver which is
   11792             :            used to calculate linearly constrained steps heavily relies  on
   11793             :            good scaling of input problems.
   11794             : 
   11795             : NOTE: linear  (non-box)  constraints  are  satisfied only approximately  -
   11796             :       there  always  exists some violation due  to  numerical  errors  and
   11797             :       algorithmic limitations.
   11798             : 
   11799             : NOTE: general linear constraints  add  significant  overhead  to  solution
   11800             :       process. Although solver performs roughly same amount of  iterations
   11801             :       (when compared  with  similar  box-only  constrained  problem), each
   11802             :       iteration   now    involves  solution  of  linearly  constrained  QP
   11803             :       subproblem, which requires ~3-5 times more Cholesky  decompositions.
   11804             :       Thus, if you can reformulate your problem in such way  this  it  has
   11805             :       only box constraints, it may be beneficial to do so.
   11806             : 
   11807             :   -- ALGLIB --
   11808             :      Copyright 29.04.2017 by Bochkanov Sergey
   11809             : *************************************************************************/
   11810           0 : void lsfitsetlc(const lsfitstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams)
   11811             : {
   11812             :     jmp_buf _break_jump;
   11813             :     alglib_impl::ae_state _alglib_env_state;
   11814           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11815           0 :     if( setjmp(_break_jump) )
   11816             :     {
   11817             : #if !defined(AE_NO_EXCEPTIONS)
   11818           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11819             : #else
   11820             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11821             :         return;
   11822             : #endif
   11823             :     }
   11824           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11825           0 :     if( _xparams.flags!=0x0 )
   11826           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11827           0 :     alglib_impl::lsfitsetlc(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(c.c_ptr()), const_cast<alglib_impl::ae_vector*>(ct.c_ptr()), k, &_alglib_env_state);
   11828           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11829           0 :     return;
   11830             : }
   11831             : 
   11832             : /*************************************************************************
   11833             : This function sets linear constraints for underlying optimizer
   11834             : 
   11835             : Linear constraints are inactive by default (after initial creation).
   11836             : They are preserved until explicitly turned off with another SetLC() call.
   11837             : 
   11838             : INPUT PARAMETERS:
   11839             :     State   -   structure stores algorithm state
   11840             :     C       -   linear constraints, array[K,N+1].
   11841             :                 Each row of C represents one constraint, either equality
   11842             :                 or inequality (see below):
   11843             :                 * first N elements correspond to coefficients,
   11844             :                 * last element corresponds to the right part.
   11845             :                 All elements of C (including right part) must be finite.
   11846             :     CT      -   type of constraints, array[K]:
   11847             :                 * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1]
   11848             :                 * if CT[i]=0, then I-th constraint is C[i,*]*x  = C[i,n+1]
   11849             :                 * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1]
   11850             :     K       -   number of equality/inequality constraints, K>=0:
   11851             :                 * if given, only leading K elements of C/CT are used
   11852             :                 * if not given, automatically determined from sizes of C/CT
   11853             : 
   11854             : IMPORTANT: if you have linear constraints, it is strongly  recommended  to
   11855             :            set scale of variables with lsfitsetscale(). QP solver which is
   11856             :            used to calculate linearly constrained steps heavily relies  on
   11857             :            good scaling of input problems.
   11858             : 
   11859             : NOTE: linear  (non-box)  constraints  are  satisfied only approximately  -
   11860             :       there  always  exists some violation due  to  numerical  errors  and
   11861             :       algorithmic limitations.
   11862             : 
   11863             : NOTE: general linear constraints  add  significant  overhead  to  solution
   11864             :       process. Although solver performs roughly same amount of  iterations
   11865             :       (when compared  with  similar  box-only  constrained  problem), each
   11866             :       iteration   now    involves  solution  of  linearly  constrained  QP
   11867             :       subproblem, which requires ~3-5 times more Cholesky  decompositions.
   11868             :       Thus, if you can reformulate your problem in such way  this  it  has
   11869             :       only box constraints, it may be beneficial to do so.
   11870             : 
   11871             :   -- ALGLIB --
   11872             :      Copyright 29.04.2017 by Bochkanov Sergey
   11873             : *************************************************************************/
   11874             : #if !defined(AE_NO_EXCEPTIONS)
   11875           0 : void lsfitsetlc(const lsfitstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams)
   11876             : {
   11877             :     jmp_buf _break_jump;
   11878             :     alglib_impl::ae_state _alglib_env_state;    
   11879             :     ae_int_t k;
   11880           0 :     if( (c.rows()!=ct.length()))
   11881           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitsetlc': looks like one of arguments has wrong size");
   11882           0 :     k = c.rows();
   11883           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11884           0 :     if( setjmp(_break_jump) )
   11885           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11886           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11887           0 :     if( _xparams.flags!=0x0 )
   11888           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11889           0 :     alglib_impl::lsfitsetlc(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(c.c_ptr()), const_cast<alglib_impl::ae_vector*>(ct.c_ptr()), k, &_alglib_env_state);
   11890             : 
   11891           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11892           0 :     return;
   11893             : }
   11894             : #endif
   11895             : 
   11896             : /*************************************************************************
   11897             : This function provides reverse communication interface
   11898             : Reverse communication interface is not documented or recommended to use.
   11899             : See below for functions which provide better documented API
   11900             : *************************************************************************/
   11901           0 : bool lsfititeration(const lsfitstate &state, const xparams _xparams)
   11902             : {
   11903             :     jmp_buf _break_jump;
   11904             :     alglib_impl::ae_state _alglib_env_state;
   11905           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11906           0 :     if( setjmp(_break_jump) )
   11907             :     {
   11908             : #if !defined(AE_NO_EXCEPTIONS)
   11909           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11910             : #else
   11911             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11912             :         return 0;
   11913             : #endif
   11914             :     }
   11915           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11916           0 :     if( _xparams.flags!=0x0 )
   11917           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11918           0 :     ae_bool result = alglib_impl::lsfititeration(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
   11919           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11920           0 :     return *(reinterpret_cast<bool*>(&result));
   11921             : }
   11922             : 
   11923             : 
   11924           0 : void lsfitfit(lsfitstate &state,
   11925             :     void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr),
   11926             :     void  (*rep)(const real_1d_array &c, double func, void *ptr), 
   11927             :     void *ptr,
   11928             :     const xparams _xparams)
   11929             : {
   11930             :     jmp_buf _break_jump;
   11931             :     alglib_impl::ae_state _alglib_env_state;
   11932           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11933           0 :     if( setjmp(_break_jump) )
   11934             :     {
   11935             : #if !defined(AE_NO_EXCEPTIONS)
   11936           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11937             : #else
   11938             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11939             :         return;
   11940             : #endif
   11941             :     }
   11942           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11943           0 :     if( _xparams.flags!=0x0 )
   11944           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11945           0 :     alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'lsfitfit()' (func is NULL)", &_alglib_env_state);
   11946           0 :     while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) )
   11947             :     {
   11948             :         _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN
   11949           0 :                 if( state.needf )
   11950             :                 {
   11951           0 :                     func(state.c, state.x, state.f, ptr);
   11952           0 :                     continue;
   11953             :                 }
   11954           0 :         if( state.xupdated )
   11955             :         {
   11956           0 :             if( rep!=NULL )
   11957           0 :                 rep(state.c, state.f, ptr);
   11958           0 :             continue;
   11959             :         }
   11960           0 :         goto lbl_no_callback;
   11961           0 :         _ALGLIB_CALLBACK_EXCEPTION_GUARD_END
   11962           0 :     lbl_no_callback:
   11963           0 :         alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)", &_alglib_env_state);
   11964             :     }
   11965           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   11966           0 : }
   11967             : 
   11968             : 
   11969           0 : void lsfitfit(lsfitstate &state,
   11970             :     void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr),
   11971             :     void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
   11972             :     void  (*rep)(const real_1d_array &c, double func, void *ptr), 
   11973             :     void *ptr,
   11974             :     const xparams _xparams)
   11975             : {
   11976             :     jmp_buf _break_jump;
   11977             :     alglib_impl::ae_state _alglib_env_state;
   11978           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   11979           0 :     if( setjmp(_break_jump) )
   11980             :     {
   11981             : #if !defined(AE_NO_EXCEPTIONS)
   11982           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   11983             : #else
   11984             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   11985             :         return;
   11986             : #endif
   11987             :     }
   11988           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   11989           0 :     if( _xparams.flags!=0x0 )
   11990           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   11991           0 :     alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'lsfitfit()' (func is NULL)", &_alglib_env_state);
   11992           0 :     alglib_impl::ae_assert(grad!=NULL, "ALGLIB: error in 'lsfitfit()' (grad is NULL)", &_alglib_env_state);
   11993           0 :     while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) )
   11994             :     {
   11995             :         _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN
   11996           0 :                 if( state.needf )
   11997             :                 {
   11998           0 :                     func(state.c, state.x, state.f, ptr);
   11999           0 :                     continue;
   12000             :                 }
   12001           0 :                 if( state.needfg )
   12002             :                 {
   12003           0 :                     grad(state.c, state.x, state.f, state.g, ptr);
   12004           0 :                     continue;
   12005             :                 }
   12006           0 :         if( state.xupdated )
   12007             :         {
   12008           0 :             if( rep!=NULL )
   12009           0 :                 rep(state.c, state.f, ptr);
   12010           0 :             continue;
   12011             :         }
   12012           0 :         goto lbl_no_callback;
   12013           0 :         _ALGLIB_CALLBACK_EXCEPTION_GUARD_END
   12014           0 :     lbl_no_callback:
   12015           0 :         alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)", &_alglib_env_state);
   12016             :     }
   12017           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   12018           0 : }
   12019             : 
   12020             : 
   12021           0 : void lsfitfit(lsfitstate &state,
   12022             :     void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr),
   12023             :     void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
   12024             :     void (*hess)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr),
   12025             :     void  (*rep)(const real_1d_array &c, double func, void *ptr), 
   12026             :     void *ptr,
   12027             :     const xparams _xparams)
   12028             : {
   12029             :     jmp_buf _break_jump;
   12030             :     alglib_impl::ae_state _alglib_env_state;
   12031           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   12032           0 :     if( setjmp(_break_jump) )
   12033             :     {
   12034             : #if !defined(AE_NO_EXCEPTIONS)
   12035           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   12036             : #else
   12037             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   12038             :         return;
   12039             : #endif
   12040             :     }
   12041           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   12042           0 :     if( _xparams.flags!=0x0 )
   12043           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   12044           0 :     alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'lsfitfit()' (func is NULL)", &_alglib_env_state);
   12045           0 :     alglib_impl::ae_assert(grad!=NULL, "ALGLIB: error in 'lsfitfit()' (grad is NULL)", &_alglib_env_state);
   12046           0 :     alglib_impl::ae_assert(hess!=NULL, "ALGLIB: error in 'lsfitfit()' (hess is NULL)", &_alglib_env_state);
   12047           0 :     while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) )
   12048             :     {
   12049             :         _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN
   12050           0 :                 if( state.needf )
   12051             :                 {
   12052           0 :                     func(state.c, state.x, state.f, ptr);
   12053           0 :                     continue;
   12054             :                 }
   12055           0 :                 if( state.needfg )
   12056             :                 {
   12057           0 :                     grad(state.c, state.x, state.f, state.g, ptr);
   12058           0 :                     continue;
   12059             :                 }
   12060           0 :                 if( state.needfgh )
   12061             :                 {
   12062           0 :                     hess(state.c, state.x, state.f, state.g, state.h, ptr);
   12063           0 :                     continue;
   12064             :                 }
   12065           0 :         if( state.xupdated )
   12066             :         {
   12067           0 :             if( rep!=NULL )
   12068           0 :                 rep(state.c, state.f, ptr);
   12069           0 :             continue;
   12070             :         }
   12071           0 :         goto lbl_no_callback;
   12072           0 :         _ALGLIB_CALLBACK_EXCEPTION_GUARD_END
   12073           0 :     lbl_no_callback:
   12074           0 :         alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)", &_alglib_env_state);
   12075             :     }
   12076           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   12077           0 : }
   12078             : 
   12079             : 
   12080             : 
   12081             : /*************************************************************************
   12082             : Nonlinear least squares fitting results.
   12083             : 
   12084             : Called after return from LSFitFit().
   12085             : 
   12086             : INPUT PARAMETERS:
   12087             :     State   -   algorithm state
   12088             : 
   12089             : OUTPUT PARAMETERS:
   12090             :     Info    -   completion code:
   12091             :                     * -8    optimizer   detected  NAN/INF  in  the  target
   12092             :                             function and/or gradient
   12093             :                     * -7    gradient verification failed.
   12094             :                             See LSFitSetGradientCheck() for more information.
   12095             :                     * -3    inconsistent constraints
   12096             :                     *  2    relative step is no more than EpsX.
   12097             :                     *  5    MaxIts steps was taken
   12098             :                     *  7    stopping conditions are too stringent,
   12099             :                             further improvement is impossible
   12100             :     C       -   array[0..K-1], solution
   12101             :     Rep     -   optimization report. On success following fields are set:
   12102             :                 * R2                non-adjusted coefficient of determination
   12103             :                                     (non-weighted)
   12104             :                 * RMSError          rms error on the (X,Y).
   12105             :                 * AvgError          average error on the (X,Y).
   12106             :                 * AvgRelError       average relative error on the non-zero Y
   12107             :                 * MaxError          maximum error
   12108             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   12109             :                 * WRMSError         weighted rms error on the (X,Y).
   12110             : 
   12111             : ERRORS IN PARAMETERS
   12112             : 
   12113             : This  solver  also  calculates different kinds of errors in parameters and
   12114             : fills corresponding fields of report:
   12115             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   12116             : * Rep.ErrPar        errors in parameters, array[K],
   12117             :                     errpar = sqrt(diag(CovPar))
   12118             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   12119             :                     best-fit curve from "ideal" best-fit curve built  with
   12120             :                     infinite number of samples, array[N].
   12121             :                     errcurve = sqrt(diag(J*CovPar*J')),
   12122             :                     where J is Jacobian matrix.
   12123             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   12124             : 
   12125             : IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
   12126             :             account boundary/linear constraints! Presence  of  constraints
   12127             :             changes distribution of errors, but there is no  easy  way  to
   12128             :             account for constraints when you calculate covariance matrix.
   12129             : 
   12130             : NOTE:       noise in the data is estimated as follows:
   12131             :             * for fitting without user-supplied  weights  all  points  are
   12132             :               assumed to have same level of noise, which is estimated from
   12133             :               the data
   12134             :             * for fitting with user-supplied weights we assume that  noise
   12135             :               level in I-th point is inversely proportional to Ith weight.
   12136             :               Coefficient of proportionality is estimated from the data.
   12137             : 
   12138             : NOTE:       we apply small amount of regularization when we invert squared
   12139             :             Jacobian and calculate covariance matrix. It  guarantees  that
   12140             :             algorithm won't divide by zero  during  inversion,  but  skews
   12141             :             error estimates a bit (fractional error is about 10^-9).
   12142             : 
   12143             :             However, we believe that this difference is insignificant  for
   12144             :             all practical purposes except for the situation when you  want
   12145             :             to compare ALGLIB results with "reference"  implementation  up
   12146             :             to the last significant digit.
   12147             : 
   12148             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   12149             :             of freedom (covariances are divided by N-M instead of dividing
   12150             :             by N).
   12151             : 
   12152             :   -- ALGLIB --
   12153             :      Copyright 17.08.2009 by Bochkanov Sergey
   12154             : *************************************************************************/
   12155           0 : void lsfitresults(const lsfitstate &state, ae_int_t &info, real_1d_array &c, lsfitreport &rep, const xparams _xparams)
   12156             : {
   12157             :     jmp_buf _break_jump;
   12158             :     alglib_impl::ae_state _alglib_env_state;
   12159           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   12160           0 :     if( setjmp(_break_jump) )
   12161             :     {
   12162             : #if !defined(AE_NO_EXCEPTIONS)
   12163           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   12164             : #else
   12165             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   12166             :         return;
   12167             : #endif
   12168             :     }
   12169           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   12170           0 :     if( _xparams.flags!=0x0 )
   12171           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   12172           0 :     alglib_impl::lsfitresults(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &info, const_cast<alglib_impl::ae_vector*>(c.c_ptr()), const_cast<alglib_impl::lsfitreport*>(rep.c_ptr()), &_alglib_env_state);
   12173           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   12174           0 :     return;
   12175             : }
   12176             : 
   12177             : /*************************************************************************
   12178             : This  subroutine  turns  on  verification  of  the  user-supplied analytic
   12179             : gradient:
   12180             : * user calls this subroutine before fitting begins
   12181             : * LSFitFit() is called
   12182             : * prior to actual fitting, for  each  point  in  data  set  X_i  and  each
   12183             :   component  of  parameters  being  fited C_j algorithm performs following
   12184             :   steps:
   12185             :   * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j],
   12186             :     where C_j is j-th parameter and S[j] is a scale of j-th parameter
   12187             :   * if needed, steps are bounded with respect to constraints on C[]
   12188             :   * F(X_i|C) is evaluated at these trial points
   12189             :   * we perform one more evaluation in the middle point of the interval
   12190             :   * we  build  cubic  model using function values and derivatives at trial
   12191             :     points and we compare its prediction with actual value in  the  middle
   12192             :     point
   12193             :   * in case difference between prediction and actual value is higher  than
   12194             :     some predetermined threshold, algorithm stops with completion code -7;
   12195             :     Rep.VarIdx is set to index of the parameter with incorrect derivative.
   12196             : * after verification is over, algorithm proceeds to the actual optimization.
   12197             : 
   12198             : NOTE 1: verification needs N*K (points count * parameters count)  gradient
   12199             :         evaluations. It is very costly and you should use it only for  low
   12200             :         dimensional  problems,  when  you  want  to  be  sure  that you've
   12201             :         correctly calculated analytic derivatives. You should not  use  it
   12202             :         in the production code  (unless  you  want  to  check  derivatives
   12203             :         provided by some third party).
   12204             : 
   12205             : NOTE 2: you  should  carefully  choose  TestStep. Value which is too large
   12206             :         (so large that function behaviour is significantly non-cubic) will
   12207             :         lead to false alarms. You may use  different  step  for  different
   12208             :         parameters by means of setting scale with LSFitSetScale().
   12209             : 
   12210             : NOTE 3: this function may lead to false positives. In case it reports that
   12211             :         I-th  derivative was calculated incorrectly, you may decrease test
   12212             :         step  and  try  one  more  time  - maybe your function changes too
   12213             :         sharply  and  your  step  is  too  large for such rapidly chanding
   12214             :         function.
   12215             : 
   12216             : NOTE 4: this function works only for optimizers created with LSFitCreateWFG()
   12217             :         or LSFitCreateFG() constructors.
   12218             : 
   12219             : INPUT PARAMETERS:
   12220             :     State       -   structure used to store algorithm state
   12221             :     TestStep    -   verification step:
   12222             :                     * TestStep=0 turns verification off
   12223             :                     * TestStep>0 activates verification
   12224             : 
   12225             :   -- ALGLIB --
   12226             :      Copyright 15.06.2012 by Bochkanov Sergey
   12227             : *************************************************************************/
   12228           0 : void lsfitsetgradientcheck(const lsfitstate &state, const double teststep, const xparams _xparams)
   12229             : {
   12230             :     jmp_buf _break_jump;
   12231             :     alglib_impl::ae_state _alglib_env_state;
   12232           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   12233           0 :     if( setjmp(_break_jump) )
   12234             :     {
   12235             : #if !defined(AE_NO_EXCEPTIONS)
   12236           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   12237             : #else
   12238             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   12239             :         return;
   12240             : #endif
   12241             :     }
   12242           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   12243           0 :     if( _xparams.flags!=0x0 )
   12244           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   12245           0 :     alglib_impl::lsfitsetgradientcheck(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), teststep, &_alglib_env_state);
   12246           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   12247           0 :     return;
   12248             : }
   12249             : #endif
   12250             : 
   12251             : #if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD)
   12252             : 
   12253             : #endif
   12254             : 
   12255             : #if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD)
   12256             : /*************************************************************************
   12257             : 2-dimensional spline inteprolant
   12258             : *************************************************************************/
   12259           0 : _spline2dinterpolant_owner::_spline2dinterpolant_owner()
   12260             : {
   12261             :     jmp_buf _break_jump;
   12262             :     alglib_impl::ae_state _state;
   12263             :     
   12264           0 :     alglib_impl::ae_state_init(&_state);
   12265           0 :     if( setjmp(_break_jump) )
   12266             :     {
   12267           0 :         if( p_struct!=NULL )
   12268             :         {
   12269           0 :             alglib_impl::_spline2dinterpolant_destroy(p_struct);
   12270           0 :             alglib_impl::ae_free(p_struct);
   12271             :         }
   12272           0 :         p_struct = NULL;
   12273             : #if !defined(AE_NO_EXCEPTIONS)
   12274           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   12275             : #else
   12276             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   12277             :         return;
   12278             : #endif
   12279             :     }
   12280           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   12281           0 :     p_struct = NULL;
   12282           0 :     p_struct = (alglib_impl::spline2dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dinterpolant), &_state);
   12283           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline2dinterpolant));
   12284           0 :     alglib_impl::_spline2dinterpolant_init(p_struct, &_state, ae_false);
   12285           0 :     ae_state_clear(&_state);
   12286           0 : }
   12287             : 
   12288           0 : _spline2dinterpolant_owner::_spline2dinterpolant_owner(const _spline2dinterpolant_owner &rhs)
   12289             : {
   12290             :     jmp_buf _break_jump;
   12291             :     alglib_impl::ae_state _state;
   12292             :     
   12293           0 :     alglib_impl::ae_state_init(&_state);
   12294           0 :     if( setjmp(_break_jump) )
   12295             :     {
   12296           0 :         if( p_struct!=NULL )
   12297             :         {
   12298           0 :             alglib_impl::_spline2dinterpolant_destroy(p_struct);
   12299           0 :             alglib_impl::ae_free(p_struct);
   12300             :         }
   12301           0 :         p_struct = NULL;
   12302             : #if !defined(AE_NO_EXCEPTIONS)
   12303           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   12304             : #else
   12305             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   12306             :         return;
   12307             : #endif
   12308             :     }
   12309           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   12310           0 :     p_struct = NULL;
   12311           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dinterpolant copy constructor failure (source is not initialized)", &_state);
   12312           0 :     p_struct = (alglib_impl::spline2dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dinterpolant), &_state);
   12313           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline2dinterpolant));
   12314           0 :     alglib_impl::_spline2dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline2dinterpolant*>(rhs.p_struct), &_state, ae_false);
   12315           0 :     ae_state_clear(&_state);
   12316           0 : }
   12317             : 
   12318           0 : _spline2dinterpolant_owner& _spline2dinterpolant_owner::operator=(const _spline2dinterpolant_owner &rhs)
   12319             : {
   12320           0 :     if( this==&rhs )
   12321           0 :         return *this;
   12322             :     jmp_buf _break_jump;
   12323             :     alglib_impl::ae_state _state;
   12324             :     
   12325           0 :     alglib_impl::ae_state_init(&_state);
   12326           0 :     if( setjmp(_break_jump) )
   12327             :     {
   12328             : #if !defined(AE_NO_EXCEPTIONS)
   12329           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   12330             : #else
   12331             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   12332             :         return *this;
   12333             : #endif
   12334             :     }
   12335           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   12336           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline2dinterpolant assignment constructor failure (destination is not initialized)", &_state);
   12337           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dinterpolant assignment constructor failure (source is not initialized)", &_state);
   12338           0 :     alglib_impl::_spline2dinterpolant_destroy(p_struct);
   12339           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline2dinterpolant));
   12340           0 :     alglib_impl::_spline2dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline2dinterpolant*>(rhs.p_struct), &_state, ae_false);
   12341           0 :     ae_state_clear(&_state);
   12342           0 :     return *this;
   12343             : }
   12344             : 
   12345           0 : _spline2dinterpolant_owner::~_spline2dinterpolant_owner()
   12346             : {
   12347           0 :     if( p_struct!=NULL )
   12348             :     {
   12349           0 :         alglib_impl::_spline2dinterpolant_destroy(p_struct);
   12350           0 :         ae_free(p_struct);
   12351             :     }
   12352           0 : }
   12353             : 
   12354           0 : alglib_impl::spline2dinterpolant* _spline2dinterpolant_owner::c_ptr()
   12355             : {
   12356           0 :     return p_struct;
   12357             : }
   12358             : 
   12359           0 : alglib_impl::spline2dinterpolant* _spline2dinterpolant_owner::c_ptr() const
   12360             : {
   12361           0 :     return const_cast<alglib_impl::spline2dinterpolant*>(p_struct);
   12362             : }
   12363           0 : spline2dinterpolant::spline2dinterpolant() : _spline2dinterpolant_owner() 
   12364             : {
   12365           0 : }
   12366             : 
   12367           0 : spline2dinterpolant::spline2dinterpolant(const spline2dinterpolant &rhs):_spline2dinterpolant_owner(rhs) 
   12368             : {
   12369           0 : }
   12370             : 
   12371           0 : spline2dinterpolant& spline2dinterpolant::operator=(const spline2dinterpolant &rhs)
   12372             : {
   12373           0 :     if( this==&rhs )
   12374           0 :         return *this;
   12375           0 :     _spline2dinterpolant_owner::operator=(rhs);
   12376           0 :     return *this;
   12377             : }
   12378             : 
   12379           0 : spline2dinterpolant::~spline2dinterpolant()
   12380             : {
   12381           0 : }
   12382             : 
   12383             : 
   12384             : /*************************************************************************
   12385             : Nonlinear least squares solver used to fit 2D splines to data
   12386             : *************************************************************************/
   12387           0 : _spline2dbuilder_owner::_spline2dbuilder_owner()
   12388             : {
   12389             :     jmp_buf _break_jump;
   12390             :     alglib_impl::ae_state _state;
   12391             :     
   12392           0 :     alglib_impl::ae_state_init(&_state);
   12393           0 :     if( setjmp(_break_jump) )
   12394             :     {
   12395           0 :         if( p_struct!=NULL )
   12396             :         {
   12397           0 :             alglib_impl::_spline2dbuilder_destroy(p_struct);
   12398           0 :             alglib_impl::ae_free(p_struct);
   12399             :         }
   12400           0 :         p_struct = NULL;
   12401             : #if !defined(AE_NO_EXCEPTIONS)
   12402           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   12403             : #else
   12404             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   12405             :         return;
   12406             : #endif
   12407             :     }
   12408           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   12409           0 :     p_struct = NULL;
   12410           0 :     p_struct = (alglib_impl::spline2dbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dbuilder), &_state);
   12411           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline2dbuilder));
   12412           0 :     alglib_impl::_spline2dbuilder_init(p_struct, &_state, ae_false);
   12413           0 :     ae_state_clear(&_state);
   12414           0 : }
   12415             : 
   12416           0 : _spline2dbuilder_owner::_spline2dbuilder_owner(const _spline2dbuilder_owner &rhs)
   12417             : {
   12418             :     jmp_buf _break_jump;
   12419             :     alglib_impl::ae_state _state;
   12420             :     
   12421           0 :     alglib_impl::ae_state_init(&_state);
   12422           0 :     if( setjmp(_break_jump) )
   12423             :     {
   12424           0 :         if( p_struct!=NULL )
   12425             :         {
   12426           0 :             alglib_impl::_spline2dbuilder_destroy(p_struct);
   12427           0 :             alglib_impl::ae_free(p_struct);
   12428             :         }
   12429           0 :         p_struct = NULL;
   12430             : #if !defined(AE_NO_EXCEPTIONS)
   12431           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   12432             : #else
   12433             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   12434             :         return;
   12435             : #endif
   12436             :     }
   12437           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   12438           0 :     p_struct = NULL;
   12439           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dbuilder copy constructor failure (source is not initialized)", &_state);
   12440           0 :     p_struct = (alglib_impl::spline2dbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dbuilder), &_state);
   12441           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline2dbuilder));
   12442           0 :     alglib_impl::_spline2dbuilder_init_copy(p_struct, const_cast<alglib_impl::spline2dbuilder*>(rhs.p_struct), &_state, ae_false);
   12443           0 :     ae_state_clear(&_state);
   12444           0 : }
   12445             : 
   12446           0 : _spline2dbuilder_owner& _spline2dbuilder_owner::operator=(const _spline2dbuilder_owner &rhs)
   12447             : {
   12448           0 :     if( this==&rhs )
   12449           0 :         return *this;
   12450             :     jmp_buf _break_jump;
   12451             :     alglib_impl::ae_state _state;
   12452             :     
   12453           0 :     alglib_impl::ae_state_init(&_state);
   12454           0 :     if( setjmp(_break_jump) )
   12455             :     {
   12456             : #if !defined(AE_NO_EXCEPTIONS)
   12457           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   12458             : #else
   12459             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   12460             :         return *this;
   12461             : #endif
   12462             :     }
   12463           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   12464           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline2dbuilder assignment constructor failure (destination is not initialized)", &_state);
   12465           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dbuilder assignment constructor failure (source is not initialized)", &_state);
   12466           0 :     alglib_impl::_spline2dbuilder_destroy(p_struct);
   12467           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline2dbuilder));
   12468           0 :     alglib_impl::_spline2dbuilder_init_copy(p_struct, const_cast<alglib_impl::spline2dbuilder*>(rhs.p_struct), &_state, ae_false);
   12469           0 :     ae_state_clear(&_state);
   12470           0 :     return *this;
   12471             : }
   12472             : 
   12473           0 : _spline2dbuilder_owner::~_spline2dbuilder_owner()
   12474             : {
   12475           0 :     if( p_struct!=NULL )
   12476             :     {
   12477           0 :         alglib_impl::_spline2dbuilder_destroy(p_struct);
   12478           0 :         ae_free(p_struct);
   12479             :     }
   12480           0 : }
   12481             : 
   12482           0 : alglib_impl::spline2dbuilder* _spline2dbuilder_owner::c_ptr()
   12483             : {
   12484           0 :     return p_struct;
   12485             : }
   12486             : 
   12487           0 : alglib_impl::spline2dbuilder* _spline2dbuilder_owner::c_ptr() const
   12488             : {
   12489           0 :     return const_cast<alglib_impl::spline2dbuilder*>(p_struct);
   12490             : }
   12491           0 : spline2dbuilder::spline2dbuilder() : _spline2dbuilder_owner() 
   12492             : {
   12493           0 : }
   12494             : 
   12495           0 : spline2dbuilder::spline2dbuilder(const spline2dbuilder &rhs):_spline2dbuilder_owner(rhs) 
   12496             : {
   12497           0 : }
   12498             : 
   12499           0 : spline2dbuilder& spline2dbuilder::operator=(const spline2dbuilder &rhs)
   12500             : {
   12501           0 :     if( this==&rhs )
   12502           0 :         return *this;
   12503           0 :     _spline2dbuilder_owner::operator=(rhs);
   12504           0 :     return *this;
   12505             : }
   12506             : 
   12507           0 : spline2dbuilder::~spline2dbuilder()
   12508             : {
   12509           0 : }
   12510             : 
   12511             : 
   12512             : /*************************************************************************
   12513             : Spline 2D fitting report:
   12514             :     rmserror        RMS error
   12515             :     avgerror        average error
   12516             :     maxerror        maximum error
   12517             :     r2              coefficient of determination,  R-squared, 1-RSS/TSS
   12518             : *************************************************************************/
   12519           0 : _spline2dfitreport_owner::_spline2dfitreport_owner()
   12520             : {
   12521             :     jmp_buf _break_jump;
   12522             :     alglib_impl::ae_state _state;
   12523             :     
   12524           0 :     alglib_impl::ae_state_init(&_state);
   12525           0 :     if( setjmp(_break_jump) )
   12526             :     {
   12527           0 :         if( p_struct!=NULL )
   12528             :         {
   12529           0 :             alglib_impl::_spline2dfitreport_destroy(p_struct);
   12530           0 :             alglib_impl::ae_free(p_struct);
   12531             :         }
   12532           0 :         p_struct = NULL;
   12533             : #if !defined(AE_NO_EXCEPTIONS)
   12534           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   12535             : #else
   12536             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   12537             :         return;
   12538             : #endif
   12539             :     }
   12540           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   12541           0 :     p_struct = NULL;
   12542           0 :     p_struct = (alglib_impl::spline2dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dfitreport), &_state);
   12543           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline2dfitreport));
   12544           0 :     alglib_impl::_spline2dfitreport_init(p_struct, &_state, ae_false);
   12545           0 :     ae_state_clear(&_state);
   12546           0 : }
   12547             : 
   12548           0 : _spline2dfitreport_owner::_spline2dfitreport_owner(const _spline2dfitreport_owner &rhs)
   12549             : {
   12550             :     jmp_buf _break_jump;
   12551             :     alglib_impl::ae_state _state;
   12552             :     
   12553           0 :     alglib_impl::ae_state_init(&_state);
   12554           0 :     if( setjmp(_break_jump) )
   12555             :     {
   12556           0 :         if( p_struct!=NULL )
   12557             :         {
   12558           0 :             alglib_impl::_spline2dfitreport_destroy(p_struct);
   12559           0 :             alglib_impl::ae_free(p_struct);
   12560             :         }
   12561           0 :         p_struct = NULL;
   12562             : #if !defined(AE_NO_EXCEPTIONS)
   12563           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   12564             : #else
   12565             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   12566             :         return;
   12567             : #endif
   12568             :     }
   12569           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   12570           0 :     p_struct = NULL;
   12571           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dfitreport copy constructor failure (source is not initialized)", &_state);
   12572           0 :     p_struct = (alglib_impl::spline2dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dfitreport), &_state);
   12573           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline2dfitreport));
   12574           0 :     alglib_impl::_spline2dfitreport_init_copy(p_struct, const_cast<alglib_impl::spline2dfitreport*>(rhs.p_struct), &_state, ae_false);
   12575           0 :     ae_state_clear(&_state);
   12576           0 : }
   12577             : 
   12578           0 : _spline2dfitreport_owner& _spline2dfitreport_owner::operator=(const _spline2dfitreport_owner &rhs)
   12579             : {
   12580           0 :     if( this==&rhs )
   12581           0 :         return *this;
   12582             :     jmp_buf _break_jump;
   12583             :     alglib_impl::ae_state _state;
   12584             :     
   12585           0 :     alglib_impl::ae_state_init(&_state);
   12586           0 :     if( setjmp(_break_jump) )
   12587             :     {
   12588             : #if !defined(AE_NO_EXCEPTIONS)
   12589           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   12590             : #else
   12591             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   12592             :         return *this;
   12593             : #endif
   12594             :     }
   12595           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   12596           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline2dfitreport assignment constructor failure (destination is not initialized)", &_state);
   12597           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dfitreport assignment constructor failure (source is not initialized)", &_state);
   12598           0 :     alglib_impl::_spline2dfitreport_destroy(p_struct);
   12599           0 :     memset(p_struct, 0, sizeof(alglib_impl::spline2dfitreport));
   12600           0 :     alglib_impl::_spline2dfitreport_init_copy(p_struct, const_cast<alglib_impl::spline2dfitreport*>(rhs.p_struct), &_state, ae_false);
   12601           0 :     ae_state_clear(&_state);
   12602           0 :     return *this;
   12603             : }
   12604             : 
   12605           0 : _spline2dfitreport_owner::~_spline2dfitreport_owner()
   12606             : {
   12607           0 :     if( p_struct!=NULL )
   12608             :     {
   12609           0 :         alglib_impl::_spline2dfitreport_destroy(p_struct);
   12610           0 :         ae_free(p_struct);
   12611             :     }
   12612           0 : }
   12613             : 
   12614           0 : alglib_impl::spline2dfitreport* _spline2dfitreport_owner::c_ptr()
   12615             : {
   12616           0 :     return p_struct;
   12617             : }
   12618             : 
   12619           0 : alglib_impl::spline2dfitreport* _spline2dfitreport_owner::c_ptr() const
   12620             : {
   12621           0 :     return const_cast<alglib_impl::spline2dfitreport*>(p_struct);
   12622             : }
   12623           0 : spline2dfitreport::spline2dfitreport() : _spline2dfitreport_owner() ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2)
   12624             : {
   12625           0 : }
   12626             : 
   12627           0 : spline2dfitreport::spline2dfitreport(const spline2dfitreport &rhs):_spline2dfitreport_owner(rhs) ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2)
   12628             : {
   12629           0 : }
   12630             : 
   12631           0 : spline2dfitreport& spline2dfitreport::operator=(const spline2dfitreport &rhs)
   12632             : {
   12633           0 :     if( this==&rhs )
   12634           0 :         return *this;
   12635           0 :     _spline2dfitreport_owner::operator=(rhs);
   12636           0 :     return *this;
   12637             : }
   12638             : 
   12639           0 : spline2dfitreport::~spline2dfitreport()
   12640             : {
   12641           0 : }
   12642             : 
   12643             : 
   12644             : /*************************************************************************
   12645             : This function serializes data structure to string.
   12646             : 
   12647             : Important properties of s_out:
   12648             : * it contains alphanumeric characters, dots, underscores, minus signs
   12649             : * these symbols are grouped into words, which are separated by spaces
   12650             :   and Windows-style (CR+LF) newlines
   12651             : * although  serializer  uses  spaces and CR+LF as separators, you can 
   12652             :   replace any separator character by arbitrary combination of spaces,
   12653             :   tabs, Windows or Unix newlines. It allows flexible reformatting  of
   12654             :   the  string  in  case you want to include it into text or XML file. 
   12655             :   But you should not insert separators into the middle of the "words"
   12656             :   nor you should change case of letters.
   12657             : * s_out can be freely moved between 32-bit and 64-bit systems, little
   12658             :   and big endian machines, and so on. You can serialize structure  on
   12659             :   32-bit machine and unserialize it on 64-bit one (or vice versa), or
   12660             :   serialize  it  on  SPARC  and  unserialize  on  x86.  You  can also 
   12661             :   serialize  it  in  C++ version of ALGLIB and unserialize in C# one, 
   12662             :   and vice versa.
   12663             : *************************************************************************/
   12664           0 : void spline2dserialize(spline2dinterpolant &obj, std::string &s_out)
   12665             : {
   12666             :     jmp_buf _break_jump;
   12667             :     alglib_impl::ae_state state;
   12668             :     alglib_impl::ae_serializer serializer;
   12669             :     alglib_impl::ae_int_t ssize;
   12670             : 
   12671           0 :     alglib_impl::ae_state_init(&state);
   12672           0 :     if( setjmp(_break_jump) )
   12673             :     {
   12674             : #if !defined(AE_NO_EXCEPTIONS)
   12675           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
   12676             : #else
   12677             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
   12678             :         return;
   12679             : #endif
   12680             :     }
   12681           0 :     ae_state_set_break_jump(&state, &_break_jump);
   12682           0 :     alglib_impl::ae_serializer_init(&serializer);
   12683           0 :     alglib_impl::ae_serializer_alloc_start(&serializer);
   12684           0 :     alglib_impl::spline2dalloc(&serializer, obj.c_ptr(), &state);
   12685           0 :     ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer);
   12686           0 :     s_out.clear();
   12687           0 :     s_out.reserve((size_t)(ssize+1));
   12688           0 :     alglib_impl::ae_serializer_sstart_str(&serializer, &s_out);
   12689           0 :     alglib_impl::spline2dserialize(&serializer, obj.c_ptr(), &state);
   12690           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
   12691           0 :     alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state);
   12692           0 :     alglib_impl::ae_serializer_clear(&serializer);
   12693           0 :     alglib_impl::ae_state_clear(&state);
   12694           0 : }
   12695             : /*************************************************************************
   12696             : This function unserializes data structure from string.
   12697             : *************************************************************************/
   12698           0 : void spline2dunserialize(const std::string &s_in, spline2dinterpolant &obj)
   12699             : {
   12700             :     jmp_buf _break_jump;
   12701             :     alglib_impl::ae_state state;
   12702             :     alglib_impl::ae_serializer serializer;
   12703             : 
   12704           0 :     alglib_impl::ae_state_init(&state);
   12705           0 :     if( setjmp(_break_jump) )
   12706             :     {
   12707             : #if !defined(AE_NO_EXCEPTIONS)
   12708           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
   12709             : #else
   12710             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
   12711             :         return;
   12712             : #endif
   12713             :     }
   12714           0 :     ae_state_set_break_jump(&state, &_break_jump);
   12715           0 :     alglib_impl::ae_serializer_init(&serializer);
   12716           0 :     alglib_impl::ae_serializer_ustart_str(&serializer, &s_in);
   12717           0 :     alglib_impl::spline2dunserialize(&serializer, obj.c_ptr(), &state);
   12718           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
   12719           0 :     alglib_impl::ae_serializer_clear(&serializer);
   12720           0 :     alglib_impl::ae_state_clear(&state);
   12721           0 : }
   12722             : 
   12723             : 
   12724             : /*************************************************************************
   12725             : This function serializes data structure to C++ stream.
   12726             : 
   12727             : Data stream generated by this function is same as  string  representation
   12728             : generated  by  string  version  of  serializer - alphanumeric characters,
   12729             : dots, underscores, minus signs, which are grouped into words separated by
   12730             : spaces and CR+LF.
   12731             : 
   12732             : We recommend you to read comments on string version of serializer to find
   12733             : out more about serialization of AlGLIB objects.
   12734             : *************************************************************************/
   12735           0 : void spline2dserialize(spline2dinterpolant &obj, std::ostream &s_out)
   12736             : {
   12737             :     jmp_buf _break_jump;
   12738             :     alglib_impl::ae_state state;
   12739             :     alglib_impl::ae_serializer serializer;
   12740             : 
   12741           0 :     alglib_impl::ae_state_init(&state);
   12742           0 :     if( setjmp(_break_jump) )
   12743             :     {
   12744             : #if !defined(AE_NO_EXCEPTIONS)
   12745           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
   12746             : #else
   12747             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
   12748             :         return;
   12749             : #endif
   12750             :     }
   12751           0 :     ae_state_set_break_jump(&state, &_break_jump);
   12752           0 :     alglib_impl::ae_serializer_init(&serializer);
   12753           0 :     alglib_impl::ae_serializer_alloc_start(&serializer);
   12754           0 :     alglib_impl::spline2dalloc(&serializer, obj.c_ptr(), &state);
   12755           0 :     alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask
   12756           0 :     alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out);
   12757           0 :     alglib_impl::spline2dserialize(&serializer, obj.c_ptr(), &state);
   12758           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
   12759           0 :     alglib_impl::ae_serializer_clear(&serializer);
   12760           0 :     alglib_impl::ae_state_clear(&state);
   12761           0 : }
   12762             : /*************************************************************************
   12763             : This function unserializes data structure from stream.
   12764             : *************************************************************************/
   12765           0 : void spline2dunserialize(const std::istream &s_in, spline2dinterpolant &obj)
   12766             : {
   12767             :     jmp_buf _break_jump;
   12768             :     alglib_impl::ae_state state;
   12769             :     alglib_impl::ae_serializer serializer;
   12770             : 
   12771           0 :     alglib_impl::ae_state_init(&state);
   12772           0 :     if( setjmp(_break_jump) )
   12773             :     {
   12774             : #if !defined(AE_NO_EXCEPTIONS)
   12775           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
   12776             : #else
   12777             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
   12778             :         return;
   12779             : #endif
   12780             :     }
   12781           0 :     ae_state_set_break_jump(&state, &_break_jump);
   12782           0 :     alglib_impl::ae_serializer_init(&serializer);
   12783           0 :     alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in);
   12784           0 :     alglib_impl::spline2dunserialize(&serializer, obj.c_ptr(), &state);
   12785           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
   12786           0 :     alglib_impl::ae_serializer_clear(&serializer);
   12787           0 :     alglib_impl::ae_state_clear(&state);
   12788           0 : }
   12789             : 
   12790             : /*************************************************************************
   12791             : This subroutine calculates the value of the bilinear or bicubic spline  at
   12792             : the given point X.
   12793             : 
   12794             : Input parameters:
   12795             :     C   -   2D spline object.
   12796             :             Built by spline2dbuildbilinearv or spline2dbuildbicubicv.
   12797             :     X, Y-   point
   12798             : 
   12799             : Result:
   12800             :     S(x,y)
   12801             : 
   12802             :   -- ALGLIB PROJECT --
   12803             :      Copyright 05.07.2007 by Bochkanov Sergey
   12804             : *************************************************************************/
   12805           0 : double spline2dcalc(const spline2dinterpolant &c, const double x, const double y, const xparams _xparams)
   12806             : {
   12807             :     jmp_buf _break_jump;
   12808             :     alglib_impl::ae_state _alglib_env_state;
   12809           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   12810           0 :     if( setjmp(_break_jump) )
   12811             :     {
   12812             : #if !defined(AE_NO_EXCEPTIONS)
   12813           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   12814             : #else
   12815             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   12816             :         return 0;
   12817             : #endif
   12818             :     }
   12819           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   12820           0 :     if( _xparams.flags!=0x0 )
   12821           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   12822           0 :     double result = alglib_impl::spline2dcalc(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), x, y, &_alglib_env_state);
   12823           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   12824           0 :     return *(reinterpret_cast<double*>(&result));
   12825             : }
   12826             : 
   12827             : /*************************************************************************
   12828             : This subroutine calculates the value of the bilinear or bicubic spline  at
   12829             : the given point X and its derivatives.
   12830             : 
   12831             : Input parameters:
   12832             :     C   -   spline interpolant.
   12833             :     X, Y-   point
   12834             : 
   12835             : Output parameters:
   12836             :     F   -   S(x,y)
   12837             :     FX  -   dS(x,y)/dX
   12838             :     FY  -   dS(x,y)/dY
   12839             :     FXY -   d2S(x,y)/dXdY
   12840             : 
   12841             :   -- ALGLIB PROJECT --
   12842             :      Copyright 05.07.2007 by Bochkanov Sergey
   12843             : *************************************************************************/
   12844           0 : void spline2ddiff(const spline2dinterpolant &c, const double x, const double y, double &f, double &fx, double &fy, double &fxy, const xparams _xparams)
   12845             : {
   12846             :     jmp_buf _break_jump;
   12847             :     alglib_impl::ae_state _alglib_env_state;
   12848           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   12849           0 :     if( setjmp(_break_jump) )
   12850             :     {
   12851             : #if !defined(AE_NO_EXCEPTIONS)
   12852           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   12853             : #else
   12854             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   12855             :         return;
   12856             : #endif
   12857             :     }
   12858           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   12859           0 :     if( _xparams.flags!=0x0 )
   12860           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   12861           0 :     alglib_impl::spline2ddiff(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), x, y, &f, &fx, &fy, &fxy, &_alglib_env_state);
   12862           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   12863           0 :     return;
   12864             : }
   12865             : 
   12866             : /*************************************************************************
   12867             : This subroutine calculates bilinear or bicubic vector-valued spline at the
   12868             : given point (X,Y).
   12869             : 
   12870             : If you need just some specific component of vector-valued spline, you  can
   12871             : use spline2dcalcvi() function.
   12872             : 
   12873             : INPUT PARAMETERS:
   12874             :     C   -   spline interpolant.
   12875             :     X, Y-   point
   12876             :     F   -   output buffer, possibly preallocated array. In case array size
   12877             :             is large enough to store result, it is not reallocated.  Array
   12878             :             which is too short will be reallocated
   12879             : 
   12880             : OUTPUT PARAMETERS:
   12881             :     F   -   array[D] (or larger) which stores function values
   12882             : 
   12883             :   -- ALGLIB PROJECT --
   12884             :      Copyright 01.02.2018 by Bochkanov Sergey
   12885             : *************************************************************************/
   12886           0 : void spline2dcalcvbuf(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f, const xparams _xparams)
   12887             : {
   12888             :     jmp_buf _break_jump;
   12889             :     alglib_impl::ae_state _alglib_env_state;
   12890           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   12891           0 :     if( setjmp(_break_jump) )
   12892             :     {
   12893             : #if !defined(AE_NO_EXCEPTIONS)
   12894           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   12895             : #else
   12896             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   12897             :         return;
   12898             : #endif
   12899             :     }
   12900           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   12901           0 :     if( _xparams.flags!=0x0 )
   12902           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   12903           0 :     alglib_impl::spline2dcalcvbuf(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), x, y, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), &_alglib_env_state);
   12904           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   12905           0 :     return;
   12906             : }
   12907             : 
   12908             : /*************************************************************************
   12909             : This subroutine calculates specific component of vector-valued bilinear or
   12910             : bicubic spline at the given point (X,Y).
   12911             : 
   12912             : INPUT PARAMETERS:
   12913             :     C   -   spline interpolant.
   12914             :     X, Y-   point
   12915             :     I   -   component index, in [0,D). An exception is generated for out
   12916             :             of range values.
   12917             : 
   12918             : RESULT:
   12919             :     value of I-th component
   12920             : 
   12921             :   -- ALGLIB PROJECT --
   12922             :      Copyright 01.02.2018 by Bochkanov Sergey
   12923             : *************************************************************************/
   12924           0 : double spline2dcalcvi(const spline2dinterpolant &c, const double x, const double y, const ae_int_t i, const xparams _xparams)
   12925             : {
   12926             :     jmp_buf _break_jump;
   12927             :     alglib_impl::ae_state _alglib_env_state;
   12928           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   12929           0 :     if( setjmp(_break_jump) )
   12930             :     {
   12931             : #if !defined(AE_NO_EXCEPTIONS)
   12932           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   12933             : #else
   12934             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   12935             :         return 0;
   12936             : #endif
   12937             :     }
   12938           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   12939           0 :     if( _xparams.flags!=0x0 )
   12940           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   12941           0 :     double result = alglib_impl::spline2dcalcvi(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), x, y, i, &_alglib_env_state);
   12942           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   12943           0 :     return *(reinterpret_cast<double*>(&result));
   12944             : }
   12945             : 
   12946             : /*************************************************************************
   12947             : This subroutine calculates bilinear or bicubic vector-valued spline at the
   12948             : given point (X,Y).
   12949             : 
   12950             : INPUT PARAMETERS:
   12951             :     C   -   spline interpolant.
   12952             :     X, Y-   point
   12953             : 
   12954             : OUTPUT PARAMETERS:
   12955             :     F   -   array[D] which stores function values.  F is out-parameter and
   12956             :             it  is  reallocated  after  call to this function. In case you
   12957             :             want  to    reuse  previously  allocated  F,   you   may   use
   12958             :             Spline2DCalcVBuf(),  which  reallocates  F only when it is too
   12959             :             small.
   12960             : 
   12961             :   -- ALGLIB PROJECT --
   12962             :      Copyright 16.04.2012 by Bochkanov Sergey
   12963             : *************************************************************************/
   12964           0 : void spline2dcalcv(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f, const xparams _xparams)
   12965             : {
   12966             :     jmp_buf _break_jump;
   12967             :     alglib_impl::ae_state _alglib_env_state;
   12968           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   12969           0 :     if( setjmp(_break_jump) )
   12970             :     {
   12971             : #if !defined(AE_NO_EXCEPTIONS)
   12972           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   12973             : #else
   12974             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   12975             :         return;
   12976             : #endif
   12977             :     }
   12978           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   12979           0 :     if( _xparams.flags!=0x0 )
   12980           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   12981           0 :     alglib_impl::spline2dcalcv(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), x, y, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), &_alglib_env_state);
   12982           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   12983           0 :     return;
   12984             : }
   12985             : 
   12986             : /*************************************************************************
   12987             : This subroutine calculates value of  specific  component  of  bilinear  or
   12988             : bicubic vector-valued spline and its derivatives.
   12989             : 
   12990             : Input parameters:
   12991             :     C   -   spline interpolant.
   12992             :     X, Y-   point
   12993             :     I   -   component index, in [0,D)
   12994             : 
   12995             : Output parameters:
   12996             :     F   -   S(x,y)
   12997             :     FX  -   dS(x,y)/dX
   12998             :     FY  -   dS(x,y)/dY
   12999             :     FXY -   d2S(x,y)/dXdY
   13000             : 
   13001             :   -- ALGLIB PROJECT --
   13002             :      Copyright 05.07.2007 by Bochkanov Sergey
   13003             : *************************************************************************/
   13004           0 : void spline2ddiffvi(const spline2dinterpolant &c, const double x, const double y, const ae_int_t i, double &f, double &fx, double &fy, double &fxy, const xparams _xparams)
   13005             : {
   13006             :     jmp_buf _break_jump;
   13007             :     alglib_impl::ae_state _alglib_env_state;
   13008           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13009           0 :     if( setjmp(_break_jump) )
   13010             :     {
   13011             : #if !defined(AE_NO_EXCEPTIONS)
   13012           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13013             : #else
   13014             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13015             :         return;
   13016             : #endif
   13017             :     }
   13018           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13019           0 :     if( _xparams.flags!=0x0 )
   13020           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13021           0 :     alglib_impl::spline2ddiffvi(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), x, y, i, &f, &fx, &fy, &fxy, &_alglib_env_state);
   13022           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13023           0 :     return;
   13024             : }
   13025             : 
   13026             : /*************************************************************************
   13027             : This subroutine performs linear transformation of the spline argument.
   13028             : 
   13029             : Input parameters:
   13030             :     C       -   spline interpolant
   13031             :     AX, BX  -   transformation coefficients: x = A*t + B
   13032             :     AY, BY  -   transformation coefficients: y = A*u + B
   13033             : Result:
   13034             :     C   -   transformed spline
   13035             : 
   13036             :   -- ALGLIB PROJECT --
   13037             :      Copyright 30.06.2007 by Bochkanov Sergey
   13038             : *************************************************************************/
   13039           0 : void spline2dlintransxy(const spline2dinterpolant &c, const double ax, const double bx, const double ay, const double by, const xparams _xparams)
   13040             : {
   13041             :     jmp_buf _break_jump;
   13042             :     alglib_impl::ae_state _alglib_env_state;
   13043           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13044           0 :     if( setjmp(_break_jump) )
   13045             :     {
   13046             : #if !defined(AE_NO_EXCEPTIONS)
   13047           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13048             : #else
   13049             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13050             :         return;
   13051             : #endif
   13052             :     }
   13053           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13054           0 :     if( _xparams.flags!=0x0 )
   13055           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13056           0 :     alglib_impl::spline2dlintransxy(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), ax, bx, ay, by, &_alglib_env_state);
   13057           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13058           0 :     return;
   13059             : }
   13060             : 
   13061             : /*************************************************************************
   13062             : This subroutine performs linear transformation of the spline.
   13063             : 
   13064             : Input parameters:
   13065             :     C   -   spline interpolant.
   13066             :     A, B-   transformation coefficients: S2(x,y) = A*S(x,y) + B
   13067             : 
   13068             : Output parameters:
   13069             :     C   -   transformed spline
   13070             : 
   13071             :   -- ALGLIB PROJECT --
   13072             :      Copyright 30.06.2007 by Bochkanov Sergey
   13073             : *************************************************************************/
   13074           0 : void spline2dlintransf(const spline2dinterpolant &c, const double a, const double b, const xparams _xparams)
   13075             : {
   13076             :     jmp_buf _break_jump;
   13077             :     alglib_impl::ae_state _alglib_env_state;
   13078           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13079           0 :     if( setjmp(_break_jump) )
   13080             :     {
   13081             : #if !defined(AE_NO_EXCEPTIONS)
   13082           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13083             : #else
   13084             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13085             :         return;
   13086             : #endif
   13087             :     }
   13088           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13089           0 :     if( _xparams.flags!=0x0 )
   13090           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13091           0 :     alglib_impl::spline2dlintransf(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), a, b, &_alglib_env_state);
   13092           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13093           0 :     return;
   13094             : }
   13095             : 
   13096             : /*************************************************************************
   13097             : This subroutine makes the copy of the spline model.
   13098             : 
   13099             : Input parameters:
   13100             :     C   -   spline interpolant
   13101             : 
   13102             : Output parameters:
   13103             :     CC  -   spline copy
   13104             : 
   13105             :   -- ALGLIB PROJECT --
   13106             :      Copyright 29.06.2007 by Bochkanov Sergey
   13107             : *************************************************************************/
   13108           0 : void spline2dcopy(const spline2dinterpolant &c, spline2dinterpolant &cc, const xparams _xparams)
   13109             : {
   13110             :     jmp_buf _break_jump;
   13111             :     alglib_impl::ae_state _alglib_env_state;
   13112           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13113           0 :     if( setjmp(_break_jump) )
   13114             :     {
   13115             : #if !defined(AE_NO_EXCEPTIONS)
   13116           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13117             : #else
   13118             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13119             :         return;
   13120             : #endif
   13121             :     }
   13122           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13123           0 :     if( _xparams.flags!=0x0 )
   13124           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13125           0 :     alglib_impl::spline2dcopy(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), const_cast<alglib_impl::spline2dinterpolant*>(cc.c_ptr()), &_alglib_env_state);
   13126           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13127           0 :     return;
   13128             : }
   13129             : 
   13130             : /*************************************************************************
   13131             : Bicubic spline resampling
   13132             : 
   13133             : Input parameters:
   13134             :     A           -   function values at the old grid,
   13135             :                     array[0..OldHeight-1, 0..OldWidth-1]
   13136             :     OldHeight   -   old grid height, OldHeight>1
   13137             :     OldWidth    -   old grid width, OldWidth>1
   13138             :     NewHeight   -   new grid height, NewHeight>1
   13139             :     NewWidth    -   new grid width, NewWidth>1
   13140             : 
   13141             : Output parameters:
   13142             :     B           -   function values at the new grid,
   13143             :                     array[0..NewHeight-1, 0..NewWidth-1]
   13144             : 
   13145             :   -- ALGLIB routine --
   13146             :      15 May, 2007
   13147             :      Copyright by Bochkanov Sergey
   13148             : *************************************************************************/
   13149           0 : 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)
   13150             : {
   13151             :     jmp_buf _break_jump;
   13152             :     alglib_impl::ae_state _alglib_env_state;
   13153           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13154           0 :     if( setjmp(_break_jump) )
   13155             :     {
   13156             : #if !defined(AE_NO_EXCEPTIONS)
   13157           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13158             : #else
   13159             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13160             :         return;
   13161             : #endif
   13162             :     }
   13163           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13164           0 :     if( _xparams.flags!=0x0 )
   13165           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13166           0 :     alglib_impl::spline2dresamplebicubic(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), oldheight, oldwidth, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), newheight, newwidth, &_alglib_env_state);
   13167           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13168           0 :     return;
   13169             : }
   13170             : 
   13171             : /*************************************************************************
   13172             : Bilinear spline resampling
   13173             : 
   13174             : Input parameters:
   13175             :     A           -   function values at the old grid,
   13176             :                     array[0..OldHeight-1, 0..OldWidth-1]
   13177             :     OldHeight   -   old grid height, OldHeight>1
   13178             :     OldWidth    -   old grid width, OldWidth>1
   13179             :     NewHeight   -   new grid height, NewHeight>1
   13180             :     NewWidth    -   new grid width, NewWidth>1
   13181             : 
   13182             : Output parameters:
   13183             :     B           -   function values at the new grid,
   13184             :                     array[0..NewHeight-1, 0..NewWidth-1]
   13185             : 
   13186             :   -- ALGLIB routine --
   13187             :      09.07.2007
   13188             :      Copyright by Bochkanov Sergey
   13189             : *************************************************************************/
   13190           0 : 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)
   13191             : {
   13192             :     jmp_buf _break_jump;
   13193             :     alglib_impl::ae_state _alglib_env_state;
   13194           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13195           0 :     if( setjmp(_break_jump) )
   13196             :     {
   13197             : #if !defined(AE_NO_EXCEPTIONS)
   13198           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13199             : #else
   13200             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13201             :         return;
   13202             : #endif
   13203             :     }
   13204           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13205           0 :     if( _xparams.flags!=0x0 )
   13206           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13207           0 :     alglib_impl::spline2dresamplebilinear(const_cast<alglib_impl::ae_matrix*>(a.c_ptr()), oldheight, oldwidth, const_cast<alglib_impl::ae_matrix*>(b.c_ptr()), newheight, newwidth, &_alglib_env_state);
   13208           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13209           0 :     return;
   13210             : }
   13211             : 
   13212             : /*************************************************************************
   13213             : This subroutine builds bilinear vector-valued spline.
   13214             : 
   13215             : Input parameters:
   13216             :     X   -   spline abscissas, array[0..N-1]
   13217             :     Y   -   spline ordinates, array[0..M-1]
   13218             :     F   -   function values, array[0..M*N*D-1]:
   13219             :             * first D elements store D values at (X[0],Y[0])
   13220             :             * next D elements store D values at (X[1],Y[0])
   13221             :             * general form - D function values at (X[i],Y[j]) are stored
   13222             :               at F[D*(J*N+I)...D*(J*N+I)+D-1].
   13223             :     M,N -   grid size, M>=2, N>=2
   13224             :     D   -   vector dimension, D>=1
   13225             : 
   13226             : Output parameters:
   13227             :     C   -   spline interpolant
   13228             : 
   13229             :   -- ALGLIB PROJECT --
   13230             :      Copyright 16.04.2012 by Bochkanov Sergey
   13231             : *************************************************************************/
   13232           0 : 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)
   13233             : {
   13234             :     jmp_buf _break_jump;
   13235             :     alglib_impl::ae_state _alglib_env_state;
   13236           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13237           0 :     if( setjmp(_break_jump) )
   13238             :     {
   13239             : #if !defined(AE_NO_EXCEPTIONS)
   13240           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13241             : #else
   13242             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13243             :         return;
   13244             : #endif
   13245             :     }
   13246           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13247           0 :     if( _xparams.flags!=0x0 )
   13248           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13249           0 :     alglib_impl::spline2dbuildbilinearv(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), m, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), d, const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), &_alglib_env_state);
   13250           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13251           0 :     return;
   13252             : }
   13253             : 
   13254             : /*************************************************************************
   13255             : This subroutine builds bicubic vector-valued spline.
   13256             : 
   13257             : Input parameters:
   13258             :     X   -   spline abscissas, array[0..N-1]
   13259             :     Y   -   spline ordinates, array[0..M-1]
   13260             :     F   -   function values, array[0..M*N*D-1]:
   13261             :             * first D elements store D values at (X[0],Y[0])
   13262             :             * next D elements store D values at (X[1],Y[0])
   13263             :             * general form - D function values at (X[i],Y[j]) are stored
   13264             :               at F[D*(J*N+I)...D*(J*N+I)+D-1].
   13265             :     M,N -   grid size, M>=2, N>=2
   13266             :     D   -   vector dimension, D>=1
   13267             : 
   13268             : Output parameters:
   13269             :     C   -   spline interpolant
   13270             : 
   13271             :   -- ALGLIB PROJECT --
   13272             :      Copyright 16.04.2012 by Bochkanov Sergey
   13273             : *************************************************************************/
   13274           0 : 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)
   13275             : {
   13276             :     jmp_buf _break_jump;
   13277             :     alglib_impl::ae_state _alglib_env_state;
   13278           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13279           0 :     if( setjmp(_break_jump) )
   13280             :     {
   13281             : #if !defined(AE_NO_EXCEPTIONS)
   13282           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13283             : #else
   13284             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13285             :         return;
   13286             : #endif
   13287             :     }
   13288           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13289           0 :     if( _xparams.flags!=0x0 )
   13290           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13291           0 :     alglib_impl::spline2dbuildbicubicv(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), m, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), d, const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), &_alglib_env_state);
   13292           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13293           0 :     return;
   13294             : }
   13295             : 
   13296             : /*************************************************************************
   13297             : This subroutine unpacks two-dimensional spline into the coefficients table
   13298             : 
   13299             : Input parameters:
   13300             :     C   -   spline interpolant.
   13301             : 
   13302             : Result:
   13303             :     M, N-   grid size (x-axis and y-axis)
   13304             :     D   -   number of components
   13305             :     Tbl -   coefficients table, unpacked format,
   13306             :             D - components: [0..(N-1)*(M-1)*D-1, 0..19].
   13307             :             For T=0..D-1 (component index), I = 0...N-2 (x index),
   13308             :             J=0..M-2 (y index):
   13309             :                 K :=  T + I*D + J*D*(N-1)
   13310             : 
   13311             :                 K-th row stores decomposition for T-th component of the
   13312             :                 vector-valued function
   13313             : 
   13314             :                 Tbl[K,0] = X[i]
   13315             :                 Tbl[K,1] = X[i+1]
   13316             :                 Tbl[K,2] = Y[j]
   13317             :                 Tbl[K,3] = Y[j+1]
   13318             :                 Tbl[K,4] = C00
   13319             :                 Tbl[K,5] = C01
   13320             :                 Tbl[K,6] = C02
   13321             :                 Tbl[K,7] = C03
   13322             :                 Tbl[K,8] = C10
   13323             :                 Tbl[K,9] = C11
   13324             :                 ...
   13325             :                 Tbl[K,19] = C33
   13326             :             On each grid square spline is equals to:
   13327             :                 S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3)
   13328             :                 t = x-x[j]
   13329             :                 u = y-y[i]
   13330             : 
   13331             :   -- ALGLIB PROJECT --
   13332             :      Copyright 16.04.2012 by Bochkanov Sergey
   13333             : *************************************************************************/
   13334           0 : void spline2dunpackv(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, ae_int_t &d, real_2d_array &tbl, const xparams _xparams)
   13335             : {
   13336             :     jmp_buf _break_jump;
   13337             :     alglib_impl::ae_state _alglib_env_state;
   13338           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13339           0 :     if( setjmp(_break_jump) )
   13340             :     {
   13341             : #if !defined(AE_NO_EXCEPTIONS)
   13342           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13343             : #else
   13344             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13345             :         return;
   13346             : #endif
   13347             :     }
   13348           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13349           0 :     if( _xparams.flags!=0x0 )
   13350           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13351           0 :     alglib_impl::spline2dunpackv(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), &m, &n, &d, const_cast<alglib_impl::ae_matrix*>(tbl.c_ptr()), &_alglib_env_state);
   13352           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13353           0 :     return;
   13354             : }
   13355             : 
   13356             : /*************************************************************************
   13357             : This subroutine was deprecated in ALGLIB 3.6.0
   13358             : 
   13359             : We recommend you to switch  to  Spline2DBuildBilinearV(),  which  is  more
   13360             : flexible and accepts its arguments in more convenient order.
   13361             : 
   13362             :   -- ALGLIB PROJECT --
   13363             :      Copyright 05.07.2007 by Bochkanov Sergey
   13364             : *************************************************************************/
   13365           0 : 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)
   13366             : {
   13367             :     jmp_buf _break_jump;
   13368             :     alglib_impl::ae_state _alglib_env_state;
   13369           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13370           0 :     if( setjmp(_break_jump) )
   13371             :     {
   13372             : #if !defined(AE_NO_EXCEPTIONS)
   13373           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13374             : #else
   13375             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13376             :         return;
   13377             : #endif
   13378             :     }
   13379           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13380           0 :     if( _xparams.flags!=0x0 )
   13381           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13382           0 :     alglib_impl::spline2dbuildbilinear(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_matrix*>(f.c_ptr()), m, n, const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), &_alglib_env_state);
   13383           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13384           0 :     return;
   13385             : }
   13386             : 
   13387             : /*************************************************************************
   13388             : This subroutine was deprecated in ALGLIB 3.6.0
   13389             : 
   13390             : We recommend you to switch  to  Spline2DBuildBicubicV(),  which  is  more
   13391             : flexible and accepts its arguments in more convenient order.
   13392             : 
   13393             :   -- ALGLIB PROJECT --
   13394             :      Copyright 05.07.2007 by Bochkanov Sergey
   13395             : *************************************************************************/
   13396           0 : 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)
   13397             : {
   13398             :     jmp_buf _break_jump;
   13399             :     alglib_impl::ae_state _alglib_env_state;
   13400           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13401           0 :     if( setjmp(_break_jump) )
   13402             :     {
   13403             : #if !defined(AE_NO_EXCEPTIONS)
   13404           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13405             : #else
   13406             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13407             :         return;
   13408             : #endif
   13409             :     }
   13410           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13411           0 :     if( _xparams.flags!=0x0 )
   13412           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13413           0 :     alglib_impl::spline2dbuildbicubic(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_matrix*>(f.c_ptr()), m, n, const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), &_alglib_env_state);
   13414           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13415           0 :     return;
   13416             : }
   13417             : 
   13418             : /*************************************************************************
   13419             : This subroutine was deprecated in ALGLIB 3.6.0
   13420             : 
   13421             : We recommend you to switch  to  Spline2DUnpackV(),  which is more flexible
   13422             : and accepts its arguments in more convenient order.
   13423             : 
   13424             :   -- ALGLIB PROJECT --
   13425             :      Copyright 29.06.2007 by Bochkanov Sergey
   13426             : *************************************************************************/
   13427           0 : void spline2dunpack(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, real_2d_array &tbl, const xparams _xparams)
   13428             : {
   13429             :     jmp_buf _break_jump;
   13430             :     alglib_impl::ae_state _alglib_env_state;
   13431           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13432           0 :     if( setjmp(_break_jump) )
   13433             :     {
   13434             : #if !defined(AE_NO_EXCEPTIONS)
   13435           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13436             : #else
   13437             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13438             :         return;
   13439             : #endif
   13440             :     }
   13441           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13442           0 :     if( _xparams.flags!=0x0 )
   13443           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13444           0 :     alglib_impl::spline2dunpack(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), &m, &n, const_cast<alglib_impl::ae_matrix*>(tbl.c_ptr()), &_alglib_env_state);
   13445           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13446           0 :     return;
   13447             : }
   13448             : 
   13449             : /*************************************************************************
   13450             : This subroutine creates least squares solver used to  fit  2D  splines  to
   13451             : irregularly sampled (scattered) data.
   13452             : 
   13453             : Solver object is used to perform spline fits as follows:
   13454             : * solver object is created with spline2dbuildercreate() function
   13455             : * dataset is added with spline2dbuildersetpoints() function
   13456             : * fit area is chosen:
   13457             :   * spline2dbuildersetarea()     - for user-defined area
   13458             :   * spline2dbuildersetareaauto() - for automatically chosen area
   13459             : * number of grid nodes is chosen with spline2dbuildersetgrid()
   13460             : * prior term is chosen with one of the following functions:
   13461             :   * spline2dbuildersetlinterm()   to set linear prior
   13462             :   * spline2dbuildersetconstterm() to set constant prior
   13463             :   * spline2dbuildersetzeroterm()  to set zero prior
   13464             :   * spline2dbuildersetuserterm()  to set user-defined constant prior
   13465             : * solver algorithm is chosen with either:
   13466             :   * spline2dbuildersetalgoblocklls() - BlockLLS algorithm, medium-scale problems
   13467             :   * spline2dbuildersetalgofastddm()  - FastDDM algorithm, large-scale problems
   13468             : * finally, fitting itself is performed with spline2dfit() function.
   13469             : 
   13470             : Most of the steps above can be omitted,  solver  is  configured with  good
   13471             : defaults. The minimum is to call:
   13472             : * spline2dbuildercreate() to create solver object
   13473             : * spline2dbuildersetpoints() to specify dataset
   13474             : * spline2dbuildersetgrid() to tell how many nodes you need
   13475             : * spline2dfit() to perform fit
   13476             : 
   13477             :   ! COMMERCIAL EDITION OF ALGLIB:
   13478             :   !
   13479             :   ! Commercial Edition of ALGLIB includes following important improvements
   13480             :   ! of this function:
   13481             :   ! * high-performance native backend with same C# interface (C# version)
   13482             :   ! * multithreading support (C++ and C# versions)
   13483             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   13484             :   !   (C++ and C# versions, x86/x64 platform)
   13485             :   !
   13486             :   ! We recommend you to read 'Working with commercial version' section  of
   13487             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   13488             :   ! related features provided by commercial edition of ALGLIB.
   13489             : 
   13490             : INPUT PARAMETERS:
   13491             :     D   -   positive number, number of Y-components: D=1 for simple scalar
   13492             :             fit, D>1 for vector-valued spline fitting.
   13493             : 
   13494             : OUTPUT PARAMETERS:
   13495             :     S   -   solver object
   13496             : 
   13497             :   -- ALGLIB PROJECT --
   13498             :      Copyright 29.01.2018 by Bochkanov Sergey
   13499             : *************************************************************************/
   13500           0 : void spline2dbuildercreate(const ae_int_t d, spline2dbuilder &state, const xparams _xparams)
   13501             : {
   13502             :     jmp_buf _break_jump;
   13503             :     alglib_impl::ae_state _alglib_env_state;
   13504           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13505           0 :     if( setjmp(_break_jump) )
   13506             :     {
   13507             : #if !defined(AE_NO_EXCEPTIONS)
   13508           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13509             : #else
   13510             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13511             :         return;
   13512             : #endif
   13513             :     }
   13514           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13515           0 :     if( _xparams.flags!=0x0 )
   13516           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13517           0 :     alglib_impl::spline2dbuildercreate(d, const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), &_alglib_env_state);
   13518           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13519           0 :     return;
   13520             : }
   13521             : 
   13522             : /*************************************************************************
   13523             : This function sets constant prior term (model is a sum of  bicubic  spline
   13524             : and global prior, which can be linear, constant, user-defined  constant or
   13525             : zero).
   13526             : 
   13527             : Constant prior term is determined by least squares fitting.
   13528             : 
   13529             : INPUT PARAMETERS:
   13530             :     S       -   spline builder
   13531             :     V       -   value for user-defined prior
   13532             : 
   13533             :   -- ALGLIB --
   13534             :      Copyright 01.02.2018 by Bochkanov Sergey
   13535             : *************************************************************************/
   13536           0 : void spline2dbuildersetuserterm(const spline2dbuilder &state, const double v, const xparams _xparams)
   13537             : {
   13538             :     jmp_buf _break_jump;
   13539             :     alglib_impl::ae_state _alglib_env_state;
   13540           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13541           0 :     if( setjmp(_break_jump) )
   13542             :     {
   13543             : #if !defined(AE_NO_EXCEPTIONS)
   13544           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13545             : #else
   13546             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13547             :         return;
   13548             : #endif
   13549             :     }
   13550           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13551           0 :     if( _xparams.flags!=0x0 )
   13552           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13553           0 :     alglib_impl::spline2dbuildersetuserterm(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), v, &_alglib_env_state);
   13554           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13555           0 :     return;
   13556             : }
   13557             : 
   13558             : /*************************************************************************
   13559             : This function sets linear prior term (model is a sum of bicubic spline and
   13560             : global  prior,  which  can  be  linear, constant, user-defined constant or
   13561             : zero).
   13562             : 
   13563             : Linear prior term is determined by least squares fitting.
   13564             : 
   13565             : INPUT PARAMETERS:
   13566             :     S       -   spline builder
   13567             : 
   13568             :   -- ALGLIB --
   13569             :      Copyright 01.02.2018 by Bochkanov Sergey
   13570             : *************************************************************************/
   13571           0 : void spline2dbuildersetlinterm(const spline2dbuilder &state, const xparams _xparams)
   13572             : {
   13573             :     jmp_buf _break_jump;
   13574             :     alglib_impl::ae_state _alglib_env_state;
   13575           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13576           0 :     if( setjmp(_break_jump) )
   13577             :     {
   13578             : #if !defined(AE_NO_EXCEPTIONS)
   13579           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13580             : #else
   13581             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13582             :         return;
   13583             : #endif
   13584             :     }
   13585           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13586           0 :     if( _xparams.flags!=0x0 )
   13587           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13588           0 :     alglib_impl::spline2dbuildersetlinterm(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), &_alglib_env_state);
   13589           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13590           0 :     return;
   13591             : }
   13592             : 
   13593             : /*************************************************************************
   13594             : This function sets constant prior term (model is a sum of  bicubic  spline
   13595             : and global prior, which can be linear, constant, user-defined  constant or
   13596             : zero).
   13597             : 
   13598             : Constant prior term is determined by least squares fitting.
   13599             : 
   13600             : INPUT PARAMETERS:
   13601             :     S       -   spline builder
   13602             : 
   13603             :   -- ALGLIB --
   13604             :      Copyright 01.02.2018 by Bochkanov Sergey
   13605             : *************************************************************************/
   13606           0 : void spline2dbuildersetconstterm(const spline2dbuilder &state, const xparams _xparams)
   13607             : {
   13608             :     jmp_buf _break_jump;
   13609             :     alglib_impl::ae_state _alglib_env_state;
   13610           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13611           0 :     if( setjmp(_break_jump) )
   13612             :     {
   13613             : #if !defined(AE_NO_EXCEPTIONS)
   13614           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13615             : #else
   13616             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13617             :         return;
   13618             : #endif
   13619             :     }
   13620           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13621           0 :     if( _xparams.flags!=0x0 )
   13622           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13623           0 :     alglib_impl::spline2dbuildersetconstterm(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), &_alglib_env_state);
   13624           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13625           0 :     return;
   13626             : }
   13627             : 
   13628             : /*************************************************************************
   13629             : This function sets zero prior term (model is a sum of bicubic  spline  and
   13630             : global  prior,  which  can  be  linear, constant, user-defined constant or
   13631             : zero).
   13632             : 
   13633             : INPUT PARAMETERS:
   13634             :     S       -   spline builder
   13635             : 
   13636             :   -- ALGLIB --
   13637             :      Copyright 01.02.2018 by Bochkanov Sergey
   13638             : *************************************************************************/
   13639           0 : void spline2dbuildersetzeroterm(const spline2dbuilder &state, const xparams _xparams)
   13640             : {
   13641             :     jmp_buf _break_jump;
   13642             :     alglib_impl::ae_state _alglib_env_state;
   13643           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13644           0 :     if( setjmp(_break_jump) )
   13645             :     {
   13646             : #if !defined(AE_NO_EXCEPTIONS)
   13647           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13648             : #else
   13649             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13650             :         return;
   13651             : #endif
   13652             :     }
   13653           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13654           0 :     if( _xparams.flags!=0x0 )
   13655           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13656           0 :     alglib_impl::spline2dbuildersetzeroterm(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), &_alglib_env_state);
   13657           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13658           0 :     return;
   13659             : }
   13660             : 
   13661             : /*************************************************************************
   13662             : This function adds dataset to the builder object.
   13663             : 
   13664             : This function overrides results of the previous calls, i.e. multiple calls
   13665             : of this function will result in only the last set being added.
   13666             : 
   13667             : INPUT PARAMETERS:
   13668             :     S       -   spline 2D builder object
   13669             :     XY      -   points, array[N,2+D]. One  row  corresponds to  one  point
   13670             :                 in the dataset. First 2  elements  are  coordinates,  next
   13671             :                 D  elements are function values. Array may  be larger than
   13672             :                 specified, in  this  case  only leading [N,NX+NY] elements
   13673             :                 will be used.
   13674             :     N       -   number of points in the dataset
   13675             : 
   13676             :   -- ALGLIB --
   13677             :      Copyright 05.02.2018 by Bochkanov Sergey
   13678             : *************************************************************************/
   13679           0 : void spline2dbuildersetpoints(const spline2dbuilder &state, const real_2d_array &xy, const ae_int_t n, const xparams _xparams)
   13680             : {
   13681             :     jmp_buf _break_jump;
   13682             :     alglib_impl::ae_state _alglib_env_state;
   13683           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13684           0 :     if( setjmp(_break_jump) )
   13685             :     {
   13686             : #if !defined(AE_NO_EXCEPTIONS)
   13687           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13688             : #else
   13689             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13690             :         return;
   13691             : #endif
   13692             :     }
   13693           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13694           0 :     if( _xparams.flags!=0x0 )
   13695           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13696           0 :     alglib_impl::spline2dbuildersetpoints(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, &_alglib_env_state);
   13697           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13698           0 :     return;
   13699             : }
   13700             : 
   13701             : /*************************************************************************
   13702             : This function sets area where 2D spline interpolant is built. "Auto" means
   13703             : that area extent is determined automatically from dataset extent.
   13704             : 
   13705             : INPUT PARAMETERS:
   13706             :     S       -   spline 2D builder object
   13707             : 
   13708             :   -- ALGLIB --
   13709             :      Copyright 05.02.2018 by Bochkanov Sergey
   13710             : *************************************************************************/
   13711           0 : void spline2dbuildersetareaauto(const spline2dbuilder &state, const xparams _xparams)
   13712             : {
   13713             :     jmp_buf _break_jump;
   13714             :     alglib_impl::ae_state _alglib_env_state;
   13715           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13716           0 :     if( setjmp(_break_jump) )
   13717             :     {
   13718             : #if !defined(AE_NO_EXCEPTIONS)
   13719           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13720             : #else
   13721             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13722             :         return;
   13723             : #endif
   13724             :     }
   13725           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13726           0 :     if( _xparams.flags!=0x0 )
   13727           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13728           0 :     alglib_impl::spline2dbuildersetareaauto(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), &_alglib_env_state);
   13729           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13730           0 :     return;
   13731             : }
   13732             : 
   13733             : /*************************************************************************
   13734             : This  function  sets  area  where  2D  spline  interpolant  is   built  to
   13735             : user-defined one: [XA,XB]*[YA,YB]
   13736             : 
   13737             : INPUT PARAMETERS:
   13738             :     S       -   spline 2D builder object
   13739             :     XA,XB   -   spatial extent in the first (X) dimension, XA<XB
   13740             :     YA,YB   -   spatial extent in the second (Y) dimension, YA<YB
   13741             : 
   13742             :   -- ALGLIB --
   13743             :      Copyright 05.02.2018 by Bochkanov Sergey
   13744             : *************************************************************************/
   13745           0 : void spline2dbuildersetarea(const spline2dbuilder &state, const double xa, const double xb, const double ya, const double yb, const xparams _xparams)
   13746             : {
   13747             :     jmp_buf _break_jump;
   13748             :     alglib_impl::ae_state _alglib_env_state;
   13749           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13750           0 :     if( setjmp(_break_jump) )
   13751             :     {
   13752             : #if !defined(AE_NO_EXCEPTIONS)
   13753           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13754             : #else
   13755             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13756             :         return;
   13757             : #endif
   13758             :     }
   13759           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13760           0 :     if( _xparams.flags!=0x0 )
   13761           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13762           0 :     alglib_impl::spline2dbuildersetarea(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), xa, xb, ya, yb, &_alglib_env_state);
   13763           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13764           0 :     return;
   13765             : }
   13766             : 
   13767             : /*************************************************************************
   13768             : This  function  sets  nodes  count  for  2D spline interpolant. Fitting is
   13769             : performed on area defined with one of the "setarea"  functions;  this  one
   13770             : sets number of nodes placed upon the fitting area.
   13771             : 
   13772             : INPUT PARAMETERS:
   13773             :     S       -   spline 2D builder object
   13774             :     KX      -   nodes count for the first (X) dimension; fitting  interval
   13775             :                 [XA,XB] is separated into KX-1 subintervals, with KX nodes
   13776             :                 created at the boundaries.
   13777             :     KY      -   nodes count for the first (Y) dimension; fitting  interval
   13778             :                 [YA,YB] is separated into KY-1 subintervals, with KY nodes
   13779             :                 created at the boundaries.
   13780             : 
   13781             : NOTE: at  least  4  nodes  is  created in each dimension, so KX and KY are
   13782             :       silently increased if needed.
   13783             : 
   13784             :   -- ALGLIB --
   13785             :      Copyright 05.02.2018 by Bochkanov Sergey
   13786             : *************************************************************************/
   13787           0 : void spline2dbuildersetgrid(const spline2dbuilder &state, const ae_int_t kx, const ae_int_t ky, const xparams _xparams)
   13788             : {
   13789             :     jmp_buf _break_jump;
   13790             :     alglib_impl::ae_state _alglib_env_state;
   13791           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13792           0 :     if( setjmp(_break_jump) )
   13793             :     {
   13794             : #if !defined(AE_NO_EXCEPTIONS)
   13795           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13796             : #else
   13797             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13798             :         return;
   13799             : #endif
   13800             :     }
   13801           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13802           0 :     if( _xparams.flags!=0x0 )
   13803           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13804           0 :     alglib_impl::spline2dbuildersetgrid(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), kx, ky, &_alglib_env_state);
   13805           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13806           0 :     return;
   13807             : }
   13808             : 
   13809             : /*************************************************************************
   13810             : This  function  allows  you to choose least squares solver used to perform
   13811             : fitting. This function sets solver algorithm to "FastDDM", which  performs
   13812             : fast parallel fitting by splitting problem into smaller chunks and merging
   13813             : results together.
   13814             : 
   13815             : This solver is optimized for large-scale problems, starting  from  256x256
   13816             : grids, and up to 10000x10000 grids. Of course, it will  work  for  smaller
   13817             : grids too.
   13818             : 
   13819             : More detailed description of the algorithm is given below:
   13820             : * algorithm generates hierarchy  of  nested  grids,  ranging  from  ~16x16
   13821             :   (topmost "layer" of the model) to ~KX*KY one (final layer). Upper layers
   13822             :   model global behavior of the function, lower layers are  used  to  model
   13823             :   fine details. Moving from layer to layer doubles grid density.
   13824             : * fitting  is  started  from  topmost  layer, subsequent layers are fitted
   13825             :   using residuals from previous ones.
   13826             : * user may choose to skip generation of upper layers and generate  only  a
   13827             :   few bottom ones, which  will  result  in  much  better  performance  and
   13828             :   parallelization efficiency, at the cost of algorithm inability to "patch"
   13829             :   large holes in the dataset.
   13830             : * every layer is regularized using progressively increasing regularization
   13831             :   coefficient; thus, increasing  LambdaV  penalizes  fine  details  first,
   13832             :   leaving lower frequencies almost intact for a while.
   13833             : * after fitting is done, all layers are merged together into  one  bicubic
   13834             :   spline
   13835             : 
   13836             : IMPORTANT: regularization coefficient used by  this  solver  is  different
   13837             :            from the one used by  BlockLLS.  Latter  utilizes  nonlinearity
   13838             :            penalty,  which  is  global  in  nature  (large  regularization
   13839             :            results in global linear trend being  extracted);  this  solver
   13840             :            uses another, localized form of penalty, which is suitable  for
   13841             :            parallel processing.
   13842             : 
   13843             : Notes on memory and performance:
   13844             : * memory requirements: most memory is consumed  during  modeling   of  the
   13845             :   higher layers; ~[512*NPoints] bytes is required for a  model  with  full
   13846             :   hierarchy of grids being generated. However, if you skip a  few  topmost
   13847             :   layers, you will get nearly constant (wrt. points count and  grid  size)
   13848             :   memory consumption.
   13849             : * serial running time: O(K*K)+O(NPoints) for a KxK grid
   13850             : * parallelism potential: good. You may get  nearly  linear  speed-up  when
   13851             :   performing fitting with just a few layers. Adding more layers results in
   13852             :   model becoming more global, which somewhat  reduces  efficiency  of  the
   13853             :   parallel code.
   13854             : 
   13855             :   ! COMMERCIAL EDITION OF ALGLIB:
   13856             :   !
   13857             :   ! Commercial Edition of ALGLIB includes following important improvements
   13858             :   ! of this function:
   13859             :   ! * high-performance native backend with same C# interface (C# version)
   13860             :   ! * multithreading support (C++ and C# versions)
   13861             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   13862             :   !   (C++ and C# versions, x86/x64 platform)
   13863             :   !
   13864             :   ! We recommend you to read 'Working with commercial version' section  of
   13865             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   13866             :   ! related features provided by commercial edition of ALGLIB.
   13867             : 
   13868             : INPUT PARAMETERS:
   13869             :     S       -   spline 2D builder object
   13870             :     NLayers -   number of layers in the model:
   13871             :                 * NLayers>=1 means that up  to  chosen  number  of  bottom
   13872             :                   layers is fitted
   13873             :                 * NLayers=0 means that maximum number of layers is  chosen
   13874             :                   (according to current grid size)
   13875             :                 * NLayers<=-1 means that up to |NLayers| topmost layers is
   13876             :                   skipped
   13877             :                 Recommendations:
   13878             :                 * good "default" value is 2 layers
   13879             :                 * you may need  more  layers,  if  your  dataset  is  very
   13880             :                   irregular and you want to "patch"  large  holes.  For  a
   13881             :                   grid step H (equal to AreaWidth/GridSize) you may expect
   13882             :                   that last layer reproduces variations at distance H (and
   13883             :                   can patch holes that wide); that higher  layers  operate
   13884             :                   at distances 2*H, 4*H, 8*H and so on.
   13885             :                 * good value for "bullletproof" mode is  NLayers=0,  which
   13886             :                   results in complete hierarchy of layers being generated.
   13887             :     LambdaV -   regularization coefficient, chosen in such a way  that  it
   13888             :                 penalizes bottom layers (fine details) first.
   13889             :                 LambdaV>=0, zero value means that no penalty is applied.
   13890             : 
   13891             :   -- ALGLIB --
   13892             :      Copyright 05.02.2018 by Bochkanov Sergey
   13893             : *************************************************************************/
   13894           0 : void spline2dbuildersetalgofastddm(const spline2dbuilder &state, const ae_int_t nlayers, const double lambdav, const xparams _xparams)
   13895             : {
   13896             :     jmp_buf _break_jump;
   13897             :     alglib_impl::ae_state _alglib_env_state;
   13898           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13899           0 :     if( setjmp(_break_jump) )
   13900             :     {
   13901             : #if !defined(AE_NO_EXCEPTIONS)
   13902           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13903             : #else
   13904             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13905             :         return;
   13906             : #endif
   13907             :     }
   13908           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13909           0 :     if( _xparams.flags!=0x0 )
   13910           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13911           0 :     alglib_impl::spline2dbuildersetalgofastddm(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), nlayers, lambdav, &_alglib_env_state);
   13912           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13913           0 :     return;
   13914             : }
   13915             : 
   13916             : /*************************************************************************
   13917             : This  function  allows  you to choose least squares solver used to perform
   13918             : fitting. This function sets solver algorithm to "BlockLLS", which performs
   13919             : least squares fitting  with  fast  sparse  direct  solver,  with  optional
   13920             : nonsmoothness penalty being applied.
   13921             : 
   13922             : Nonlinearity penalty has the following form:
   13923             : 
   13924             :                           [                                            ]
   13925             :     P() ~ Lambda* integral[ (d2S/dx2)^2 + 2*(d2S/dxdy)^2 + (d2S/dy2)^2 ]dxdy
   13926             :                           [                                            ]
   13927             : 
   13928             : here integral is calculated over entire grid, and "~" means "proportional"
   13929             : because integral is normalized after calcilation. Extremely  large  values
   13930             : of Lambda result in linear fit being performed.
   13931             : 
   13932             : NOTE: this algorithm is the most robust and controllable one,  but  it  is
   13933             :       limited by 512x512 grids and (say) up to 1.000.000 points.  However,
   13934             :       ALGLIB has one more  spline  solver:  FastDDM  algorithm,  which  is
   13935             :       intended for really large-scale problems (in 10M-100M range). FastDDM
   13936             :       algorithm also has better parallelism properties.
   13937             : 
   13938             : More information on BlockLLS solver:
   13939             : * memory requirements: ~[32*K^3+256*NPoints]  bytes  for  KxK  grid   with
   13940             :   NPoints-sized dataset
   13941             : * serial running time: O(K^4+NPoints)
   13942             : * parallelism potential: limited. You may get some sublinear gain when
   13943             :   working with large grids (K's in 256..512 range)
   13944             : 
   13945             :   ! COMMERCIAL EDITION OF ALGLIB:
   13946             :   !
   13947             :   ! Commercial Edition of ALGLIB includes following important improvements
   13948             :   ! of this function:
   13949             :   ! * high-performance native backend with same C# interface (C# version)
   13950             :   ! * multithreading support (C++ and C# versions)
   13951             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   13952             :   !   (C++ and C# versions, x86/x64 platform)
   13953             :   !
   13954             :   ! We recommend you to read 'Working with commercial version' section  of
   13955             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   13956             :   ! related features provided by commercial edition of ALGLIB.
   13957             : 
   13958             : INPUT PARAMETERS:
   13959             :     S       -   spline 2D builder object
   13960             :     LambdaNS-   non-negative value:
   13961             :                 * positive value means that some smoothing is applied
   13962             :                 * zero value means  that  no  smoothing  is  applied,  and
   13963             :                   corresponding entries of design matrix  are  numerically
   13964             :                   zero and dropped from consideration.
   13965             : 
   13966             :   -- ALGLIB --
   13967             :      Copyright 05.02.2018 by Bochkanov Sergey
   13968             : *************************************************************************/
   13969           0 : void spline2dbuildersetalgoblocklls(const spline2dbuilder &state, const double lambdans, const xparams _xparams)
   13970             : {
   13971             :     jmp_buf _break_jump;
   13972             :     alglib_impl::ae_state _alglib_env_state;
   13973           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   13974           0 :     if( setjmp(_break_jump) )
   13975             :     {
   13976             : #if !defined(AE_NO_EXCEPTIONS)
   13977           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   13978             : #else
   13979             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   13980             :         return;
   13981             : #endif
   13982             :     }
   13983           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   13984           0 :     if( _xparams.flags!=0x0 )
   13985           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   13986           0 :     alglib_impl::spline2dbuildersetalgoblocklls(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), lambdans, &_alglib_env_state);
   13987           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   13988           0 :     return;
   13989             : }
   13990             : 
   13991             : /*************************************************************************
   13992             : This  function  allows  you to choose least squares solver used to perform
   13993             : fitting. This function sets solver algorithm to "NaiveLLS".
   13994             : 
   13995             : IMPORTANT: NaiveLLS is NOT intended to be used in  real  life  code!  This
   13996             :            algorithm solves problem by generated dense (K^2)x(K^2+NPoints)
   13997             :            matrix and solves  linear  least  squares  problem  with  dense
   13998             :            solver.
   13999             : 
   14000             :            It is here just  to  test  BlockLLS  against  reference  solver
   14001             :            (and maybe for someone trying to compare well optimized  solver
   14002             :            against straightforward approach to the LLS problem).
   14003             : 
   14004             : More information on naive LLS solver:
   14005             : * memory requirements: ~[8*K^4+256*NPoints] bytes for KxK grid.
   14006             : * serial running time: O(K^6+NPoints) for KxK grid
   14007             : * when compared with BlockLLS,  NaiveLLS  has ~K  larger memory demand and
   14008             :   ~K^2  larger running time.
   14009             : 
   14010             : INPUT PARAMETERS:
   14011             :     S       -   spline 2D builder object
   14012             :     LambdaNS-   nonsmoothness penalty
   14013             : 
   14014             :   -- ALGLIB --
   14015             :      Copyright 05.02.2018 by Bochkanov Sergey
   14016             : *************************************************************************/
   14017           0 : void spline2dbuildersetalgonaivells(const spline2dbuilder &state, const double lambdans, const xparams _xparams)
   14018             : {
   14019             :     jmp_buf _break_jump;
   14020             :     alglib_impl::ae_state _alglib_env_state;
   14021           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   14022           0 :     if( setjmp(_break_jump) )
   14023             :     {
   14024             : #if !defined(AE_NO_EXCEPTIONS)
   14025           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   14026             : #else
   14027             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   14028             :         return;
   14029             : #endif
   14030             :     }
   14031           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   14032           0 :     if( _xparams.flags!=0x0 )
   14033           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   14034           0 :     alglib_impl::spline2dbuildersetalgonaivells(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), lambdans, &_alglib_env_state);
   14035           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   14036           0 :     return;
   14037             : }
   14038             : 
   14039             : /*************************************************************************
   14040             : This function fits bicubic spline to current dataset, using current  area/
   14041             : grid and current LLS solver.
   14042             : 
   14043             :   ! COMMERCIAL EDITION OF ALGLIB:
   14044             :   !
   14045             :   ! Commercial Edition of ALGLIB includes following important improvements
   14046             :   ! of this function:
   14047             :   ! * high-performance native backend with same C# interface (C# version)
   14048             :   ! * multithreading support (C++ and C# versions)
   14049             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   14050             :   !   (C++ and C# versions, x86/x64 platform)
   14051             :   !
   14052             :   ! We recommend you to read 'Working with commercial version' section  of
   14053             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   14054             :   ! related features provided by commercial edition of ALGLIB.
   14055             : 
   14056             : INPUT PARAMETERS:
   14057             :     State   -   spline 2D builder object
   14058             : 
   14059             : OUTPUT PARAMETERS:
   14060             :     S       -   2D spline, fit result
   14061             :     Rep     -   fitting report, which provides some additional info  about
   14062             :                 errors, R2 coefficient and so on.
   14063             : 
   14064             :   -- ALGLIB --
   14065             :      Copyright 05.02.2018 by Bochkanov Sergey
   14066             : *************************************************************************/
   14067           0 : void spline2dfit(const spline2dbuilder &state, spline2dinterpolant &s, spline2dfitreport &rep, const xparams _xparams)
   14068             : {
   14069             :     jmp_buf _break_jump;
   14070             :     alglib_impl::ae_state _alglib_env_state;
   14071           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   14072           0 :     if( setjmp(_break_jump) )
   14073             :     {
   14074             : #if !defined(AE_NO_EXCEPTIONS)
   14075           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   14076             : #else
   14077             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   14078             :         return;
   14079             : #endif
   14080             :     }
   14081           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   14082           0 :     if( _xparams.flags!=0x0 )
   14083           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   14084           0 :     alglib_impl::spline2dfit(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), const_cast<alglib_impl::spline2dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline2dfitreport*>(rep.c_ptr()), &_alglib_env_state);
   14085           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   14086           0 :     return;
   14087             : }
   14088             : #endif
   14089             : 
   14090             : #if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD)
   14091             : 
   14092             : #endif
   14093             : 
   14094             : #if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD)
   14095             : /*************************************************************************
   14096             : Buffer object which is used to perform nearest neighbor  requests  in  the
   14097             : multithreaded mode (multiple threads working with same KD-tree object).
   14098             : 
   14099             : This object should be created with KDTreeCreateBuffer().
   14100             : *************************************************************************/
   14101           0 : _rbfcalcbuffer_owner::_rbfcalcbuffer_owner()
   14102             : {
   14103             :     jmp_buf _break_jump;
   14104             :     alglib_impl::ae_state _state;
   14105             :     
   14106           0 :     alglib_impl::ae_state_init(&_state);
   14107           0 :     if( setjmp(_break_jump) )
   14108             :     {
   14109           0 :         if( p_struct!=NULL )
   14110             :         {
   14111           0 :             alglib_impl::_rbfcalcbuffer_destroy(p_struct);
   14112           0 :             alglib_impl::ae_free(p_struct);
   14113             :         }
   14114           0 :         p_struct = NULL;
   14115             : #if !defined(AE_NO_EXCEPTIONS)
   14116           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   14117             : #else
   14118             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   14119             :         return;
   14120             : #endif
   14121             :     }
   14122           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   14123           0 :     p_struct = NULL;
   14124           0 :     p_struct = (alglib_impl::rbfcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfcalcbuffer), &_state);
   14125           0 :     memset(p_struct, 0, sizeof(alglib_impl::rbfcalcbuffer));
   14126           0 :     alglib_impl::_rbfcalcbuffer_init(p_struct, &_state, ae_false);
   14127           0 :     ae_state_clear(&_state);
   14128           0 : }
   14129             : 
   14130           0 : _rbfcalcbuffer_owner::_rbfcalcbuffer_owner(const _rbfcalcbuffer_owner &rhs)
   14131             : {
   14132             :     jmp_buf _break_jump;
   14133             :     alglib_impl::ae_state _state;
   14134             :     
   14135           0 :     alglib_impl::ae_state_init(&_state);
   14136           0 :     if( setjmp(_break_jump) )
   14137             :     {
   14138           0 :         if( p_struct!=NULL )
   14139             :         {
   14140           0 :             alglib_impl::_rbfcalcbuffer_destroy(p_struct);
   14141           0 :             alglib_impl::ae_free(p_struct);
   14142             :         }
   14143           0 :         p_struct = NULL;
   14144             : #if !defined(AE_NO_EXCEPTIONS)
   14145           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   14146             : #else
   14147             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   14148             :         return;
   14149             : #endif
   14150             :     }
   14151           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   14152           0 :     p_struct = NULL;
   14153           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfcalcbuffer copy constructor failure (source is not initialized)", &_state);
   14154           0 :     p_struct = (alglib_impl::rbfcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfcalcbuffer), &_state);
   14155           0 :     memset(p_struct, 0, sizeof(alglib_impl::rbfcalcbuffer));
   14156           0 :     alglib_impl::_rbfcalcbuffer_init_copy(p_struct, const_cast<alglib_impl::rbfcalcbuffer*>(rhs.p_struct), &_state, ae_false);
   14157           0 :     ae_state_clear(&_state);
   14158           0 : }
   14159             : 
   14160           0 : _rbfcalcbuffer_owner& _rbfcalcbuffer_owner::operator=(const _rbfcalcbuffer_owner &rhs)
   14161             : {
   14162           0 :     if( this==&rhs )
   14163           0 :         return *this;
   14164             :     jmp_buf _break_jump;
   14165             :     alglib_impl::ae_state _state;
   14166             :     
   14167           0 :     alglib_impl::ae_state_init(&_state);
   14168           0 :     if( setjmp(_break_jump) )
   14169             :     {
   14170             : #if !defined(AE_NO_EXCEPTIONS)
   14171           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   14172             : #else
   14173             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   14174             :         return *this;
   14175             : #endif
   14176             :     }
   14177           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   14178           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: rbfcalcbuffer assignment constructor failure (destination is not initialized)", &_state);
   14179           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfcalcbuffer assignment constructor failure (source is not initialized)", &_state);
   14180           0 :     alglib_impl::_rbfcalcbuffer_destroy(p_struct);
   14181           0 :     memset(p_struct, 0, sizeof(alglib_impl::rbfcalcbuffer));
   14182           0 :     alglib_impl::_rbfcalcbuffer_init_copy(p_struct, const_cast<alglib_impl::rbfcalcbuffer*>(rhs.p_struct), &_state, ae_false);
   14183           0 :     ae_state_clear(&_state);
   14184           0 :     return *this;
   14185             : }
   14186             : 
   14187           0 : _rbfcalcbuffer_owner::~_rbfcalcbuffer_owner()
   14188             : {
   14189           0 :     if( p_struct!=NULL )
   14190             :     {
   14191           0 :         alglib_impl::_rbfcalcbuffer_destroy(p_struct);
   14192           0 :         ae_free(p_struct);
   14193             :     }
   14194           0 : }
   14195             : 
   14196           0 : alglib_impl::rbfcalcbuffer* _rbfcalcbuffer_owner::c_ptr()
   14197             : {
   14198           0 :     return p_struct;
   14199             : }
   14200             : 
   14201           0 : alglib_impl::rbfcalcbuffer* _rbfcalcbuffer_owner::c_ptr() const
   14202             : {
   14203           0 :     return const_cast<alglib_impl::rbfcalcbuffer*>(p_struct);
   14204             : }
   14205           0 : rbfcalcbuffer::rbfcalcbuffer() : _rbfcalcbuffer_owner() 
   14206             : {
   14207           0 : }
   14208             : 
   14209           0 : rbfcalcbuffer::rbfcalcbuffer(const rbfcalcbuffer &rhs):_rbfcalcbuffer_owner(rhs) 
   14210             : {
   14211           0 : }
   14212             : 
   14213           0 : rbfcalcbuffer& rbfcalcbuffer::operator=(const rbfcalcbuffer &rhs)
   14214             : {
   14215           0 :     if( this==&rhs )
   14216           0 :         return *this;
   14217           0 :     _rbfcalcbuffer_owner::operator=(rhs);
   14218           0 :     return *this;
   14219             : }
   14220             : 
   14221           0 : rbfcalcbuffer::~rbfcalcbuffer()
   14222             : {
   14223           0 : }
   14224             : 
   14225             : 
   14226             : /*************************************************************************
   14227             : RBF model.
   14228             : 
   14229             : Never try to directly work with fields of this object - always use  ALGLIB
   14230             : functions to use this object.
   14231             : *************************************************************************/
   14232           0 : _rbfmodel_owner::_rbfmodel_owner()
   14233             : {
   14234             :     jmp_buf _break_jump;
   14235             :     alglib_impl::ae_state _state;
   14236             :     
   14237           0 :     alglib_impl::ae_state_init(&_state);
   14238           0 :     if( setjmp(_break_jump) )
   14239             :     {
   14240           0 :         if( p_struct!=NULL )
   14241             :         {
   14242           0 :             alglib_impl::_rbfmodel_destroy(p_struct);
   14243           0 :             alglib_impl::ae_free(p_struct);
   14244             :         }
   14245           0 :         p_struct = NULL;
   14246             : #if !defined(AE_NO_EXCEPTIONS)
   14247           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   14248             : #else
   14249             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   14250             :         return;
   14251             : #endif
   14252             :     }
   14253           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   14254           0 :     p_struct = NULL;
   14255           0 :     p_struct = (alglib_impl::rbfmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfmodel), &_state);
   14256           0 :     memset(p_struct, 0, sizeof(alglib_impl::rbfmodel));
   14257           0 :     alglib_impl::_rbfmodel_init(p_struct, &_state, ae_false);
   14258           0 :     ae_state_clear(&_state);
   14259           0 : }
   14260             : 
   14261           0 : _rbfmodel_owner::_rbfmodel_owner(const _rbfmodel_owner &rhs)
   14262             : {
   14263             :     jmp_buf _break_jump;
   14264             :     alglib_impl::ae_state _state;
   14265             :     
   14266           0 :     alglib_impl::ae_state_init(&_state);
   14267           0 :     if( setjmp(_break_jump) )
   14268             :     {
   14269           0 :         if( p_struct!=NULL )
   14270             :         {
   14271           0 :             alglib_impl::_rbfmodel_destroy(p_struct);
   14272           0 :             alglib_impl::ae_free(p_struct);
   14273             :         }
   14274           0 :         p_struct = NULL;
   14275             : #if !defined(AE_NO_EXCEPTIONS)
   14276           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   14277             : #else
   14278             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   14279             :         return;
   14280             : #endif
   14281             :     }
   14282           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   14283           0 :     p_struct = NULL;
   14284           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfmodel copy constructor failure (source is not initialized)", &_state);
   14285           0 :     p_struct = (alglib_impl::rbfmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfmodel), &_state);
   14286           0 :     memset(p_struct, 0, sizeof(alglib_impl::rbfmodel));
   14287           0 :     alglib_impl::_rbfmodel_init_copy(p_struct, const_cast<alglib_impl::rbfmodel*>(rhs.p_struct), &_state, ae_false);
   14288           0 :     ae_state_clear(&_state);
   14289           0 : }
   14290             : 
   14291           0 : _rbfmodel_owner& _rbfmodel_owner::operator=(const _rbfmodel_owner &rhs)
   14292             : {
   14293           0 :     if( this==&rhs )
   14294           0 :         return *this;
   14295             :     jmp_buf _break_jump;
   14296             :     alglib_impl::ae_state _state;
   14297             :     
   14298           0 :     alglib_impl::ae_state_init(&_state);
   14299           0 :     if( setjmp(_break_jump) )
   14300             :     {
   14301             : #if !defined(AE_NO_EXCEPTIONS)
   14302           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   14303             : #else
   14304             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   14305             :         return *this;
   14306             : #endif
   14307             :     }
   14308           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   14309           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: rbfmodel assignment constructor failure (destination is not initialized)", &_state);
   14310           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfmodel assignment constructor failure (source is not initialized)", &_state);
   14311           0 :     alglib_impl::_rbfmodel_destroy(p_struct);
   14312           0 :     memset(p_struct, 0, sizeof(alglib_impl::rbfmodel));
   14313           0 :     alglib_impl::_rbfmodel_init_copy(p_struct, const_cast<alglib_impl::rbfmodel*>(rhs.p_struct), &_state, ae_false);
   14314           0 :     ae_state_clear(&_state);
   14315           0 :     return *this;
   14316             : }
   14317             : 
   14318           0 : _rbfmodel_owner::~_rbfmodel_owner()
   14319             : {
   14320           0 :     if( p_struct!=NULL )
   14321             :     {
   14322           0 :         alglib_impl::_rbfmodel_destroy(p_struct);
   14323           0 :         ae_free(p_struct);
   14324             :     }
   14325           0 : }
   14326             : 
   14327           0 : alglib_impl::rbfmodel* _rbfmodel_owner::c_ptr()
   14328             : {
   14329           0 :     return p_struct;
   14330             : }
   14331             : 
   14332           0 : alglib_impl::rbfmodel* _rbfmodel_owner::c_ptr() const
   14333             : {
   14334           0 :     return const_cast<alglib_impl::rbfmodel*>(p_struct);
   14335             : }
   14336           0 : rbfmodel::rbfmodel() : _rbfmodel_owner() 
   14337             : {
   14338           0 : }
   14339             : 
   14340           0 : rbfmodel::rbfmodel(const rbfmodel &rhs):_rbfmodel_owner(rhs) 
   14341             : {
   14342           0 : }
   14343             : 
   14344           0 : rbfmodel& rbfmodel::operator=(const rbfmodel &rhs)
   14345             : {
   14346           0 :     if( this==&rhs )
   14347           0 :         return *this;
   14348           0 :     _rbfmodel_owner::operator=(rhs);
   14349           0 :     return *this;
   14350             : }
   14351             : 
   14352           0 : rbfmodel::~rbfmodel()
   14353             : {
   14354           0 : }
   14355             : 
   14356             : 
   14357             : /*************************************************************************
   14358             : RBF solution report:
   14359             : * TerminationType   -   termination type, positive values - success,
   14360             :                         non-positive - failure.
   14361             : 
   14362             : Fields which are set by modern RBF solvers (hierarchical):
   14363             : * RMSError          -   root-mean-square error; NAN for old solvers (ML, QNN)
   14364             : * MaxError          -   maximum error; NAN for old solvers (ML, QNN)
   14365             : *************************************************************************/
   14366           0 : _rbfreport_owner::_rbfreport_owner()
   14367             : {
   14368             :     jmp_buf _break_jump;
   14369             :     alglib_impl::ae_state _state;
   14370             :     
   14371           0 :     alglib_impl::ae_state_init(&_state);
   14372           0 :     if( setjmp(_break_jump) )
   14373             :     {
   14374           0 :         if( p_struct!=NULL )
   14375             :         {
   14376           0 :             alglib_impl::_rbfreport_destroy(p_struct);
   14377           0 :             alglib_impl::ae_free(p_struct);
   14378             :         }
   14379           0 :         p_struct = NULL;
   14380             : #if !defined(AE_NO_EXCEPTIONS)
   14381           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   14382             : #else
   14383             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   14384             :         return;
   14385             : #endif
   14386             :     }
   14387           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   14388           0 :     p_struct = NULL;
   14389           0 :     p_struct = (alglib_impl::rbfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfreport), &_state);
   14390           0 :     memset(p_struct, 0, sizeof(alglib_impl::rbfreport));
   14391           0 :     alglib_impl::_rbfreport_init(p_struct, &_state, ae_false);
   14392           0 :     ae_state_clear(&_state);
   14393           0 : }
   14394             : 
   14395           0 : _rbfreport_owner::_rbfreport_owner(const _rbfreport_owner &rhs)
   14396             : {
   14397             :     jmp_buf _break_jump;
   14398             :     alglib_impl::ae_state _state;
   14399             :     
   14400           0 :     alglib_impl::ae_state_init(&_state);
   14401           0 :     if( setjmp(_break_jump) )
   14402             :     {
   14403           0 :         if( p_struct!=NULL )
   14404             :         {
   14405           0 :             alglib_impl::_rbfreport_destroy(p_struct);
   14406           0 :             alglib_impl::ae_free(p_struct);
   14407             :         }
   14408           0 :         p_struct = NULL;
   14409             : #if !defined(AE_NO_EXCEPTIONS)
   14410           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   14411             : #else
   14412             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   14413             :         return;
   14414             : #endif
   14415             :     }
   14416           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   14417           0 :     p_struct = NULL;
   14418           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfreport copy constructor failure (source is not initialized)", &_state);
   14419           0 :     p_struct = (alglib_impl::rbfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfreport), &_state);
   14420           0 :     memset(p_struct, 0, sizeof(alglib_impl::rbfreport));
   14421           0 :     alglib_impl::_rbfreport_init_copy(p_struct, const_cast<alglib_impl::rbfreport*>(rhs.p_struct), &_state, ae_false);
   14422           0 :     ae_state_clear(&_state);
   14423           0 : }
   14424             : 
   14425           0 : _rbfreport_owner& _rbfreport_owner::operator=(const _rbfreport_owner &rhs)
   14426             : {
   14427           0 :     if( this==&rhs )
   14428           0 :         return *this;
   14429             :     jmp_buf _break_jump;
   14430             :     alglib_impl::ae_state _state;
   14431             :     
   14432           0 :     alglib_impl::ae_state_init(&_state);
   14433           0 :     if( setjmp(_break_jump) )
   14434             :     {
   14435             : #if !defined(AE_NO_EXCEPTIONS)
   14436           0 :         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
   14437             : #else
   14438             :         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
   14439             :         return *this;
   14440             : #endif
   14441             :     }
   14442           0 :     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
   14443           0 :     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: rbfreport assignment constructor failure (destination is not initialized)", &_state);
   14444           0 :     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfreport assignment constructor failure (source is not initialized)", &_state);
   14445           0 :     alglib_impl::_rbfreport_destroy(p_struct);
   14446           0 :     memset(p_struct, 0, sizeof(alglib_impl::rbfreport));
   14447           0 :     alglib_impl::_rbfreport_init_copy(p_struct, const_cast<alglib_impl::rbfreport*>(rhs.p_struct), &_state, ae_false);
   14448           0 :     ae_state_clear(&_state);
   14449           0 :     return *this;
   14450             : }
   14451             : 
   14452           0 : _rbfreport_owner::~_rbfreport_owner()
   14453             : {
   14454           0 :     if( p_struct!=NULL )
   14455             :     {
   14456           0 :         alglib_impl::_rbfreport_destroy(p_struct);
   14457           0 :         ae_free(p_struct);
   14458             :     }
   14459           0 : }
   14460             : 
   14461           0 : alglib_impl::rbfreport* _rbfreport_owner::c_ptr()
   14462             : {
   14463           0 :     return p_struct;
   14464             : }
   14465             : 
   14466           0 : alglib_impl::rbfreport* _rbfreport_owner::c_ptr() const
   14467             : {
   14468           0 :     return const_cast<alglib_impl::rbfreport*>(p_struct);
   14469             : }
   14470           0 : 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)
   14471             : {
   14472           0 : }
   14473             : 
   14474           0 : 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)
   14475             : {
   14476           0 : }
   14477             : 
   14478           0 : rbfreport& rbfreport::operator=(const rbfreport &rhs)
   14479             : {
   14480           0 :     if( this==&rhs )
   14481           0 :         return *this;
   14482           0 :     _rbfreport_owner::operator=(rhs);
   14483           0 :     return *this;
   14484             : }
   14485             : 
   14486           0 : rbfreport::~rbfreport()
   14487             : {
   14488           0 : }
   14489             : 
   14490             : 
   14491             : /*************************************************************************
   14492             : This function serializes data structure to string.
   14493             : 
   14494             : Important properties of s_out:
   14495             : * it contains alphanumeric characters, dots, underscores, minus signs
   14496             : * these symbols are grouped into words, which are separated by spaces
   14497             :   and Windows-style (CR+LF) newlines
   14498             : * although  serializer  uses  spaces and CR+LF as separators, you can 
   14499             :   replace any separator character by arbitrary combination of spaces,
   14500             :   tabs, Windows or Unix newlines. It allows flexible reformatting  of
   14501             :   the  string  in  case you want to include it into text or XML file. 
   14502             :   But you should not insert separators into the middle of the "words"
   14503             :   nor you should change case of letters.
   14504             : * s_out can be freely moved between 32-bit and 64-bit systems, little
   14505             :   and big endian machines, and so on. You can serialize structure  on
   14506             :   32-bit machine and unserialize it on 64-bit one (or vice versa), or
   14507             :   serialize  it  on  SPARC  and  unserialize  on  x86.  You  can also 
   14508             :   serialize  it  in  C++ version of ALGLIB and unserialize in C# one, 
   14509             :   and vice versa.
   14510             : *************************************************************************/
   14511           0 : void rbfserialize(rbfmodel &obj, std::string &s_out)
   14512             : {
   14513             :     jmp_buf _break_jump;
   14514             :     alglib_impl::ae_state state;
   14515             :     alglib_impl::ae_serializer serializer;
   14516             :     alglib_impl::ae_int_t ssize;
   14517             : 
   14518           0 :     alglib_impl::ae_state_init(&state);
   14519           0 :     if( setjmp(_break_jump) )
   14520             :     {
   14521             : #if !defined(AE_NO_EXCEPTIONS)
   14522           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
   14523             : #else
   14524             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
   14525             :         return;
   14526             : #endif
   14527             :     }
   14528           0 :     ae_state_set_break_jump(&state, &_break_jump);
   14529           0 :     alglib_impl::ae_serializer_init(&serializer);
   14530           0 :     alglib_impl::ae_serializer_alloc_start(&serializer);
   14531           0 :     alglib_impl::rbfalloc(&serializer, obj.c_ptr(), &state);
   14532           0 :     ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer);
   14533           0 :     s_out.clear();
   14534           0 :     s_out.reserve((size_t)(ssize+1));
   14535           0 :     alglib_impl::ae_serializer_sstart_str(&serializer, &s_out);
   14536           0 :     alglib_impl::rbfserialize(&serializer, obj.c_ptr(), &state);
   14537           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
   14538           0 :     alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state);
   14539           0 :     alglib_impl::ae_serializer_clear(&serializer);
   14540           0 :     alglib_impl::ae_state_clear(&state);
   14541           0 : }
   14542             : /*************************************************************************
   14543             : This function unserializes data structure from string.
   14544             : *************************************************************************/
   14545           0 : void rbfunserialize(const std::string &s_in, rbfmodel &obj)
   14546             : {
   14547             :     jmp_buf _break_jump;
   14548             :     alglib_impl::ae_state state;
   14549             :     alglib_impl::ae_serializer serializer;
   14550             : 
   14551           0 :     alglib_impl::ae_state_init(&state);
   14552           0 :     if( setjmp(_break_jump) )
   14553             :     {
   14554             : #if !defined(AE_NO_EXCEPTIONS)
   14555           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
   14556             : #else
   14557             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
   14558             :         return;
   14559             : #endif
   14560             :     }
   14561           0 :     ae_state_set_break_jump(&state, &_break_jump);
   14562           0 :     alglib_impl::ae_serializer_init(&serializer);
   14563           0 :     alglib_impl::ae_serializer_ustart_str(&serializer, &s_in);
   14564           0 :     alglib_impl::rbfunserialize(&serializer, obj.c_ptr(), &state);
   14565           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
   14566           0 :     alglib_impl::ae_serializer_clear(&serializer);
   14567           0 :     alglib_impl::ae_state_clear(&state);
   14568           0 : }
   14569             : 
   14570             : 
   14571             : /*************************************************************************
   14572             : This function serializes data structure to C++ stream.
   14573             : 
   14574             : Data stream generated by this function is same as  string  representation
   14575             : generated  by  string  version  of  serializer - alphanumeric characters,
   14576             : dots, underscores, minus signs, which are grouped into words separated by
   14577             : spaces and CR+LF.
   14578             : 
   14579             : We recommend you to read comments on string version of serializer to find
   14580             : out more about serialization of AlGLIB objects.
   14581             : *************************************************************************/
   14582           0 : void rbfserialize(rbfmodel &obj, std::ostream &s_out)
   14583             : {
   14584             :     jmp_buf _break_jump;
   14585             :     alglib_impl::ae_state state;
   14586             :     alglib_impl::ae_serializer serializer;
   14587             : 
   14588           0 :     alglib_impl::ae_state_init(&state);
   14589           0 :     if( setjmp(_break_jump) )
   14590             :     {
   14591             : #if !defined(AE_NO_EXCEPTIONS)
   14592           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
   14593             : #else
   14594             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
   14595             :         return;
   14596             : #endif
   14597             :     }
   14598           0 :     ae_state_set_break_jump(&state, &_break_jump);
   14599           0 :     alglib_impl::ae_serializer_init(&serializer);
   14600           0 :     alglib_impl::ae_serializer_alloc_start(&serializer);
   14601           0 :     alglib_impl::rbfalloc(&serializer, obj.c_ptr(), &state);
   14602           0 :     alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask
   14603           0 :     alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out);
   14604           0 :     alglib_impl::rbfserialize(&serializer, obj.c_ptr(), &state);
   14605           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
   14606           0 :     alglib_impl::ae_serializer_clear(&serializer);
   14607           0 :     alglib_impl::ae_state_clear(&state);
   14608           0 : }
   14609             : /*************************************************************************
   14610             : This function unserializes data structure from stream.
   14611             : *************************************************************************/
   14612           0 : void rbfunserialize(const std::istream &s_in, rbfmodel &obj)
   14613             : {
   14614             :     jmp_buf _break_jump;
   14615             :     alglib_impl::ae_state state;
   14616             :     alglib_impl::ae_serializer serializer;
   14617             : 
   14618           0 :     alglib_impl::ae_state_init(&state);
   14619           0 :     if( setjmp(_break_jump) )
   14620             :     {
   14621             : #if !defined(AE_NO_EXCEPTIONS)
   14622           0 :         _ALGLIB_CPP_EXCEPTION(state.error_msg);
   14623             : #else
   14624             :         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
   14625             :         return;
   14626             : #endif
   14627             :     }
   14628           0 :     ae_state_set_break_jump(&state, &_break_jump);
   14629           0 :     alglib_impl::ae_serializer_init(&serializer);
   14630           0 :     alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in);
   14631           0 :     alglib_impl::rbfunserialize(&serializer, obj.c_ptr(), &state);
   14632           0 :     alglib_impl::ae_serializer_stop(&serializer, &state);
   14633           0 :     alglib_impl::ae_serializer_clear(&serializer);
   14634           0 :     alglib_impl::ae_state_clear(&state);
   14635           0 : }
   14636             : 
   14637             : /*************************************************************************
   14638             : This function creates RBF  model  for  a  scalar (NY=1)  or  vector (NY>1)
   14639             : function in a NX-dimensional space (NX>=1).
   14640             : 
   14641             : Newly created model is empty. It can be used for interpolation right after
   14642             : creation, but it just returns zeros. You have to add points to the  model,
   14643             : tune interpolation settings, and then  call  model  construction  function
   14644             : rbfbuildmodel() which will update model according to your specification.
   14645             : 
   14646             : USAGE:
   14647             : 1. User creates model with rbfcreate()
   14648             : 2. User adds dataset with rbfsetpoints() (points do NOT have to  be  on  a
   14649             :    regular grid) or rbfsetpointsandscales().
   14650             : 3. (OPTIONAL) User chooses polynomial term by calling:
   14651             :    * rbflinterm() to set linear term
   14652             :    * rbfconstterm() to set constant term
   14653             :    * rbfzeroterm() to set zero term
   14654             :    By default, linear term is used.
   14655             : 4. User tweaks algorithm properties with  rbfsetalgohierarchical()  method
   14656             :    (or chooses one of the legacy algorithms - QNN  (rbfsetalgoqnn)  or  ML
   14657             :    (rbfsetalgomultilayer)).
   14658             : 5. User calls rbfbuildmodel() function which rebuilds model  according  to
   14659             :    the specification
   14660             : 6. User may call rbfcalc() to calculate model value at the specified point,
   14661             :    rbfgridcalc() to  calculate   model  values at the points of the regular
   14662             :    grid. User may extract model coefficients with rbfunpack() call.
   14663             : 
   14664             : IMPORTANT: we recommend you to use latest model construction  algorithm  -
   14665             :            hierarchical RBFs, which is activated by rbfsetalgohierarchical()
   14666             :            function. This algorithm is the fastest one, and  most  memory-
   14667             :            efficient.
   14668             :            However,  it  is  incompatible  with older versions  of  ALGLIB
   14669             :            (pre-3.11). So, if you serialize hierarchical model,  you  will
   14670             :            be unable to load it in pre-3.11 ALGLIB. Other model types (QNN
   14671             :            and RBF-ML) are still backward-compatible.
   14672             : 
   14673             : INPUT PARAMETERS:
   14674             :     NX      -   dimension of the space, NX>=1
   14675             :     NY      -   function dimension, NY>=1
   14676             : 
   14677             : OUTPUT PARAMETERS:
   14678             :     S       -   RBF model (initially equals to zero)
   14679             : 
   14680             : NOTE 1: memory requirements. RBF models require amount of memory  which is
   14681             :         proportional  to the number of data points. Some additional memory
   14682             :         is allocated during model construction, but most of this memory is
   14683             :         freed after model coefficients  are  calculated.  Amount  of  this
   14684             :         additional memory depends on model  construction  algorithm  being
   14685             :         used.
   14686             : 
   14687             : NOTE 2: prior to ALGLIB version 3.11, RBF models supported  only  NX=2  or
   14688             :         NX=3. Any  attempt  to  create  single-dimensional  or  more  than
   14689             :         3-dimensional RBF model resulted in exception.
   14690             : 
   14691             :         ALGLIB 3.11 supports any NX>0, but models created with  NX!=2  and
   14692             :         NX!=3 are incompatible with (a) older versions of ALGLIB, (b)  old
   14693             :         model construction algorithms (QNN or RBF-ML).
   14694             : 
   14695             :         So, if you create a model with NX=2 or NX=3,  then,  depending  on
   14696             :         specific  model construction algorithm being chosen, you will (QNN
   14697             :         and RBF-ML) or will not (HierarchicalRBF) get backward compatibility
   14698             :         with older versions of ALGLIB. You have a choice here.
   14699             : 
   14700             :         However, if you create a model with NX neither 2 nor 3,  you  have
   14701             :         no backward compatibility from the start, and you  are  forced  to
   14702             :         use hierarchical RBFs and ALGLIB 3.11 or later.
   14703             : 
   14704             :   -- ALGLIB --
   14705             :      Copyright 13.12.2011, 20.06.2016 by Bochkanov Sergey
   14706             : *************************************************************************/
   14707           0 : void rbfcreate(const ae_int_t nx, const ae_int_t ny, rbfmodel &s, const xparams _xparams)
   14708             : {
   14709             :     jmp_buf _break_jump;
   14710             :     alglib_impl::ae_state _alglib_env_state;
   14711           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   14712           0 :     if( setjmp(_break_jump) )
   14713             :     {
   14714             : #if !defined(AE_NO_EXCEPTIONS)
   14715           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   14716             : #else
   14717             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   14718             :         return;
   14719             : #endif
   14720             :     }
   14721           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   14722           0 :     if( _xparams.flags!=0x0 )
   14723           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   14724           0 :     alglib_impl::rbfcreate(nx, ny, const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
   14725           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   14726           0 :     return;
   14727             : }
   14728             : 
   14729             : /*************************************************************************
   14730             : This function creates buffer  structure  which  can  be  used  to  perform
   14731             : parallel  RBF  model  evaluations  (with  one  RBF  model  instance  being
   14732             : used from multiple threads, as long as  different  threads  use  different
   14733             : instances of buffer).
   14734             : 
   14735             : This buffer object can be used with  rbftscalcbuf()  function  (here  "ts"
   14736             : stands for "thread-safe", "buf" is a suffix which denotes  function  which
   14737             : reuses previously allocated output space).
   14738             : 
   14739             : How to use it:
   14740             : * create RBF model structure with rbfcreate()
   14741             : * load data, tune parameters
   14742             : * call rbfbuildmodel()
   14743             : * call rbfcreatecalcbuffer(), once per thread working with RBF model  (you
   14744             :   should call this function only AFTER call to rbfbuildmodel(), see  below
   14745             :   for more information)
   14746             : * call rbftscalcbuf() from different threads,  with  each  thread  working
   14747             :   with its own copy of buffer object.
   14748             : 
   14749             : INPUT PARAMETERS
   14750             :     S           -   RBF model
   14751             : 
   14752             : OUTPUT PARAMETERS
   14753             :     Buf         -   external buffer.
   14754             : 
   14755             : 
   14756             : IMPORTANT: buffer object should be used only with  RBF model object  which
   14757             :            was used to initialize buffer. Any attempt to use buffer   with
   14758             :            different object is dangerous - you may  get  memory  violation
   14759             :            error because sizes of internal arrays do not fit to dimensions
   14760             :            of RBF structure.
   14761             : 
   14762             : IMPORTANT: you  should  call  this function only for model which was built
   14763             :            with rbfbuildmodel() function, after successful  invocation  of
   14764             :            rbfbuildmodel().  Sizes   of   some   internal  structures  are
   14765             :            determined only after model is built, so buffer object  created
   14766             :            before model  construction  stage  will  be  useless  (and  any
   14767             :            attempt to use it will result in exception).
   14768             : 
   14769             :   -- ALGLIB --
   14770             :      Copyright 02.04.2016 by Sergey Bochkanov
   14771             : *************************************************************************/
   14772           0 : void rbfcreatecalcbuffer(const rbfmodel &s, rbfcalcbuffer &buf, const xparams _xparams)
   14773             : {
   14774             :     jmp_buf _break_jump;
   14775             :     alglib_impl::ae_state _alglib_env_state;
   14776           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   14777           0 :     if( setjmp(_break_jump) )
   14778             :     {
   14779             : #if !defined(AE_NO_EXCEPTIONS)
   14780           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   14781             : #else
   14782             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   14783             :         return;
   14784             : #endif
   14785             :     }
   14786           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   14787           0 :     if( _xparams.flags!=0x0 )
   14788           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   14789           0 :     alglib_impl::rbfcreatecalcbuffer(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::rbfcalcbuffer*>(buf.c_ptr()), &_alglib_env_state);
   14790           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   14791           0 :     return;
   14792             : }
   14793             : 
   14794             : /*************************************************************************
   14795             : This function adds dataset.
   14796             : 
   14797             : This function overrides results of the previous calls, i.e. multiple calls
   14798             : of this function will result in only the last set being added.
   14799             : 
   14800             : IMPORTANT: ALGLIB version 3.11 and later allows you to specify  a  set  of
   14801             :            per-dimension scales. Interpolation radii are multiplied by the
   14802             :            scale vector. It may be useful if you have mixed spatio-temporal
   14803             :            data (say, a set of 3D slices recorded at different times).
   14804             :            You should call rbfsetpointsandscales() function  to  use  this
   14805             :            feature.
   14806             : 
   14807             : INPUT PARAMETERS:
   14808             :     S       -   RBF model, initialized by rbfcreate() call.
   14809             :     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
   14810             :                 in the dataset. First NX elements  are  coordinates,  next
   14811             :                 NY elements are function values. Array may  be larger than
   14812             :                 specified, in  this  case  only leading [N,NX+NY] elements
   14813             :                 will be used.
   14814             :     N       -   number of points in the dataset
   14815             : 
   14816             : After you've added dataset and (optionally) tuned algorithm  settings  you
   14817             : should call rbfbuildmodel() in order to build a model for you.
   14818             : 
   14819             : NOTE: dataset added by this function is not saved during model serialization.
   14820             :       MODEL ITSELF is serialized, but data used to build it are not.
   14821             : 
   14822             :       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
   14823             :       unserialize it, then you will get an empty RBF model with no dataset
   14824             :       being attached.
   14825             : 
   14826             :       From the other side, if you call rbfbuildmodel() between (1) and (2),
   14827             :       then after (2) you will get your fully constructed RBF model  -  but
   14828             :       again with no dataset attached, so subsequent calls to rbfbuildmodel()
   14829             :       will produce empty model.
   14830             : 
   14831             : 
   14832             :   -- ALGLIB --
   14833             :      Copyright 13.12.2011 by Bochkanov Sergey
   14834             : *************************************************************************/
   14835           0 : void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy, const ae_int_t n, const xparams _xparams)
   14836             : {
   14837             :     jmp_buf _break_jump;
   14838             :     alglib_impl::ae_state _alglib_env_state;
   14839           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   14840           0 :     if( setjmp(_break_jump) )
   14841             :     {
   14842             : #if !defined(AE_NO_EXCEPTIONS)
   14843           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   14844             : #else
   14845             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   14846             :         return;
   14847             : #endif
   14848             :     }
   14849           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   14850           0 :     if( _xparams.flags!=0x0 )
   14851           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   14852           0 :     alglib_impl::rbfsetpoints(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, &_alglib_env_state);
   14853           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   14854           0 :     return;
   14855             : }
   14856             : 
   14857             : /*************************************************************************
   14858             : This function adds dataset.
   14859             : 
   14860             : This function overrides results of the previous calls, i.e. multiple calls
   14861             : of this function will result in only the last set being added.
   14862             : 
   14863             : IMPORTANT: ALGLIB version 3.11 and later allows you to specify  a  set  of
   14864             :            per-dimension scales. Interpolation radii are multiplied by the
   14865             :            scale vector. It may be useful if you have mixed spatio-temporal
   14866             :            data (say, a set of 3D slices recorded at different times).
   14867             :            You should call rbfsetpointsandscales() function  to  use  this
   14868             :            feature.
   14869             : 
   14870             : INPUT PARAMETERS:
   14871             :     S       -   RBF model, initialized by rbfcreate() call.
   14872             :     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
   14873             :                 in the dataset. First NX elements  are  coordinates,  next
   14874             :                 NY elements are function values. Array may  be larger than
   14875             :                 specified, in  this  case  only leading [N,NX+NY] elements
   14876             :                 will be used.
   14877             :     N       -   number of points in the dataset
   14878             : 
   14879             : After you've added dataset and (optionally) tuned algorithm  settings  you
   14880             : should call rbfbuildmodel() in order to build a model for you.
   14881             : 
   14882             : NOTE: dataset added by this function is not saved during model serialization.
   14883             :       MODEL ITSELF is serialized, but data used to build it are not.
   14884             : 
   14885             :       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
   14886             :       unserialize it, then you will get an empty RBF model with no dataset
   14887             :       being attached.
   14888             : 
   14889             :       From the other side, if you call rbfbuildmodel() between (1) and (2),
   14890             :       then after (2) you will get your fully constructed RBF model  -  but
   14891             :       again with no dataset attached, so subsequent calls to rbfbuildmodel()
   14892             :       will produce empty model.
   14893             : 
   14894             : 
   14895             :   -- ALGLIB --
   14896             :      Copyright 13.12.2011 by Bochkanov Sergey
   14897             : *************************************************************************/
   14898             : #if !defined(AE_NO_EXCEPTIONS)
   14899           0 : void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy, const xparams _xparams)
   14900             : {
   14901             :     jmp_buf _break_jump;
   14902             :     alglib_impl::ae_state _alglib_env_state;    
   14903             :     ae_int_t n;
   14904             : 
   14905           0 :     n = xy.rows();
   14906           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   14907           0 :     if( setjmp(_break_jump) )
   14908           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   14909           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   14910           0 :     if( _xparams.flags!=0x0 )
   14911           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   14912           0 :     alglib_impl::rbfsetpoints(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, &_alglib_env_state);
   14913             : 
   14914           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   14915           0 :     return;
   14916             : }
   14917             : #endif
   14918             : 
   14919             : /*************************************************************************
   14920             : This function adds dataset and a vector of per-dimension scales.
   14921             : 
   14922             : It may be useful if you have mixed spatio-temporal data - say, a set of 3D
   14923             : slices recorded at different times. Such data typically require  different
   14924             : RBF radii for spatial and temporal dimensions. ALGLIB solves this  problem
   14925             : by specifying single RBF radius, which is (optionally) multiplied  by  the
   14926             : scale vector.
   14927             : 
   14928             : This function overrides results of the previous calls, i.e. multiple calls
   14929             : of this function will result in only the last set being added.
   14930             : 
   14931             : IMPORTANT: only HierarchicalRBF algorithm can work with scaled points. So,
   14932             :            using this function results in RBF models which can be used  in
   14933             :            ALGLIB 3.11 or later. Previous versions of the library will  be
   14934             :            unable  to unserialize models produced by HierarchicalRBF algo.
   14935             : 
   14936             :            Any attempt to use this function with RBF-ML or QNN  algorithms
   14937             :            will result  in  -3  error  code   being   returned  (incorrect
   14938             :            algorithm).
   14939             : 
   14940             : INPUT PARAMETERS:
   14941             :     R       -   RBF model, initialized by rbfcreate() call.
   14942             :     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
   14943             :                 in the dataset. First NX elements  are  coordinates,  next
   14944             :                 NY elements are function values. Array may  be larger than
   14945             :                 specified, in  this  case  only leading [N,NX+NY] elements
   14946             :                 will be used.
   14947             :     N       -   number of points in the dataset
   14948             :     S       -   array[NX], scale vector, S[i]>0.
   14949             : 
   14950             : After you've added dataset and (optionally) tuned algorithm  settings  you
   14951             : should call rbfbuildmodel() in order to build a model for you.
   14952             : 
   14953             : NOTE: dataset added by this function is not saved during model serialization.
   14954             :       MODEL ITSELF is serialized, but data used to build it are not.
   14955             : 
   14956             :       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
   14957             :       unserialize it, then you will get an empty RBF model with no dataset
   14958             :       being attached.
   14959             : 
   14960             :       From the other side, if you call rbfbuildmodel() between (1) and (2),
   14961             :       then after (2) you will get your fully constructed RBF model  -  but
   14962             :       again with no dataset attached, so subsequent calls to rbfbuildmodel()
   14963             :       will produce empty model.
   14964             : 
   14965             : 
   14966             :   -- ALGLIB --
   14967             :      Copyright 20.06.2016 by Bochkanov Sergey
   14968             : *************************************************************************/
   14969           0 : void rbfsetpointsandscales(const rbfmodel &r, const real_2d_array &xy, const ae_int_t n, const real_1d_array &s, const xparams _xparams)
   14970             : {
   14971             :     jmp_buf _break_jump;
   14972             :     alglib_impl::ae_state _alglib_env_state;
   14973           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   14974           0 :     if( setjmp(_break_jump) )
   14975             :     {
   14976             : #if !defined(AE_NO_EXCEPTIONS)
   14977           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   14978             : #else
   14979             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   14980             :         return;
   14981             : #endif
   14982             :     }
   14983           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   14984           0 :     if( _xparams.flags!=0x0 )
   14985           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   14986           0 :     alglib_impl::rbfsetpointsandscales(const_cast<alglib_impl::rbfmodel*>(r.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(s.c_ptr()), &_alglib_env_state);
   14987           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   14988           0 :     return;
   14989             : }
   14990             : 
   14991             : /*************************************************************************
   14992             : This function adds dataset and a vector of per-dimension scales.
   14993             : 
   14994             : It may be useful if you have mixed spatio-temporal data - say, a set of 3D
   14995             : slices recorded at different times. Such data typically require  different
   14996             : RBF radii for spatial and temporal dimensions. ALGLIB solves this  problem
   14997             : by specifying single RBF radius, which is (optionally) multiplied  by  the
   14998             : scale vector.
   14999             : 
   15000             : This function overrides results of the previous calls, i.e. multiple calls
   15001             : of this function will result in only the last set being added.
   15002             : 
   15003             : IMPORTANT: only HierarchicalRBF algorithm can work with scaled points. So,
   15004             :            using this function results in RBF models which can be used  in
   15005             :            ALGLIB 3.11 or later. Previous versions of the library will  be
   15006             :            unable  to unserialize models produced by HierarchicalRBF algo.
   15007             : 
   15008             :            Any attempt to use this function with RBF-ML or QNN  algorithms
   15009             :            will result  in  -3  error  code   being   returned  (incorrect
   15010             :            algorithm).
   15011             : 
   15012             : INPUT PARAMETERS:
   15013             :     R       -   RBF model, initialized by rbfcreate() call.
   15014             :     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
   15015             :                 in the dataset. First NX elements  are  coordinates,  next
   15016             :                 NY elements are function values. Array may  be larger than
   15017             :                 specified, in  this  case  only leading [N,NX+NY] elements
   15018             :                 will be used.
   15019             :     N       -   number of points in the dataset
   15020             :     S       -   array[NX], scale vector, S[i]>0.
   15021             : 
   15022             : After you've added dataset and (optionally) tuned algorithm  settings  you
   15023             : should call rbfbuildmodel() in order to build a model for you.
   15024             : 
   15025             : NOTE: dataset added by this function is not saved during model serialization.
   15026             :       MODEL ITSELF is serialized, but data used to build it are not.
   15027             : 
   15028             :       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
   15029             :       unserialize it, then you will get an empty RBF model with no dataset
   15030             :       being attached.
   15031             : 
   15032             :       From the other side, if you call rbfbuildmodel() between (1) and (2),
   15033             :       then after (2) you will get your fully constructed RBF model  -  but
   15034             :       again with no dataset attached, so subsequent calls to rbfbuildmodel()
   15035             :       will produce empty model.
   15036             : 
   15037             : 
   15038             :   -- ALGLIB --
   15039             :      Copyright 20.06.2016 by Bochkanov Sergey
   15040             : *************************************************************************/
   15041             : #if !defined(AE_NO_EXCEPTIONS)
   15042           0 : void rbfsetpointsandscales(const rbfmodel &r, const real_2d_array &xy, const real_1d_array &s, const xparams _xparams)
   15043             : {
   15044             :     jmp_buf _break_jump;
   15045             :     alglib_impl::ae_state _alglib_env_state;    
   15046             :     ae_int_t n;
   15047             : 
   15048           0 :     n = xy.rows();
   15049           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15050           0 :     if( setjmp(_break_jump) )
   15051           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15052           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15053           0 :     if( _xparams.flags!=0x0 )
   15054           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15055           0 :     alglib_impl::rbfsetpointsandscales(const_cast<alglib_impl::rbfmodel*>(r.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, const_cast<alglib_impl::ae_vector*>(s.c_ptr()), &_alglib_env_state);
   15056             : 
   15057           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15058           0 :     return;
   15059             : }
   15060             : #endif
   15061             : 
   15062             : /*************************************************************************
   15063             : DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
   15064             :            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
   15065             :            requires less memory than QNN and RBF-ML. It is especially good
   15066             :            for large-scale interpolation problems. So, we recommend you to
   15067             :            consider Hierarchical RBF as default option.
   15068             : 
   15069             : ==========================================================================
   15070             : 
   15071             : This  function  sets  RBF interpolation algorithm. ALGLIB supports several
   15072             : RBF algorithms with different properties.
   15073             : 
   15074             : This algorithm is called RBF-QNN and  it  is  good  for  point  sets  with
   15075             : following properties:
   15076             : a) all points are distinct
   15077             : b) all points are well separated.
   15078             : c) points  distribution  is  approximately  uniform.  There is no "contour
   15079             :    lines", clusters of points, or other small-scale structures.
   15080             : 
   15081             : Algorithm description:
   15082             : 1) interpolation centers are allocated to data points
   15083             : 2) interpolation radii are calculated as distances to the  nearest centers
   15084             :    times Q coefficient (where Q is a value from [0.75,1.50]).
   15085             : 3) after  performing (2) radii are transformed in order to avoid situation
   15086             :    when single outlier has very large radius and  influences  many  points
   15087             :    across all dataset. Transformation has following form:
   15088             :        new_r[i] = min(r[i],Z*median(r[]))
   15089             :    where r[i] is I-th radius, median()  is a median  radius across  entire
   15090             :    dataset, Z is user-specified value which controls amount  of  deviation
   15091             :    from median radius.
   15092             : 
   15093             : When (a) is violated,  we  will  be unable to build RBF model. When (b) or
   15094             : (c) are violated, model will be built, but interpolation quality  will  be
   15095             : low. See http://www.alglib.net/interpolation/ for more information on this
   15096             : subject.
   15097             : 
   15098             : This algorithm is used by default.
   15099             : 
   15100             : Additional Q parameter controls smoothness properties of the RBF basis:
   15101             : * Q<0.75 will give perfectly conditioned basis,  but  terrible  smoothness
   15102             :   properties (RBF interpolant will have sharp peaks around function values)
   15103             : * Q around 1.0 gives good balance between smoothness and condition number
   15104             : * Q>1.5 will lead to badly conditioned systems and slow convergence of the
   15105             :   underlying linear solver (although smoothness will be very good)
   15106             : * Q>2.0 will effectively make optimizer useless because it won't  converge
   15107             :   within reasonable amount of iterations. It is possible to set such large
   15108             :   Q, but it is advised not to do so.
   15109             : 
   15110             : INPUT PARAMETERS:
   15111             :     S       -   RBF model, initialized by RBFCreate() call
   15112             :     Q       -   Q parameter, Q>0, recommended value - 1.0
   15113             :     Z       -   Z parameter, Z>0, recommended value - 5.0
   15114             : 
   15115             : NOTE: this   function  has   some   serialization-related  subtleties.  We
   15116             :       recommend you to study serialization examples from ALGLIB  Reference
   15117             :       Manual if you want to perform serialization of your models.
   15118             : 
   15119             : 
   15120             :   -- ALGLIB --
   15121             :      Copyright 13.12.2011 by Bochkanov Sergey
   15122             : *************************************************************************/
   15123           0 : void rbfsetalgoqnn(const rbfmodel &s, const double q, const double z, const xparams _xparams)
   15124             : {
   15125             :     jmp_buf _break_jump;
   15126             :     alglib_impl::ae_state _alglib_env_state;
   15127           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15128           0 :     if( setjmp(_break_jump) )
   15129             :     {
   15130             : #if !defined(AE_NO_EXCEPTIONS)
   15131           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15132             : #else
   15133             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15134             :         return;
   15135             : #endif
   15136             :     }
   15137           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15138           0 :     if( _xparams.flags!=0x0 )
   15139           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15140           0 :     alglib_impl::rbfsetalgoqnn(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), q, z, &_alglib_env_state);
   15141           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15142           0 :     return;
   15143             : }
   15144             : 
   15145             : /*************************************************************************
   15146             : DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
   15147             :            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
   15148             :            requires less memory than QNN and RBF-ML. It is especially good
   15149             :            for large-scale interpolation problems. So, we recommend you to
   15150             :            consider Hierarchical RBF as default option.
   15151             : 
   15152             : ==========================================================================
   15153             : 
   15154             : This  function  sets  RBF interpolation algorithm. ALGLIB supports several
   15155             : RBF algorithms with different properties.
   15156             : 
   15157             : This algorithm is called RBF-QNN and  it  is  good  for  point  sets  with
   15158             : following properties:
   15159             : a) all points are distinct
   15160             : b) all points are well separated.
   15161             : c) points  distribution  is  approximately  uniform.  There is no "contour
   15162             :    lines", clusters of points, or other small-scale structures.
   15163             : 
   15164             : Algorithm description:
   15165             : 1) interpolation centers are allocated to data points
   15166             : 2) interpolation radii are calculated as distances to the  nearest centers
   15167             :    times Q coefficient (where Q is a value from [0.75,1.50]).
   15168             : 3) after  performing (2) radii are transformed in order to avoid situation
   15169             :    when single outlier has very large radius and  influences  many  points
   15170             :    across all dataset. Transformation has following form:
   15171             :        new_r[i] = min(r[i],Z*median(r[]))
   15172             :    where r[i] is I-th radius, median()  is a median  radius across  entire
   15173             :    dataset, Z is user-specified value which controls amount  of  deviation
   15174             :    from median radius.
   15175             : 
   15176             : When (a) is violated,  we  will  be unable to build RBF model. When (b) or
   15177             : (c) are violated, model will be built, but interpolation quality  will  be
   15178             : low. See http://www.alglib.net/interpolation/ for more information on this
   15179             : subject.
   15180             : 
   15181             : This algorithm is used by default.
   15182             : 
   15183             : Additional Q parameter controls smoothness properties of the RBF basis:
   15184             : * Q<0.75 will give perfectly conditioned basis,  but  terrible  smoothness
   15185             :   properties (RBF interpolant will have sharp peaks around function values)
   15186             : * Q around 1.0 gives good balance between smoothness and condition number
   15187             : * Q>1.5 will lead to badly conditioned systems and slow convergence of the
   15188             :   underlying linear solver (although smoothness will be very good)
   15189             : * Q>2.0 will effectively make optimizer useless because it won't  converge
   15190             :   within reasonable amount of iterations. It is possible to set such large
   15191             :   Q, but it is advised not to do so.
   15192             : 
   15193             : INPUT PARAMETERS:
   15194             :     S       -   RBF model, initialized by RBFCreate() call
   15195             :     Q       -   Q parameter, Q>0, recommended value - 1.0
   15196             :     Z       -   Z parameter, Z>0, recommended value - 5.0
   15197             : 
   15198             : NOTE: this   function  has   some   serialization-related  subtleties.  We
   15199             :       recommend you to study serialization examples from ALGLIB  Reference
   15200             :       Manual if you want to perform serialization of your models.
   15201             : 
   15202             : 
   15203             :   -- ALGLIB --
   15204             :      Copyright 13.12.2011 by Bochkanov Sergey
   15205             : *************************************************************************/
   15206             : #if !defined(AE_NO_EXCEPTIONS)
   15207           0 : void rbfsetalgoqnn(const rbfmodel &s, const xparams _xparams)
   15208             : {
   15209             :     jmp_buf _break_jump;
   15210             :     alglib_impl::ae_state _alglib_env_state;    
   15211             :     double q;
   15212             :     double z;
   15213             : 
   15214           0 :     q = 1.0;
   15215           0 :     z = 5.0;
   15216           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15217           0 :     if( setjmp(_break_jump) )
   15218           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15219           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15220           0 :     if( _xparams.flags!=0x0 )
   15221           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15222           0 :     alglib_impl::rbfsetalgoqnn(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), q, z, &_alglib_env_state);
   15223             : 
   15224           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15225           0 :     return;
   15226             : }
   15227             : #endif
   15228             : 
   15229             : /*************************************************************************
   15230             : DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
   15231             :            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
   15232             :            requires less memory than QNN and RBF-ML. It is especially good
   15233             :            for large-scale interpolation problems. So, we recommend you to
   15234             :            consider Hierarchical RBF as default option.
   15235             : 
   15236             : ==========================================================================
   15237             : 
   15238             : This  function  sets  RBF interpolation algorithm. ALGLIB supports several
   15239             : RBF algorithms with different properties.
   15240             : 
   15241             : This  algorithm is called RBF-ML. It builds  multilayer  RBF  model,  i.e.
   15242             : model with subsequently decreasing  radii,  which  allows  us  to  combine
   15243             : smoothness (due to  large radii of  the first layers) with  exactness (due
   15244             : to small radii of the last layers) and fast convergence.
   15245             : 
   15246             : Internally RBF-ML uses many different  means  of acceleration, from sparse
   15247             : matrices  to  KD-trees,  which  results in algorithm whose working time is
   15248             : roughly proportional to N*log(N)*Density*RBase^2*NLayers,  where  N  is  a
   15249             : number of points, Density is an average density if points per unit of  the
   15250             : interpolation space, RBase is an initial radius, NLayers is  a  number  of
   15251             : layers.
   15252             : 
   15253             : RBF-ML is good for following kinds of interpolation problems:
   15254             : 1. "exact" problems (perfect fit) with well separated points
   15255             : 2. least squares problems with arbitrary distribution of points (algorithm
   15256             :    gives  perfect  fit  where it is possible, and resorts to least squares
   15257             :    fit in the hard areas).
   15258             : 3. noisy problems where  we  want  to  apply  some  controlled  amount  of
   15259             :    smoothing.
   15260             : 
   15261             : INPUT PARAMETERS:
   15262             :     S       -   RBF model, initialized by RBFCreate() call
   15263             :     RBase   -   RBase parameter, RBase>0
   15264             :     NLayers -   NLayers parameter, NLayers>0, recommended value  to  start
   15265             :                 with - about 5.
   15266             :     LambdaV -   regularization value, can be useful when  solving  problem
   15267             :                 in the least squares sense.  Optimal  lambda  is  problem-
   15268             :                 dependent and require trial and error. In our  experience,
   15269             :                 good lambda can be as large as 0.1, and you can use  0.001
   15270             :                 as initial guess.
   15271             :                 Default  value  - 0.01, which is used when LambdaV is  not
   15272             :                 given.  You  can  specify  zero  value,  but  it  is   not
   15273             :                 recommended to do so.
   15274             : 
   15275             : TUNING ALGORITHM
   15276             : 
   15277             : In order to use this algorithm you have to choose three parameters:
   15278             : * initial radius RBase
   15279             : * number of layers in the model NLayers
   15280             : * regularization coefficient LambdaV
   15281             : 
   15282             : Initial radius is easy to choose - you can pick any number  several  times
   15283             : larger  than  the  average  distance between points. Algorithm won't break
   15284             : down if you choose radius which is too large (model construction time will
   15285             : increase, but model will be built correctly).
   15286             : 
   15287             : Choose such number of layers that RLast=RBase/2^(NLayers-1)  (radius  used
   15288             : by  the  last  layer)  will  be  smaller than the typical distance between
   15289             : points.  In  case  model  error  is  too large, you can increase number of
   15290             : layers.  Having  more  layers  will make model construction and evaluation
   15291             : proportionally slower, but it will allow you to have model which precisely
   15292             : fits your data. From the other side, if you want to  suppress  noise,  you
   15293             : can DECREASE number of layers to make your model less flexible.
   15294             : 
   15295             : Regularization coefficient LambdaV controls smoothness of  the  individual
   15296             : models built for each layer. We recommend you to use default value in case
   15297             : you don't want to tune this parameter,  because  having  non-zero  LambdaV
   15298             : accelerates and stabilizes internal iterative algorithm. In case you  want
   15299             : to suppress noise you can use  LambdaV  as  additional  parameter  (larger
   15300             : value = more smoothness) to tune.
   15301             : 
   15302             : TYPICAL ERRORS
   15303             : 
   15304             : 1. Using  initial  radius  which is too large. Memory requirements  of the
   15305             :    RBF-ML are roughly proportional to N*Density*RBase^2 (where Density  is
   15306             :    an average density of points per unit of the interpolation  space).  In
   15307             :    the extreme case of the very large RBase we will need O(N^2)  units  of
   15308             :    memory - and many layers in order to decrease radius to some reasonably
   15309             :    small value.
   15310             : 
   15311             : 2. Using too small number of layers - RBF models with large radius are not
   15312             :    flexible enough to reproduce small variations in the  target  function.
   15313             :    You  need  many  layers  with  different radii, from large to small, in
   15314             :    order to have good model.
   15315             : 
   15316             : 3. Using  initial  radius  which  is  too  small.  You will get model with
   15317             :    "holes" in the areas which are too far away from interpolation centers.
   15318             :    However, algorithm will work correctly (and quickly) in this case.
   15319             : 
   15320             : 4. Using too many layers - you will get too large and too slow model. This
   15321             :    model  will  perfectly  reproduce  your function, but maybe you will be
   15322             :    able to achieve similar results with less layers (and less memory).
   15323             : 
   15324             :   -- ALGLIB --
   15325             :      Copyright 02.03.2012 by Bochkanov Sergey
   15326             : *************************************************************************/
   15327           0 : void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdav, const xparams _xparams)
   15328             : {
   15329             :     jmp_buf _break_jump;
   15330             :     alglib_impl::ae_state _alglib_env_state;
   15331           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15332           0 :     if( setjmp(_break_jump) )
   15333             :     {
   15334             : #if !defined(AE_NO_EXCEPTIONS)
   15335           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15336             : #else
   15337             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15338             :         return;
   15339             : #endif
   15340             :     }
   15341           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15342           0 :     if( _xparams.flags!=0x0 )
   15343           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15344           0 :     alglib_impl::rbfsetalgomultilayer(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), rbase, nlayers, lambdav, &_alglib_env_state);
   15345           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15346           0 :     return;
   15347             : }
   15348             : 
   15349             : /*************************************************************************
   15350             : DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
   15351             :            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
   15352             :            requires less memory than QNN and RBF-ML. It is especially good
   15353             :            for large-scale interpolation problems. So, we recommend you to
   15354             :            consider Hierarchical RBF as default option.
   15355             : 
   15356             : ==========================================================================
   15357             : 
   15358             : This  function  sets  RBF interpolation algorithm. ALGLIB supports several
   15359             : RBF algorithms with different properties.
   15360             : 
   15361             : This  algorithm is called RBF-ML. It builds  multilayer  RBF  model,  i.e.
   15362             : model with subsequently decreasing  radii,  which  allows  us  to  combine
   15363             : smoothness (due to  large radii of  the first layers) with  exactness (due
   15364             : to small radii of the last layers) and fast convergence.
   15365             : 
   15366             : Internally RBF-ML uses many different  means  of acceleration, from sparse
   15367             : matrices  to  KD-trees,  which  results in algorithm whose working time is
   15368             : roughly proportional to N*log(N)*Density*RBase^2*NLayers,  where  N  is  a
   15369             : number of points, Density is an average density if points per unit of  the
   15370             : interpolation space, RBase is an initial radius, NLayers is  a  number  of
   15371             : layers.
   15372             : 
   15373             : RBF-ML is good for following kinds of interpolation problems:
   15374             : 1. "exact" problems (perfect fit) with well separated points
   15375             : 2. least squares problems with arbitrary distribution of points (algorithm
   15376             :    gives  perfect  fit  where it is possible, and resorts to least squares
   15377             :    fit in the hard areas).
   15378             : 3. noisy problems where  we  want  to  apply  some  controlled  amount  of
   15379             :    smoothing.
   15380             : 
   15381             : INPUT PARAMETERS:
   15382             :     S       -   RBF model, initialized by RBFCreate() call
   15383             :     RBase   -   RBase parameter, RBase>0
   15384             :     NLayers -   NLayers parameter, NLayers>0, recommended value  to  start
   15385             :                 with - about 5.
   15386             :     LambdaV -   regularization value, can be useful when  solving  problem
   15387             :                 in the least squares sense.  Optimal  lambda  is  problem-
   15388             :                 dependent and require trial and error. In our  experience,
   15389             :                 good lambda can be as large as 0.1, and you can use  0.001
   15390             :                 as initial guess.
   15391             :                 Default  value  - 0.01, which is used when LambdaV is  not
   15392             :                 given.  You  can  specify  zero  value,  but  it  is   not
   15393             :                 recommended to do so.
   15394             : 
   15395             : TUNING ALGORITHM
   15396             : 
   15397             : In order to use this algorithm you have to choose three parameters:
   15398             : * initial radius RBase
   15399             : * number of layers in the model NLayers
   15400             : * regularization coefficient LambdaV
   15401             : 
   15402             : Initial radius is easy to choose - you can pick any number  several  times
   15403             : larger  than  the  average  distance between points. Algorithm won't break
   15404             : down if you choose radius which is too large (model construction time will
   15405             : increase, but model will be built correctly).
   15406             : 
   15407             : Choose such number of layers that RLast=RBase/2^(NLayers-1)  (radius  used
   15408             : by  the  last  layer)  will  be  smaller than the typical distance between
   15409             : points.  In  case  model  error  is  too large, you can increase number of
   15410             : layers.  Having  more  layers  will make model construction and evaluation
   15411             : proportionally slower, but it will allow you to have model which precisely
   15412             : fits your data. From the other side, if you want to  suppress  noise,  you
   15413             : can DECREASE number of layers to make your model less flexible.
   15414             : 
   15415             : Regularization coefficient LambdaV controls smoothness of  the  individual
   15416             : models built for each layer. We recommend you to use default value in case
   15417             : you don't want to tune this parameter,  because  having  non-zero  LambdaV
   15418             : accelerates and stabilizes internal iterative algorithm. In case you  want
   15419             : to suppress noise you can use  LambdaV  as  additional  parameter  (larger
   15420             : value = more smoothness) to tune.
   15421             : 
   15422             : TYPICAL ERRORS
   15423             : 
   15424             : 1. Using  initial  radius  which is too large. Memory requirements  of the
   15425             :    RBF-ML are roughly proportional to N*Density*RBase^2 (where Density  is
   15426             :    an average density of points per unit of the interpolation  space).  In
   15427             :    the extreme case of the very large RBase we will need O(N^2)  units  of
   15428             :    memory - and many layers in order to decrease radius to some reasonably
   15429             :    small value.
   15430             : 
   15431             : 2. Using too small number of layers - RBF models with large radius are not
   15432             :    flexible enough to reproduce small variations in the  target  function.
   15433             :    You  need  many  layers  with  different radii, from large to small, in
   15434             :    order to have good model.
   15435             : 
   15436             : 3. Using  initial  radius  which  is  too  small.  You will get model with
   15437             :    "holes" in the areas which are too far away from interpolation centers.
   15438             :    However, algorithm will work correctly (and quickly) in this case.
   15439             : 
   15440             : 4. Using too many layers - you will get too large and too slow model. This
   15441             :    model  will  perfectly  reproduce  your function, but maybe you will be
   15442             :    able to achieve similar results with less layers (and less memory).
   15443             : 
   15444             :   -- ALGLIB --
   15445             :      Copyright 02.03.2012 by Bochkanov Sergey
   15446             : *************************************************************************/
   15447             : #if !defined(AE_NO_EXCEPTIONS)
   15448           0 : void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers, const xparams _xparams)
   15449             : {
   15450             :     jmp_buf _break_jump;
   15451             :     alglib_impl::ae_state _alglib_env_state;    
   15452             :     double lambdav;
   15453             : 
   15454           0 :     lambdav = 0.01;
   15455           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15456           0 :     if( setjmp(_break_jump) )
   15457           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15458           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15459           0 :     if( _xparams.flags!=0x0 )
   15460           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15461           0 :     alglib_impl::rbfsetalgomultilayer(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), rbase, nlayers, lambdav, &_alglib_env_state);
   15462             : 
   15463           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15464           0 :     return;
   15465             : }
   15466             : #endif
   15467             : 
   15468             : /*************************************************************************
   15469             : This  function  sets  RBF interpolation algorithm. ALGLIB supports several
   15470             : RBF algorithms with different properties.
   15471             : 
   15472             : This  algorithm is called Hierarchical RBF. It  similar  to  its  previous
   15473             : incarnation, RBF-ML, i.e.  it  also  builds  a  sequence  of  models  with
   15474             : decreasing radii. However, it uses more economical way of  building  upper
   15475             : layers (ones with large radii), which results in faster model construction
   15476             : and evaluation, as well as smaller memory footprint during construction.
   15477             : 
   15478             : This algorithm has following important features:
   15479             : * ability to handle millions of points
   15480             : * controllable smoothing via nonlinearity penalization
   15481             : * support for NX-dimensional models with NX=1 or NX>3 (unlike QNN or RBF-ML)
   15482             : * support for specification of per-dimensional  radii  via  scale  vector,
   15483             :   which is set by means of rbfsetpointsandscales() function. This  feature
   15484             :   is useful if you solve  spatio-temporal  interpolation  problems,  where
   15485             :   different radii are required for spatial and temporal dimensions.
   15486             : 
   15487             : Running times are roughly proportional to:
   15488             : * N*log(N)*NLayers - for model construction
   15489             : * N*NLayers - for model evaluation
   15490             : You may see that running time does not depend on search radius  or  points
   15491             : density, just on number of layers in the hierarchy.
   15492             : 
   15493             : IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.11
   15494             :            and  produces  models  which  are  INCOMPATIBLE  with  previous
   15495             :            versions of ALGLIB. You can  not  unserialize  models  produced
   15496             :            with this function in ALGLIB 3.10 or earlier.
   15497             : 
   15498             : INPUT PARAMETERS:
   15499             :     S       -   RBF model, initialized by rbfcreate() call
   15500             :     RBase   -   RBase parameter, RBase>0
   15501             :     NLayers -   NLayers parameter, NLayers>0, recommended value  to  start
   15502             :                 with - about 5.
   15503             :     LambdaNS-   >=0, nonlinearity penalty coefficient, negative values are
   15504             :                 not allowed. This parameter adds controllable smoothing to
   15505             :                 the problem, which may reduce noise. Specification of non-
   15506             :                 zero lambda means that in addition to fitting error solver
   15507             :                 will  also  minimize   LambdaNS*|S''(x)|^2  (appropriately
   15508             :                 generalized to multiple dimensions.
   15509             : 
   15510             :                 Specification of exactly zero value means that no  penalty
   15511             :                 is added  (we  do  not  even  evaluate  matrix  of  second
   15512             :                 derivatives which is necessary for smoothing).
   15513             : 
   15514             :                 Calculation of nonlinearity penalty is costly - it results
   15515             :                 in  several-fold  increase  of  model  construction  time.
   15516             :                 Evaluation time remains the same.
   15517             : 
   15518             :                 Optimal  lambda  is  problem-dependent and requires  trial
   15519             :                 and  error.  Good  value to  start  from  is  1e-5...1e-6,
   15520             :                 which corresponds to slightly noticeable smoothing  of the
   15521             :                 function.  Value  1e-2  usually  means  that  quite  heavy
   15522             :                 smoothing is applied.
   15523             : 
   15524             : TUNING ALGORITHM
   15525             : 
   15526             : In order to use this algorithm you have to choose three parameters:
   15527             : * initial radius RBase
   15528             : * number of layers in the model NLayers
   15529             : * penalty coefficient LambdaNS
   15530             : 
   15531             : Initial radius is easy to choose - you can pick any number  several  times
   15532             : larger  than  the  average  distance between points. Algorithm won't break
   15533             : down if you choose radius which is too large (model construction time will
   15534             : increase, but model will be built correctly).
   15535             : 
   15536             : Choose such number of layers that RLast=RBase/2^(NLayers-1)  (radius  used
   15537             : by  the  last  layer)  will  be  smaller than the typical distance between
   15538             : points.  In  case  model  error  is  too large, you can increase number of
   15539             : layers.  Having  more  layers  will make model construction and evaluation
   15540             : proportionally slower, but it will allow you to have model which precisely
   15541             : fits your data. From the other side, if you want to  suppress  noise,  you
   15542             : can DECREASE number of layers to make your model less flexible (or specify
   15543             : non-zero LambdaNS).
   15544             : 
   15545             : TYPICAL ERRORS
   15546             : 
   15547             : 1. Using too small number of layers - RBF models with large radius are not
   15548             :    flexible enough to reproduce small variations in the  target  function.
   15549             :    You  need  many  layers  with  different radii, from large to small, in
   15550             :    order to have good model.
   15551             : 
   15552             : 2. Using  initial  radius  which  is  too  small.  You will get model with
   15553             :    "holes" in the areas which are too far away from interpolation centers.
   15554             :    However, algorithm will work correctly (and quickly) in this case.
   15555             : 
   15556             :   -- ALGLIB --
   15557             :      Copyright 20.06.2016 by Bochkanov Sergey
   15558             : *************************************************************************/
   15559           0 : void rbfsetalgohierarchical(const rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdans, const xparams _xparams)
   15560             : {
   15561             :     jmp_buf _break_jump;
   15562             :     alglib_impl::ae_state _alglib_env_state;
   15563           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15564           0 :     if( setjmp(_break_jump) )
   15565             :     {
   15566             : #if !defined(AE_NO_EXCEPTIONS)
   15567           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15568             : #else
   15569             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15570             :         return;
   15571             : #endif
   15572             :     }
   15573           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15574           0 :     if( _xparams.flags!=0x0 )
   15575           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15576           0 :     alglib_impl::rbfsetalgohierarchical(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), rbase, nlayers, lambdans, &_alglib_env_state);
   15577           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15578           0 :     return;
   15579             : }
   15580             : 
   15581             : /*************************************************************************
   15582             : This function sets linear term (model is a sum of radial  basis  functions
   15583             : plus linear polynomial). This function won't have effect until  next  call
   15584             : to RBFBuildModel().
   15585             : 
   15586             : INPUT PARAMETERS:
   15587             :     S       -   RBF model, initialized by RBFCreate() call
   15588             : 
   15589             : NOTE: this   function  has   some   serialization-related  subtleties.  We
   15590             :       recommend you to study serialization examples from ALGLIB  Reference
   15591             :       Manual if you want to perform serialization of your models.
   15592             : 
   15593             :   -- ALGLIB --
   15594             :      Copyright 13.12.2011 by Bochkanov Sergey
   15595             : *************************************************************************/
   15596           0 : void rbfsetlinterm(const rbfmodel &s, const xparams _xparams)
   15597             : {
   15598             :     jmp_buf _break_jump;
   15599             :     alglib_impl::ae_state _alglib_env_state;
   15600           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15601           0 :     if( setjmp(_break_jump) )
   15602             :     {
   15603             : #if !defined(AE_NO_EXCEPTIONS)
   15604           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15605             : #else
   15606             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15607             :         return;
   15608             : #endif
   15609             :     }
   15610           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15611           0 :     if( _xparams.flags!=0x0 )
   15612           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15613           0 :     alglib_impl::rbfsetlinterm(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
   15614           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15615           0 :     return;
   15616             : }
   15617             : 
   15618             : /*************************************************************************
   15619             : This function sets constant term (model is a sum of radial basis functions
   15620             : plus constant).  This  function  won't  have  effect  until  next  call to
   15621             : RBFBuildModel().
   15622             : 
   15623             : INPUT PARAMETERS:
   15624             :     S       -   RBF model, initialized by RBFCreate() call
   15625             : 
   15626             : NOTE: this   function  has   some   serialization-related  subtleties.  We
   15627             :       recommend you to study serialization examples from ALGLIB  Reference
   15628             :       Manual if you want to perform serialization of your models.
   15629             : 
   15630             :   -- ALGLIB --
   15631             :      Copyright 13.12.2011 by Bochkanov Sergey
   15632             : *************************************************************************/
   15633           0 : void rbfsetconstterm(const rbfmodel &s, const xparams _xparams)
   15634             : {
   15635             :     jmp_buf _break_jump;
   15636             :     alglib_impl::ae_state _alglib_env_state;
   15637           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15638           0 :     if( setjmp(_break_jump) )
   15639             :     {
   15640             : #if !defined(AE_NO_EXCEPTIONS)
   15641           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15642             : #else
   15643             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15644             :         return;
   15645             : #endif
   15646             :     }
   15647           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15648           0 :     if( _xparams.flags!=0x0 )
   15649           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15650           0 :     alglib_impl::rbfsetconstterm(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
   15651           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15652           0 :     return;
   15653             : }
   15654             : 
   15655             : /*************************************************************************
   15656             : This  function  sets  zero  term (model is a sum of radial basis functions
   15657             : without polynomial term). This function won't have effect until next  call
   15658             : to RBFBuildModel().
   15659             : 
   15660             : INPUT PARAMETERS:
   15661             :     S       -   RBF model, initialized by RBFCreate() call
   15662             : 
   15663             : NOTE: this   function  has   some   serialization-related  subtleties.  We
   15664             :       recommend you to study serialization examples from ALGLIB  Reference
   15665             :       Manual if you want to perform serialization of your models.
   15666             : 
   15667             :   -- ALGLIB --
   15668             :      Copyright 13.12.2011 by Bochkanov Sergey
   15669             : *************************************************************************/
   15670           0 : void rbfsetzeroterm(const rbfmodel &s, const xparams _xparams)
   15671             : {
   15672             :     jmp_buf _break_jump;
   15673             :     alglib_impl::ae_state _alglib_env_state;
   15674           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15675           0 :     if( setjmp(_break_jump) )
   15676             :     {
   15677             : #if !defined(AE_NO_EXCEPTIONS)
   15678           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15679             : #else
   15680             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15681             :         return;
   15682             : #endif
   15683             :     }
   15684           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15685           0 :     if( _xparams.flags!=0x0 )
   15686           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15687           0 :     alglib_impl::rbfsetzeroterm(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
   15688           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15689           0 :     return;
   15690             : }
   15691             : 
   15692             : /*************************************************************************
   15693             : This function sets basis function type, which can be:
   15694             : * 0 for classic Gaussian
   15695             : * 1 for fast and compact bell-like basis function, which  becomes  exactly
   15696             :   zero at distance equal to 3*R (default option).
   15697             : 
   15698             : INPUT PARAMETERS:
   15699             :     S       -   RBF model, initialized by RBFCreate() call
   15700             :     BF      -   basis function type:
   15701             :                 * 0 - classic Gaussian
   15702             :                 * 1 - fast and compact one
   15703             : 
   15704             :   -- ALGLIB --
   15705             :      Copyright 01.02.2017 by Bochkanov Sergey
   15706             : *************************************************************************/
   15707           0 : void rbfsetv2bf(const rbfmodel &s, const ae_int_t bf, const xparams _xparams)
   15708             : {
   15709             :     jmp_buf _break_jump;
   15710             :     alglib_impl::ae_state _alglib_env_state;
   15711           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15712           0 :     if( setjmp(_break_jump) )
   15713             :     {
   15714             : #if !defined(AE_NO_EXCEPTIONS)
   15715           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15716             : #else
   15717             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15718             :         return;
   15719             : #endif
   15720             :     }
   15721           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15722           0 :     if( _xparams.flags!=0x0 )
   15723           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15724           0 :     alglib_impl::rbfsetv2bf(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), bf, &_alglib_env_state);
   15725           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15726           0 :     return;
   15727             : }
   15728             : 
   15729             : /*************************************************************************
   15730             : This function sets stopping criteria of the underlying linear  solver  for
   15731             : hierarchical (version 2) RBF constructor.
   15732             : 
   15733             : INPUT PARAMETERS:
   15734             :     S       -   RBF model, initialized by RBFCreate() call
   15735             :     MaxIts  -   this criterion will stop algorithm after MaxIts iterations.
   15736             :                 Typically a few hundreds iterations is required,  with 400
   15737             :                 being a good default value to start experimentation.
   15738             :                 Zero value means that default value will be selected.
   15739             : 
   15740             :   -- ALGLIB --
   15741             :      Copyright 01.02.2017 by Bochkanov Sergey
   15742             : *************************************************************************/
   15743           0 : void rbfsetv2its(const rbfmodel &s, const ae_int_t maxits, const xparams _xparams)
   15744             : {
   15745             :     jmp_buf _break_jump;
   15746             :     alglib_impl::ae_state _alglib_env_state;
   15747           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15748           0 :     if( setjmp(_break_jump) )
   15749             :     {
   15750             : #if !defined(AE_NO_EXCEPTIONS)
   15751           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15752             : #else
   15753             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15754             :         return;
   15755             : #endif
   15756             :     }
   15757           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15758           0 :     if( _xparams.flags!=0x0 )
   15759           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15760           0 :     alglib_impl::rbfsetv2its(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), maxits, &_alglib_env_state);
   15761           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15762           0 :     return;
   15763             : }
   15764             : 
   15765             : /*************************************************************************
   15766             : This function sets support radius parameter  of  hierarchical  (version 2)
   15767             : RBF constructor.
   15768             : 
   15769             : Hierarchical RBF model achieves great speed-up  by removing from the model
   15770             : excessive (too dense) nodes. Say, if you have RBF radius equal to 1 meter,
   15771             : and two nodes are just 1 millimeter apart, you  may  remove  one  of  them
   15772             : without reducing model quality.
   15773             : 
   15774             : Support radius parameter is used to justify which points need removal, and
   15775             : which do not. If two points are less than  SUPPORT_R*CUR_RADIUS  units  of
   15776             : distance apart, one of them is removed from the model. The larger  support
   15777             : radius  is, the faster model  construction  AND  evaluation are.  However,
   15778             : too large values result in "bumpy" models.
   15779             : 
   15780             : INPUT PARAMETERS:
   15781             :     S       -   RBF model, initialized by RBFCreate() call
   15782             :     R       -   support radius coefficient, >=0.
   15783             :                 Recommended values are [0.1,0.4] range, with 0.1 being
   15784             :                 default value.
   15785             : 
   15786             :   -- ALGLIB --
   15787             :      Copyright 01.02.2017 by Bochkanov Sergey
   15788             : *************************************************************************/
   15789           0 : void rbfsetv2supportr(const rbfmodel &s, const double r, const xparams _xparams)
   15790             : {
   15791             :     jmp_buf _break_jump;
   15792             :     alglib_impl::ae_state _alglib_env_state;
   15793           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15794           0 :     if( setjmp(_break_jump) )
   15795             :     {
   15796             : #if !defined(AE_NO_EXCEPTIONS)
   15797           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15798             : #else
   15799             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15800             :         return;
   15801             : #endif
   15802             :     }
   15803           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15804           0 :     if( _xparams.flags!=0x0 )
   15805           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15806           0 :     alglib_impl::rbfsetv2supportr(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), r, &_alglib_env_state);
   15807           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15808           0 :     return;
   15809             : }
   15810             : 
   15811             : /*************************************************************************
   15812             : This   function  builds  RBF  model  and  returns  report  (contains  some
   15813             : information which can be used for evaluation of the algorithm properties).
   15814             : 
   15815             : Call to this function modifies RBF model by calculating its centers/radii/
   15816             : weights  and  saving  them  into  RBFModel  structure.  Initially RBFModel
   15817             : contain zero coefficients, but after call to this function  we  will  have
   15818             : coefficients which were calculated in order to fit our dataset.
   15819             : 
   15820             : After you called this function you can call RBFCalc(),  RBFGridCalc()  and
   15821             : other model calculation functions.
   15822             : 
   15823             : INPUT PARAMETERS:
   15824             :     S       -   RBF model, initialized by RBFCreate() call
   15825             :     Rep     -   report:
   15826             :                 * Rep.TerminationType:
   15827             :                   * -5 - non-distinct basis function centers were detected,
   15828             :                          interpolation  aborted;  only  QNN  returns  this
   15829             :                          error   code, other  algorithms  can  handle non-
   15830             :                          distinct nodes.
   15831             :                   * -4 - nonconvergence of the internal SVD solver
   15832             :                   * -3   incorrect model construction algorithm was chosen:
   15833             :                          QNN or RBF-ML, combined with one of the incompatible
   15834             :                          features - NX=1 or NX>3; points with per-dimension
   15835             :                          scales.
   15836             :                   *  1 - successful termination
   15837             :                   *  8 - a termination request was submitted via
   15838             :                          rbfrequesttermination() function.
   15839             : 
   15840             :                 Fields which are set only by modern RBF solvers (hierarchical
   15841             :                 or nonnegative; older solvers like QNN and ML initialize these
   15842             :                 fields by NANs):
   15843             :                 * rep.rmserror - root-mean-square error at nodes
   15844             :                 * rep.maxerror - maximum error at nodes
   15845             : 
   15846             :                 Fields are used for debugging purposes:
   15847             :                 * Rep.IterationsCount - iterations count of the LSQR solver
   15848             :                 * Rep.NMV - number of matrix-vector products
   15849             :                 * Rep.ARows - rows count for the system matrix
   15850             :                 * Rep.ACols - columns count for the system matrix
   15851             :                 * Rep.ANNZ - number of significantly non-zero elements
   15852             :                   (elements above some algorithm-determined threshold)
   15853             : 
   15854             : NOTE:  failure  to  build  model will leave current state of the structure
   15855             : unchanged.
   15856             : 
   15857             :   -- ALGLIB --
   15858             :      Copyright 13.12.2011 by Bochkanov Sergey
   15859             : *************************************************************************/
   15860           0 : void rbfbuildmodel(const rbfmodel &s, rbfreport &rep, const xparams _xparams)
   15861             : {
   15862             :     jmp_buf _break_jump;
   15863             :     alglib_impl::ae_state _alglib_env_state;
   15864           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15865           0 :     if( setjmp(_break_jump) )
   15866             :     {
   15867             : #if !defined(AE_NO_EXCEPTIONS)
   15868           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15869             : #else
   15870             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15871             :         return;
   15872             : #endif
   15873             :     }
   15874           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15875           0 :     if( _xparams.flags!=0x0 )
   15876           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15877           0 :     alglib_impl::rbfbuildmodel(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::rbfreport*>(rep.c_ptr()), &_alglib_env_state);
   15878           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15879           0 :     return;
   15880             : }
   15881             : 
   15882             : /*************************************************************************
   15883             : This function calculates values of the RBF model in the given point.
   15884             : 
   15885             : IMPORTANT: this function works only with modern  (hierarchical)  RBFs.  It
   15886             :            can not be used with legacy (version 1) RBFs because older  RBF
   15887             :            code does not support 1-dimensional models.
   15888             : 
   15889             : This function should be used when we have NY=1 (scalar function) and  NX=1
   15890             : (1-dimensional space). If you have 3-dimensional space, use rbfcalc3(). If
   15891             : you  have  2-dimensional  space,  use  rbfcalc3().  If  you  have  general
   15892             : situation (NX-dimensional space, NY-dimensional function)  you  should use
   15893             : generic rbfcalc().
   15894             : 
   15895             : If you want to perform parallel model evaluation  from  multiple  threads,
   15896             : use rbftscalcbuf() with per-thread buffer object.
   15897             : 
   15898             : This function returns 0.0 when:
   15899             : * model is not initialized
   15900             : * NX<>1
   15901             : * NY<>1
   15902             : 
   15903             : INPUT PARAMETERS:
   15904             :     S       -   RBF model
   15905             :     X0      -   X-coordinate, finite number
   15906             : 
   15907             : RESULT:
   15908             :     value of the model or 0.0 (as defined above)
   15909             : 
   15910             :   -- ALGLIB --
   15911             :      Copyright 13.12.2011 by Bochkanov Sergey
   15912             : *************************************************************************/
   15913           0 : double rbfcalc1(const rbfmodel &s, const double x0, const xparams _xparams)
   15914             : {
   15915             :     jmp_buf _break_jump;
   15916             :     alglib_impl::ae_state _alglib_env_state;
   15917           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15918           0 :     if( setjmp(_break_jump) )
   15919             :     {
   15920             : #if !defined(AE_NO_EXCEPTIONS)
   15921           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15922             : #else
   15923             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15924             :         return 0;
   15925             : #endif
   15926             :     }
   15927           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15928           0 :     if( _xparams.flags!=0x0 )
   15929           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15930           0 :     double result = alglib_impl::rbfcalc1(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), x0, &_alglib_env_state);
   15931           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15932           0 :     return *(reinterpret_cast<double*>(&result));
   15933             : }
   15934             : 
   15935             : /*************************************************************************
   15936             : This function calculates values of the RBF model in the given point.
   15937             : 
   15938             : This function should be used when we have NY=1 (scalar function) and  NX=2
   15939             : (2-dimensional space). If you have 3-dimensional space, use rbfcalc3(). If
   15940             : you have general situation (NX-dimensional space, NY-dimensional function)
   15941             : you should use generic rbfcalc().
   15942             : 
   15943             : If  you  want  to  calculate  function  values  many times, consider using
   15944             : rbfgridcalc2v(), which is far more efficient than many subsequent calls to
   15945             : rbfcalc2().
   15946             : 
   15947             : If you want to perform parallel model evaluation  from  multiple  threads,
   15948             : use rbftscalcbuf() with per-thread buffer object.
   15949             : 
   15950             : This function returns 0.0 when:
   15951             : * model is not initialized
   15952             : * NX<>2
   15953             :  *NY<>1
   15954             : 
   15955             : INPUT PARAMETERS:
   15956             :     S       -   RBF model
   15957             :     X0      -   first coordinate, finite number
   15958             :     X1      -   second coordinate, finite number
   15959             : 
   15960             : RESULT:
   15961             :     value of the model or 0.0 (as defined above)
   15962             : 
   15963             :   -- ALGLIB --
   15964             :      Copyright 13.12.2011 by Bochkanov Sergey
   15965             : *************************************************************************/
   15966           0 : double rbfcalc2(const rbfmodel &s, const double x0, const double x1, const xparams _xparams)
   15967             : {
   15968             :     jmp_buf _break_jump;
   15969             :     alglib_impl::ae_state _alglib_env_state;
   15970           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   15971           0 :     if( setjmp(_break_jump) )
   15972             :     {
   15973             : #if !defined(AE_NO_EXCEPTIONS)
   15974           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   15975             : #else
   15976             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   15977             :         return 0;
   15978             : #endif
   15979             :     }
   15980           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   15981           0 :     if( _xparams.flags!=0x0 )
   15982           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   15983           0 :     double result = alglib_impl::rbfcalc2(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), x0, x1, &_alglib_env_state);
   15984           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   15985           0 :     return *(reinterpret_cast<double*>(&result));
   15986             : }
   15987             : 
   15988             : /*************************************************************************
   15989             : This function calculates value of the RBF model in the given point.
   15990             : 
   15991             : This function should be used when we have NY=1 (scalar function) and  NX=3
   15992             : (3-dimensional space). If you have 2-dimensional space, use rbfcalc2(). If
   15993             : you have general situation (NX-dimensional space, NY-dimensional function)
   15994             : you should use generic rbfcalc().
   15995             : 
   15996             : If  you  want  to  calculate  function  values  many times, consider using
   15997             : rbfgridcalc3v(), which is far more efficient than many subsequent calls to
   15998             : rbfcalc3().
   15999             : 
   16000             : If you want to perform parallel model evaluation  from  multiple  threads,
   16001             : use rbftscalcbuf() with per-thread buffer object.
   16002             : 
   16003             : This function returns 0.0 when:
   16004             : * model is not initialized
   16005             : * NX<>3
   16006             :  *NY<>1
   16007             : 
   16008             : INPUT PARAMETERS:
   16009             :     S       -   RBF model
   16010             :     X0      -   first coordinate, finite number
   16011             :     X1      -   second coordinate, finite number
   16012             :     X2      -   third coordinate, finite number
   16013             : 
   16014             : RESULT:
   16015             :     value of the model or 0.0 (as defined above)
   16016             : 
   16017             :   -- ALGLIB --
   16018             :      Copyright 13.12.2011 by Bochkanov Sergey
   16019             : *************************************************************************/
   16020           0 : double rbfcalc3(const rbfmodel &s, const double x0, const double x1, const double x2, const xparams _xparams)
   16021             : {
   16022             :     jmp_buf _break_jump;
   16023             :     alglib_impl::ae_state _alglib_env_state;
   16024           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16025           0 :     if( setjmp(_break_jump) )
   16026             :     {
   16027             : #if !defined(AE_NO_EXCEPTIONS)
   16028           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16029             : #else
   16030             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16031             :         return 0;
   16032             : #endif
   16033             :     }
   16034           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16035           0 :     if( _xparams.flags!=0x0 )
   16036           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16037           0 :     double result = alglib_impl::rbfcalc3(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), x0, x1, x2, &_alglib_env_state);
   16038           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16039           0 :     return *(reinterpret_cast<double*>(&result));
   16040             : }
   16041             : 
   16042             : /*************************************************************************
   16043             : This function calculates values of the RBF model at the given point.
   16044             : 
   16045             : This is general function which can be used for arbitrary NX (dimension  of
   16046             : the space of arguments) and NY (dimension of the function itself). However
   16047             : when  you  have  NY=1  you  may  find more convenient to use rbfcalc2() or
   16048             : rbfcalc3().
   16049             : 
   16050             : If you want to perform parallel model evaluation  from  multiple  threads,
   16051             : use rbftscalcbuf() with per-thread buffer object.
   16052             : 
   16053             : This function returns 0.0 when model is not initialized.
   16054             : 
   16055             : INPUT PARAMETERS:
   16056             :     S       -   RBF model
   16057             :     X       -   coordinates, array[NX].
   16058             :                 X may have more than NX elements, in this case only
   16059             :                 leading NX will be used.
   16060             : 
   16061             : OUTPUT PARAMETERS:
   16062             :     Y       -   function value, array[NY]. Y is out-parameter and
   16063             :                 reallocated after call to this function. In case you  want
   16064             :                 to reuse previously allocated Y, you may use RBFCalcBuf(),
   16065             :                 which reallocates Y only when it is too small.
   16066             : 
   16067             :   -- ALGLIB --
   16068             :      Copyright 13.12.2011 by Bochkanov Sergey
   16069             : *************************************************************************/
   16070           0 : void rbfcalc(const rbfmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
   16071             : {
   16072             :     jmp_buf _break_jump;
   16073             :     alglib_impl::ae_state _alglib_env_state;
   16074           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16075           0 :     if( setjmp(_break_jump) )
   16076             :     {
   16077             : #if !defined(AE_NO_EXCEPTIONS)
   16078           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16079             : #else
   16080             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16081             :         return;
   16082             : #endif
   16083             :     }
   16084           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16085           0 :     if( _xparams.flags!=0x0 )
   16086           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16087           0 :     alglib_impl::rbfcalc(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), &_alglib_env_state);
   16088           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16089           0 :     return;
   16090             : }
   16091             : 
   16092             : /*************************************************************************
   16093             : This function calculates values of the RBF model at the given point.
   16094             : 
   16095             : Same as rbfcalc(), but does not reallocate Y when in is large enough to
   16096             : store function values.
   16097             : 
   16098             : If you want to perform parallel model evaluation  from  multiple  threads,
   16099             : use rbftscalcbuf() with per-thread buffer object.
   16100             : 
   16101             : INPUT PARAMETERS:
   16102             :     S       -   RBF model
   16103             :     X       -   coordinates, array[NX].
   16104             :                 X may have more than NX elements, in this case only
   16105             :                 leading NX will be used.
   16106             :     Y       -   possibly preallocated array
   16107             : 
   16108             : OUTPUT PARAMETERS:
   16109             :     Y       -   function value, array[NY]. Y is not reallocated when it
   16110             :                 is larger than NY.
   16111             : 
   16112             :   -- ALGLIB --
   16113             :      Copyright 13.12.2011 by Bochkanov Sergey
   16114             : *************************************************************************/
   16115           0 : void rbfcalcbuf(const rbfmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
   16116             : {
   16117             :     jmp_buf _break_jump;
   16118             :     alglib_impl::ae_state _alglib_env_state;
   16119           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16120           0 :     if( setjmp(_break_jump) )
   16121             :     {
   16122             : #if !defined(AE_NO_EXCEPTIONS)
   16123           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16124             : #else
   16125             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16126             :         return;
   16127             : #endif
   16128             :     }
   16129           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16130           0 :     if( _xparams.flags!=0x0 )
   16131           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16132           0 :     alglib_impl::rbfcalcbuf(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), &_alglib_env_state);
   16133           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16134           0 :     return;
   16135             : }
   16136             : 
   16137             : /*************************************************************************
   16138             : This function calculates values of the RBF model at the given point, using
   16139             : external  buffer  object  (internal  temporaries  of  RBF  model  are  not
   16140             : modified).
   16141             : 
   16142             : This function allows to use same RBF model object  in  different  threads,
   16143             : assuming  that  different   threads  use  different  instances  of  buffer
   16144             : structure.
   16145             : 
   16146             : INPUT PARAMETERS:
   16147             :     S       -   RBF model, may be shared between different threads
   16148             :     Buf     -   buffer object created for this particular instance of  RBF
   16149             :                 model with rbfcreatecalcbuffer().
   16150             :     X       -   coordinates, array[NX].
   16151             :                 X may have more than NX elements, in this case only
   16152             :                 leading NX will be used.
   16153             :     Y       -   possibly preallocated array
   16154             : 
   16155             : OUTPUT PARAMETERS:
   16156             :     Y       -   function value, array[NY]. Y is not reallocated when it
   16157             :                 is larger than NY.
   16158             : 
   16159             :   -- ALGLIB --
   16160             :      Copyright 13.12.2011 by Bochkanov Sergey
   16161             : *************************************************************************/
   16162           0 : void rbftscalcbuf(const rbfmodel &s, const rbfcalcbuffer &buf, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
   16163             : {
   16164             :     jmp_buf _break_jump;
   16165             :     alglib_impl::ae_state _alglib_env_state;
   16166           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16167           0 :     if( setjmp(_break_jump) )
   16168             :     {
   16169             : #if !defined(AE_NO_EXCEPTIONS)
   16170           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16171             : #else
   16172             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16173             :         return;
   16174             : #endif
   16175             :     }
   16176           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16177           0 :     if( _xparams.flags!=0x0 )
   16178           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16179           0 :     alglib_impl::rbftscalcbuf(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::rbfcalcbuffer*>(buf.c_ptr()), const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), &_alglib_env_state);
   16180           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16181           0 :     return;
   16182             : }
   16183             : 
   16184             : /*************************************************************************
   16185             : This is legacy function for gridded calculation of RBF model.
   16186             : 
   16187             : It is superseded by rbfgridcalc2v() and  rbfgridcalc2vsubset()  functions.
   16188             : 
   16189             :   -- ALGLIB --
   16190             :      Copyright 13.12.2011 by Bochkanov Sergey
   16191             : *************************************************************************/
   16192           0 : 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, const xparams _xparams)
   16193             : {
   16194             :     jmp_buf _break_jump;
   16195             :     alglib_impl::ae_state _alglib_env_state;
   16196           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16197           0 :     if( setjmp(_break_jump) )
   16198             :     {
   16199             : #if !defined(AE_NO_EXCEPTIONS)
   16200           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16201             : #else
   16202             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16203             :         return;
   16204             : #endif
   16205             :     }
   16206           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16207           0 :     if( _xparams.flags!=0x0 )
   16208           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16209           0 :     alglib_impl::rbfgridcalc2(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_vector*>(x0.c_ptr()), n0, const_cast<alglib_impl::ae_vector*>(x1.c_ptr()), n1, const_cast<alglib_impl::ae_matrix*>(y.c_ptr()), &_alglib_env_state);
   16210           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16211           0 :     return;
   16212             : }
   16213             : 
   16214             : /*************************************************************************
   16215             : This function calculates values of the RBF  model  at  the  regular  grid,
   16216             : which  has  N0*N1 points, with Point[I,J] = (X0[I], X1[J]).  Vector-valued
   16217             : RBF models are supported.
   16218             : 
   16219             : This function returns 0.0 when:
   16220             : * model is not initialized
   16221             : * NX<>2
   16222             : 
   16223             :   ! COMMERCIAL EDITION OF ALGLIB:
   16224             :   !
   16225             :   ! Commercial Edition of ALGLIB includes following important improvements
   16226             :   ! of this function:
   16227             :   ! * high-performance native backend with same C# interface (C# version)
   16228             :   ! * multithreading support (C++ and C# versions)
   16229             :   !
   16230             :   ! We recommend you to read 'Working with commercial version' section  of
   16231             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   16232             :   ! related features provided by commercial edition of ALGLIB.
   16233             : 
   16234             : NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
   16235             :       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
   16236             :       processed serially.
   16237             : 
   16238             : INPUT PARAMETERS:
   16239             :     S       -   RBF model, used in read-only mode, can be  shared  between
   16240             :                 multiple   invocations  of  this  function  from  multiple
   16241             :                 threads.
   16242             : 
   16243             :     X0      -   array of grid nodes, first coordinates, array[N0].
   16244             :                 Must be ordered by ascending. Exception is generated
   16245             :                 if the array is not correctly ordered.
   16246             :     N0      -   grid size (number of nodes) in the first dimension
   16247             : 
   16248             :     X1      -   array of grid nodes, second coordinates, array[N1]
   16249             :                 Must be ordered by ascending. Exception is generated
   16250             :                 if the array is not correctly ordered.
   16251             :     N1      -   grid size (number of nodes) in the second dimension
   16252             : 
   16253             : OUTPUT PARAMETERS:
   16254             :     Y       -   function values, array[NY*N0*N1], where NY is a  number of
   16255             :                 "output" vector values (this  function   supports  vector-
   16256             :                 valued RBF models). Y is out-variable and  is  reallocated
   16257             :                 by this function.
   16258             :                 Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), for:
   16259             :                 *  K=0...NY-1
   16260             :                 * I0=0...N0-1
   16261             :                 * I1=0...N1-1
   16262             : 
   16263             : NOTE: this function supports weakly ordered grid nodes, i.e. you may  have
   16264             :       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
   16265             :       benefits  due  to   duplication  of  points,  just  convenience  and
   16266             :       flexibility.
   16267             : 
   16268             : NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
   16269             :       structure in multiple threads calling  this function  for  different
   16270             :       grids.
   16271             : 
   16272             : NOTE: if you need function values on some subset  of  regular  grid, which
   16273             :       may be described as "several compact and  dense  islands",  you  may
   16274             :       use rbfgridcalc2vsubset().
   16275             : 
   16276             :   -- ALGLIB --
   16277             :      Copyright 27.01.2017 by Bochkanov Sergey
   16278             : *************************************************************************/
   16279           0 : 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)
   16280             : {
   16281             :     jmp_buf _break_jump;
   16282             :     alglib_impl::ae_state _alglib_env_state;
   16283           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16284           0 :     if( setjmp(_break_jump) )
   16285             :     {
   16286             : #if !defined(AE_NO_EXCEPTIONS)
   16287           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16288             : #else
   16289             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16290             :         return;
   16291             : #endif
   16292             :     }
   16293           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16294           0 :     if( _xparams.flags!=0x0 )
   16295           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16296           0 :     alglib_impl::rbfgridcalc2v(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_vector*>(x0.c_ptr()), n0, const_cast<alglib_impl::ae_vector*>(x1.c_ptr()), n1, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), &_alglib_env_state);
   16297           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16298           0 :     return;
   16299             : }
   16300             : 
   16301             : /*************************************************************************
   16302             : This function calculates values of the RBF model at some subset of regular
   16303             : grid:
   16304             : * grid has N0*N1 points, with Point[I,J] = (X0[I], X1[J])
   16305             : * only values at some subset of this grid are required
   16306             : Vector-valued RBF models are supported.
   16307             : 
   16308             : This function returns 0.0 when:
   16309             : * model is not initialized
   16310             : * NX<>2
   16311             : 
   16312             :   ! COMMERCIAL EDITION OF ALGLIB:
   16313             :   !
   16314             :   ! Commercial Edition of ALGLIB includes following important improvements
   16315             :   ! of this function:
   16316             :   ! * high-performance native backend with same C# interface (C# version)
   16317             :   ! * multithreading support (C++ and C# versions)
   16318             :   !
   16319             :   ! We recommend you to read 'Working with commercial version' section  of
   16320             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   16321             :   ! related features provided by commercial edition of ALGLIB.
   16322             : 
   16323             : NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
   16324             :       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
   16325             :       processed serially.
   16326             : 
   16327             : INPUT PARAMETERS:
   16328             :     S       -   RBF model, used in read-only mode, can be  shared  between
   16329             :                 multiple   invocations  of  this  function  from  multiple
   16330             :                 threads.
   16331             : 
   16332             :     X0      -   array of grid nodes, first coordinates, array[N0].
   16333             :                 Must be ordered by ascending. Exception is generated
   16334             :                 if the array is not correctly ordered.
   16335             :     N0      -   grid size (number of nodes) in the first dimension
   16336             : 
   16337             :     X1      -   array of grid nodes, second coordinates, array[N1]
   16338             :                 Must be ordered by ascending. Exception is generated
   16339             :                 if the array is not correctly ordered.
   16340             :     N1      -   grid size (number of nodes) in the second dimension
   16341             : 
   16342             :     FlagY   -   array[N0*N1]:
   16343             :                 * Y[I0+I1*N0] corresponds to node (X0[I0],X1[I1])
   16344             :                 * it is a "bitmap" array which contains  False  for  nodes
   16345             :                   which are NOT calculated, and True for nodes  which  are
   16346             :                   required.
   16347             : 
   16348             : OUTPUT PARAMETERS:
   16349             :     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
   16350             :                 of "output" vector values (this function  supports vector-
   16351             :                 valued RBF models):
   16352             :                 * Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]),
   16353             :                   for K=0...NY-1, I0=0...N0-1, I1=0...N1-1.
   16354             :                 * elements of Y[] which correspond  to  FlagY[]=True   are
   16355             :                   loaded by model values (which may be  exactly  zero  for
   16356             :                   some nodes).
   16357             :                 * elements of Y[] which correspond to FlagY[]=False MAY be
   16358             :                   initialized by zeros OR may be calculated. This function
   16359             :                   processes  grid  as  a  hierarchy  of  nested blocks and
   16360             :                   micro-rows. If just one element of micro-row is required,
   16361             :                   entire micro-row (up to 8 nodes in the current  version,
   16362             :                   but no promises) is calculated.
   16363             : 
   16364             : NOTE: this function supports weakly ordered grid nodes, i.e. you may  have
   16365             :       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
   16366             :       benefits  due  to   duplication  of  points,  just  convenience  and
   16367             :       flexibility.
   16368             : 
   16369             : NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
   16370             :       structure in multiple threads calling  this function  for  different
   16371             :       grids.
   16372             : 
   16373             :   -- ALGLIB --
   16374             :      Copyright 04.03.2016 by Bochkanov Sergey
   16375             : *************************************************************************/
   16376           0 : 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)
   16377             : {
   16378             :     jmp_buf _break_jump;
   16379             :     alglib_impl::ae_state _alglib_env_state;
   16380           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16381           0 :     if( setjmp(_break_jump) )
   16382             :     {
   16383             : #if !defined(AE_NO_EXCEPTIONS)
   16384           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16385             : #else
   16386             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16387             :         return;
   16388             : #endif
   16389             :     }
   16390           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16391           0 :     if( _xparams.flags!=0x0 )
   16392           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16393           0 :     alglib_impl::rbfgridcalc2vsubset(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_vector*>(x0.c_ptr()), n0, const_cast<alglib_impl::ae_vector*>(x1.c_ptr()), n1, const_cast<alglib_impl::ae_vector*>(flagy.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), &_alglib_env_state);
   16394           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16395           0 :     return;
   16396             : }
   16397             : 
   16398             : /*************************************************************************
   16399             : This function calculates values of the RBF  model  at  the  regular  grid,
   16400             : which  has  N0*N1*N2  points,  with  Point[I,J,K] = (X0[I], X1[J], X2[K]).
   16401             : Vector-valued RBF models are supported.
   16402             : 
   16403             : This function returns 0.0 when:
   16404             : * model is not initialized
   16405             : * NX<>3
   16406             : 
   16407             :   ! COMMERCIAL EDITION OF ALGLIB:
   16408             :   !
   16409             :   ! Commercial Edition of ALGLIB includes following important improvements
   16410             :   ! of this function:
   16411             :   ! * high-performance native backend with same C# interface (C# version)
   16412             :   ! * multithreading support (C++ and C# versions)
   16413             :   !
   16414             :   ! We recommend you to read 'Working with commercial version' section  of
   16415             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   16416             :   ! related features provided by commercial edition of ALGLIB.
   16417             : 
   16418             : NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
   16419             :       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
   16420             :       processed serially.
   16421             : 
   16422             : INPUT PARAMETERS:
   16423             :     S       -   RBF model, used in read-only mode, can be  shared  between
   16424             :                 multiple   invocations  of  this  function  from  multiple
   16425             :                 threads.
   16426             : 
   16427             :     X0      -   array of grid nodes, first coordinates, array[N0].
   16428             :                 Must be ordered by ascending. Exception is generated
   16429             :                 if the array is not correctly ordered.
   16430             :     N0      -   grid size (number of nodes) in the first dimension
   16431             : 
   16432             :     X1      -   array of grid nodes, second coordinates, array[N1]
   16433             :                 Must be ordered by ascending. Exception is generated
   16434             :                 if the array is not correctly ordered.
   16435             :     N1      -   grid size (number of nodes) in the second dimension
   16436             : 
   16437             :     X2      -   array of grid nodes, third coordinates, array[N2]
   16438             :                 Must be ordered by ascending. Exception is generated
   16439             :                 if the array is not correctly ordered.
   16440             :     N2      -   grid size (number of nodes) in the third dimension
   16441             : 
   16442             : OUTPUT PARAMETERS:
   16443             :     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
   16444             :                 of "output" vector values (this function  supports vector-
   16445             :                 valued RBF models). Y is out-variable and  is  reallocated
   16446             :                 by this function.
   16447             :                 Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]), for:
   16448             :                 *  K=0...NY-1
   16449             :                 * I0=0...N0-1
   16450             :                 * I1=0...N1-1
   16451             :                 * I2=0...N2-1
   16452             : 
   16453             : NOTE: this function supports weakly ordered grid nodes, i.e. you may  have
   16454             :       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
   16455             :       benefits  due  to   duplication  of  points,  just  convenience  and
   16456             :       flexibility.
   16457             : 
   16458             : NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
   16459             :       structure in multiple threads calling  this function  for  different
   16460             :       grids.
   16461             : 
   16462             : NOTE: if you need function values on some subset  of  regular  grid, which
   16463             :       may be described as "several compact and  dense  islands",  you  may
   16464             :       use rbfgridcalc3vsubset().
   16465             : 
   16466             :   -- ALGLIB --
   16467             :      Copyright 04.03.2016 by Bochkanov Sergey
   16468             : *************************************************************************/
   16469           0 : 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)
   16470             : {
   16471             :     jmp_buf _break_jump;
   16472             :     alglib_impl::ae_state _alglib_env_state;
   16473           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16474           0 :     if( setjmp(_break_jump) )
   16475             :     {
   16476             : #if !defined(AE_NO_EXCEPTIONS)
   16477           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16478             : #else
   16479             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16480             :         return;
   16481             : #endif
   16482             :     }
   16483           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16484           0 :     if( _xparams.flags!=0x0 )
   16485           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16486           0 :     alglib_impl::rbfgridcalc3v(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_vector*>(x0.c_ptr()), n0, const_cast<alglib_impl::ae_vector*>(x1.c_ptr()), n1, const_cast<alglib_impl::ae_vector*>(x2.c_ptr()), n2, const_cast<alglib_impl::ae_vector*>(y.c_ptr()), &_alglib_env_state);
   16487           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16488           0 :     return;
   16489             : }
   16490             : 
   16491             : /*************************************************************************
   16492             : This function calculates values of the RBF model at some subset of regular
   16493             : grid:
   16494             : * grid has N0*N1*N2 points, with Point[I,J,K] = (X0[I], X1[J], X2[K])
   16495             : * only values at some subset of this grid are required
   16496             : Vector-valued RBF models are supported.
   16497             : 
   16498             : This function returns 0.0 when:
   16499             : * model is not initialized
   16500             : * NX<>3
   16501             : 
   16502             :   ! COMMERCIAL EDITION OF ALGLIB:
   16503             :   !
   16504             :   ! Commercial Edition of ALGLIB includes following important improvements
   16505             :   ! of this function:
   16506             :   ! * high-performance native backend with same C# interface (C# version)
   16507             :   ! * multithreading support (C++ and C# versions)
   16508             :   !
   16509             :   ! We recommend you to read 'Working with commercial version' section  of
   16510             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   16511             :   ! related features provided by commercial edition of ALGLIB.
   16512             : 
   16513             : NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
   16514             :       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
   16515             :       processed serially.
   16516             : 
   16517             : INPUT PARAMETERS:
   16518             :     S       -   RBF model, used in read-only mode, can be  shared  between
   16519             :                 multiple   invocations  of  this  function  from  multiple
   16520             :                 threads.
   16521             : 
   16522             :     X0      -   array of grid nodes, first coordinates, array[N0].
   16523             :                 Must be ordered by ascending. Exception is generated
   16524             :                 if the array is not correctly ordered.
   16525             :     N0      -   grid size (number of nodes) in the first dimension
   16526             : 
   16527             :     X1      -   array of grid nodes, second coordinates, array[N1]
   16528             :                 Must be ordered by ascending. Exception is generated
   16529             :                 if the array is not correctly ordered.
   16530             :     N1      -   grid size (number of nodes) in the second dimension
   16531             : 
   16532             :     X2      -   array of grid nodes, third coordinates, array[N2]
   16533             :                 Must be ordered by ascending. Exception is generated
   16534             :                 if the array is not correctly ordered.
   16535             :     N2      -   grid size (number of nodes) in the third dimension
   16536             : 
   16537             :     FlagY   -   array[N0*N1*N2]:
   16538             :                 * Y[I0+I1*N0+I2*N0*N1] corresponds to node (X0[I0],X1[I1],X2[I2])
   16539             :                 * it is a "bitmap" array which contains  False  for  nodes
   16540             :                   which are NOT calculated, and True for nodes  which  are
   16541             :                   required.
   16542             : 
   16543             : OUTPUT PARAMETERS:
   16544             :     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
   16545             :                 of "output" vector values (this function  supports vector-
   16546             :                 valued RBF models):
   16547             :                 * Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]),
   16548             :                   for K=0...NY-1, I0=0...N0-1, I1=0...N1-1, I2=0...N2-1.
   16549             :                 * elements of Y[] which correspond  to  FlagY[]=True   are
   16550             :                   loaded by model values (which may be  exactly  zero  for
   16551             :                   some nodes).
   16552             :                 * elements of Y[] which correspond to FlagY[]=False MAY be
   16553             :                   initialized by zeros OR may be calculated. This function
   16554             :                   processes  grid  as  a  hierarchy  of  nested blocks and
   16555             :                   micro-rows. If just one element of micro-row is required,
   16556             :                   entire micro-row (up to 8 nodes in the current  version,
   16557             :                   but no promises) is calculated.
   16558             : 
   16559             : NOTE: this function supports weakly ordered grid nodes, i.e. you may  have
   16560             :       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
   16561             :       benefits  due  to   duplication  of  points,  just  convenience  and
   16562             :       flexibility.
   16563             : 
   16564             : NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
   16565             :       structure in multiple threads calling  this function  for  different
   16566             :       grids.
   16567             : 
   16568             :   -- ALGLIB --
   16569             :      Copyright 04.03.2016 by Bochkanov Sergey
   16570             : *************************************************************************/
   16571           0 : 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)
   16572             : {
   16573             :     jmp_buf _break_jump;
   16574             :     alglib_impl::ae_state _alglib_env_state;
   16575           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16576           0 :     if( setjmp(_break_jump) )
   16577             :     {
   16578             : #if !defined(AE_NO_EXCEPTIONS)
   16579           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16580             : #else
   16581             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16582             :         return;
   16583             : #endif
   16584             :     }
   16585           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16586           0 :     if( _xparams.flags!=0x0 )
   16587           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16588           0 :     alglib_impl::rbfgridcalc3vsubset(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_vector*>(x0.c_ptr()), n0, const_cast<alglib_impl::ae_vector*>(x1.c_ptr()), n1, const_cast<alglib_impl::ae_vector*>(x2.c_ptr()), n2, const_cast<alglib_impl::ae_vector*>(flagy.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), &_alglib_env_state);
   16589           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16590           0 :     return;
   16591             : }
   16592             : 
   16593             : /*************************************************************************
   16594             : This function "unpacks" RBF model by extracting its coefficients.
   16595             : 
   16596             : INPUT PARAMETERS:
   16597             :     S       -   RBF model
   16598             : 
   16599             : OUTPUT PARAMETERS:
   16600             :     NX      -   dimensionality of argument
   16601             :     NY      -   dimensionality of the target function
   16602             :     XWR     -   model information, array[NC,NX+NY+1].
   16603             :                 One row of the array corresponds to one basis function:
   16604             :                 * first NX columns  - coordinates of the center
   16605             :                 * next NY columns   - weights, one per dimension of the
   16606             :                                       function being modelled
   16607             :                 For ModelVersion=1:
   16608             :                 * last column       - radius, same for all dimensions of
   16609             :                                       the function being modelled
   16610             :                 For ModelVersion=2:
   16611             :                 * last NX columns   - radii, one per dimension
   16612             :     NC      -   number of the centers
   16613             :     V       -   polynomial  term , array[NY,NX+1]. One row per one
   16614             :                 dimension of the function being modelled. First NX
   16615             :                 elements are linear coefficients, V[NX] is equal to the
   16616             :                 constant part.
   16617             :     ModelVersion-version of the RBF model:
   16618             :                 * 1 - for models created by QNN and RBF-ML algorithms,
   16619             :                   compatible with ALGLIB 3.10 or earlier.
   16620             :                 * 2 - for models created by HierarchicalRBF, requires
   16621             :                   ALGLIB 3.11 or later
   16622             : 
   16623             :   -- ALGLIB --
   16624             :      Copyright 13.12.2011 by Bochkanov Sergey
   16625             : *************************************************************************/
   16626           0 : 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, ae_int_t &modelversion, const xparams _xparams)
   16627             : {
   16628             :     jmp_buf _break_jump;
   16629             :     alglib_impl::ae_state _alglib_env_state;
   16630           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16631           0 :     if( setjmp(_break_jump) )
   16632             :     {
   16633             : #if !defined(AE_NO_EXCEPTIONS)
   16634           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16635             : #else
   16636             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16637             :         return;
   16638             : #endif
   16639             :     }
   16640           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16641           0 :     if( _xparams.flags!=0x0 )
   16642           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16643           0 :     alglib_impl::rbfunpack(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &nx, &ny, const_cast<alglib_impl::ae_matrix*>(xwr.c_ptr()), &nc, const_cast<alglib_impl::ae_matrix*>(v.c_ptr()), &modelversion, &_alglib_env_state);
   16644           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16645           0 :     return;
   16646             : }
   16647             : 
   16648             : /*************************************************************************
   16649             : This function returns model version.
   16650             : 
   16651             : INPUT PARAMETERS:
   16652             :     S       -   RBF model
   16653             : 
   16654             : RESULT:
   16655             :     * 1 - for models created by QNN and RBF-ML algorithms,
   16656             :       compatible with ALGLIB 3.10 or earlier.
   16657             :     * 2 - for models created by HierarchicalRBF, requires
   16658             :       ALGLIB 3.11 or later
   16659             : 
   16660             :   -- ALGLIB --
   16661             :      Copyright 06.07.2016 by Bochkanov Sergey
   16662             : *************************************************************************/
   16663           0 : ae_int_t rbfgetmodelversion(const rbfmodel &s, const xparams _xparams)
   16664             : {
   16665             :     jmp_buf _break_jump;
   16666             :     alglib_impl::ae_state _alglib_env_state;
   16667           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16668           0 :     if( setjmp(_break_jump) )
   16669             :     {
   16670             : #if !defined(AE_NO_EXCEPTIONS)
   16671           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16672             : #else
   16673             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16674             :         return 0;
   16675             : #endif
   16676             :     }
   16677           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16678           0 :     if( _xparams.flags!=0x0 )
   16679           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16680           0 :     alglib_impl::ae_int_t result = alglib_impl::rbfgetmodelversion(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
   16681           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16682           0 :     return *(reinterpret_cast<ae_int_t*>(&result));
   16683             : }
   16684             : 
   16685             : /*************************************************************************
   16686             : This function is used to peek into hierarchical RBF  construction  process
   16687             : from  some  other  thread  and  get current progress indicator. It returns
   16688             : value in [0,1].
   16689             : 
   16690             : IMPORTANT: only HRBFs (hierarchical RBFs) support  peeking  into  progress
   16691             :            indicator. Legacy RBF-ML and RBF-QNN do  not  support  it.  You
   16692             :            will always get 0 value.
   16693             : 
   16694             : INPUT PARAMETERS:
   16695             :     S           -   RBF model object
   16696             : 
   16697             : RESULT:
   16698             :     progress value, in [0,1]
   16699             : 
   16700             :   -- ALGLIB --
   16701             :      Copyright 17.11.2018 by Bochkanov Sergey
   16702             : *************************************************************************/
   16703           0 : double rbfpeekprogress(const rbfmodel &s, const xparams _xparams)
   16704             : {
   16705             :     jmp_buf _break_jump;
   16706             :     alglib_impl::ae_state _alglib_env_state;
   16707           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16708           0 :     if( setjmp(_break_jump) )
   16709             :     {
   16710             : #if !defined(AE_NO_EXCEPTIONS)
   16711           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16712             : #else
   16713             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16714             :         return 0;
   16715             : #endif
   16716             :     }
   16717           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16718           0 :     if( _xparams.flags!=0x0 )
   16719           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16720           0 :     double result = alglib_impl::rbfpeekprogress(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
   16721           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16722           0 :     return *(reinterpret_cast<double*>(&result));
   16723             : }
   16724             : 
   16725             : /*************************************************************************
   16726             : This function  is  used  to  submit  a  request  for  termination  of  the
   16727             : hierarchical RBF construction process from some other thread.  As  result,
   16728             : RBF construction is terminated smoothly (with proper deallocation  of  all
   16729             : necessary resources) and resultant model is filled by zeros.
   16730             : 
   16731             : A rep.terminationtype=8 will be returned upon receiving such request.
   16732             : 
   16733             : IMPORTANT: only  HRBFs  (hierarchical  RBFs) support termination requests.
   16734             :            Legacy RBF-ML and RBF-QNN do not  support  it.  An  attempt  to
   16735             :            terminate their construction will be ignored.
   16736             : 
   16737             : IMPORTANT: termination request flag is cleared when the model construction
   16738             :            starts. Thus, any pre-construction termination requests will be
   16739             :            silently ignored - only ones submitted AFTER  construction  has
   16740             :            actually began will be handled.
   16741             : 
   16742             : INPUT PARAMETERS:
   16743             :     S           -   RBF model object
   16744             : 
   16745             :   -- ALGLIB --
   16746             :      Copyright 17.11.2018 by Bochkanov Sergey
   16747             : *************************************************************************/
   16748           0 : void rbfrequesttermination(const rbfmodel &s, const xparams _xparams)
   16749             : {
   16750             :     jmp_buf _break_jump;
   16751             :     alglib_impl::ae_state _alglib_env_state;
   16752           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16753           0 :     if( setjmp(_break_jump) )
   16754             :     {
   16755             : #if !defined(AE_NO_EXCEPTIONS)
   16756           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16757             : #else
   16758             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16759             :         return;
   16760             : #endif
   16761             :     }
   16762           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16763           0 :     if( _xparams.flags!=0x0 )
   16764           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16765           0 :     alglib_impl::rbfrequesttermination(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
   16766           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16767           0 :     return;
   16768             : }
   16769             : #endif
   16770             : 
   16771             : #if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD)
   16772             : /*************************************************************************
   16773             : This function is left for backward compatibility.
   16774             : Use fitspheremc() instead.
   16775             : 
   16776             : 
   16777             :   -- ALGLIB --
   16778             :      Copyright 14.04.2017 by Bochkanov Sergey
   16779             : *************************************************************************/
   16780           0 : 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)
   16781             : {
   16782             :     jmp_buf _break_jump;
   16783             :     alglib_impl::ae_state _alglib_env_state;
   16784           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16785           0 :     if( setjmp(_break_jump) )
   16786             :     {
   16787             : #if !defined(AE_NO_EXCEPTIONS)
   16788           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16789             : #else
   16790             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16791             :         return;
   16792             : #endif
   16793             :     }
   16794           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16795           0 :     if( _xparams.flags!=0x0 )
   16796           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16797           0 :     alglib_impl::nsfitspheremcc(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), npoints, nx, const_cast<alglib_impl::ae_vector*>(cx.c_ptr()), &rhi, &_alglib_env_state);
   16798           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16799           0 :     return;
   16800             : }
   16801             : 
   16802             : /*************************************************************************
   16803             : This function is left for backward compatibility.
   16804             : Use fitspheremi() instead.
   16805             : 
   16806             :   -- ALGLIB --
   16807             :      Copyright 14.04.2017 by Bochkanov Sergey
   16808             : *************************************************************************/
   16809           0 : 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)
   16810             : {
   16811             :     jmp_buf _break_jump;
   16812             :     alglib_impl::ae_state _alglib_env_state;
   16813           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16814           0 :     if( setjmp(_break_jump) )
   16815             :     {
   16816             : #if !defined(AE_NO_EXCEPTIONS)
   16817           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16818             : #else
   16819             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16820             :         return;
   16821             : #endif
   16822             :     }
   16823           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16824           0 :     if( _xparams.flags!=0x0 )
   16825           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16826           0 :     alglib_impl::nsfitspheremic(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), npoints, nx, const_cast<alglib_impl::ae_vector*>(cx.c_ptr()), &rlo, &_alglib_env_state);
   16827           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16828           0 :     return;
   16829             : }
   16830             : 
   16831             : /*************************************************************************
   16832             : This function is left for backward compatibility.
   16833             : Use fitspheremz() instead.
   16834             : 
   16835             :   -- ALGLIB --
   16836             :      Copyright 14.04.2017 by Bochkanov Sergey
   16837             : *************************************************************************/
   16838           0 : 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)
   16839             : {
   16840             :     jmp_buf _break_jump;
   16841             :     alglib_impl::ae_state _alglib_env_state;
   16842           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16843           0 :     if( setjmp(_break_jump) )
   16844             :     {
   16845             : #if !defined(AE_NO_EXCEPTIONS)
   16846           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16847             : #else
   16848             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16849             :         return;
   16850             : #endif
   16851             :     }
   16852           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16853           0 :     if( _xparams.flags!=0x0 )
   16854           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16855           0 :     alglib_impl::nsfitspheremzc(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), npoints, nx, const_cast<alglib_impl::ae_vector*>(cx.c_ptr()), &rlo, &rhi, &_alglib_env_state);
   16856           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16857           0 :     return;
   16858             : }
   16859             : 
   16860             : /*************************************************************************
   16861             : This function is left for backward compatibility.
   16862             : Use fitspherex() instead.
   16863             : 
   16864             :   -- ALGLIB --
   16865             :      Copyright 14.04.2017 by Bochkanov Sergey
   16866             : *************************************************************************/
   16867           0 : 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)
   16868             : {
   16869             :     jmp_buf _break_jump;
   16870             :     alglib_impl::ae_state _alglib_env_state;
   16871           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16872           0 :     if( setjmp(_break_jump) )
   16873             :     {
   16874             : #if !defined(AE_NO_EXCEPTIONS)
   16875           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16876             : #else
   16877             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16878             :         return;
   16879             : #endif
   16880             :     }
   16881           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16882           0 :     if( _xparams.flags!=0x0 )
   16883           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16884           0 :     alglib_impl::nsfitspherex(const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), npoints, nx, problemtype, epsx, aulits, penalty, const_cast<alglib_impl::ae_vector*>(cx.c_ptr()), &rlo, &rhi, &_alglib_env_state);
   16885           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16886           0 :     return;
   16887             : }
   16888             : 
   16889             : /*************************************************************************
   16890             : This function is an obsolete and deprecated version of fitting by
   16891             : penalized cubic spline.
   16892             : 
   16893             : It was superseded by spline1dfit(), which is an orders of magnitude faster
   16894             : and more memory-efficient implementation.
   16895             : 
   16896             : Do NOT use this function in the new code!
   16897             : 
   16898             :   -- ALGLIB PROJECT --
   16899             :      Copyright 18.08.2009 by Bochkanov Sergey
   16900             : *************************************************************************/
   16901           0 : 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)
   16902             : {
   16903             :     jmp_buf _break_jump;
   16904             :     alglib_impl::ae_state _alglib_env_state;
   16905           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16906           0 :     if( setjmp(_break_jump) )
   16907             :     {
   16908             : #if !defined(AE_NO_EXCEPTIONS)
   16909           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16910             : #else
   16911             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16912             :         return;
   16913             : #endif
   16914             :     }
   16915           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16916           0 :     if( _xparams.flags!=0x0 )
   16917           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16918           0 :     alglib_impl::spline1dfitpenalized(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, rho, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
   16919           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16920           0 :     return;
   16921             : }
   16922             : 
   16923             : /*************************************************************************
   16924             : This function is an obsolete and deprecated version of fitting by
   16925             : penalized cubic spline.
   16926             : 
   16927             : It was superseded by spline1dfit(), which is an orders of magnitude faster
   16928             : and more memory-efficient implementation.
   16929             : 
   16930             : Do NOT use this function in the new code!
   16931             : 
   16932             :   -- ALGLIB PROJECT --
   16933             :      Copyright 18.08.2009 by Bochkanov Sergey
   16934             : *************************************************************************/
   16935             : #if !defined(AE_NO_EXCEPTIONS)
   16936           0 : 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)
   16937             : {
   16938             :     jmp_buf _break_jump;
   16939             :     alglib_impl::ae_state _alglib_env_state;    
   16940             :     ae_int_t n;
   16941           0 :     if( (x.length()!=y.length()))
   16942           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitpenalized': looks like one of arguments has wrong size");
   16943           0 :     n = x.length();
   16944           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16945           0 :     if( setjmp(_break_jump) )
   16946           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16947           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16948           0 :     if( _xparams.flags!=0x0 )
   16949           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16950           0 :     alglib_impl::spline1dfitpenalized(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), n, m, rho, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
   16951             : 
   16952           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16953           0 :     return;
   16954             : }
   16955             : #endif
   16956             : 
   16957             : /*************************************************************************
   16958             : This function is an obsolete and deprecated version of fitting by
   16959             : penalized cubic spline.
   16960             : 
   16961             : It was superseded by spline1dfit(), which is an orders of magnitude faster
   16962             : and more memory-efficient implementation.
   16963             : 
   16964             : Do NOT use this function in the new code!
   16965             : 
   16966             :   -- ALGLIB PROJECT --
   16967             :      Copyright 19.10.2010 by Bochkanov Sergey
   16968             : *************************************************************************/
   16969           0 : 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)
   16970             : {
   16971             :     jmp_buf _break_jump;
   16972             :     alglib_impl::ae_state _alglib_env_state;
   16973           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   16974           0 :     if( setjmp(_break_jump) )
   16975             :     {
   16976             : #if !defined(AE_NO_EXCEPTIONS)
   16977           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   16978             : #else
   16979             :         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
   16980             :         return;
   16981             : #endif
   16982             :     }
   16983           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   16984           0 :     if( _xparams.flags!=0x0 )
   16985           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   16986           0 :     alglib_impl::spline1dfitpenalizedw(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), n, m, rho, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
   16987           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   16988           0 :     return;
   16989             : }
   16990             : 
   16991             : /*************************************************************************
   16992             : This function is an obsolete and deprecated version of fitting by
   16993             : penalized cubic spline.
   16994             : 
   16995             : It was superseded by spline1dfit(), which is an orders of magnitude faster
   16996             : and more memory-efficient implementation.
   16997             : 
   16998             : Do NOT use this function in the new code!
   16999             : 
   17000             :   -- ALGLIB PROJECT --
   17001             :      Copyright 19.10.2010 by Bochkanov Sergey
   17002             : *************************************************************************/
   17003             : #if !defined(AE_NO_EXCEPTIONS)
   17004           0 : 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)
   17005             : {
   17006             :     jmp_buf _break_jump;
   17007             :     alglib_impl::ae_state _alglib_env_state;    
   17008             :     ae_int_t n;
   17009           0 :     if( (x.length()!=y.length()) || (x.length()!=w.length()))
   17010           0 :         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitpenalizedw': looks like one of arguments has wrong size");
   17011           0 :     n = x.length();
   17012           0 :     alglib_impl::ae_state_init(&_alglib_env_state);
   17013           0 :     if( setjmp(_break_jump) )
   17014           0 :         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
   17015           0 :     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
   17016           0 :     if( _xparams.flags!=0x0 )
   17017           0 :         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
   17018           0 :     alglib_impl::spline1dfitpenalizedw(const_cast<alglib_impl::ae_vector*>(x.c_ptr()), const_cast<alglib_impl::ae_vector*>(y.c_ptr()), const_cast<alglib_impl::ae_vector*>(w.c_ptr()), n, m, rho, &info, const_cast<alglib_impl::spline1dinterpolant*>(s.c_ptr()), const_cast<alglib_impl::spline1dfitreport*>(rep.c_ptr()), &_alglib_env_state);
   17019             : 
   17020           0 :     alglib_impl::ae_state_clear(&_alglib_env_state);
   17021           0 :     return;
   17022             : }
   17023             : #endif
   17024             : #endif
   17025             : }
   17026             : 
   17027             : /////////////////////////////////////////////////////////////////////////
   17028             : //
   17029             : // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE
   17030             : //
   17031             : /////////////////////////////////////////////////////////////////////////
   17032             : namespace alglib_impl
   17033             : {
   17034             : #if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD)
   17035             : static double idw_w0 = 1.0;
   17036             : static double idw_meps = 1.0E-50;
   17037             : static ae_int_t idw_defaultnlayers = 16;
   17038             : static double idw_defaultlambda0 = 0.3333;
   17039             : static void idw_errormetricsviacalc(idwbuilder* state,
   17040             :      idwmodel* model,
   17041             :      idwreport* rep,
   17042             :      ae_state *_state);
   17043             : 
   17044             : 
   17045             : #endif
   17046             : #if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD)
   17047             : static void ratint_barycentricnormalize(barycentricinterpolant* b,
   17048             :      ae_state *_state);
   17049             : 
   17050             : 
   17051             : #endif
   17052             : #if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD)
   17053             : 
   17054             : 
   17055             : #endif
   17056             : #if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD)
   17057             : 
   17058             : 
   17059             : #endif
   17060             : #if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD)
   17061             : static double spline1d_lambdareg = 1.0e-9;
   17062             : static double spline1d_cholreg = 1.0e-12;
   17063             : static void spline1d_spline1dgriddiffcubicinternal(/* Real    */ ae_vector* x,
   17064             :      /* Real    */ ae_vector* y,
   17065             :      ae_int_t n,
   17066             :      ae_int_t boundltype,
   17067             :      double boundl,
   17068             :      ae_int_t boundrtype,
   17069             :      double boundr,
   17070             :      /* Real    */ ae_vector* d,
   17071             :      /* Real    */ ae_vector* a1,
   17072             :      /* Real    */ ae_vector* a2,
   17073             :      /* Real    */ ae_vector* a3,
   17074             :      /* Real    */ ae_vector* b,
   17075             :      /* Real    */ ae_vector* dt,
   17076             :      ae_state *_state);
   17077             : static void spline1d_heapsortpoints(/* Real    */ ae_vector* x,
   17078             :      /* Real    */ ae_vector* y,
   17079             :      ae_int_t n,
   17080             :      ae_state *_state);
   17081             : static void spline1d_heapsortppoints(/* Real    */ ae_vector* x,
   17082             :      /* Real    */ ae_vector* y,
   17083             :      /* Integer */ ae_vector* p,
   17084             :      ae_int_t n,
   17085             :      ae_state *_state);
   17086             : static void spline1d_solvetridiagonal(/* Real    */ ae_vector* a,
   17087             :      /* Real    */ ae_vector* b,
   17088             :      /* Real    */ ae_vector* c,
   17089             :      /* Real    */ ae_vector* d,
   17090             :      ae_int_t n,
   17091             :      /* Real    */ ae_vector* x,
   17092             :      ae_state *_state);
   17093             : static void spline1d_solvecyclictridiagonal(/* Real    */ ae_vector* a,
   17094             :      /* Real    */ ae_vector* b,
   17095             :      /* Real    */ ae_vector* c,
   17096             :      /* Real    */ ae_vector* d,
   17097             :      ae_int_t n,
   17098             :      /* Real    */ ae_vector* x,
   17099             :      ae_state *_state);
   17100             : static double spline1d_diffthreepoint(double t,
   17101             :      double x0,
   17102             :      double f0,
   17103             :      double x1,
   17104             :      double f1,
   17105             :      double x2,
   17106             :      double f2,
   17107             :      ae_state *_state);
   17108             : static void spline1d_hermitecalc(double p0,
   17109             :      double m0,
   17110             :      double p1,
   17111             :      double m1,
   17112             :      double t,
   17113             :      double* s,
   17114             :      double* ds,
   17115             :      ae_state *_state);
   17116             : static double spline1d_rescaleval(double a0,
   17117             :      double b0,
   17118             :      double a1,
   17119             :      double b1,
   17120             :      double t,
   17121             :      ae_state *_state);
   17122             : 
   17123             : 
   17124             : #endif
   17125             : #if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD)
   17126             : static void parametric_pspline2par(/* Real    */ ae_matrix* xy,
   17127             :      ae_int_t n,
   17128             :      ae_int_t pt,
   17129             :      /* Real    */ ae_vector* p,
   17130             :      ae_state *_state);
   17131             : static void parametric_pspline3par(/* Real    */ ae_matrix* xy,
   17132             :      ae_int_t n,
   17133             :      ae_int_t pt,
   17134             :      /* Real    */ ae_vector* p,
   17135             :      ae_state *_state);
   17136             : static void parametric_rdpanalyzesectionpar(/* Real    */ ae_matrix* xy,
   17137             :      ae_int_t i0,
   17138             :      ae_int_t i1,
   17139             :      ae_int_t d,
   17140             :      ae_int_t* worstidx,
   17141             :      double* worsterror,
   17142             :      ae_state *_state);
   17143             : 
   17144             : 
   17145             : #endif
   17146             : #if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD)
   17147             : static void spline3d_spline3ddiff(spline3dinterpolant* c,
   17148             :      double x,
   17149             :      double y,
   17150             :      double z,
   17151             :      double* f,
   17152             :      double* fx,
   17153             :      double* fy,
   17154             :      double* fxy,
   17155             :      ae_state *_state);
   17156             : 
   17157             : 
   17158             : #endif
   17159             : #if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD)
   17160             : 
   17161             : 
   17162             : #endif
   17163             : #if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD)
   17164             : static void lsfit_rdpanalyzesection(/* Real    */ ae_vector* x,
   17165             :      /* Real    */ ae_vector* y,
   17166             :      ae_int_t i0,
   17167             :      ae_int_t i1,
   17168             :      ae_int_t* worstidx,
   17169             :      double* worsterror,
   17170             :      ae_state *_state);
   17171             : static void lsfit_rdprecursive(/* Real    */ ae_vector* x,
   17172             :      /* Real    */ ae_vector* y,
   17173             :      ae_int_t i0,
   17174             :      ae_int_t i1,
   17175             :      double eps,
   17176             :      /* Real    */ ae_vector* xout,
   17177             :      /* Real    */ ae_vector* yout,
   17178             :      ae_int_t* nout,
   17179             :      ae_state *_state);
   17180             : static void lsfit_logisticfitinternal(/* Real    */ ae_vector* x,
   17181             :      /* Real    */ ae_vector* y,
   17182             :      ae_int_t n,
   17183             :      ae_bool is4pl,
   17184             :      double lambdav,
   17185             :      minlmstate* state,
   17186             :      minlmreport* replm,
   17187             :      /* Real    */ ae_vector* p1,
   17188             :      double* flast,
   17189             :      ae_state *_state);
   17190             : static void lsfit_logisticfit45errors(/* Real    */ ae_vector* x,
   17191             :      /* Real    */ ae_vector* y,
   17192             :      ae_int_t n,
   17193             :      double a,
   17194             :      double b,
   17195             :      double c,
   17196             :      double d,
   17197             :      double g,
   17198             :      lsfitreport* rep,
   17199             :      ae_state *_state);
   17200             : static void lsfit_spline1dfitinternal(ae_int_t st,
   17201             :      /* Real    */ ae_vector* x,
   17202             :      /* Real    */ ae_vector* y,
   17203             :      /* Real    */ ae_vector* w,
   17204             :      ae_int_t n,
   17205             :      /* Real    */ ae_vector* xc,
   17206             :      /* Real    */ ae_vector* yc,
   17207             :      /* Integer */ ae_vector* dc,
   17208             :      ae_int_t k,
   17209             :      ae_int_t m,
   17210             :      ae_int_t* info,
   17211             :      spline1dinterpolant* s,
   17212             :      spline1dfitreport* rep,
   17213             :      ae_state *_state);
   17214             : static void lsfit_lsfitlinearinternal(/* Real    */ ae_vector* y,
   17215             :      /* Real    */ ae_vector* w,
   17216             :      /* Real    */ ae_matrix* fmatrix,
   17217             :      ae_int_t n,
   17218             :      ae_int_t m,
   17219             :      ae_int_t* info,
   17220             :      /* Real    */ ae_vector* c,
   17221             :      lsfitreport* rep,
   17222             :      ae_state *_state);
   17223             : static void lsfit_lsfitclearrequestfields(lsfitstate* state,
   17224             :      ae_state *_state);
   17225             : static void lsfit_barycentriccalcbasis(barycentricinterpolant* b,
   17226             :      double t,
   17227             :      /* Real    */ ae_vector* y,
   17228             :      ae_state *_state);
   17229             : static void lsfit_internalchebyshevfit(/* Real    */ ae_vector* x,
   17230             :      /* Real    */ ae_vector* y,
   17231             :      /* Real    */ ae_vector* w,
   17232             :      ae_int_t n,
   17233             :      /* Real    */ ae_vector* xc,
   17234             :      /* Real    */ ae_vector* yc,
   17235             :      /* Integer */ ae_vector* dc,
   17236             :      ae_int_t k,
   17237             :      ae_int_t m,
   17238             :      ae_int_t* info,
   17239             :      /* Real    */ ae_vector* c,
   17240             :      lsfitreport* rep,
   17241             :      ae_state *_state);
   17242             : static void lsfit_barycentricfitwcfixedd(/* Real    */ ae_vector* x,
   17243             :      /* Real    */ ae_vector* y,
   17244             :      /* Real    */ ae_vector* w,
   17245             :      ae_int_t n,
   17246             :      /* Real    */ ae_vector* xc,
   17247             :      /* Real    */ ae_vector* yc,
   17248             :      /* Integer */ ae_vector* dc,
   17249             :      ae_int_t k,
   17250             :      ae_int_t m,
   17251             :      ae_int_t d,
   17252             :      ae_int_t* info,
   17253             :      barycentricinterpolant* b,
   17254             :      barycentricfitreport* rep,
   17255             :      ae_state *_state);
   17256             : static void lsfit_clearreport(lsfitreport* rep, ae_state *_state);
   17257             : static void lsfit_estimateerrors(/* Real    */ ae_matrix* f1,
   17258             :      /* Real    */ ae_vector* f0,
   17259             :      /* Real    */ ae_vector* y,
   17260             :      /* Real    */ ae_vector* w,
   17261             :      /* Real    */ ae_vector* x,
   17262             :      /* Real    */ ae_vector* s,
   17263             :      ae_int_t n,
   17264             :      ae_int_t k,
   17265             :      lsfitreport* rep,
   17266             :      /* Real    */ ae_matrix* z,
   17267             :      ae_int_t zkind,
   17268             :      ae_state *_state);
   17269             : 
   17270             : 
   17271             : #endif
   17272             : #if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD)
   17273             : static double rbfv2_defaultlambdareg = 1.0E-6;
   17274             : static double rbfv2_defaultsupportr = 0.10;
   17275             : static ae_int_t rbfv2_defaultmaxits = 400;
   17276             : static ae_int_t rbfv2_defaultbf = 1;
   17277             : static ae_int_t rbfv2_maxnodesize = 6;
   17278             : static double rbfv2_complexitymultiplier = 100.0;
   17279             : static ae_bool rbfv2_rbfv2buildlinearmodel(/* Real    */ ae_matrix* x,
   17280             :      /* Real    */ ae_matrix* y,
   17281             :      ae_int_t n,
   17282             :      ae_int_t nx,
   17283             :      ae_int_t ny,
   17284             :      ae_int_t modeltype,
   17285             :      /* Real    */ ae_matrix* v,
   17286             :      ae_state *_state);
   17287             : static void rbfv2_allocatecalcbuffer(rbfv2model* s,
   17288             :      rbfv2calcbuffer* buf,
   17289             :      ae_state *_state);
   17290             : static void rbfv2_convertandappendtree(kdtree* curtree,
   17291             :      ae_int_t n,
   17292             :      ae_int_t nx,
   17293             :      ae_int_t ny,
   17294             :      /* Integer */ ae_vector* kdnodes,
   17295             :      /* Real    */ ae_vector* kdsplits,
   17296             :      /* Real    */ ae_vector* cw,
   17297             :      ae_state *_state);
   17298             : static void rbfv2_converttreerec(kdtree* curtree,
   17299             :      ae_int_t n,
   17300             :      ae_int_t nx,
   17301             :      ae_int_t ny,
   17302             :      ae_int_t nodeoffset,
   17303             :      ae_int_t nodesbase,
   17304             :      ae_int_t splitsbase,
   17305             :      ae_int_t cwbase,
   17306             :      /* Integer */ ae_vector* localnodes,
   17307             :      ae_int_t* localnodessize,
   17308             :      /* Real    */ ae_vector* localsplits,
   17309             :      ae_int_t* localsplitssize,
   17310             :      /* Real    */ ae_vector* localcw,
   17311             :      ae_int_t* localcwsize,
   17312             :      /* Real    */ ae_matrix* xybuf,
   17313             :      ae_state *_state);
   17314             : static void rbfv2_partialcalcrec(rbfv2model* s,
   17315             :      rbfv2calcbuffer* buf,
   17316             :      ae_int_t rootidx,
   17317             :      double invr2,
   17318             :      double queryr2,
   17319             :      /* Real    */ ae_vector* x,
   17320             :      /* Real    */ ae_vector* y,
   17321             :      ae_state *_state);
   17322             : static void rbfv2_partialrowcalcrec(rbfv2model* s,
   17323             :      rbfv2calcbuffer* buf,
   17324             :      ae_int_t rootidx,
   17325             :      double invr2,
   17326             :      double rquery2,
   17327             :      double rfar2,
   17328             :      /* Real    */ ae_vector* cx,
   17329             :      /* Real    */ ae_vector* rx,
   17330             :      /* Boolean */ ae_vector* rf,
   17331             :      ae_int_t rowsize,
   17332             :      /* Real    */ ae_vector* ry,
   17333             :      ae_state *_state);
   17334             : static void rbfv2_preparepartialquery(/* Real    */ ae_vector* x,
   17335             :      /* Real    */ ae_vector* kdboxmin,
   17336             :      /* Real    */ ae_vector* kdboxmax,
   17337             :      ae_int_t nx,
   17338             :      rbfv2calcbuffer* buf,
   17339             :      ae_int_t* cnt,
   17340             :      ae_state *_state);
   17341             : static void rbfv2_partialqueryrec(/* Integer */ ae_vector* kdnodes,
   17342             :      /* Real    */ ae_vector* kdsplits,
   17343             :      /* Real    */ ae_vector* cw,
   17344             :      ae_int_t nx,
   17345             :      ae_int_t ny,
   17346             :      rbfv2calcbuffer* buf,
   17347             :      ae_int_t rootidx,
   17348             :      double queryr2,
   17349             :      /* Real    */ ae_vector* x,
   17350             :      /* Real    */ ae_vector* r2,
   17351             :      /* Integer */ ae_vector* offs,
   17352             :      ae_int_t* k,
   17353             :      ae_state *_state);
   17354             : static ae_int_t rbfv2_partialcountrec(/* Integer */ ae_vector* kdnodes,
   17355             :      /* Real    */ ae_vector* kdsplits,
   17356             :      /* Real    */ ae_vector* cw,
   17357             :      ae_int_t nx,
   17358             :      ae_int_t ny,
   17359             :      rbfv2calcbuffer* buf,
   17360             :      ae_int_t rootidx,
   17361             :      double queryr2,
   17362             :      /* Real    */ ae_vector* x,
   17363             :      ae_state *_state);
   17364             : static void rbfv2_partialunpackrec(/* Integer */ ae_vector* kdnodes,
   17365             :      /* Real    */ ae_vector* kdsplits,
   17366             :      /* Real    */ ae_vector* cw,
   17367             :      /* Real    */ ae_vector* s,
   17368             :      ae_int_t nx,
   17369             :      ae_int_t ny,
   17370             :      ae_int_t rootidx,
   17371             :      double r,
   17372             :      /* Real    */ ae_matrix* xwr,
   17373             :      ae_int_t* k,
   17374             :      ae_state *_state);
   17375             : static ae_int_t rbfv2_designmatrixrowsize(/* Integer */ ae_vector* kdnodes,
   17376             :      /* Real    */ ae_vector* kdsplits,
   17377             :      /* Real    */ ae_vector* cw,
   17378             :      /* Real    */ ae_vector* ri,
   17379             :      /* Integer */ ae_vector* kdroots,
   17380             :      /* Real    */ ae_vector* kdboxmin,
   17381             :      /* Real    */ ae_vector* kdboxmax,
   17382             :      ae_int_t nx,
   17383             :      ae_int_t ny,
   17384             :      ae_int_t nh,
   17385             :      ae_int_t level,
   17386             :      double rcoeff,
   17387             :      /* Real    */ ae_vector* x0,
   17388             :      rbfv2calcbuffer* calcbuf,
   17389             :      ae_state *_state);
   17390             : static void rbfv2_designmatrixgeneraterow(/* Integer */ ae_vector* kdnodes,
   17391             :      /* Real    */ ae_vector* kdsplits,
   17392             :      /* Real    */ ae_vector* cw,
   17393             :      /* Real    */ ae_vector* ri,
   17394             :      /* Integer */ ae_vector* kdroots,
   17395             :      /* Real    */ ae_vector* kdboxmin,
   17396             :      /* Real    */ ae_vector* kdboxmax,
   17397             :      /* Integer */ ae_vector* cwrange,
   17398             :      ae_int_t nx,
   17399             :      ae_int_t ny,
   17400             :      ae_int_t nh,
   17401             :      ae_int_t level,
   17402             :      ae_int_t bf,
   17403             :      double rcoeff,
   17404             :      ae_int_t rowsperpoint,
   17405             :      double penalty,
   17406             :      /* Real    */ ae_vector* x0,
   17407             :      rbfv2calcbuffer* calcbuf,
   17408             :      /* Real    */ ae_vector* tmpr2,
   17409             :      /* Integer */ ae_vector* tmpoffs,
   17410             :      /* Integer */ ae_vector* rowidx,
   17411             :      /* Real    */ ae_vector* rowval,
   17412             :      ae_int_t* rowsize,
   17413             :      ae_state *_state);
   17414             : static void rbfv2_zerofill(rbfv2model* s,
   17415             :      ae_int_t nx,
   17416             :      ae_int_t ny,
   17417             :      ae_int_t bf,
   17418             :      ae_state *_state);
   17419             : 
   17420             : 
   17421             : #endif
   17422             : #if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD)
   17423             : static double spline2d_cholreg = 1.0E-12;
   17424             : static double spline2d_lambdaregblocklls = 1.0E-6;
   17425             : static double spline2d_lambdaregfastddm = 1.0E-4;
   17426             : static double spline2d_lambdadecay = 0.5;
   17427             : static void spline2d_bicubiccalcderivatives(/* Real    */ ae_matrix* a,
   17428             :      /* Real    */ ae_vector* x,
   17429             :      /* Real    */ ae_vector* y,
   17430             :      ae_int_t m,
   17431             :      ae_int_t n,
   17432             :      /* Real    */ ae_matrix* dx,
   17433             :      /* Real    */ ae_matrix* dy,
   17434             :      /* Real    */ ae_matrix* dxy,
   17435             :      ae_state *_state);
   17436             : static void spline2d_generatedesignmatrix(/* Real    */ ae_vector* xy,
   17437             :      ae_int_t npoints,
   17438             :      ae_int_t d,
   17439             :      ae_int_t kx,
   17440             :      ae_int_t ky,
   17441             :      double smoothing,
   17442             :      double lambdareg,
   17443             :      spline1dinterpolant* basis1,
   17444             :      sparsematrix* av,
   17445             :      sparsematrix* ah,
   17446             :      ae_int_t* arows,
   17447             :      ae_state *_state);
   17448             : static void spline2d_updatesplinetable(/* Real    */ ae_vector* z,
   17449             :      ae_int_t kx,
   17450             :      ae_int_t ky,
   17451             :      ae_int_t d,
   17452             :      spline1dinterpolant* basis1,
   17453             :      ae_int_t bfrad,
   17454             :      /* Real    */ ae_vector* ftbl,
   17455             :      ae_int_t m,
   17456             :      ae_int_t n,
   17457             :      ae_int_t scalexy,
   17458             :      ae_state *_state);
   17459             : static void spline2d_fastddmfit(/* Real    */ ae_vector* xy,
   17460             :      ae_int_t npoints,
   17461             :      ae_int_t d,
   17462             :      ae_int_t kx,
   17463             :      ae_int_t ky,
   17464             :      ae_int_t basecasex,
   17465             :      ae_int_t basecasey,
   17466             :      ae_int_t maxcoresize,
   17467             :      ae_int_t interfacesize,
   17468             :      ae_int_t nlayers,
   17469             :      double smoothing,
   17470             :      ae_int_t lsqrcnt,
   17471             :      spline1dinterpolant* basis1,
   17472             :      spline2dinterpolant* spline,
   17473             :      spline2dfitreport* rep,
   17474             :      double tss,
   17475             :      ae_state *_state);
   17476             : static void spline2d_fastddmfitlayer(/* Real    */ ae_vector* xy,
   17477             :      ae_int_t d,
   17478             :      ae_int_t scalexy,
   17479             :      /* Integer */ ae_vector* xyindex,
   17480             :      ae_int_t basecasex,
   17481             :      ae_int_t tilex0,
   17482             :      ae_int_t tilex1,
   17483             :      ae_int_t tilescountx,
   17484             :      ae_int_t basecasey,
   17485             :      ae_int_t tiley0,
   17486             :      ae_int_t tiley1,
   17487             :      ae_int_t tilescounty,
   17488             :      ae_int_t maxcoresize,
   17489             :      ae_int_t interfacesize,
   17490             :      ae_int_t lsqrcnt,
   17491             :      double lambdareg,
   17492             :      spline1dinterpolant* basis1,
   17493             :      ae_shared_pool* pool,
   17494             :      spline2dinterpolant* spline,
   17495             :      ae_state *_state);
   17496             : ae_bool _trypexec_spline2d_fastddmfitlayer(/* Real    */ ae_vector* xy,
   17497             :     ae_int_t d,
   17498             :     ae_int_t scalexy,
   17499             :     /* Integer */ ae_vector* xyindex,
   17500             :     ae_int_t basecasex,
   17501             :     ae_int_t tilex0,
   17502             :     ae_int_t tilex1,
   17503             :     ae_int_t tilescountx,
   17504             :     ae_int_t basecasey,
   17505             :     ae_int_t tiley0,
   17506             :     ae_int_t tiley1,
   17507             :     ae_int_t tilescounty,
   17508             :     ae_int_t maxcoresize,
   17509             :     ae_int_t interfacesize,
   17510             :     ae_int_t lsqrcnt,
   17511             :     double lambdareg,
   17512             :     spline1dinterpolant* basis1,
   17513             :     ae_shared_pool* pool,
   17514             :     spline2dinterpolant* spline, ae_state *_state);
   17515             : static void spline2d_blockllsfit(spline2dxdesignmatrix* xdesign,
   17516             :      ae_int_t lsqrcnt,
   17517             :      /* Real    */ ae_vector* z,
   17518             :      spline2dfitreport* rep,
   17519             :      double tss,
   17520             :      spline2dblockllsbuf* buf,
   17521             :      ae_state *_state);
   17522             : static void spline2d_naivellsfit(sparsematrix* av,
   17523             :      sparsematrix* ah,
   17524             :      ae_int_t arows,
   17525             :      /* Real    */ ae_vector* xy,
   17526             :      ae_int_t kx,
   17527             :      ae_int_t ky,
   17528             :      ae_int_t npoints,
   17529             :      ae_int_t d,
   17530             :      ae_int_t lsqrcnt,
   17531             :      /* Real    */ ae_vector* z,
   17532             :      spline2dfitreport* rep,
   17533             :      double tss,
   17534             :      ae_state *_state);
   17535             : static ae_int_t spline2d_getcelloffset(ae_int_t kx,
   17536             :      ae_int_t ky,
   17537             :      ae_int_t blockbandwidth,
   17538             :      ae_int_t i,
   17539             :      ae_int_t j,
   17540             :      ae_state *_state);
   17541             : static void spline2d_copycellto(ae_int_t kx,
   17542             :      ae_int_t ky,
   17543             :      ae_int_t blockbandwidth,
   17544             :      /* Real    */ ae_matrix* blockata,
   17545             :      ae_int_t i,
   17546             :      ae_int_t j,
   17547             :      /* Real    */ ae_matrix* dst,
   17548             :      ae_int_t dst0,
   17549             :      ae_int_t dst1,
   17550             :      ae_state *_state);
   17551             : static void spline2d_flushtozerocell(ae_int_t kx,
   17552             :      ae_int_t ky,
   17553             :      ae_int_t blockbandwidth,
   17554             :      /* Real    */ ae_matrix* blockata,
   17555             :      ae_int_t i,
   17556             :      ae_int_t j,
   17557             :      double eps,
   17558             :      ae_state *_state);
   17559             : static void spline2d_blockllsgenerateata(sparsematrix* ah,
   17560             :      ae_int_t ky0,
   17561             :      ae_int_t ky1,
   17562             :      ae_int_t kx,
   17563             :      ae_int_t ky,
   17564             :      /* Real    */ ae_matrix* blockata,
   17565             :      sreal* mxata,
   17566             :      ae_state *_state);
   17567             : ae_bool _trypexec_spline2d_blockllsgenerateata(sparsematrix* ah,
   17568             :     ae_int_t ky0,
   17569             :     ae_int_t ky1,
   17570             :     ae_int_t kx,
   17571             :     ae_int_t ky,
   17572             :     /* Real    */ ae_matrix* blockata,
   17573             :     sreal* mxata, ae_state *_state);
   17574             : static ae_bool spline2d_blockllscholesky(/* Real    */ ae_matrix* blockata,
   17575             :      ae_int_t kx,
   17576             :      ae_int_t ky,
   17577             :      /* Real    */ ae_matrix* trsmbuf2,
   17578             :      /* Real    */ ae_matrix* cholbuf2,
   17579             :      /* Real    */ ae_vector* cholbuf1,
   17580             :      ae_state *_state);
   17581             : static void spline2d_blockllstrsv(/* Real    */ ae_matrix* blockata,
   17582             :      ae_int_t kx,
   17583             :      ae_int_t ky,
   17584             :      ae_bool transu,
   17585             :      /* Real    */ ae_vector* b,
   17586             :      ae_state *_state);
   17587             : static void spline2d_computeresidualsfromscratch(/* Real    */ ae_vector* xy,
   17588             :      /* Real    */ ae_vector* yraw,
   17589             :      ae_int_t npoints,
   17590             :      ae_int_t d,
   17591             :      ae_int_t scalexy,
   17592             :      spline2dinterpolant* spline,
   17593             :      ae_state *_state);
   17594             : ae_bool _trypexec_spline2d_computeresidualsfromscratch(/* Real    */ ae_vector* xy,
   17595             :     /* Real    */ ae_vector* yraw,
   17596             :     ae_int_t npoints,
   17597             :     ae_int_t d,
   17598             :     ae_int_t scalexy,
   17599             :     spline2dinterpolant* spline, ae_state *_state);
   17600             : static void spline2d_computeresidualsfromscratchrec(/* Real    */ ae_vector* xy,
   17601             :      /* Real    */ ae_vector* yraw,
   17602             :      ae_int_t pt0,
   17603             :      ae_int_t pt1,
   17604             :      ae_int_t chunksize,
   17605             :      ae_int_t d,
   17606             :      ae_int_t scalexy,
   17607             :      spline2dinterpolant* spline,
   17608             :      ae_shared_pool* pool,
   17609             :      ae_state *_state);
   17610             : ae_bool _trypexec_spline2d_computeresidualsfromscratchrec(/* Real    */ ae_vector* xy,
   17611             :     /* Real    */ ae_vector* yraw,
   17612             :     ae_int_t pt0,
   17613             :     ae_int_t pt1,
   17614             :     ae_int_t chunksize,
   17615             :     ae_int_t d,
   17616             :     ae_int_t scalexy,
   17617             :     spline2dinterpolant* spline,
   17618             :     ae_shared_pool* pool, ae_state *_state);
   17619             : static void spline2d_reorderdatasetandbuildindex(/* Real    */ ae_vector* xy,
   17620             :      ae_int_t npoints,
   17621             :      ae_int_t d,
   17622             :      /* Real    */ ae_vector* shadow,
   17623             :      ae_int_t ns,
   17624             :      ae_int_t kx,
   17625             :      ae_int_t ky,
   17626             :      /* Integer */ ae_vector* xyindex,
   17627             :      /* Integer */ ae_vector* bufi,
   17628             :      ae_state *_state);
   17629             : static void spline2d_rescaledatasetandrefineindex(/* Real    */ ae_vector* xy,
   17630             :      ae_int_t npoints,
   17631             :      ae_int_t d,
   17632             :      /* Real    */ ae_vector* shadow,
   17633             :      ae_int_t ns,
   17634             :      ae_int_t kx,
   17635             :      ae_int_t ky,
   17636             :      /* Integer */ ae_vector* xyindex,
   17637             :      /* Integer */ ae_vector* bufi,
   17638             :      ae_state *_state);
   17639             : static void spline2d_expandindexrows(/* Real    */ ae_vector* xy,
   17640             :      ae_int_t d,
   17641             :      /* Real    */ ae_vector* shadow,
   17642             :      ae_int_t ns,
   17643             :      /* Integer */ ae_vector* cidx,
   17644             :      ae_int_t pt0,
   17645             :      ae_int_t pt1,
   17646             :      /* Integer */ ae_vector* xyindexprev,
   17647             :      ae_int_t row0,
   17648             :      ae_int_t row1,
   17649             :      /* Integer */ ae_vector* xyindexnew,
   17650             :      ae_int_t kxnew,
   17651             :      ae_int_t kynew,
   17652             :      ae_bool rootcall,
   17653             :      ae_state *_state);
   17654             : ae_bool _trypexec_spline2d_expandindexrows(/* Real    */ ae_vector* xy,
   17655             :     ae_int_t d,
   17656             :     /* Real    */ ae_vector* shadow,
   17657             :     ae_int_t ns,
   17658             :     /* Integer */ ae_vector* cidx,
   17659             :     ae_int_t pt0,
   17660             :     ae_int_t pt1,
   17661             :     /* Integer */ ae_vector* xyindexprev,
   17662             :     ae_int_t row0,
   17663             :     ae_int_t row1,
   17664             :     /* Integer */ ae_vector* xyindexnew,
   17665             :     ae_int_t kxnew,
   17666             :     ae_int_t kynew,
   17667             :     ae_bool rootcall, ae_state *_state);
   17668             : static void spline2d_reorderdatasetandbuildindexrec(/* Real    */ ae_vector* xy,
   17669             :      ae_int_t d,
   17670             :      /* Real    */ ae_vector* shadow,
   17671             :      ae_int_t ns,
   17672             :      /* Integer */ ae_vector* cidx,
   17673             :      ae_int_t pt0,
   17674             :      ae_int_t pt1,
   17675             :      /* Integer */ ae_vector* xyindex,
   17676             :      ae_int_t idx0,
   17677             :      ae_int_t idx1,
   17678             :      ae_bool rootcall,
   17679             :      ae_state *_state);
   17680             : ae_bool _trypexec_spline2d_reorderdatasetandbuildindexrec(/* Real    */ ae_vector* xy,
   17681             :     ae_int_t d,
   17682             :     /* Real    */ ae_vector* shadow,
   17683             :     ae_int_t ns,
   17684             :     /* Integer */ ae_vector* cidx,
   17685             :     ae_int_t pt0,
   17686             :     ae_int_t pt1,
   17687             :     /* Integer */ ae_vector* xyindex,
   17688             :     ae_int_t idx0,
   17689             :     ae_int_t idx1,
   17690             :     ae_bool rootcall, ae_state *_state);
   17691             : static void spline2d_xdesigngenerate(/* Real    */ ae_vector* xy,
   17692             :      /* Integer */ ae_vector* xyindex,
   17693             :      ae_int_t kx0,
   17694             :      ae_int_t kx1,
   17695             :      ae_int_t kxtotal,
   17696             :      ae_int_t ky0,
   17697             :      ae_int_t ky1,
   17698             :      ae_int_t kytotal,
   17699             :      ae_int_t d,
   17700             :      double lambdareg,
   17701             :      double lambdans,
   17702             :      spline1dinterpolant* basis1,
   17703             :      spline2dxdesignmatrix* a,
   17704             :      ae_state *_state);
   17705             : static void spline2d_xdesignmv(spline2dxdesignmatrix* a,
   17706             :      /* Real    */ ae_vector* x,
   17707             :      /* Real    */ ae_vector* y,
   17708             :      ae_state *_state);
   17709             : static void spline2d_xdesignmtv(spline2dxdesignmatrix* a,
   17710             :      /* Real    */ ae_vector* x,
   17711             :      /* Real    */ ae_vector* y,
   17712             :      ae_state *_state);
   17713             : static void spline2d_xdesignblockata(spline2dxdesignmatrix* a,
   17714             :      /* Real    */ ae_matrix* blockata,
   17715             :      double* mxata,
   17716             :      ae_state *_state);
   17717             : 
   17718             : 
   17719             : #endif
   17720             : #if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD)
   17721             : static ae_int_t rbfv1_mxnx = 3;
   17722             : static double rbfv1_rbffarradius = 6;
   17723             : static double rbfv1_rbfnearradius = 2.1;
   17724             : static double rbfv1_rbfmlradius = 3;
   17725             : static double rbfv1_minbasecasecost = 100000;
   17726             : static ae_bool rbfv1_rbfv1buildlinearmodel(/* Real    */ ae_matrix* x,
   17727             :      /* Real    */ ae_matrix* y,
   17728             :      ae_int_t n,
   17729             :      ae_int_t ny,
   17730             :      ae_int_t modeltype,
   17731             :      /* Real    */ ae_matrix* v,
   17732             :      ae_state *_state);
   17733             : static void rbfv1_buildrbfmodellsqr(/* Real    */ ae_matrix* x,
   17734             :      /* Real    */ ae_matrix* y,
   17735             :      /* Real    */ ae_matrix* xc,
   17736             :      /* Real    */ ae_vector* r,
   17737             :      ae_int_t n,
   17738             :      ae_int_t nc,
   17739             :      ae_int_t ny,
   17740             :      kdtree* pointstree,
   17741             :      kdtree* centerstree,
   17742             :      double epsort,
   17743             :      double epserr,
   17744             :      ae_int_t maxits,
   17745             :      ae_int_t* gnnz,
   17746             :      ae_int_t* snnz,
   17747             :      /* Real    */ ae_matrix* w,
   17748             :      ae_int_t* info,
   17749             :      ae_int_t* iterationscount,
   17750             :      ae_int_t* nmv,
   17751             :      ae_state *_state);
   17752             : static void rbfv1_buildrbfmlayersmodellsqr(/* Real    */ ae_matrix* x,
   17753             :      /* Real    */ ae_matrix* y,
   17754             :      /* Real    */ ae_matrix* xc,
   17755             :      double rval,
   17756             :      /* Real    */ ae_vector* r,
   17757             :      ae_int_t n,
   17758             :      ae_int_t* nc,
   17759             :      ae_int_t ny,
   17760             :      ae_int_t nlayers,
   17761             :      kdtree* centerstree,
   17762             :      double epsort,
   17763             :      double epserr,
   17764             :      ae_int_t maxits,
   17765             :      double lambdav,
   17766             :      ae_int_t* annz,
   17767             :      /* Real    */ ae_matrix* w,
   17768             :      ae_int_t* info,
   17769             :      ae_int_t* iterationscount,
   17770             :      ae_int_t* nmv,
   17771             :      ae_state *_state);
   17772             : 
   17773             : 
   17774             : #endif
   17775             : #if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD)
   17776             : static double rbf_eps = 1.0E-6;
   17777             : static double rbf_rbffarradius = 6;
   17778             : static ae_int_t rbf_rbffirstversion = 0;
   17779             : static ae_int_t rbf_rbfversion2 = 2;
   17780             : static void rbf_rbfpreparenonserializablefields(rbfmodel* s,
   17781             :      ae_state *_state);
   17782             : static void rbf_initializev1(ae_int_t nx,
   17783             :      ae_int_t ny,
   17784             :      rbfv1model* s,
   17785             :      ae_state *_state);
   17786             : static void rbf_initializev2(ae_int_t nx,
   17787             :      ae_int_t ny,
   17788             :      rbfv2model* s,
   17789             :      ae_state *_state);
   17790             : static void rbf_clearreportfields(rbfreport* rep, ae_state *_state);
   17791             : 
   17792             : 
   17793             : #endif
   17794             : #if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD)
   17795             : 
   17796             : 
   17797             : #endif
   17798             : 
   17799             : #if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD)
   17800             : 
   17801             : 
   17802             : /*************************************************************************
   17803             : This function creates buffer  structure  which  can  be  used  to  perform
   17804             : parallel  IDW  model  evaluations  (with  one  IDW  model  instance  being
   17805             : used from multiple threads, as long as  different  threads  use  different
   17806             : instances of buffer).
   17807             : 
   17808             : This buffer object can be used with  idwtscalcbuf()  function  (here  "ts"
   17809             : stands for "thread-safe", "buf" is a suffix which denotes  function  which
   17810             : reuses previously allocated output space).
   17811             : 
   17812             : How to use it:
   17813             : * create IDW model structure or load it from file
   17814             : * call idwcreatecalcbuffer(), once per thread working with IDW model  (you
   17815             :   should call this function only AFTER model initialization, see below for
   17816             :   more information)
   17817             : * call idwtscalcbuf() from different threads,  with  each  thread  working
   17818             :   with its own copy of buffer object.
   17819             : 
   17820             : INPUT PARAMETERS
   17821             :     S           -   IDW model
   17822             : 
   17823             : OUTPUT PARAMETERS
   17824             :     Buf         -   external buffer.
   17825             :     
   17826             :     
   17827             : IMPORTANT: buffer object should be used only with  IDW model object  which
   17828             :            was used to initialize buffer. Any attempt to use buffer   with
   17829             :            different object is dangerous - you may  get  memory  violation
   17830             :            error because sizes of internal arrays do not fit to dimensions
   17831             :            of the IDW structure.
   17832             :            
   17833             : IMPORTANT: you  should  call  this function only for model which was built
   17834             :            with model builder (or unserialized from file). Sizes  of  some
   17835             :            internal structures are determined only after model  is  built,
   17836             :            so buffer object created before model construction  stage  will
   17837             :            be useless (and any attempt to use it will result in exception).
   17838             : 
   17839             :   -- ALGLIB --
   17840             :      Copyright 22.10.2018 by Sergey Bochkanov
   17841             : *************************************************************************/
   17842           0 : void idwcreatecalcbuffer(idwmodel* s,
   17843             :      idwcalcbuffer* buf,
   17844             :      ae_state *_state)
   17845             : {
   17846             : 
   17847           0 :     _idwcalcbuffer_clear(buf);
   17848             : 
   17849           0 :     ae_assert(s->nx>=1, "IDWCreateCalcBuffer: integrity check failed", _state);
   17850           0 :     ae_assert(s->ny>=1, "IDWCreateCalcBuffer: integrity check failed", _state);
   17851           0 :     ae_assert(s->nlayers>=0, "IDWCreateCalcBuffer: integrity check failed", _state);
   17852           0 :     ae_assert(s->algotype>=0, "IDWCreateCalcBuffer: integrity check failed", _state);
   17853           0 :     if( s->nlayers>=1&&s->algotype!=0 )
   17854             :     {
   17855           0 :         kdtreecreaterequestbuffer(&s->tree, &buf->requestbuffer, _state);
   17856             :     }
   17857           0 :     rvectorsetlengthatleast(&buf->x, s->nx, _state);
   17858           0 :     rvectorsetlengthatleast(&buf->y, s->ny, _state);
   17859           0 :     rvectorsetlengthatleast(&buf->tsyw, s->ny*ae_maxint(s->nlayers, 1, _state), _state);
   17860           0 :     rvectorsetlengthatleast(&buf->tsw, ae_maxint(s->nlayers, 1, _state), _state);
   17861           0 : }
   17862             : 
   17863             : 
   17864             : /*************************************************************************
   17865             : This subroutine creates builder object used  to  generate IDW  model  from
   17866             : irregularly sampled (scattered) dataset.  Multidimensional  scalar/vector-
   17867             : -valued are supported.
   17868             : 
   17869             : Builder object is used to fit model to data as follows:
   17870             : * builder object is created with idwbuildercreate() function
   17871             : * dataset is added with idwbuildersetpoints() function
   17872             : * one of the modern IDW algorithms is chosen with either:
   17873             :   * idwbuildersetalgomstab()            - Multilayer STABilized algorithm (interpolation)
   17874             :   Alternatively, one of the textbook algorithms can be chosen (not recommended):
   17875             :   * idwbuildersetalgotextbookshepard()  - textbook Shepard algorithm
   17876             :   * idwbuildersetalgotextbookmodshepard()-textbook modified Shepard algorithm
   17877             : * finally, model construction is performed with idwfit() function.
   17878             : 
   17879             :   ! COMMERCIAL EDITION OF ALGLIB:
   17880             :   ! 
   17881             :   ! Commercial Edition of ALGLIB includes following important improvements
   17882             :   ! of this function:
   17883             :   ! * high-performance native backend with same C# interface (C# version)
   17884             :   ! * multithreading support (C++ and C# versions)
   17885             :   ! 
   17886             :   ! We recommend you to read 'Working with commercial version' section  of
   17887             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   17888             :   ! related features provided by commercial edition of ALGLIB.
   17889             : 
   17890             : INPUT PARAMETERS:
   17891             :     NX  -   dimensionality of the argument, NX>=1
   17892             :     NY  -   dimensionality of the function being modeled, NY>=1;
   17893             :             NY=1 corresponds to classic scalar function, NY>=1 corresponds
   17894             :             to vector-valued function.
   17895             :     
   17896             : OUTPUT PARAMETERS:
   17897             :     State-  builder object
   17898             : 
   17899             :   -- ALGLIB PROJECT --
   17900             :      Copyright 22.10.2018 by Bochkanov Sergey
   17901             : *************************************************************************/
   17902           0 : void idwbuildercreate(ae_int_t nx,
   17903             :      ae_int_t ny,
   17904             :      idwbuilder* state,
   17905             :      ae_state *_state)
   17906             : {
   17907             : 
   17908           0 :     _idwbuilder_clear(state);
   17909             : 
   17910           0 :     ae_assert(nx>=1, "IDWBuilderCreate: NX<=0", _state);
   17911           0 :     ae_assert(ny>=1, "IDWBuilderCreate: NY<=0", _state);
   17912             :     
   17913             :     /*
   17914             :      * We choose reasonable defaults for the algorithm:
   17915             :      * * MSTAB algorithm
   17916             :      * * 12 layers
   17917             :      * * default radius
   17918             :      * * default Lambda0
   17919             :      */
   17920           0 :     state->algotype = 2;
   17921           0 :     state->priortermtype = 2;
   17922           0 :     rvectorsetlengthatleast(&state->priortermval, ny, _state);
   17923           0 :     state->nlayers = idw_defaultnlayers;
   17924           0 :     state->r0 = (double)(0);
   17925           0 :     state->rdecay = 0.5;
   17926           0 :     state->lambda0 = idw_defaultlambda0;
   17927           0 :     state->lambdalast = (double)(0);
   17928           0 :     state->lambdadecay = 1.0;
   17929             :     
   17930             :     /*
   17931             :      * Other parameters, not used but initialized
   17932             :      */
   17933           0 :     state->shepardp = (double)(0);
   17934             :     
   17935             :     /*
   17936             :      * Initial dataset is empty
   17937             :      */
   17938           0 :     state->npoints = 0;
   17939           0 :     state->nx = nx;
   17940           0 :     state->ny = ny;
   17941           0 : }
   17942             : 
   17943             : 
   17944             : /*************************************************************************
   17945             : This function changes number of layers used by IDW-MSTAB algorithm.
   17946             : 
   17947             : The more layers you have, the finer details can  be  reproduced  with  IDW
   17948             : model. The less layers you have, the less memory and CPU time is  consumed
   17949             : by the model.
   17950             : 
   17951             : Memory consumption grows linearly with layers count,  running  time  grows
   17952             : sub-linearly.
   17953             : 
   17954             : The default number of layers is 16, which allows you to reproduce  details
   17955             : at distance down to SRad/65536. You will rarely need to change it.
   17956             : 
   17957             : INPUT PARAMETERS:
   17958             :     State   -   builder object
   17959             :     NLayers -   NLayers>=1, the number of layers used by the model.
   17960             : 
   17961             :   -- ALGLIB --
   17962             :      Copyright 22.10.2018 by Bochkanov Sergey
   17963             : *************************************************************************/
   17964           0 : void idwbuildersetnlayers(idwbuilder* state,
   17965             :      ae_int_t nlayers,
   17966             :      ae_state *_state)
   17967             : {
   17968             : 
   17969             : 
   17970           0 :     ae_assert(nlayers>=1, "IDWBuilderSetNLayers: N<1", _state);
   17971           0 :     state->nlayers = nlayers;
   17972           0 : }
   17973             : 
   17974             : 
   17975             : /*************************************************************************
   17976             : This function adds dataset to the builder object.
   17977             : 
   17978             : This function overrides results of the previous calls, i.e. multiple calls
   17979             : of this function will result in only the last set being added.
   17980             : 
   17981             : INPUT PARAMETERS:
   17982             :     State   -   builder object
   17983             :     XY      -   points, array[N,NX+NY]. One row  corresponds to  one point
   17984             :                 in the dataset. First NX elements  are  coordinates,  next
   17985             :                 NY elements are function values. Array may  be larger than 
   17986             :                 specified, in  this  case  only leading [N,NX+NY] elements 
   17987             :                 will be used.
   17988             :     N       -   number of points in the dataset, N>=0.
   17989             : 
   17990             :   -- ALGLIB --
   17991             :      Copyright 22.10.2018 by Bochkanov Sergey
   17992             : *************************************************************************/
   17993           0 : void idwbuildersetpoints(idwbuilder* state,
   17994             :      /* Real    */ ae_matrix* xy,
   17995             :      ae_int_t n,
   17996             :      ae_state *_state)
   17997             : {
   17998             :     ae_int_t i;
   17999             :     ae_int_t j;
   18000             :     ae_int_t ew;
   18001             : 
   18002             : 
   18003           0 :     ae_assert(n>=0, "IDWBuilderSetPoints: N<0", _state);
   18004           0 :     ae_assert(xy->rows>=n, "IDWBuilderSetPoints: Rows(XY)<N", _state);
   18005           0 :     ae_assert(n==0||xy->cols>=state->nx+state->ny, "IDWBuilderSetPoints: Cols(XY)<NX+NY", _state);
   18006           0 :     ae_assert(apservisfinitematrix(xy, n, state->nx+state->ny, _state), "IDWBuilderSetPoints: XY contains infinite or NaN values!", _state);
   18007           0 :     state->npoints = n;
   18008           0 :     ew = state->nx+state->ny;
   18009           0 :     rvectorsetlengthatleast(&state->xy, n*ew, _state);
   18010           0 :     for(i=0; i<=n-1; i++)
   18011             :     {
   18012           0 :         for(j=0; j<=ew-1; j++)
   18013             :         {
   18014           0 :             state->xy.ptr.p_double[i*ew+j] = xy->ptr.pp_double[i][j];
   18015             :         }
   18016             :     }
   18017           0 : }
   18018             : 
   18019             : 
   18020             : /*************************************************************************
   18021             : This function sets IDW model  construction  algorithm  to  the  Multilayer
   18022             : Stabilized IDW method (IDW-MSTAB), a  latest  incarnation  of  the inverse
   18023             : distance weighting interpolation which fixes shortcomings of  the original
   18024             : and modified Shepard's variants.
   18025             : 
   18026             : The distinctive features of IDW-MSTAB are:
   18027             : 1) exact interpolation  is  pursued  (as  opposed  to  fitting  and  noise
   18028             :    suppression)
   18029             : 2) improved robustness when compared with that of other algorithms:
   18030             :    * MSTAB shows almost no strange  fitting  artifacts  like  ripples  and
   18031             :      sharp spikes (unlike N-dimensional splines and HRBFs)
   18032             :    * MSTAB does not return function values far from the  interval  spanned
   18033             :      by the dataset; say, if all your points have |f|<=1, you  can be sure
   18034             :      that model value won't deviate too much from [-1,+1]
   18035             : 3) good model construction time competing with that of HRBFs  and  bicubic
   18036             :    splines
   18037             : 4) ability to work with any number of dimensions, starting from NX=1
   18038             : 
   18039             : The drawbacks of IDW-MSTAB (and all IDW algorithms in general) are:
   18040             : 1) dependence of the model evaluation time on the search radius
   18041             : 2) bad extrapolation properties, models built by this method  are  usually
   18042             :    conservative in their predictions
   18043             : 
   18044             : Thus, IDW-MSTAB is  a  good  "default"  option  if  you  want  to  perform
   18045             : scattered multidimensional interpolation. Although it has  its  drawbacks,
   18046             : it is easy to use and robust, which makes it a good first step.
   18047             : 
   18048             : 
   18049             : INPUT PARAMETERS:
   18050             :     State   -   builder object
   18051             :     SRad    -   initial search radius, SRad>0 is required. A model  value
   18052             :                 is obtained by "smart" averaging  of  the  dataset  points
   18053             :                 within search radius.
   18054             : 
   18055             : NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
   18056             :         datasets with non-distinct points. In case non-distinct points are
   18057             :         found, an average value for this point will be calculated.
   18058             :         
   18059             : NOTE 2: the memory requirements for model storage are O(NPoints*NLayers).
   18060             :         The model construction needs twice as much memory as model storage.
   18061             :   
   18062             : NOTE 3: by default 16 IDW layers are built which is enough for most cases.
   18063             :         You can change this parameter with idwbuildersetnlayers()  method.
   18064             :         Larger values may be necessary if you need to reproduce  extrafine
   18065             :         details at distances smaller than SRad/65536.  Smaller value   may
   18066             :         be necessary if you have to save memory and  computing  time,  and
   18067             :         ready to sacrifice some model quality.
   18068             : 
   18069             : 
   18070             : ALGORITHM DESCRIPTION
   18071             :   
   18072             : ALGLIB implementation of IDW is somewhat similar to the modified Shepard's
   18073             : method (one with search radius R) but overcomes several of its  drawbacks,
   18074             : namely:
   18075             : 1) a tendency to show stepwise behavior for uniform datasets
   18076             : 2) a tendency to show terrible interpolation properties for highly
   18077             :    nonuniform datasets which often arise in geospatial tasks
   18078             :   (function values are densely sampled across multiple separated
   18079             :   "tracks")
   18080             : 
   18081             : IDW-MSTAB method performs several passes over dataset and builds a sequence
   18082             : of progressively refined IDW models  (layers),  which starts from one with
   18083             : largest search radius SRad  and continues to smaller  search  radii  until
   18084             : required number of  layers  is  built.  Highest  layers  reproduce  global
   18085             : behavior of the target function at larger distances  whilst  lower  layers
   18086             : reproduce fine details at smaller distances.
   18087             : 
   18088             : Each layer is an IDW model built with following modifications:
   18089             : * weights go to zero when distance approach to the current search radius
   18090             : * an additional regularizing term is added to the distance: w=1/(d^2+lambda)
   18091             : * an additional fictional term with unit weight and zero function value is
   18092             :   added in order to promote continuity  properties  at  the  isolated  and
   18093             :   boundary points
   18094             :   
   18095             : By default, 16 layers is built, which is enough for most  cases.  You  can
   18096             : change this parameter with idwbuildersetnlayers() method.
   18097             :    
   18098             :   -- ALGLIB --
   18099             :      Copyright 22.10.2018 by Bochkanov Sergey
   18100             : *************************************************************************/
   18101           0 : void idwbuildersetalgomstab(idwbuilder* state,
   18102             :      double srad,
   18103             :      ae_state *_state)
   18104             : {
   18105             : 
   18106             : 
   18107           0 :     ae_assert(ae_isfinite(srad, _state), "IDWBuilderSetAlgoMSTAB: SRad is not finite", _state);
   18108           0 :     ae_assert(ae_fp_greater(srad,(double)(0)), "IDWBuilderSetAlgoMSTAB: SRad<=0", _state);
   18109             :     
   18110             :     /*
   18111             :      * Set algorithm
   18112             :      */
   18113           0 :     state->algotype = 2;
   18114             :     
   18115             :     /*
   18116             :      * Set options
   18117             :      */
   18118           0 :     state->r0 = srad;
   18119           0 :     state->rdecay = 0.5;
   18120           0 :     state->lambda0 = idw_defaultlambda0;
   18121           0 :     state->lambdalast = (double)(0);
   18122           0 :     state->lambdadecay = 1.0;
   18123           0 : }
   18124             : 
   18125             : 
   18126             : /*************************************************************************
   18127             : This function sets  IDW  model  construction  algorithm  to  the  textbook
   18128             : Shepard's algorithm with custom (user-specified) power parameter.
   18129             : 
   18130             : IMPORTANT: we do NOT recommend using textbook IDW algorithms because  they
   18131             :            have terrible interpolation properties. Use MSTAB in all cases.
   18132             : 
   18133             : INPUT PARAMETERS:
   18134             :     State   -   builder object
   18135             :     P       -   power parameter, P>0; good value to start with is 2.0
   18136             : 
   18137             : NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
   18138             :         datasets with non-distinct points. In case non-distinct points are
   18139             :         found, an average value for this point will be calculated.
   18140             :    
   18141             :   -- ALGLIB --
   18142             :      Copyright 22.10.2018 by Bochkanov Sergey
   18143             : *************************************************************************/
   18144           0 : void idwbuildersetalgotextbookshepard(idwbuilder* state,
   18145             :      double p,
   18146             :      ae_state *_state)
   18147             : {
   18148             : 
   18149             : 
   18150           0 :     ae_assert(ae_isfinite(p, _state), "IDWBuilderSetAlgoShepard: P is not finite", _state);
   18151           0 :     ae_assert(ae_fp_greater(p,(double)(0)), "IDWBuilderSetAlgoShepard: P<=0", _state);
   18152             :     
   18153             :     /*
   18154             :      * Set algorithm and options
   18155             :      */
   18156           0 :     state->algotype = 0;
   18157           0 :     state->shepardp = p;
   18158           0 : }
   18159             : 
   18160             : 
   18161             : /*************************************************************************
   18162             : This function sets  IDW  model  construction  algorithm  to the 'textbook'
   18163             : modified Shepard's algorithm with user-specified search radius.
   18164             : 
   18165             : IMPORTANT: we do NOT recommend using textbook IDW algorithms because  they
   18166             :            have terrible interpolation properties. Use MSTAB in all cases.
   18167             : 
   18168             : INPUT PARAMETERS:
   18169             :     State   -   builder object
   18170             :     R       -   search radius
   18171             : 
   18172             : NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
   18173             :         datasets with non-distinct points. In case non-distinct points are
   18174             :         found, an average value for this point will be calculated.
   18175             :    
   18176             :   -- ALGLIB --
   18177             :      Copyright 22.10.2018 by Bochkanov Sergey
   18178             : *************************************************************************/
   18179           0 : void idwbuildersetalgotextbookmodshepard(idwbuilder* state,
   18180             :      double r,
   18181             :      ae_state *_state)
   18182             : {
   18183             : 
   18184             : 
   18185           0 :     ae_assert(ae_isfinite(r, _state), "IDWBuilderSetAlgoModShepard: R is not finite", _state);
   18186           0 :     ae_assert(ae_fp_greater(r,(double)(0)), "IDWBuilderSetAlgoModShepard: R<=0", _state);
   18187             :     
   18188             :     /*
   18189             :      * Set algorithm and options
   18190             :      */
   18191           0 :     state->algotype = 1;
   18192           0 :     state->r0 = r;
   18193           0 : }
   18194             : 
   18195             : 
   18196             : /*************************************************************************
   18197             : This function sets prior term (model value at infinity) as  user-specified
   18198             : value.
   18199             : 
   18200             : INPUT PARAMETERS:
   18201             :     S       -   spline builder
   18202             :     V       -   value for user-defined prior
   18203             :     
   18204             : NOTE: for vector-valued models all components of the prior are set to same
   18205             :       user-specified value
   18206             : 
   18207             :   -- ALGLIB --
   18208             :      Copyright 29.10.2018 by Bochkanov Sergey
   18209             : *************************************************************************/
   18210           0 : void idwbuildersetuserterm(idwbuilder* state, double v, ae_state *_state)
   18211             : {
   18212             :     ae_int_t j;
   18213             : 
   18214             : 
   18215           0 :     ae_assert(ae_isfinite(v, _state), "IDWBuilderSetUserTerm: infinite/NAN value passed", _state);
   18216           0 :     state->priortermtype = 0;
   18217           0 :     for(j=0; j<=state->ny-1; j++)
   18218             :     {
   18219           0 :         state->priortermval.ptr.p_double[j] = v;
   18220             :     }
   18221           0 : }
   18222             : 
   18223             : 
   18224             : /*************************************************************************
   18225             : This function sets constant prior term (model value at infinity).
   18226             : 
   18227             : Constant prior term is determined as mean value over dataset.
   18228             : 
   18229             : INPUT PARAMETERS:
   18230             :     S       -   spline builder
   18231             : 
   18232             :   -- ALGLIB --
   18233             :      Copyright 29.10.2018 by Bochkanov Sergey
   18234             : *************************************************************************/
   18235           0 : void idwbuildersetconstterm(idwbuilder* state, ae_state *_state)
   18236             : {
   18237             : 
   18238             : 
   18239           0 :     state->priortermtype = 2;
   18240           0 : }
   18241             : 
   18242             : 
   18243             : /*************************************************************************
   18244             : This function sets zero prior term (model value at infinity).
   18245             : 
   18246             : INPUT PARAMETERS:
   18247             :     S       -   spline builder
   18248             : 
   18249             :   -- ALGLIB --
   18250             :      Copyright 29.10.2018 by Bochkanov Sergey
   18251             : *************************************************************************/
   18252           0 : void idwbuildersetzeroterm(idwbuilder* state, ae_state *_state)
   18253             : {
   18254             : 
   18255             : 
   18256           0 :     state->priortermtype = 3;
   18257           0 : }
   18258             : 
   18259             : 
   18260             : /*************************************************************************
   18261             : IDW interpolation: scalar target, 1-dimensional argument
   18262             : 
   18263             : NOTE: this function modifies internal temporaries of the  IDW  model, thus
   18264             :       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
   18265             :       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
   18266             :       thread buffer object. 
   18267             :       
   18268             : INPUT PARAMETERS:
   18269             :     S   -   IDW interpolant built with IDW builder
   18270             :     X0  -   argument value
   18271             : 
   18272             : Result:
   18273             :     IDW interpolant S(X0)
   18274             : 
   18275             :   -- ALGLIB --
   18276             :      Copyright 22.10.2018 by Bochkanov Sergey
   18277             : *************************************************************************/
   18278           0 : double idwcalc1(idwmodel* s, double x0, ae_state *_state)
   18279             : {
   18280             :     double result;
   18281             : 
   18282             : 
   18283           0 :     ae_assert(s->nx==1, "IDWCalc1: S.NX<>1", _state);
   18284           0 :     ae_assert(s->ny==1, "IDWCalc1: S.NY<>1", _state);
   18285           0 :     ae_assert(ae_isfinite(x0, _state), "IDWCalc1: X0 is INF or NAN", _state);
   18286           0 :     s->buffer.x.ptr.p_double[0] = x0;
   18287           0 :     idwtscalcbuf(s, &s->buffer, &s->buffer.x, &s->buffer.y, _state);
   18288           0 :     result = s->buffer.y.ptr.p_double[0];
   18289           0 :     return result;
   18290             : }
   18291             : 
   18292             : 
   18293             : /*************************************************************************
   18294             : IDW interpolation: scalar target, 2-dimensional argument
   18295             : 
   18296             : NOTE: this function modifies internal temporaries of the  IDW  model, thus
   18297             :       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
   18298             :       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
   18299             :       thread buffer object. 
   18300             :       
   18301             : INPUT PARAMETERS:
   18302             :     S       -   IDW interpolant built with IDW builder
   18303             :     X0, X1  -   argument value
   18304             : 
   18305             : Result:
   18306             :     IDW interpolant S(X0,X1)
   18307             : 
   18308             :   -- ALGLIB --
   18309             :      Copyright 22.10.2018 by Bochkanov Sergey
   18310             : *************************************************************************/
   18311           0 : double idwcalc2(idwmodel* s, double x0, double x1, ae_state *_state)
   18312             : {
   18313             :     double result;
   18314             : 
   18315             : 
   18316           0 :     ae_assert(s->nx==2, "IDWCalc2: S.NX<>2", _state);
   18317           0 :     ae_assert(s->ny==1, "IDWCalc2: S.NY<>1", _state);
   18318           0 :     ae_assert(ae_isfinite(x0, _state), "IDWCalc2: X0 is INF or NAN", _state);
   18319           0 :     ae_assert(ae_isfinite(x1, _state), "IDWCalc2: X1 is INF or NAN", _state);
   18320           0 :     s->buffer.x.ptr.p_double[0] = x0;
   18321           0 :     s->buffer.x.ptr.p_double[1] = x1;
   18322           0 :     idwtscalcbuf(s, &s->buffer, &s->buffer.x, &s->buffer.y, _state);
   18323           0 :     result = s->buffer.y.ptr.p_double[0];
   18324           0 :     return result;
   18325             : }
   18326             : 
   18327             : 
   18328             : /*************************************************************************
   18329             : IDW interpolation: scalar target, 3-dimensional argument
   18330             : 
   18331             : NOTE: this function modifies internal temporaries of the  IDW  model, thus
   18332             :       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
   18333             :       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
   18334             :       thread buffer object. 
   18335             : 
   18336             : INPUT PARAMETERS:
   18337             :     S       -   IDW interpolant built with IDW builder
   18338             :     X0,X1,X2-   argument value
   18339             : 
   18340             : Result:
   18341             :     IDW interpolant S(X0,X1,X2)
   18342             : 
   18343             :   -- ALGLIB --
   18344             :      Copyright 22.10.2018 by Bochkanov Sergey
   18345             : *************************************************************************/
   18346           0 : double idwcalc3(idwmodel* s,
   18347             :      double x0,
   18348             :      double x1,
   18349             :      double x2,
   18350             :      ae_state *_state)
   18351             : {
   18352             :     double result;
   18353             : 
   18354             : 
   18355           0 :     ae_assert(s->nx==3, "IDWCalc3: S.NX<>3", _state);
   18356           0 :     ae_assert(s->ny==1, "IDWCalc3: S.NY<>1", _state);
   18357           0 :     ae_assert(ae_isfinite(x0, _state), "IDWCalc3: X0 is INF or NAN", _state);
   18358           0 :     ae_assert(ae_isfinite(x1, _state), "IDWCalc3: X1 is INF or NAN", _state);
   18359           0 :     ae_assert(ae_isfinite(x2, _state), "IDWCalc3: X2 is INF or NAN", _state);
   18360           0 :     s->buffer.x.ptr.p_double[0] = x0;
   18361           0 :     s->buffer.x.ptr.p_double[1] = x1;
   18362           0 :     s->buffer.x.ptr.p_double[2] = x2;
   18363           0 :     idwtscalcbuf(s, &s->buffer, &s->buffer.x, &s->buffer.y, _state);
   18364           0 :     result = s->buffer.y.ptr.p_double[0];
   18365           0 :     return result;
   18366             : }
   18367             : 
   18368             : 
   18369             : /*************************************************************************
   18370             : This function calculates values of the IDW model at the given point.
   18371             : 
   18372             : This is general function which can be used for arbitrary NX (dimension  of 
   18373             : the space of arguments) and NY (dimension of the function itself). However
   18374             : when  you  have  NY=1  you  may  find more convenient to  use  idwcalc1(),
   18375             : idwcalc2() or idwcalc3().
   18376             : 
   18377             : NOTE: this function modifies internal temporaries of the  IDW  model, thus
   18378             :       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
   18379             :       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
   18380             :       thread buffer object. 
   18381             :       
   18382             : INPUT PARAMETERS:
   18383             :     S       -   IDW model
   18384             :     X       -   coordinates, array[NX]. X may have more than NX  elements,
   18385             :                 in this case only leading NX will be used.
   18386             : 
   18387             : OUTPUT PARAMETERS:
   18388             :     Y       -   function value, array[NY]. Y is out-parameter and will  be
   18389             :                 reallocated after call to this function. In case you  want
   18390             :                 to reuse previously allocated Y, you may use idwcalcbuf(),
   18391             :                 which reallocates Y only when it is too small.
   18392             : 
   18393             :   -- ALGLIB --
   18394             :      Copyright 22.10.2018 by Bochkanov Sergey
   18395             : *************************************************************************/
   18396           0 : void idwcalc(idwmodel* s,
   18397             :      /* Real    */ ae_vector* x,
   18398             :      /* Real    */ ae_vector* y,
   18399             :      ae_state *_state)
   18400             : {
   18401             : 
   18402           0 :     ae_vector_clear(y);
   18403             : 
   18404           0 :     idwtscalcbuf(s, &s->buffer, x, y, _state);
   18405           0 : }
   18406             : 
   18407             : 
   18408             : /*************************************************************************
   18409             : This function calculates values of the IDW model at the given point.
   18410             : 
   18411             : Same as idwcalc(), but does not reallocate Y when in is large enough to 
   18412             : store function values.
   18413             : 
   18414             : NOTE: this function modifies internal temporaries of the  IDW  model, thus
   18415             :       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
   18416             :       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
   18417             :       thread buffer object. 
   18418             :       
   18419             : INPUT PARAMETERS:
   18420             :     S       -   IDW model
   18421             :     X       -   coordinates, array[NX]. X may have more than NX  elements,
   18422             :                 in this case only leading NX will be used.
   18423             :     Y       -   possibly preallocated array
   18424             : 
   18425             : OUTPUT PARAMETERS:
   18426             :     Y       -   function value, array[NY]. Y is not reallocated when it
   18427             :                 is larger than NY.
   18428             : 
   18429             :   -- ALGLIB --
   18430             :      Copyright 22.10.2018 by Bochkanov Sergey
   18431             : *************************************************************************/
   18432           0 : void idwcalcbuf(idwmodel* s,
   18433             :      /* Real    */ ae_vector* x,
   18434             :      /* Real    */ ae_vector* y,
   18435             :      ae_state *_state)
   18436             : {
   18437             : 
   18438             : 
   18439           0 :     idwtscalcbuf(s, &s->buffer, x, y, _state);
   18440           0 : }
   18441             : 
   18442             : 
   18443             : /*************************************************************************
   18444             : This function calculates values of the IDW model at the given point, using
   18445             : external  buffer  object  (internal  temporaries  of  IDW  model  are  not
   18446             : modified).
   18447             : 
   18448             : This function allows to use same IDW model object  in  different  threads,
   18449             : assuming  that  different   threads  use different instances of the buffer
   18450             : structure.
   18451             : 
   18452             : INPUT PARAMETERS:
   18453             :     S       -   IDW model, may be shared between different threads
   18454             :     Buf     -   buffer object created for this particular instance of  IDW
   18455             :                 model with idwcreatecalcbuffer().
   18456             :     X       -   coordinates, array[NX]. X may have more than NX  elements,
   18457             :                 in this case only  leading NX will be used.
   18458             :     Y       -   possibly preallocated array
   18459             : 
   18460             : OUTPUT PARAMETERS:
   18461             :     Y       -   function value, array[NY]. Y is not reallocated when it
   18462             :                 is larger than NY.
   18463             : 
   18464             :   -- ALGLIB --
   18465             :      Copyright 13.12.2011 by Bochkanov Sergey
   18466             : *************************************************************************/
   18467           0 : void idwtscalcbuf(idwmodel* s,
   18468             :      idwcalcbuffer* buf,
   18469             :      /* Real    */ ae_vector* x,
   18470             :      /* Real    */ ae_vector* y,
   18471             :      ae_state *_state)
   18472             : {
   18473             :     ae_int_t i;
   18474             :     ae_int_t j;
   18475             :     ae_int_t ew;
   18476             :     ae_int_t k;
   18477             :     ae_int_t layeridx;
   18478             :     ae_int_t nx;
   18479             :     ae_int_t ny;
   18480             :     ae_int_t npoints;
   18481             :     double v;
   18482             :     double vv;
   18483             :     double f;
   18484             :     double p;
   18485             :     double r;
   18486             :     double eps;
   18487             :     double lambdacur;
   18488             :     double lambdadecay;
   18489             :     double invrdecay;
   18490             :     double invr;
   18491             :     ae_bool fastcalcpossible;
   18492             :     double wf0;
   18493             :     double ws0;
   18494             :     double wf1;
   18495             :     double ws1;
   18496             : 
   18497             : 
   18498           0 :     nx = s->nx;
   18499           0 :     ny = s->ny;
   18500           0 :     ae_assert(x->cnt>=nx, "IDWTsCalcBuf: Length(X)<NX", _state);
   18501           0 :     ae_assert(isfinitevector(x, nx, _state), "IDWTsCalcBuf: X contains infinite or NaN values", _state);
   18502             :     
   18503             :     /*
   18504             :      * Avoid spurious compiler warnings
   18505             :      */
   18506           0 :     wf0 = (double)(0);
   18507           0 :     ws0 = (double)(0);
   18508           0 :     wf1 = (double)(0);
   18509           0 :     ws1 = (double)(0);
   18510             :     
   18511             :     /*
   18512             :      * Allocate output
   18513             :      */
   18514           0 :     if( y->cnt<ny )
   18515             :     {
   18516           0 :         ae_vector_set_length(y, ny, _state);
   18517             :     }
   18518             :     
   18519             :     /*
   18520             :      * Quick exit for NLayers=0 (no dataset)
   18521             :      */
   18522           0 :     if( s->nlayers==0 )
   18523             :     {
   18524           0 :         for(j=0; j<=ny-1; j++)
   18525             :         {
   18526           0 :             y->ptr.p_double[j] = s->globalprior.ptr.p_double[j];
   18527             :         }
   18528           0 :         return;
   18529             :     }
   18530             :     
   18531             :     /*
   18532             :      * Textbook Shepard's method
   18533             :      */
   18534           0 :     if( s->algotype==0 )
   18535             :     {
   18536           0 :         npoints = s->npoints;
   18537           0 :         ae_assert(npoints>0, "IDWTsCalcBuf: integrity check failed", _state);
   18538           0 :         eps = 1.0E-50;
   18539           0 :         ew = nx+ny;
   18540           0 :         p = s->shepardp;
   18541           0 :         for(j=0; j<=ny-1; j++)
   18542             :         {
   18543           0 :             y->ptr.p_double[j] = (double)(0);
   18544           0 :             buf->tsyw.ptr.p_double[j] = eps;
   18545             :         }
   18546           0 :         for(i=0; i<=npoints-1; i++)
   18547             :         {
   18548             :             
   18549             :             /*
   18550             :              * Compute squared distance
   18551             :              */
   18552           0 :             v = (double)(0);
   18553           0 :             for(j=0; j<=nx-1; j++)
   18554             :             {
   18555           0 :                 vv = s->shepardxy.ptr.p_double[i*ew+j]-x->ptr.p_double[j];
   18556           0 :                 v = v+vv*vv;
   18557             :             }
   18558             :             
   18559             :             /*
   18560             :              * Compute weight (with small regularizing addition)
   18561             :              */
   18562           0 :             v = ae_pow(v, p*0.5, _state);
   18563           0 :             v = 1/(eps+v);
   18564             :             
   18565             :             /*
   18566             :              * Accumulate
   18567             :              */
   18568           0 :             for(j=0; j<=ny-1; j++)
   18569             :             {
   18570           0 :                 y->ptr.p_double[j] = y->ptr.p_double[j]+v*s->shepardxy.ptr.p_double[i*ew+nx+j];
   18571           0 :                 buf->tsyw.ptr.p_double[j] = buf->tsyw.ptr.p_double[j]+v;
   18572             :             }
   18573             :         }
   18574           0 :         for(j=0; j<=ny-1; j++)
   18575             :         {
   18576           0 :             y->ptr.p_double[j] = y->ptr.p_double[j]/buf->tsyw.ptr.p_double[j]+s->globalprior.ptr.p_double[j];
   18577             :         }
   18578           0 :         return;
   18579             :     }
   18580             :     
   18581             :     /*
   18582             :      * Textbook modified Shepard's method
   18583             :      */
   18584           0 :     if( s->algotype==1 )
   18585             :     {
   18586           0 :         eps = 1.0E-50;
   18587           0 :         r = s->r0;
   18588           0 :         for(j=0; j<=ny-1; j++)
   18589             :         {
   18590           0 :             y->ptr.p_double[j] = (double)(0);
   18591           0 :             buf->tsyw.ptr.p_double[j] = eps;
   18592             :         }
   18593           0 :         k = kdtreetsqueryrnn(&s->tree, &buf->requestbuffer, x, r, ae_true, _state);
   18594           0 :         kdtreetsqueryresultsxy(&s->tree, &buf->requestbuffer, &buf->tsxy, _state);
   18595           0 :         kdtreetsqueryresultsdistances(&s->tree, &buf->requestbuffer, &buf->tsdist, _state);
   18596           0 :         for(i=0; i<=k-1; i++)
   18597             :         {
   18598           0 :             v = buf->tsdist.ptr.p_double[i];
   18599           0 :             v = (r-v)/(r*v+eps);
   18600           0 :             v = v*v;
   18601           0 :             for(j=0; j<=ny-1; j++)
   18602             :             {
   18603           0 :                 y->ptr.p_double[j] = y->ptr.p_double[j]+v*buf->tsxy.ptr.pp_double[i][nx+j];
   18604           0 :                 buf->tsyw.ptr.p_double[j] = buf->tsyw.ptr.p_double[j]+v;
   18605             :             }
   18606             :         }
   18607           0 :         for(j=0; j<=ny-1; j++)
   18608             :         {
   18609           0 :             y->ptr.p_double[j] = y->ptr.p_double[j]/buf->tsyw.ptr.p_double[j]+s->globalprior.ptr.p_double[j];
   18610             :         }
   18611           0 :         return;
   18612             :     }
   18613             :     
   18614             :     /*
   18615             :      * MSTAB
   18616             :      */
   18617           0 :     if( s->algotype==2 )
   18618             :     {
   18619           0 :         ae_assert(ae_fp_eq(idw_w0,(double)(1)), "IDWTsCalcBuf: unexpected W0, integrity check failed", _state);
   18620           0 :         invrdecay = 1/s->rdecay;
   18621           0 :         invr = 1/s->r0;
   18622           0 :         lambdadecay = s->lambdadecay;
   18623           0 :         fastcalcpossible = (ny==1&&s->nlayers>=3)&&ae_fp_eq(lambdadecay,(double)(1));
   18624           0 :         if( fastcalcpossible )
   18625             :         {
   18626             :             
   18627             :             /*
   18628             :              * Important special case, NY=1, no lambda-decay,
   18629             :              * we can perform optimized fast evaluation
   18630             :              */
   18631           0 :             wf0 = (double)(0);
   18632           0 :             ws0 = idw_w0;
   18633           0 :             wf1 = (double)(0);
   18634           0 :             ws1 = idw_w0;
   18635           0 :             for(j=0; j<=s->nlayers-1; j++)
   18636             :             {
   18637           0 :                 buf->tsyw.ptr.p_double[j] = (double)(0);
   18638           0 :                 buf->tsw.ptr.p_double[j] = idw_w0;
   18639             :             }
   18640             :         }
   18641             :         else
   18642             :         {
   18643             :             
   18644             :             /*
   18645             :              * Setup variables for generic evaluation path
   18646             :              */
   18647           0 :             for(j=0; j<=ny*s->nlayers-1; j++)
   18648             :             {
   18649           0 :                 buf->tsyw.ptr.p_double[j] = (double)(0);
   18650             :             }
   18651           0 :             for(j=0; j<=s->nlayers-1; j++)
   18652             :             {
   18653           0 :                 buf->tsw.ptr.p_double[j] = idw_w0;
   18654             :             }
   18655             :         }
   18656           0 :         k = kdtreetsqueryrnnu(&s->tree, &buf->requestbuffer, x, s->r0, ae_true, _state);
   18657           0 :         kdtreetsqueryresultsxy(&s->tree, &buf->requestbuffer, &buf->tsxy, _state);
   18658           0 :         kdtreetsqueryresultsdistances(&s->tree, &buf->requestbuffer, &buf->tsdist, _state);
   18659           0 :         for(i=0; i<=k-1; i++)
   18660             :         {
   18661           0 :             lambdacur = s->lambda0;
   18662           0 :             vv = buf->tsdist.ptr.p_double[i]*invr;
   18663           0 :             if( fastcalcpossible )
   18664             :             {
   18665             :                 
   18666             :                 /*
   18667             :                  * Important special case, fast evaluation possible
   18668             :                  */
   18669           0 :                 v = vv*vv;
   18670           0 :                 v = (1-v)*(1-v)/(v+lambdacur);
   18671           0 :                 f = buf->tsxy.ptr.pp_double[i][nx+0];
   18672           0 :                 wf0 = wf0+v*f;
   18673           0 :                 ws0 = ws0+v;
   18674           0 :                 vv = vv*invrdecay;
   18675           0 :                 if( vv>=1.0 )
   18676             :                 {
   18677           0 :                     continue;
   18678             :                 }
   18679           0 :                 v = vv*vv;
   18680           0 :                 v = (1-v)*(1-v)/(v+lambdacur);
   18681           0 :                 f = buf->tsxy.ptr.pp_double[i][nx+1];
   18682           0 :                 wf1 = wf1+v*f;
   18683           0 :                 ws1 = ws1+v;
   18684           0 :                 vv = vv*invrdecay;
   18685           0 :                 if( vv>=1.0 )
   18686             :                 {
   18687           0 :                     continue;
   18688             :                 }
   18689           0 :                 for(layeridx=2; layeridx<=s->nlayers-1; layeridx++)
   18690             :                 {
   18691           0 :                     if( layeridx==s->nlayers-1 )
   18692             :                     {
   18693           0 :                         lambdacur = s->lambdalast;
   18694             :                     }
   18695           0 :                     v = vv*vv;
   18696           0 :                     v = (1-v)*(1-v)/(v+lambdacur);
   18697           0 :                     f = buf->tsxy.ptr.pp_double[i][nx+layeridx];
   18698           0 :                     buf->tsyw.ptr.p_double[layeridx] = buf->tsyw.ptr.p_double[layeridx]+v*f;
   18699           0 :                     buf->tsw.ptr.p_double[layeridx] = buf->tsw.ptr.p_double[layeridx]+v;
   18700           0 :                     vv = vv*invrdecay;
   18701           0 :                     if( vv>=1.0 )
   18702             :                     {
   18703           0 :                         break;
   18704             :                     }
   18705             :                 }
   18706             :             }
   18707             :             else
   18708             :             {
   18709             :                 
   18710             :                 /*
   18711             :                  * General case
   18712             :                  */
   18713           0 :                 for(layeridx=0; layeridx<=s->nlayers-1; layeridx++)
   18714             :                 {
   18715           0 :                     if( layeridx==s->nlayers-1 )
   18716             :                     {
   18717           0 :                         lambdacur = s->lambdalast;
   18718             :                     }
   18719           0 :                     if( vv>=1.0 )
   18720             :                     {
   18721           0 :                         break;
   18722             :                     }
   18723           0 :                     v = vv*vv;
   18724           0 :                     v = (1-v)*(1-v)/(v+lambdacur);
   18725           0 :                     for(j=0; j<=ny-1; j++)
   18726             :                     {
   18727           0 :                         f = buf->tsxy.ptr.pp_double[i][nx+layeridx*ny+j];
   18728           0 :                         buf->tsyw.ptr.p_double[layeridx*ny+j] = buf->tsyw.ptr.p_double[layeridx*ny+j]+v*f;
   18729             :                     }
   18730           0 :                     buf->tsw.ptr.p_double[layeridx] = buf->tsw.ptr.p_double[layeridx]+v;
   18731           0 :                     lambdacur = lambdacur*lambdadecay;
   18732           0 :                     vv = vv*invrdecay;
   18733             :                 }
   18734             :             }
   18735             :         }
   18736           0 :         if( fastcalcpossible )
   18737             :         {
   18738             :             
   18739             :             /*
   18740             :              * Important special case, finalize evaluations
   18741             :              */
   18742           0 :             buf->tsyw.ptr.p_double[0] = wf0;
   18743           0 :             buf->tsw.ptr.p_double[0] = ws0;
   18744           0 :             buf->tsyw.ptr.p_double[1] = wf1;
   18745           0 :             buf->tsw.ptr.p_double[1] = ws1;
   18746             :         }
   18747           0 :         for(j=0; j<=ny-1; j++)
   18748             :         {
   18749           0 :             y->ptr.p_double[j] = s->globalprior.ptr.p_double[j];
   18750             :         }
   18751           0 :         for(layeridx=0; layeridx<=s->nlayers-1; layeridx++)
   18752             :         {
   18753           0 :             for(j=0; j<=ny-1; j++)
   18754             :             {
   18755           0 :                 y->ptr.p_double[j] = y->ptr.p_double[j]+buf->tsyw.ptr.p_double[layeridx*ny+j]/buf->tsw.ptr.p_double[layeridx];
   18756             :             }
   18757             :         }
   18758           0 :         return;
   18759             :     }
   18760             :     
   18761             :     /*
   18762             :      *
   18763             :      */
   18764           0 :     ae_assert(ae_false, "IDWTsCalcBuf: unexpected AlgoType", _state);
   18765             : }
   18766             : 
   18767             : 
   18768             : /*************************************************************************
   18769             : This function fits IDW model to the dataset using current IDW construction
   18770             : algorithm. A model being built and fitting report are returned.
   18771             : 
   18772             : INPUT PARAMETERS:
   18773             :     State   -   builder object
   18774             : 
   18775             : OUTPUT PARAMETERS:
   18776             :     Model   -   an IDW model built with current algorithm
   18777             :     Rep     -   model fitting report, fields of this structure contain
   18778             :                 information about average fitting errors.
   18779             :                 
   18780             : NOTE: although IDW-MSTAB algorithm is an  interpolation  method,  i.e.  it
   18781             :       tries to fit the model exactly, it can  handle  datasets  with  non-
   18782             :       distinct points which can not be fit exactly; in such  cases  least-
   18783             :       squares fitting is performed.
   18784             :    
   18785             :   -- ALGLIB --
   18786             :      Copyright 22.10.2018 by Bochkanov Sergey
   18787             : *************************************************************************/
   18788           0 : void idwfit(idwbuilder* state,
   18789             :      idwmodel* model,
   18790             :      idwreport* rep,
   18791             :      ae_state *_state)
   18792             : {
   18793             :     ae_int_t i;
   18794             :     ae_int_t i0;
   18795             :     ae_int_t j;
   18796             :     ae_int_t k;
   18797             :     ae_int_t layeridx;
   18798             :     ae_int_t srcidx;
   18799             :     double v;
   18800             :     double vv;
   18801             :     ae_int_t npoints;
   18802             :     ae_int_t nx;
   18803             :     ae_int_t ny;
   18804             :     double rcur;
   18805             :     double lambdacur;
   18806             :     double rss;
   18807             :     double tss;
   18808             : 
   18809           0 :     _idwmodel_clear(model);
   18810           0 :     _idwreport_clear(rep);
   18811             : 
   18812           0 :     nx = state->nx;
   18813           0 :     ny = state->ny;
   18814           0 :     npoints = state->npoints;
   18815             :     
   18816             :     /*
   18817             :      * Clear report fields
   18818             :      */
   18819           0 :     rep->rmserror = (double)(0);
   18820           0 :     rep->avgerror = (double)(0);
   18821           0 :     rep->maxerror = (double)(0);
   18822           0 :     rep->r2 = 1.0;
   18823             :     
   18824             :     /*
   18825             :      * Quick exit for empty dataset
   18826             :      */
   18827           0 :     if( state->npoints==0 )
   18828             :     {
   18829           0 :         model->nx = nx;
   18830           0 :         model->ny = ny;
   18831           0 :         ae_vector_set_length(&model->globalprior, ny, _state);
   18832           0 :         for(i=0; i<=ny-1; i++)
   18833             :         {
   18834           0 :             model->globalprior.ptr.p_double[i] = (double)(0);
   18835             :         }
   18836           0 :         model->algotype = 0;
   18837           0 :         model->nlayers = 0;
   18838           0 :         model->r0 = (double)(1);
   18839           0 :         model->rdecay = 0.5;
   18840           0 :         model->lambda0 = (double)(0);
   18841           0 :         model->lambdalast = (double)(0);
   18842           0 :         model->lambdadecay = (double)(1);
   18843           0 :         model->shepardp = (double)(2);
   18844           0 :         model->npoints = 0;
   18845           0 :         idwcreatecalcbuffer(model, &model->buffer, _state);
   18846           0 :         return;
   18847             :     }
   18848             :     
   18849             :     /*
   18850             :      * Compute temporaries which will be required later:
   18851             :      * * global mean
   18852             :      */
   18853           0 :     ae_assert(state->npoints>0, "IDWFit: integrity check failed", _state);
   18854           0 :     rvectorsetlengthatleast(&state->tmpmean, ny, _state);
   18855           0 :     for(j=0; j<=ny-1; j++)
   18856             :     {
   18857           0 :         state->tmpmean.ptr.p_double[j] = (double)(0);
   18858             :     }
   18859           0 :     for(i=0; i<=npoints-1; i++)
   18860             :     {
   18861           0 :         for(j=0; j<=ny-1; j++)
   18862             :         {
   18863           0 :             state->tmpmean.ptr.p_double[j] = state->tmpmean.ptr.p_double[j]+state->xy.ptr.p_double[i*(nx+ny)+nx+j];
   18864             :         }
   18865             :     }
   18866           0 :     for(j=0; j<=ny-1; j++)
   18867             :     {
   18868           0 :         state->tmpmean.ptr.p_double[j] = state->tmpmean.ptr.p_double[j]/npoints;
   18869             :     }
   18870             :     
   18871             :     /*
   18872             :      * Compute global prior
   18873             :      *
   18874             :      * NOTE: for original Shepard's method it is always mean value
   18875             :      */
   18876           0 :     rvectorsetlengthatleast(&model->globalprior, ny, _state);
   18877           0 :     for(j=0; j<=ny-1; j++)
   18878             :     {
   18879           0 :         model->globalprior.ptr.p_double[j] = state->tmpmean.ptr.p_double[j];
   18880             :     }
   18881           0 :     if( state->algotype!=0 )
   18882             :     {
   18883             :         
   18884             :         /*
   18885             :          * Algorithm is set to one of the "advanced" versions with search
   18886             :          * radius which can handle non-mean prior term
   18887             :          */
   18888           0 :         if( state->priortermtype==0 )
   18889             :         {
   18890             :             
   18891             :             /*
   18892             :              * User-specified prior
   18893             :              */
   18894           0 :             for(j=0; j<=ny-1; j++)
   18895             :             {
   18896           0 :                 model->globalprior.ptr.p_double[j] = state->priortermval.ptr.p_double[j];
   18897             :             }
   18898             :         }
   18899           0 :         if( state->priortermtype==3 )
   18900             :         {
   18901             :             
   18902             :             /*
   18903             :              * Zero prior
   18904             :              */
   18905           0 :             for(j=0; j<=ny-1; j++)
   18906             :             {
   18907           0 :                 model->globalprior.ptr.p_double[j] = (double)(0);
   18908             :             }
   18909             :         }
   18910             :     }
   18911             :     
   18912             :     /*
   18913             :      * Textbook Shepard
   18914             :      */
   18915           0 :     if( state->algotype==0 )
   18916             :     {
   18917             :         
   18918             :         /*
   18919             :          * Initialize model
   18920             :          */
   18921           0 :         model->algotype = 0;
   18922           0 :         model->nx = nx;
   18923           0 :         model->ny = ny;
   18924           0 :         model->nlayers = 1;
   18925           0 :         model->r0 = (double)(1);
   18926           0 :         model->rdecay = 0.5;
   18927           0 :         model->lambda0 = (double)(0);
   18928           0 :         model->lambdalast = (double)(0);
   18929           0 :         model->lambdadecay = (double)(1);
   18930           0 :         model->shepardp = state->shepardp;
   18931             :         
   18932             :         /*
   18933             :          * Copy dataset
   18934             :          */
   18935           0 :         rvectorsetlengthatleast(&model->shepardxy, npoints*(nx+ny), _state);
   18936           0 :         for(i=0; i<=npoints-1; i++)
   18937             :         {
   18938           0 :             for(j=0; j<=nx-1; j++)
   18939             :             {
   18940           0 :                 model->shepardxy.ptr.p_double[i*(nx+ny)+j] = state->xy.ptr.p_double[i*(nx+ny)+j];
   18941             :             }
   18942           0 :             for(j=0; j<=ny-1; j++)
   18943             :             {
   18944           0 :                 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];
   18945             :             }
   18946             :         }
   18947           0 :         model->npoints = npoints;
   18948             :         
   18949             :         /*
   18950             :          * Prepare internal buffer
   18951             :          * Evaluate report fields
   18952             :          */
   18953           0 :         idwcreatecalcbuffer(model, &model->buffer, _state);
   18954           0 :         idw_errormetricsviacalc(state, model, rep, _state);
   18955           0 :         return;
   18956             :     }
   18957             :     
   18958             :     /*
   18959             :      * Textbook modified Shepard's method
   18960             :      */
   18961           0 :     if( state->algotype==1 )
   18962             :     {
   18963             :         
   18964             :         /*
   18965             :          * Initialize model
   18966             :          */
   18967           0 :         model->algotype = 1;
   18968           0 :         model->nx = nx;
   18969           0 :         model->ny = ny;
   18970           0 :         model->nlayers = 1;
   18971           0 :         model->r0 = state->r0;
   18972           0 :         model->rdecay = (double)(1);
   18973           0 :         model->lambda0 = (double)(0);
   18974           0 :         model->lambdalast = (double)(0);
   18975           0 :         model->lambdadecay = (double)(1);
   18976           0 :         model->shepardp = (double)(0);
   18977             :         
   18978             :         /*
   18979             :          * Build kd-tree search structure
   18980             :          */
   18981           0 :         rmatrixsetlengthatleast(&state->tmpxy, npoints, nx+ny, _state);
   18982           0 :         for(i=0; i<=npoints-1; i++)
   18983             :         {
   18984           0 :             for(j=0; j<=nx-1; j++)
   18985             :             {
   18986           0 :                 state->tmpxy.ptr.pp_double[i][j] = state->xy.ptr.p_double[i*(nx+ny)+j];
   18987             :             }
   18988           0 :             for(j=0; j<=ny-1; j++)
   18989             :             {
   18990           0 :                 state->tmpxy.ptr.pp_double[i][nx+j] = state->xy.ptr.p_double[i*(nx+ny)+nx+j]-model->globalprior.ptr.p_double[j];
   18991             :             }
   18992             :         }
   18993           0 :         kdtreebuild(&state->tmpxy, npoints, nx, ny, 2, &model->tree, _state);
   18994             :         
   18995             :         /*
   18996             :          * Prepare internal buffer
   18997             :          * Evaluate report fields
   18998             :          */
   18999           0 :         idwcreatecalcbuffer(model, &model->buffer, _state);
   19000           0 :         idw_errormetricsviacalc(state, model, rep, _state);
   19001           0 :         return;
   19002             :     }
   19003             :     
   19004             :     /*
   19005             :      * MSTAB algorithm
   19006             :      */
   19007           0 :     if( state->algotype==2 )
   19008             :     {
   19009           0 :         ae_assert(state->nlayers>=1, "IDWFit: integrity check failed", _state);
   19010             :         
   19011             :         /*
   19012             :          * Initialize model
   19013             :          */
   19014           0 :         model->algotype = 2;
   19015           0 :         model->nx = nx;
   19016           0 :         model->ny = ny;
   19017           0 :         model->nlayers = state->nlayers;
   19018           0 :         model->r0 = state->r0;
   19019           0 :         model->rdecay = 0.5;
   19020           0 :         model->lambda0 = state->lambda0;
   19021           0 :         model->lambdadecay = 1.0;
   19022           0 :         model->lambdalast = idw_meps;
   19023           0 :         model->shepardp = (double)(0);
   19024             :         
   19025             :         /*
   19026             :          * Build kd-tree search structure,
   19027             :          * prepare input residuals for the first layer of the model
   19028             :          */
   19029           0 :         rmatrixsetlengthatleast(&state->tmpxy, npoints, nx, _state);
   19030           0 :         rmatrixsetlengthatleast(&state->tmplayers, npoints, nx+ny*(state->nlayers+1), _state);
   19031           0 :         ivectorsetlengthatleast(&state->tmptags, npoints, _state);
   19032           0 :         for(i=0; i<=npoints-1; i++)
   19033             :         {
   19034           0 :             for(j=0; j<=nx-1; j++)
   19035             :             {
   19036           0 :                 v = state->xy.ptr.p_double[i*(nx+ny)+j];
   19037           0 :                 state->tmpxy.ptr.pp_double[i][j] = v;
   19038           0 :                 state->tmplayers.ptr.pp_double[i][j] = v;
   19039             :             }
   19040           0 :             state->tmptags.ptr.p_int[i] = i;
   19041           0 :             for(j=0; j<=ny-1; j++)
   19042             :             {
   19043           0 :                 state->tmplayers.ptr.pp_double[i][nx+j] = state->xy.ptr.p_double[i*(nx+ny)+nx+j]-model->globalprior.ptr.p_double[j];
   19044             :             }
   19045             :         }
   19046           0 :         kdtreebuildtagged(&state->tmpxy, &state->tmptags, npoints, nx, 0, 2, &state->tmptree, _state);
   19047             :         
   19048             :         /*
   19049             :          * Iteratively build layer by layer
   19050             :          */
   19051           0 :         rvectorsetlengthatleast(&state->tmpx, nx, _state);
   19052           0 :         rvectorsetlengthatleast(&state->tmpwy, ny, _state);
   19053           0 :         rvectorsetlengthatleast(&state->tmpw, ny, _state);
   19054           0 :         for(layeridx=0; layeridx<=state->nlayers-1; layeridx++)
   19055             :         {
   19056             :             
   19057             :             /*
   19058             :              * Determine layer metrics
   19059             :              */
   19060           0 :             rcur = model->r0*ae_pow(model->rdecay, (double)(layeridx), _state);
   19061           0 :             lambdacur = model->lambda0*ae_pow(model->lambdadecay, (double)(layeridx), _state);
   19062           0 :             if( layeridx==state->nlayers-1 )
   19063             :             {
   19064           0 :                 lambdacur = model->lambdalast;
   19065             :             }
   19066             :             
   19067             :             /*
   19068             :              * For each point compute residual from fitting with current layer
   19069             :              */
   19070           0 :             for(i=0; i<=npoints-1; i++)
   19071             :             {
   19072           0 :                 for(j=0; j<=nx-1; j++)
   19073             :                 {
   19074           0 :                     state->tmpx.ptr.p_double[j] = state->tmplayers.ptr.pp_double[i][j];
   19075             :                 }
   19076           0 :                 k = kdtreequeryrnn(&state->tmptree, &state->tmpx, rcur, ae_true, _state);
   19077           0 :                 kdtreequeryresultstags(&state->tmptree, &state->tmptags, _state);
   19078           0 :                 kdtreequeryresultsdistances(&state->tmptree, &state->tmpdist, _state);
   19079           0 :                 for(j=0; j<=ny-1; j++)
   19080             :                 {
   19081           0 :                     state->tmpwy.ptr.p_double[j] = (double)(0);
   19082           0 :                     state->tmpw.ptr.p_double[j] = idw_w0;
   19083             :                 }
   19084           0 :                 for(i0=0; i0<=k-1; i0++)
   19085             :                 {
   19086           0 :                     vv = state->tmpdist.ptr.p_double[i0]/rcur;
   19087           0 :                     vv = vv*vv;
   19088           0 :                     v = (1-vv)*(1-vv)/(vv+lambdacur);
   19089           0 :                     srcidx = state->tmptags.ptr.p_int[i0];
   19090           0 :                     for(j=0; j<=ny-1; j++)
   19091             :                     {
   19092           0 :                         state->tmpwy.ptr.p_double[j] = state->tmpwy.ptr.p_double[j]+v*state->tmplayers.ptr.pp_double[srcidx][nx+layeridx*ny+j];
   19093           0 :                         state->tmpw.ptr.p_double[j] = state->tmpw.ptr.p_double[j]+v;
   19094             :                     }
   19095             :                 }
   19096           0 :                 for(j=0; j<=ny-1; j++)
   19097             :                 {
   19098           0 :                     v = state->tmplayers.ptr.pp_double[i][nx+layeridx*ny+j];
   19099           0 :                     state->tmplayers.ptr.pp_double[i][nx+(layeridx+1)*ny+j] = v-state->tmpwy.ptr.p_double[j]/state->tmpw.ptr.p_double[j];
   19100             :                 }
   19101             :             }
   19102             :         }
   19103           0 :         kdtreebuild(&state->tmplayers, npoints, nx, ny*state->nlayers, 2, &model->tree, _state);
   19104             :         
   19105             :         /*
   19106             :          * Evaluate report fields
   19107             :          */
   19108           0 :         rep->rmserror = (double)(0);
   19109           0 :         rep->avgerror = (double)(0);
   19110           0 :         rep->maxerror = (double)(0);
   19111           0 :         rss = (double)(0);
   19112           0 :         tss = (double)(0);
   19113           0 :         for(i=0; i<=npoints-1; i++)
   19114             :         {
   19115           0 :             for(j=0; j<=ny-1; j++)
   19116             :             {
   19117           0 :                 v = ae_fabs(state->tmplayers.ptr.pp_double[i][nx+state->nlayers*ny+j], _state);
   19118           0 :                 rep->rmserror = rep->rmserror+v*v;
   19119           0 :                 rep->avgerror = rep->avgerror+v;
   19120           0 :                 rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
   19121           0 :                 rss = rss+v*v;
   19122           0 :                 tss = tss+ae_sqr(state->xy.ptr.p_double[i*(nx+ny)+nx+j]-state->tmpmean.ptr.p_double[j], _state);
   19123             :             }
   19124             :         }
   19125           0 :         rep->rmserror = ae_sqrt(rep->rmserror/(npoints*ny), _state);
   19126           0 :         rep->avgerror = rep->avgerror/(npoints*ny);
   19127           0 :         rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state);
   19128             :         
   19129             :         /*
   19130             :          * Prepare internal buffer
   19131             :          */
   19132           0 :         idwcreatecalcbuffer(model, &model->buffer, _state);
   19133           0 :         return;
   19134             :     }
   19135             :     
   19136             :     /*
   19137             :      * Unknown algorithm
   19138             :      */
   19139           0 :     ae_assert(ae_false, "IDWFit: integrity check failed, unexpected algorithm", _state);
   19140             : }
   19141             : 
   19142             : 
   19143             : /*************************************************************************
   19144             : Serializer: allocation
   19145             : 
   19146             :   -- ALGLIB --
   19147             :      Copyright 28.02.2018 by Bochkanov Sergey
   19148             : *************************************************************************/
   19149           0 : void idwalloc(ae_serializer* s, idwmodel* model, ae_state *_state)
   19150             : {
   19151             :     ae_bool processed;
   19152             : 
   19153             : 
   19154             :     
   19155             :     /*
   19156             :      * Header
   19157             :      */
   19158           0 :     ae_serializer_alloc_entry(s);
   19159             :     
   19160             :     /*
   19161             :      * Algorithm type and fields which are set for all algorithms
   19162             :      */
   19163           0 :     ae_serializer_alloc_entry(s);
   19164           0 :     ae_serializer_alloc_entry(s);
   19165           0 :     ae_serializer_alloc_entry(s);
   19166           0 :     allocrealarray(s, &model->globalprior, -1, _state);
   19167           0 :     ae_serializer_alloc_entry(s);
   19168           0 :     ae_serializer_alloc_entry(s);
   19169           0 :     ae_serializer_alloc_entry(s);
   19170           0 :     ae_serializer_alloc_entry(s);
   19171           0 :     ae_serializer_alloc_entry(s);
   19172           0 :     ae_serializer_alloc_entry(s);
   19173           0 :     ae_serializer_alloc_entry(s);
   19174             :     
   19175             :     /*
   19176             :      * Algorithm-specific fields
   19177             :      */
   19178           0 :     processed = ae_false;
   19179           0 :     if( model->algotype==0 )
   19180             :     {
   19181           0 :         ae_serializer_alloc_entry(s);
   19182           0 :         allocrealarray(s, &model->shepardxy, -1, _state);
   19183           0 :         processed = ae_true;
   19184             :     }
   19185           0 :     if( model->algotype>0 )
   19186             :     {
   19187           0 :         kdtreealloc(s, &model->tree, _state);
   19188           0 :         processed = ae_true;
   19189             :     }
   19190           0 :     ae_assert(processed, "IDW: integrity check failed during serialization", _state);
   19191           0 : }
   19192             : 
   19193             : 
   19194             : /*************************************************************************
   19195             : Serializer: serialization
   19196             : 
   19197             :   -- ALGLIB --
   19198             :      Copyright 28.02.2018 by Bochkanov Sergey
   19199             : *************************************************************************/
   19200           0 : void idwserialize(ae_serializer* s, idwmodel* model, ae_state *_state)
   19201             : {
   19202             :     ae_bool processed;
   19203             : 
   19204             : 
   19205             :     
   19206             :     /*
   19207             :      * Header
   19208             :      */
   19209           0 :     ae_serializer_serialize_int(s, getidwserializationcode(_state), _state);
   19210             :     
   19211             :     /*
   19212             :      * Algorithm type and fields which are set for all algorithms
   19213             :      */
   19214           0 :     ae_serializer_serialize_int(s, model->algotype, _state);
   19215           0 :     ae_serializer_serialize_int(s, model->nx, _state);
   19216           0 :     ae_serializer_serialize_int(s, model->ny, _state);
   19217           0 :     serializerealarray(s, &model->globalprior, -1, _state);
   19218           0 :     ae_serializer_serialize_int(s, model->nlayers, _state);
   19219           0 :     ae_serializer_serialize_double(s, model->r0, _state);
   19220           0 :     ae_serializer_serialize_double(s, model->rdecay, _state);
   19221           0 :     ae_serializer_serialize_double(s, model->lambda0, _state);
   19222           0 :     ae_serializer_serialize_double(s, model->lambdalast, _state);
   19223           0 :     ae_serializer_serialize_double(s, model->lambdadecay, _state);
   19224           0 :     ae_serializer_serialize_double(s, model->shepardp, _state);
   19225             :     
   19226             :     /*
   19227             :      * Algorithm-specific fields
   19228             :      */
   19229           0 :     processed = ae_false;
   19230           0 :     if( model->algotype==0 )
   19231             :     {
   19232           0 :         ae_serializer_serialize_int(s, model->npoints, _state);
   19233           0 :         serializerealarray(s, &model->shepardxy, -1, _state);
   19234           0 :         processed = ae_true;
   19235             :     }
   19236           0 :     if( model->algotype>0 )
   19237             :     {
   19238           0 :         kdtreeserialize(s, &model->tree, _state);
   19239           0 :         processed = ae_true;
   19240             :     }
   19241           0 :     ae_assert(processed, "IDW: integrity check failed during serialization", _state);
   19242           0 : }
   19243             : 
   19244             : 
   19245             : /*************************************************************************
   19246             : Serializer: unserialization
   19247             : 
   19248             :   -- ALGLIB --
   19249             :      Copyright 28.02.2018 by Bochkanov Sergey
   19250             : *************************************************************************/
   19251           0 : void idwunserialize(ae_serializer* s, idwmodel* model, ae_state *_state)
   19252             : {
   19253             :     ae_bool processed;
   19254             :     ae_int_t scode;
   19255             : 
   19256           0 :     _idwmodel_clear(model);
   19257             : 
   19258             :     
   19259             :     /*
   19260             :      * Header
   19261             :      */
   19262           0 :     ae_serializer_unserialize_int(s, &scode, _state);
   19263           0 :     ae_assert(scode==getidwserializationcode(_state), "IDWUnserialize: stream header corrupted", _state);
   19264             :     
   19265             :     /*
   19266             :      * Algorithm type and fields which are set for all algorithms
   19267             :      */
   19268           0 :     ae_serializer_unserialize_int(s, &model->algotype, _state);
   19269           0 :     ae_serializer_unserialize_int(s, &model->nx, _state);
   19270           0 :     ae_serializer_unserialize_int(s, &model->ny, _state);
   19271           0 :     unserializerealarray(s, &model->globalprior, _state);
   19272           0 :     ae_serializer_unserialize_int(s, &model->nlayers, _state);
   19273           0 :     ae_serializer_unserialize_double(s, &model->r0, _state);
   19274           0 :     ae_serializer_unserialize_double(s, &model->rdecay, _state);
   19275           0 :     ae_serializer_unserialize_double(s, &model->lambda0, _state);
   19276           0 :     ae_serializer_unserialize_double(s, &model->lambdalast, _state);
   19277           0 :     ae_serializer_unserialize_double(s, &model->lambdadecay, _state);
   19278           0 :     ae_serializer_unserialize_double(s, &model->shepardp, _state);
   19279             :     
   19280             :     /*
   19281             :      * Algorithm-specific fields
   19282             :      */
   19283           0 :     processed = ae_false;
   19284           0 :     if( model->algotype==0 )
   19285             :     {
   19286           0 :         ae_serializer_unserialize_int(s, &model->npoints, _state);
   19287           0 :         unserializerealarray(s, &model->shepardxy, _state);
   19288           0 :         processed = ae_true;
   19289             :     }
   19290           0 :     if( model->algotype>0 )
   19291             :     {
   19292           0 :         kdtreeunserialize(s, &model->tree, _state);
   19293           0 :         processed = ae_true;
   19294             :     }
   19295           0 :     ae_assert(processed, "IDW: integrity check failed during serialization", _state);
   19296             :     
   19297             :     /*
   19298             :      * Temporary buffers
   19299             :      */
   19300           0 :     idwcreatecalcbuffer(model, &model->buffer, _state);
   19301           0 : }
   19302             : 
   19303             : 
   19304             : /*************************************************************************
   19305             : This function evaluates error metrics for the model  using  IDWTsCalcBuf()
   19306             : to calculate model at each point.
   19307             : 
   19308             : NOTE: modern IDW algorithms (MSTAB, MSMOOTH) can generate residuals during
   19309             :       model construction, so they do not need this function  in  order  to
   19310             :       evaluate error metrics.
   19311             : 
   19312             : Following fields of Rep are filled:
   19313             : * rep.rmserror
   19314             : * rep.avgerror
   19315             : * rep.maxerror
   19316             : * rep.r2
   19317             :    
   19318             :   -- ALGLIB --
   19319             :      Copyright 22.10.2018 by Bochkanov Sergey
   19320             : *************************************************************************/
   19321           0 : static void idw_errormetricsviacalc(idwbuilder* state,
   19322             :      idwmodel* model,
   19323             :      idwreport* rep,
   19324             :      ae_state *_state)
   19325             : {
   19326             :     ae_int_t npoints;
   19327             :     ae_int_t nx;
   19328             :     ae_int_t ny;
   19329             :     ae_int_t i;
   19330             :     ae_int_t j;
   19331             :     double v;
   19332             :     double vv;
   19333             :     double rss;
   19334             :     double tss;
   19335             : 
   19336             : 
   19337           0 :     npoints = state->npoints;
   19338           0 :     nx = state->nx;
   19339           0 :     ny = state->ny;
   19340           0 :     if( npoints==0 )
   19341             :     {
   19342           0 :         rep->rmserror = (double)(0);
   19343           0 :         rep->avgerror = (double)(0);
   19344           0 :         rep->maxerror = (double)(0);
   19345           0 :         rep->r2 = (double)(1);
   19346           0 :         return;
   19347             :     }
   19348           0 :     rep->rmserror = (double)(0);
   19349           0 :     rep->avgerror = (double)(0);
   19350           0 :     rep->maxerror = (double)(0);
   19351           0 :     rss = (double)(0);
   19352           0 :     tss = (double)(0);
   19353           0 :     for(i=0; i<=npoints-1; i++)
   19354             :     {
   19355           0 :         for(j=0; j<=nx-1; j++)
   19356             :         {
   19357           0 :             model->buffer.x.ptr.p_double[j] = state->xy.ptr.p_double[i*(nx+ny)+j];
   19358             :         }
   19359           0 :         idwtscalcbuf(model, &model->buffer, &model->buffer.x, &model->buffer.y, _state);
   19360           0 :         for(j=0; j<=ny-1; j++)
   19361             :         {
   19362           0 :             vv = state->xy.ptr.p_double[i*(nx+ny)+nx+j];
   19363           0 :             v = ae_fabs(vv-model->buffer.y.ptr.p_double[j], _state);
   19364           0 :             rep->rmserror = rep->rmserror+v*v;
   19365           0 :             rep->avgerror = rep->avgerror+v;
   19366           0 :             rep->maxerror = ae_maxreal(rep->maxerror, v, _state);
   19367           0 :             rss = rss+v*v;
   19368           0 :             tss = tss+ae_sqr(vv-state->tmpmean.ptr.p_double[j], _state);
   19369             :         }
   19370             :     }
   19371           0 :     rep->rmserror = ae_sqrt(rep->rmserror/(npoints*ny), _state);
   19372           0 :     rep->avgerror = rep->avgerror/(npoints*ny);
   19373           0 :     rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state);
   19374             : }
   19375             : 
   19376             : 
   19377           0 : void _idwcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic)
   19378             : {
   19379           0 :     idwcalcbuffer *p = (idwcalcbuffer*)_p;
   19380           0 :     ae_touch_ptr((void*)p);
   19381           0 :     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
   19382           0 :     ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic);
   19383           0 :     ae_vector_init(&p->tsyw, 0, DT_REAL, _state, make_automatic);
   19384           0 :     ae_vector_init(&p->tsw, 0, DT_REAL, _state, make_automatic);
   19385           0 :     ae_matrix_init(&p->tsxy, 0, 0, DT_REAL, _state, make_automatic);
   19386           0 :     ae_vector_init(&p->tsdist, 0, DT_REAL, _state, make_automatic);
   19387           0 :     _kdtreerequestbuffer_init(&p->requestbuffer, _state, make_automatic);
   19388           0 : }
   19389             : 
   19390             : 
   19391           0 : void _idwcalcbuffer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   19392             : {
   19393           0 :     idwcalcbuffer *dst = (idwcalcbuffer*)_dst;
   19394           0 :     idwcalcbuffer *src = (idwcalcbuffer*)_src;
   19395           0 :     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
   19396           0 :     ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic);
   19397           0 :     ae_vector_init_copy(&dst->tsyw, &src->tsyw, _state, make_automatic);
   19398           0 :     ae_vector_init_copy(&dst->tsw, &src->tsw, _state, make_automatic);
   19399           0 :     ae_matrix_init_copy(&dst->tsxy, &src->tsxy, _state, make_automatic);
   19400           0 :     ae_vector_init_copy(&dst->tsdist, &src->tsdist, _state, make_automatic);
   19401           0 :     _kdtreerequestbuffer_init_copy(&dst->requestbuffer, &src->requestbuffer, _state, make_automatic);
   19402           0 : }
   19403             : 
   19404             : 
   19405           0 : void _idwcalcbuffer_clear(void* _p)
   19406             : {
   19407           0 :     idwcalcbuffer *p = (idwcalcbuffer*)_p;
   19408           0 :     ae_touch_ptr((void*)p);
   19409           0 :     ae_vector_clear(&p->x);
   19410           0 :     ae_vector_clear(&p->y);
   19411           0 :     ae_vector_clear(&p->tsyw);
   19412           0 :     ae_vector_clear(&p->tsw);
   19413           0 :     ae_matrix_clear(&p->tsxy);
   19414           0 :     ae_vector_clear(&p->tsdist);
   19415           0 :     _kdtreerequestbuffer_clear(&p->requestbuffer);
   19416           0 : }
   19417             : 
   19418             : 
   19419           0 : void _idwcalcbuffer_destroy(void* _p)
   19420             : {
   19421           0 :     idwcalcbuffer *p = (idwcalcbuffer*)_p;
   19422           0 :     ae_touch_ptr((void*)p);
   19423           0 :     ae_vector_destroy(&p->x);
   19424           0 :     ae_vector_destroy(&p->y);
   19425           0 :     ae_vector_destroy(&p->tsyw);
   19426           0 :     ae_vector_destroy(&p->tsw);
   19427           0 :     ae_matrix_destroy(&p->tsxy);
   19428           0 :     ae_vector_destroy(&p->tsdist);
   19429           0 :     _kdtreerequestbuffer_destroy(&p->requestbuffer);
   19430           0 : }
   19431             : 
   19432             : 
   19433           0 : void _idwmodel_init(void* _p, ae_state *_state, ae_bool make_automatic)
   19434             : {
   19435           0 :     idwmodel *p = (idwmodel*)_p;
   19436           0 :     ae_touch_ptr((void*)p);
   19437           0 :     ae_vector_init(&p->globalprior, 0, DT_REAL, _state, make_automatic);
   19438           0 :     _kdtree_init(&p->tree, _state, make_automatic);
   19439           0 :     ae_vector_init(&p->shepardxy, 0, DT_REAL, _state, make_automatic);
   19440           0 :     _idwcalcbuffer_init(&p->buffer, _state, make_automatic);
   19441           0 : }
   19442             : 
   19443             : 
   19444           0 : void _idwmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   19445             : {
   19446           0 :     idwmodel *dst = (idwmodel*)_dst;
   19447           0 :     idwmodel *src = (idwmodel*)_src;
   19448           0 :     dst->nx = src->nx;
   19449           0 :     dst->ny = src->ny;
   19450           0 :     ae_vector_init_copy(&dst->globalprior, &src->globalprior, _state, make_automatic);
   19451           0 :     dst->algotype = src->algotype;
   19452           0 :     dst->nlayers = src->nlayers;
   19453           0 :     dst->r0 = src->r0;
   19454           0 :     dst->rdecay = src->rdecay;
   19455           0 :     dst->lambda0 = src->lambda0;
   19456           0 :     dst->lambdalast = src->lambdalast;
   19457           0 :     dst->lambdadecay = src->lambdadecay;
   19458           0 :     dst->shepardp = src->shepardp;
   19459           0 :     _kdtree_init_copy(&dst->tree, &src->tree, _state, make_automatic);
   19460           0 :     dst->npoints = src->npoints;
   19461           0 :     ae_vector_init_copy(&dst->shepardxy, &src->shepardxy, _state, make_automatic);
   19462           0 :     _idwcalcbuffer_init_copy(&dst->buffer, &src->buffer, _state, make_automatic);
   19463           0 : }
   19464             : 
   19465             : 
   19466           0 : void _idwmodel_clear(void* _p)
   19467             : {
   19468           0 :     idwmodel *p = (idwmodel*)_p;
   19469           0 :     ae_touch_ptr((void*)p);
   19470           0 :     ae_vector_clear(&p->globalprior);
   19471           0 :     _kdtree_clear(&p->tree);
   19472           0 :     ae_vector_clear(&p->shepardxy);
   19473           0 :     _idwcalcbuffer_clear(&p->buffer);
   19474           0 : }
   19475             : 
   19476             : 
   19477           0 : void _idwmodel_destroy(void* _p)
   19478             : {
   19479           0 :     idwmodel *p = (idwmodel*)_p;
   19480           0 :     ae_touch_ptr((void*)p);
   19481           0 :     ae_vector_destroy(&p->globalprior);
   19482           0 :     _kdtree_destroy(&p->tree);
   19483           0 :     ae_vector_destroy(&p->shepardxy);
   19484           0 :     _idwcalcbuffer_destroy(&p->buffer);
   19485           0 : }
   19486             : 
   19487             : 
   19488           0 : void _idwbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic)
   19489             : {
   19490           0 :     idwbuilder *p = (idwbuilder*)_p;
   19491           0 :     ae_touch_ptr((void*)p);
   19492           0 :     ae_vector_init(&p->priortermval, 0, DT_REAL, _state, make_automatic);
   19493           0 :     ae_vector_init(&p->xy, 0, DT_REAL, _state, make_automatic);
   19494           0 :     ae_matrix_init(&p->tmpxy, 0, 0, DT_REAL, _state, make_automatic);
   19495           0 :     ae_matrix_init(&p->tmplayers, 0, 0, DT_REAL, _state, make_automatic);
   19496           0 :     ae_vector_init(&p->tmptags, 0, DT_INT, _state, make_automatic);
   19497           0 :     ae_vector_init(&p->tmpdist, 0, DT_REAL, _state, make_automatic);
   19498           0 :     ae_vector_init(&p->tmpx, 0, DT_REAL, _state, make_automatic);
   19499           0 :     ae_vector_init(&p->tmpwy, 0, DT_REAL, _state, make_automatic);
   19500           0 :     ae_vector_init(&p->tmpw, 0, DT_REAL, _state, make_automatic);
   19501           0 :     _kdtree_init(&p->tmptree, _state, make_automatic);
   19502           0 :     ae_vector_init(&p->tmpmean, 0, DT_REAL, _state, make_automatic);
   19503           0 : }
   19504             : 
   19505             : 
   19506           0 : void _idwbuilder_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   19507             : {
   19508           0 :     idwbuilder *dst = (idwbuilder*)_dst;
   19509           0 :     idwbuilder *src = (idwbuilder*)_src;
   19510           0 :     dst->priortermtype = src->priortermtype;
   19511           0 :     ae_vector_init_copy(&dst->priortermval, &src->priortermval, _state, make_automatic);
   19512           0 :     dst->algotype = src->algotype;
   19513           0 :     dst->nlayers = src->nlayers;
   19514           0 :     dst->r0 = src->r0;
   19515           0 :     dst->rdecay = src->rdecay;
   19516           0 :     dst->lambda0 = src->lambda0;
   19517           0 :     dst->lambdalast = src->lambdalast;
   19518           0 :     dst->lambdadecay = src->lambdadecay;
   19519           0 :     dst->shepardp = src->shepardp;
   19520           0 :     ae_vector_init_copy(&dst->xy, &src->xy, _state, make_automatic);
   19521           0 :     dst->npoints = src->npoints;
   19522           0 :     dst->nx = src->nx;
   19523           0 :     dst->ny = src->ny;
   19524           0 :     ae_matrix_init_copy(&dst->tmpxy, &src->tmpxy, _state, make_automatic);
   19525           0 :     ae_matrix_init_copy(&dst->tmplayers, &src->tmplayers, _state, make_automatic);
   19526           0 :     ae_vector_init_copy(&dst->tmptags, &src->tmptags, _state, make_automatic);
   19527           0 :     ae_vector_init_copy(&dst->tmpdist, &src->tmpdist, _state, make_automatic);
   19528           0 :     ae_vector_init_copy(&dst->tmpx, &src->tmpx, _state, make_automatic);
   19529           0 :     ae_vector_init_copy(&dst->tmpwy, &src->tmpwy, _state, make_automatic);
   19530           0 :     ae_vector_init_copy(&dst->tmpw, &src->tmpw, _state, make_automatic);
   19531           0 :     _kdtree_init_copy(&dst->tmptree, &src->tmptree, _state, make_automatic);
   19532           0 :     ae_vector_init_copy(&dst->tmpmean, &src->tmpmean, _state, make_automatic);
   19533           0 : }
   19534             : 
   19535             : 
   19536           0 : void _idwbuilder_clear(void* _p)
   19537             : {
   19538           0 :     idwbuilder *p = (idwbuilder*)_p;
   19539           0 :     ae_touch_ptr((void*)p);
   19540           0 :     ae_vector_clear(&p->priortermval);
   19541           0 :     ae_vector_clear(&p->xy);
   19542           0 :     ae_matrix_clear(&p->tmpxy);
   19543           0 :     ae_matrix_clear(&p->tmplayers);
   19544           0 :     ae_vector_clear(&p->tmptags);
   19545           0 :     ae_vector_clear(&p->tmpdist);
   19546           0 :     ae_vector_clear(&p->tmpx);
   19547           0 :     ae_vector_clear(&p->tmpwy);
   19548           0 :     ae_vector_clear(&p->tmpw);
   19549           0 :     _kdtree_clear(&p->tmptree);
   19550           0 :     ae_vector_clear(&p->tmpmean);
   19551           0 : }
   19552             : 
   19553             : 
   19554           0 : void _idwbuilder_destroy(void* _p)
   19555             : {
   19556           0 :     idwbuilder *p = (idwbuilder*)_p;
   19557           0 :     ae_touch_ptr((void*)p);
   19558           0 :     ae_vector_destroy(&p->priortermval);
   19559           0 :     ae_vector_destroy(&p->xy);
   19560           0 :     ae_matrix_destroy(&p->tmpxy);
   19561           0 :     ae_matrix_destroy(&p->tmplayers);
   19562           0 :     ae_vector_destroy(&p->tmptags);
   19563           0 :     ae_vector_destroy(&p->tmpdist);
   19564           0 :     ae_vector_destroy(&p->tmpx);
   19565           0 :     ae_vector_destroy(&p->tmpwy);
   19566           0 :     ae_vector_destroy(&p->tmpw);
   19567           0 :     _kdtree_destroy(&p->tmptree);
   19568           0 :     ae_vector_destroy(&p->tmpmean);
   19569           0 : }
   19570             : 
   19571             : 
   19572           0 : void _idwreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
   19573             : {
   19574           0 :     idwreport *p = (idwreport*)_p;
   19575           0 :     ae_touch_ptr((void*)p);
   19576           0 : }
   19577             : 
   19578             : 
   19579           0 : void _idwreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   19580             : {
   19581           0 :     idwreport *dst = (idwreport*)_dst;
   19582           0 :     idwreport *src = (idwreport*)_src;
   19583           0 :     dst->rmserror = src->rmserror;
   19584           0 :     dst->avgerror = src->avgerror;
   19585           0 :     dst->maxerror = src->maxerror;
   19586           0 :     dst->r2 = src->r2;
   19587           0 : }
   19588             : 
   19589             : 
   19590           0 : void _idwreport_clear(void* _p)
   19591             : {
   19592           0 :     idwreport *p = (idwreport*)_p;
   19593           0 :     ae_touch_ptr((void*)p);
   19594           0 : }
   19595             : 
   19596             : 
   19597           0 : void _idwreport_destroy(void* _p)
   19598             : {
   19599           0 :     idwreport *p = (idwreport*)_p;
   19600           0 :     ae_touch_ptr((void*)p);
   19601           0 : }
   19602             : 
   19603             : 
   19604             : #endif
   19605             : #if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD)
   19606             : 
   19607             : 
   19608             : /*************************************************************************
   19609             : Rational interpolation using barycentric formula
   19610             : 
   19611             : F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))
   19612             : 
   19613             : Input parameters:
   19614             :     B   -   barycentric interpolant built with one of model building
   19615             :             subroutines.
   19616             :     T   -   interpolation point
   19617             : 
   19618             : Result:
   19619             :     barycentric interpolant F(t)
   19620             : 
   19621             :   -- ALGLIB --
   19622             :      Copyright 17.08.2009 by Bochkanov Sergey
   19623             : *************************************************************************/
   19624           0 : double barycentriccalc(barycentricinterpolant* b,
   19625             :      double t,
   19626             :      ae_state *_state)
   19627             : {
   19628             :     double s1;
   19629             :     double s2;
   19630             :     double s;
   19631             :     double v;
   19632             :     ae_int_t i;
   19633             :     double result;
   19634             : 
   19635             : 
   19636           0 :     ae_assert(!ae_isinf(t, _state), "BarycentricCalc: infinite T!", _state);
   19637             :     
   19638             :     /*
   19639             :      * special case: NaN
   19640             :      */
   19641           0 :     if( ae_isnan(t, _state) )
   19642             :     {
   19643           0 :         result = _state->v_nan;
   19644           0 :         return result;
   19645             :     }
   19646             :     
   19647             :     /*
   19648             :      * special case: N=1
   19649             :      */
   19650           0 :     if( b->n==1 )
   19651             :     {
   19652           0 :         result = b->sy*b->y.ptr.p_double[0];
   19653           0 :         return result;
   19654             :     }
   19655             :     
   19656             :     /*
   19657             :      * Here we assume that task is normalized, i.e.:
   19658             :      * 1. abs(Y[i])<=1
   19659             :      * 2. abs(W[i])<=1
   19660             :      * 3. X[] is ordered
   19661             :      */
   19662           0 :     s = ae_fabs(t-b->x.ptr.p_double[0], _state);
   19663           0 :     for(i=0; i<=b->n-1; i++)
   19664             :     {
   19665           0 :         v = b->x.ptr.p_double[i];
   19666           0 :         if( ae_fp_eq(v,t) )
   19667             :         {
   19668           0 :             result = b->sy*b->y.ptr.p_double[i];
   19669           0 :             return result;
   19670             :         }
   19671           0 :         v = ae_fabs(t-v, _state);
   19672           0 :         if( ae_fp_less(v,s) )
   19673             :         {
   19674           0 :             s = v;
   19675             :         }
   19676             :     }
   19677           0 :     s1 = (double)(0);
   19678           0 :     s2 = (double)(0);
   19679           0 :     for(i=0; i<=b->n-1; i++)
   19680             :     {
   19681           0 :         v = s/(t-b->x.ptr.p_double[i]);
   19682           0 :         v = v*b->w.ptr.p_double[i];
   19683           0 :         s1 = s1+v*b->y.ptr.p_double[i];
   19684           0 :         s2 = s2+v;
   19685             :     }
   19686           0 :     result = b->sy*s1/s2;
   19687           0 :     return result;
   19688             : }
   19689             : 
   19690             : 
   19691             : /*************************************************************************
   19692             : Differentiation of barycentric interpolant: first derivative.
   19693             : 
   19694             : Algorithm used in this subroutine is very robust and should not fail until
   19695             : provided with values too close to MaxRealNumber  (usually  MaxRealNumber/N
   19696             : or greater will overflow).
   19697             : 
   19698             : INPUT PARAMETERS:
   19699             :     B   -   barycentric interpolant built with one of model building
   19700             :             subroutines.
   19701             :     T   -   interpolation point
   19702             : 
   19703             : OUTPUT PARAMETERS:
   19704             :     F   -   barycentric interpolant at T
   19705             :     DF  -   first derivative
   19706             :     
   19707             : NOTE
   19708             : 
   19709             : 
   19710             :   -- ALGLIB --
   19711             :      Copyright 17.08.2009 by Bochkanov Sergey
   19712             : *************************************************************************/
   19713           0 : void barycentricdiff1(barycentricinterpolant* b,
   19714             :      double t,
   19715             :      double* f,
   19716             :      double* df,
   19717             :      ae_state *_state)
   19718             : {
   19719             :     double v;
   19720             :     double vv;
   19721             :     ae_int_t i;
   19722             :     ae_int_t k;
   19723             :     double n0;
   19724             :     double n1;
   19725             :     double d0;
   19726             :     double d1;
   19727             :     double s0;
   19728             :     double s1;
   19729             :     double xk;
   19730             :     double xi;
   19731             :     double xmin;
   19732             :     double xmax;
   19733             :     double xscale1;
   19734             :     double xoffs1;
   19735             :     double xscale2;
   19736             :     double xoffs2;
   19737             :     double xprev;
   19738             : 
   19739           0 :     *f = 0;
   19740           0 :     *df = 0;
   19741             : 
   19742           0 :     ae_assert(!ae_isinf(t, _state), "BarycentricDiff1: infinite T!", _state);
   19743             :     
   19744             :     /*
   19745             :      * special case: NaN
   19746             :      */
   19747           0 :     if( ae_isnan(t, _state) )
   19748             :     {
   19749           0 :         *f = _state->v_nan;
   19750           0 :         *df = _state->v_nan;
   19751           0 :         return;
   19752             :     }
   19753             :     
   19754             :     /*
   19755             :      * special case: N=1
   19756             :      */
   19757           0 :     if( b->n==1 )
   19758             :     {
   19759           0 :         *f = b->sy*b->y.ptr.p_double[0];
   19760           0 :         *df = (double)(0);
   19761           0 :         return;
   19762             :     }
   19763           0 :     if( ae_fp_eq(b->sy,(double)(0)) )
   19764             :     {
   19765           0 :         *f = (double)(0);
   19766           0 :         *df = (double)(0);
   19767           0 :         return;
   19768             :     }
   19769           0 :     ae_assert(ae_fp_greater(b->sy,(double)(0)), "BarycentricDiff1: internal error", _state);
   19770             :     
   19771             :     /*
   19772             :      * We assume than N>1 and B.SY>0. Find:
   19773             :      * 1. pivot point (X[i] closest to T)
   19774             :      * 2. width of interval containing X[i]
   19775             :      */
   19776           0 :     v = ae_fabs(b->x.ptr.p_double[0]-t, _state);
   19777           0 :     k = 0;
   19778           0 :     xmin = b->x.ptr.p_double[0];
   19779           0 :     xmax = b->x.ptr.p_double[0];
   19780           0 :     for(i=1; i<=b->n-1; i++)
   19781             :     {
   19782           0 :         vv = b->x.ptr.p_double[i];
   19783           0 :         if( ae_fp_less(ae_fabs(vv-t, _state),v) )
   19784             :         {
   19785           0 :             v = ae_fabs(vv-t, _state);
   19786           0 :             k = i;
   19787             :         }
   19788           0 :         xmin = ae_minreal(xmin, vv, _state);
   19789           0 :         xmax = ae_maxreal(xmax, vv, _state);
   19790             :     }
   19791             :     
   19792             :     /*
   19793             :      * pivot point found, calculate dNumerator and dDenominator
   19794             :      */
   19795           0 :     xscale1 = 1/(xmax-xmin);
   19796           0 :     xoffs1 = -xmin/(xmax-xmin)+1;
   19797           0 :     xscale2 = (double)(2);
   19798           0 :     xoffs2 = (double)(-3);
   19799           0 :     t = t*xscale1+xoffs1;
   19800           0 :     t = t*xscale2+xoffs2;
   19801           0 :     xk = b->x.ptr.p_double[k];
   19802           0 :     xk = xk*xscale1+xoffs1;
   19803           0 :     xk = xk*xscale2+xoffs2;
   19804           0 :     v = t-xk;
   19805           0 :     n0 = (double)(0);
   19806           0 :     n1 = (double)(0);
   19807           0 :     d0 = (double)(0);
   19808           0 :     d1 = (double)(0);
   19809           0 :     xprev = (double)(-2);
   19810           0 :     for(i=0; i<=b->n-1; i++)
   19811             :     {
   19812           0 :         xi = b->x.ptr.p_double[i];
   19813           0 :         xi = xi*xscale1+xoffs1;
   19814           0 :         xi = xi*xscale2+xoffs2;
   19815           0 :         ae_assert(ae_fp_greater(xi,xprev), "BarycentricDiff1: points are too close!", _state);
   19816           0 :         xprev = xi;
   19817           0 :         if( i!=k )
   19818             :         {
   19819           0 :             vv = ae_sqr(t-xi, _state);
   19820           0 :             s0 = (t-xk)/(t-xi);
   19821           0 :             s1 = (xk-xi)/vv;
   19822             :         }
   19823             :         else
   19824             :         {
   19825           0 :             s0 = (double)(1);
   19826           0 :             s1 = (double)(0);
   19827             :         }
   19828           0 :         vv = b->w.ptr.p_double[i]*b->y.ptr.p_double[i];
   19829           0 :         n0 = n0+s0*vv;
   19830           0 :         n1 = n1+s1*vv;
   19831           0 :         vv = b->w.ptr.p_double[i];
   19832           0 :         d0 = d0+s0*vv;
   19833           0 :         d1 = d1+s1*vv;
   19834             :     }
   19835           0 :     *f = b->sy*n0/d0;
   19836           0 :     *df = (n1*d0-n0*d1)/ae_sqr(d0, _state);
   19837           0 :     if( ae_fp_neq(*df,(double)(0)) )
   19838             :     {
   19839           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);
   19840             :     }
   19841             : }
   19842             : 
   19843             : 
   19844             : /*************************************************************************
   19845             : Differentiation of barycentric interpolant: first/second derivatives.
   19846             : 
   19847             : INPUT PARAMETERS:
   19848             :     B   -   barycentric interpolant built with one of model building
   19849             :             subroutines.
   19850             :     T   -   interpolation point
   19851             : 
   19852             : OUTPUT PARAMETERS:
   19853             :     F   -   barycentric interpolant at T
   19854             :     DF  -   first derivative
   19855             :     D2F -   second derivative
   19856             : 
   19857             : NOTE: this algorithm may fail due to overflow/underflor if  used  on  data
   19858             : whose values are close to MaxRealNumber or MinRealNumber.  Use more robust
   19859             : BarycentricDiff1() subroutine in such cases.
   19860             : 
   19861             : 
   19862             :   -- ALGLIB --
   19863             :      Copyright 17.08.2009 by Bochkanov Sergey
   19864             : *************************************************************************/
   19865           0 : void barycentricdiff2(barycentricinterpolant* b,
   19866             :      double t,
   19867             :      double* f,
   19868             :      double* df,
   19869             :      double* d2f,
   19870             :      ae_state *_state)
   19871             : {
   19872             :     double v;
   19873             :     double vv;
   19874             :     ae_int_t i;
   19875             :     ae_int_t k;
   19876             :     double n0;
   19877             :     double n1;
   19878             :     double n2;
   19879             :     double d0;
   19880             :     double d1;
   19881             :     double d2;
   19882             :     double s0;
   19883             :     double s1;
   19884             :     double s2;
   19885             :     double xk;
   19886             :     double xi;
   19887             : 
   19888           0 :     *f = 0;
   19889           0 :     *df = 0;
   19890           0 :     *d2f = 0;
   19891             : 
   19892           0 :     ae_assert(!ae_isinf(t, _state), "BarycentricDiff1: infinite T!", _state);
   19893             :     
   19894             :     /*
   19895             :      * special case: NaN
   19896             :      */
   19897           0 :     if( ae_isnan(t, _state) )
   19898             :     {
   19899           0 :         *f = _state->v_nan;
   19900           0 :         *df = _state->v_nan;
   19901           0 :         *d2f = _state->v_nan;
   19902           0 :         return;
   19903             :     }
   19904             :     
   19905             :     /*
   19906             :      * special case: N=1
   19907             :      */
   19908           0 :     if( b->n==1 )
   19909             :     {
   19910           0 :         *f = b->sy*b->y.ptr.p_double[0];
   19911           0 :         *df = (double)(0);
   19912           0 :         *d2f = (double)(0);
   19913           0 :         return;
   19914             :     }
   19915           0 :     if( ae_fp_eq(b->sy,(double)(0)) )
   19916             :     {
   19917           0 :         *f = (double)(0);
   19918           0 :         *df = (double)(0);
   19919           0 :         *d2f = (double)(0);
   19920           0 :         return;
   19921             :     }
   19922             :     
   19923             :     /*
   19924             :      * We assume than N>1 and B.SY>0. Find:
   19925             :      * 1. pivot point (X[i] closest to T)
   19926             :      * 2. width of interval containing X[i]
   19927             :      */
   19928           0 :     ae_assert(ae_fp_greater(b->sy,(double)(0)), "BarycentricDiff: internal error", _state);
   19929           0 :     *f = (double)(0);
   19930           0 :     *df = (double)(0);
   19931           0 :     *d2f = (double)(0);
   19932           0 :     v = ae_fabs(b->x.ptr.p_double[0]-t, _state);
   19933           0 :     k = 0;
   19934           0 :     for(i=1; i<=b->n-1; i++)
   19935             :     {
   19936           0 :         vv = b->x.ptr.p_double[i];
   19937           0 :         if( ae_fp_less(ae_fabs(vv-t, _state),v) )
   19938             :         {
   19939           0 :             v = ae_fabs(vv-t, _state);
   19940           0 :             k = i;
   19941             :         }
   19942             :     }
   19943             :     
   19944             :     /*
   19945             :      * pivot point found, calculate dNumerator and dDenominator
   19946             :      */
   19947           0 :     xk = b->x.ptr.p_double[k];
   19948           0 :     v = t-xk;
   19949           0 :     n0 = (double)(0);
   19950           0 :     n1 = (double)(0);
   19951           0 :     n2 = (double)(0);
   19952           0 :     d0 = (double)(0);
   19953           0 :     d1 = (double)(0);
   19954           0 :     d2 = (double)(0);
   19955           0 :     for(i=0; i<=b->n-1; i++)
   19956             :     {
   19957           0 :         if( i!=k )
   19958             :         {
   19959           0 :             xi = b->x.ptr.p_double[i];
   19960           0 :             vv = ae_sqr(t-xi, _state);
   19961           0 :             s0 = (t-xk)/(t-xi);
   19962           0 :             s1 = (xk-xi)/vv;
   19963           0 :             s2 = -2*(xk-xi)/(vv*(t-xi));
   19964             :         }
   19965             :         else
   19966             :         {
   19967           0 :             s0 = (double)(1);
   19968           0 :             s1 = (double)(0);
   19969           0 :             s2 = (double)(0);
   19970             :         }
   19971           0 :         vv = b->w.ptr.p_double[i]*b->y.ptr.p_double[i];
   19972           0 :         n0 = n0+s0*vv;
   19973           0 :         n1 = n1+s1*vv;
   19974           0 :         n2 = n2+s2*vv;
   19975           0 :         vv = b->w.ptr.p_double[i];
   19976           0 :         d0 = d0+s0*vv;
   19977           0 :         d1 = d1+s1*vv;
   19978           0 :         d2 = d2+s2*vv;
   19979             :     }
   19980           0 :     *f = b->sy*n0/d0;
   19981           0 :     *df = b->sy*(n1*d0-n0*d1)/ae_sqr(d0, _state);
   19982           0 :     *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);
   19983             : }
   19984             : 
   19985             : 
   19986             : /*************************************************************************
   19987             : This subroutine performs linear transformation of the argument.
   19988             : 
   19989             : INPUT PARAMETERS:
   19990             :     B       -   rational interpolant in barycentric form
   19991             :     CA, CB  -   transformation coefficients: x = CA*t + CB
   19992             : 
   19993             : OUTPUT PARAMETERS:
   19994             :     B       -   transformed interpolant with X replaced by T
   19995             : 
   19996             :   -- ALGLIB PROJECT --
   19997             :      Copyright 19.08.2009 by Bochkanov Sergey
   19998             : *************************************************************************/
   19999           0 : void barycentriclintransx(barycentricinterpolant* b,
   20000             :      double ca,
   20001             :      double cb,
   20002             :      ae_state *_state)
   20003             : {
   20004             :     ae_int_t i;
   20005             :     ae_int_t j;
   20006             :     double v;
   20007             : 
   20008             : 
   20009             :     
   20010             :     /*
   20011             :      * special case, replace by constant F(CB)
   20012             :      */
   20013           0 :     if( ae_fp_eq(ca,(double)(0)) )
   20014             :     {
   20015           0 :         b->sy = barycentriccalc(b, cb, _state);
   20016           0 :         v = (double)(1);
   20017           0 :         for(i=0; i<=b->n-1; i++)
   20018             :         {
   20019           0 :             b->y.ptr.p_double[i] = (double)(1);
   20020           0 :             b->w.ptr.p_double[i] = v;
   20021           0 :             v = -v;
   20022             :         }
   20023           0 :         return;
   20024             :     }
   20025             :     
   20026             :     /*
   20027             :      * general case: CA<>0
   20028             :      */
   20029           0 :     for(i=0; i<=b->n-1; i++)
   20030             :     {
   20031           0 :         b->x.ptr.p_double[i] = (b->x.ptr.p_double[i]-cb)/ca;
   20032             :     }
   20033           0 :     if( ae_fp_less(ca,(double)(0)) )
   20034             :     {
   20035           0 :         for(i=0; i<=b->n-1; i++)
   20036             :         {
   20037           0 :             if( i<b->n-1-i )
   20038             :             {
   20039           0 :                 j = b->n-1-i;
   20040           0 :                 v = b->x.ptr.p_double[i];
   20041           0 :                 b->x.ptr.p_double[i] = b->x.ptr.p_double[j];
   20042           0 :                 b->x.ptr.p_double[j] = v;
   20043           0 :                 v = b->y.ptr.p_double[i];
   20044           0 :                 b->y.ptr.p_double[i] = b->y.ptr.p_double[j];
   20045           0 :                 b->y.ptr.p_double[j] = v;
   20046           0 :                 v = b->w.ptr.p_double[i];
   20047           0 :                 b->w.ptr.p_double[i] = b->w.ptr.p_double[j];
   20048           0 :                 b->w.ptr.p_double[j] = v;
   20049             :             }
   20050             :             else
   20051             :             {
   20052           0 :                 break;
   20053             :             }
   20054             :         }
   20055             :     }
   20056             : }
   20057             : 
   20058             : 
   20059             : /*************************************************************************
   20060             : This  subroutine   performs   linear  transformation  of  the  barycentric
   20061             : interpolant.
   20062             : 
   20063             : INPUT PARAMETERS:
   20064             :     B       -   rational interpolant in barycentric form
   20065             :     CA, CB  -   transformation coefficients: B2(x) = CA*B(x) + CB
   20066             : 
   20067             : OUTPUT PARAMETERS:
   20068             :     B       -   transformed interpolant
   20069             : 
   20070             :   -- ALGLIB PROJECT --
   20071             :      Copyright 19.08.2009 by Bochkanov Sergey
   20072             : *************************************************************************/
   20073           0 : void barycentriclintransy(barycentricinterpolant* b,
   20074             :      double ca,
   20075             :      double cb,
   20076             :      ae_state *_state)
   20077             : {
   20078             :     ae_int_t i;
   20079             :     double v;
   20080             : 
   20081             : 
   20082           0 :     for(i=0; i<=b->n-1; i++)
   20083             :     {
   20084           0 :         b->y.ptr.p_double[i] = ca*b->sy*b->y.ptr.p_double[i]+cb;
   20085             :     }
   20086           0 :     b->sy = (double)(0);
   20087           0 :     for(i=0; i<=b->n-1; i++)
   20088             :     {
   20089           0 :         b->sy = ae_maxreal(b->sy, ae_fabs(b->y.ptr.p_double[i], _state), _state);
   20090             :     }
   20091           0 :     if( ae_fp_greater(b->sy,(double)(0)) )
   20092             :     {
   20093           0 :         v = 1/b->sy;
   20094           0 :         ae_v_muld(&b->y.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v);
   20095             :     }
   20096           0 : }
   20097             : 
   20098             : 
   20099             : /*************************************************************************
   20100             : Extracts X/Y/W arrays from rational interpolant
   20101             : 
   20102             : INPUT PARAMETERS:
   20103             :     B   -   barycentric interpolant
   20104             : 
   20105             : OUTPUT PARAMETERS:
   20106             :     N   -   nodes count, N>0
   20107             :     X   -   interpolation nodes, array[0..N-1]
   20108             :     F   -   function values, array[0..N-1]
   20109             :     W   -   barycentric weights, array[0..N-1]
   20110             : 
   20111             :   -- ALGLIB --
   20112             :      Copyright 17.08.2009 by Bochkanov Sergey
   20113             : *************************************************************************/
   20114           0 : void barycentricunpack(barycentricinterpolant* b,
   20115             :      ae_int_t* n,
   20116             :      /* Real    */ ae_vector* x,
   20117             :      /* Real    */ ae_vector* y,
   20118             :      /* Real    */ ae_vector* w,
   20119             :      ae_state *_state)
   20120             : {
   20121             :     double v;
   20122             : 
   20123           0 :     *n = 0;
   20124           0 :     ae_vector_clear(x);
   20125           0 :     ae_vector_clear(y);
   20126           0 :     ae_vector_clear(w);
   20127             : 
   20128           0 :     *n = b->n;
   20129           0 :     ae_vector_set_length(x, *n, _state);
   20130           0 :     ae_vector_set_length(y, *n, _state);
   20131           0 :     ae_vector_set_length(w, *n, _state);
   20132           0 :     v = b->sy;
   20133           0 :     ae_v_move(&x->ptr.p_double[0], 1, &b->x.ptr.p_double[0], 1, ae_v_len(0,*n-1));
   20134           0 :     ae_v_moved(&y->ptr.p_double[0], 1, &b->y.ptr.p_double[0], 1, ae_v_len(0,*n-1), v);
   20135           0 :     ae_v_move(&w->ptr.p_double[0], 1, &b->w.ptr.p_double[0], 1, ae_v_len(0,*n-1));
   20136           0 : }
   20137             : 
   20138             : 
   20139             : /*************************************************************************
   20140             : Rational interpolant from X/Y/W arrays
   20141             : 
   20142             : F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))
   20143             : 
   20144             : INPUT PARAMETERS:
   20145             :     X   -   interpolation nodes, array[0..N-1]
   20146             :     F   -   function values, array[0..N-1]
   20147             :     W   -   barycentric weights, array[0..N-1]
   20148             :     N   -   nodes count, N>0
   20149             : 
   20150             : OUTPUT PARAMETERS:
   20151             :     B   -   barycentric interpolant built from (X, Y, W)
   20152             : 
   20153             :   -- ALGLIB --
   20154             :      Copyright 17.08.2009 by Bochkanov Sergey
   20155             : *************************************************************************/
   20156           0 : void barycentricbuildxyw(/* Real    */ ae_vector* x,
   20157             :      /* Real    */ ae_vector* y,
   20158             :      /* Real    */ ae_vector* w,
   20159             :      ae_int_t n,
   20160             :      barycentricinterpolant* b,
   20161             :      ae_state *_state)
   20162             : {
   20163             : 
   20164           0 :     _barycentricinterpolant_clear(b);
   20165             : 
   20166           0 :     ae_assert(n>0, "BarycentricBuildXYW: incorrect N!", _state);
   20167             :     
   20168             :     /*
   20169             :      * fill X/Y/W
   20170             :      */
   20171           0 :     ae_vector_set_length(&b->x, n, _state);
   20172           0 :     ae_vector_set_length(&b->y, n, _state);
   20173           0 :     ae_vector_set_length(&b->w, n, _state);
   20174           0 :     ae_v_move(&b->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
   20175           0 :     ae_v_move(&b->y.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
   20176           0 :     ae_v_move(&b->w.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
   20177           0 :     b->n = n;
   20178             :     
   20179             :     /*
   20180             :      * Normalize
   20181             :      */
   20182           0 :     ratint_barycentricnormalize(b, _state);
   20183           0 : }
   20184             : 
   20185             : 
   20186             : /*************************************************************************
   20187             : Rational interpolant without poles
   20188             : 
   20189             : The subroutine constructs the rational interpolating function without real
   20190             : poles  (see  'Barycentric rational interpolation with no  poles  and  high
   20191             : rates of approximation', Michael S. Floater. and  Kai  Hormann,  for  more
   20192             : information on this subject).
   20193             : 
   20194             : Input parameters:
   20195             :     X   -   interpolation nodes, array[0..N-1].
   20196             :     Y   -   function values, array[0..N-1].
   20197             :     N   -   number of nodes, N>0.
   20198             :     D   -   order of the interpolation scheme, 0 <= D <= N-1.
   20199             :             D<0 will cause an error.
   20200             :             D>=N it will be replaced with D=N-1.
   20201             :             if you don't know what D to choose, use small value about 3-5.
   20202             : 
   20203             : Output parameters:
   20204             :     B   -   barycentric interpolant.
   20205             : 
   20206             : Note:
   20207             :     this algorithm always succeeds and calculates the weights  with  close
   20208             :     to machine precision.
   20209             : 
   20210             :   -- ALGLIB PROJECT --
   20211             :      Copyright 17.06.2007 by Bochkanov Sergey
   20212             : *************************************************************************/
   20213           0 : void barycentricbuildfloaterhormann(/* Real    */ ae_vector* x,
   20214             :      /* Real    */ ae_vector* y,
   20215             :      ae_int_t n,
   20216             :      ae_int_t d,
   20217             :      barycentricinterpolant* b,
   20218             :      ae_state *_state)
   20219             : {
   20220             :     ae_frame _frame_block;
   20221             :     double s0;
   20222             :     double s;
   20223             :     double v;
   20224             :     ae_int_t i;
   20225             :     ae_int_t j;
   20226             :     ae_int_t k;
   20227             :     ae_vector perm;
   20228             :     ae_vector wtemp;
   20229             :     ae_vector sortrbuf;
   20230             :     ae_vector sortrbuf2;
   20231             : 
   20232           0 :     ae_frame_make(_state, &_frame_block);
   20233           0 :     memset(&perm, 0, sizeof(perm));
   20234           0 :     memset(&wtemp, 0, sizeof(wtemp));
   20235           0 :     memset(&sortrbuf, 0, sizeof(sortrbuf));
   20236           0 :     memset(&sortrbuf2, 0, sizeof(sortrbuf2));
   20237           0 :     _barycentricinterpolant_clear(b);
   20238           0 :     ae_vector_init(&perm, 0, DT_INT, _state, ae_true);
   20239           0 :     ae_vector_init(&wtemp, 0, DT_REAL, _state, ae_true);
   20240           0 :     ae_vector_init(&sortrbuf, 0, DT_REAL, _state, ae_true);
   20241           0 :     ae_vector_init(&sortrbuf2, 0, DT_REAL, _state, ae_true);
   20242             : 
   20243           0 :     ae_assert(n>0, "BarycentricFloaterHormann: N<=0!", _state);
   20244           0 :     ae_assert(d>=0, "BarycentricFloaterHormann: incorrect D!", _state);
   20245             :     
   20246             :     /*
   20247             :      * Prepare
   20248             :      */
   20249           0 :     if( d>n-1 )
   20250             :     {
   20251           0 :         d = n-1;
   20252             :     }
   20253           0 :     b->n = n;
   20254             :     
   20255             :     /*
   20256             :      * special case: N=1
   20257             :      */
   20258           0 :     if( n==1 )
   20259             :     {
   20260           0 :         ae_vector_set_length(&b->x, n, _state);
   20261           0 :         ae_vector_set_length(&b->y, n, _state);
   20262           0 :         ae_vector_set_length(&b->w, n, _state);
   20263           0 :         b->x.ptr.p_double[0] = x->ptr.p_double[0];
   20264           0 :         b->y.ptr.p_double[0] = y->ptr.p_double[0];
   20265           0 :         b->w.ptr.p_double[0] = (double)(1);
   20266           0 :         ratint_barycentricnormalize(b, _state);
   20267           0 :         ae_frame_leave(_state);
   20268           0 :         return;
   20269             :     }
   20270             :     
   20271             :     /*
   20272             :      * Fill X/Y
   20273             :      */
   20274           0 :     ae_vector_set_length(&b->x, n, _state);
   20275           0 :     ae_vector_set_length(&b->y, n, _state);
   20276           0 :     ae_v_move(&b->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
   20277           0 :     ae_v_move(&b->y.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
   20278           0 :     tagsortfastr(&b->x, &b->y, &sortrbuf, &sortrbuf2, n, _state);
   20279             :     
   20280             :     /*
   20281             :      * Calculate Wk
   20282             :      */
   20283           0 :     ae_vector_set_length(&b->w, n, _state);
   20284           0 :     s0 = (double)(1);
   20285           0 :     for(k=1; k<=d; k++)
   20286             :     {
   20287           0 :         s0 = -s0;
   20288             :     }
   20289           0 :     for(k=0; k<=n-1; k++)
   20290             :     {
   20291             :         
   20292             :         /*
   20293             :          * Wk
   20294             :          */
   20295           0 :         s = (double)(0);
   20296           0 :         for(i=ae_maxint(k-d, 0, _state); i<=ae_minint(k, n-1-d, _state); i++)
   20297             :         {
   20298           0 :             v = (double)(1);
   20299           0 :             for(j=i; j<=i+d; j++)
   20300             :             {
   20301           0 :                 if( j!=k )
   20302             :                 {
   20303           0 :                     v = v/ae_fabs(b->x.ptr.p_double[k]-b->x.ptr.p_double[j], _state);
   20304             :                 }
   20305             :             }
   20306           0 :             s = s+v;
   20307             :         }
   20308           0 :         b->w.ptr.p_double[k] = s0*s;
   20309             :         
   20310             :         /*
   20311             :          * Next S0
   20312             :          */
   20313           0 :         s0 = -s0;
   20314             :     }
   20315             :     
   20316             :     /*
   20317             :      * Normalize
   20318             :      */
   20319           0 :     ratint_barycentricnormalize(b, _state);
   20320           0 :     ae_frame_leave(_state);
   20321             : }
   20322             : 
   20323             : 
   20324             : /*************************************************************************
   20325             : Copying of the barycentric interpolant (for internal use only)
   20326             : 
   20327             : INPUT PARAMETERS:
   20328             :     B   -   barycentric interpolant
   20329             : 
   20330             : OUTPUT PARAMETERS:
   20331             :     B2  -   copy(B1)
   20332             : 
   20333             :   -- ALGLIB --
   20334             :      Copyright 17.08.2009 by Bochkanov Sergey
   20335             : *************************************************************************/
   20336           0 : void barycentriccopy(barycentricinterpolant* b,
   20337             :      barycentricinterpolant* b2,
   20338             :      ae_state *_state)
   20339             : {
   20340             : 
   20341           0 :     _barycentricinterpolant_clear(b2);
   20342             : 
   20343           0 :     b2->n = b->n;
   20344           0 :     b2->sy = b->sy;
   20345           0 :     ae_vector_set_length(&b2->x, b2->n, _state);
   20346           0 :     ae_vector_set_length(&b2->y, b2->n, _state);
   20347           0 :     ae_vector_set_length(&b2->w, b2->n, _state);
   20348           0 :     ae_v_move(&b2->x.ptr.p_double[0], 1, &b->x.ptr.p_double[0], 1, ae_v_len(0,b2->n-1));
   20349           0 :     ae_v_move(&b2->y.ptr.p_double[0], 1, &b->y.ptr.p_double[0], 1, ae_v_len(0,b2->n-1));
   20350           0 :     ae_v_move(&b2->w.ptr.p_double[0], 1, &b->w.ptr.p_double[0], 1, ae_v_len(0,b2->n-1));
   20351           0 : }
   20352             : 
   20353             : 
   20354             : /*************************************************************************
   20355             : Normalization of barycentric interpolant:
   20356             : * B.N, B.X, B.Y and B.W are initialized
   20357             : * B.SY is NOT initialized
   20358             : * Y[] is normalized, scaling coefficient is stored in B.SY
   20359             : * W[] is normalized, no scaling coefficient is stored
   20360             : * X[] is sorted
   20361             : 
   20362             : Internal subroutine.
   20363             : *************************************************************************/
   20364           0 : static void ratint_barycentricnormalize(barycentricinterpolant* b,
   20365             :      ae_state *_state)
   20366             : {
   20367             :     ae_frame _frame_block;
   20368             :     ae_vector p1;
   20369             :     ae_vector p2;
   20370             :     ae_int_t i;
   20371             :     ae_int_t j;
   20372             :     ae_int_t j2;
   20373             :     double v;
   20374             : 
   20375           0 :     ae_frame_make(_state, &_frame_block);
   20376           0 :     memset(&p1, 0, sizeof(p1));
   20377           0 :     memset(&p2, 0, sizeof(p2));
   20378           0 :     ae_vector_init(&p1, 0, DT_INT, _state, ae_true);
   20379           0 :     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
   20380             : 
   20381             :     
   20382             :     /*
   20383             :      * Normalize task: |Y|<=1, |W|<=1, sort X[]
   20384             :      */
   20385           0 :     b->sy = (double)(0);
   20386           0 :     for(i=0; i<=b->n-1; i++)
   20387             :     {
   20388           0 :         b->sy = ae_maxreal(b->sy, ae_fabs(b->y.ptr.p_double[i], _state), _state);
   20389             :     }
   20390           0 :     if( ae_fp_greater(b->sy,(double)(0))&&ae_fp_greater(ae_fabs(b->sy-1, _state),10*ae_machineepsilon) )
   20391             :     {
   20392           0 :         v = 1/b->sy;
   20393           0 :         ae_v_muld(&b->y.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v);
   20394             :     }
   20395           0 :     v = (double)(0);
   20396           0 :     for(i=0; i<=b->n-1; i++)
   20397             :     {
   20398           0 :         v = ae_maxreal(v, ae_fabs(b->w.ptr.p_double[i], _state), _state);
   20399             :     }
   20400           0 :     if( ae_fp_greater(v,(double)(0))&&ae_fp_greater(ae_fabs(v-1, _state),10*ae_machineepsilon) )
   20401             :     {
   20402           0 :         v = 1/v;
   20403           0 :         ae_v_muld(&b->w.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v);
   20404             :     }
   20405           0 :     for(i=0; i<=b->n-2; i++)
   20406             :     {
   20407           0 :         if( ae_fp_less(b->x.ptr.p_double[i+1],b->x.ptr.p_double[i]) )
   20408             :         {
   20409           0 :             tagsort(&b->x, b->n, &p1, &p2, _state);
   20410           0 :             for(j=0; j<=b->n-1; j++)
   20411             :             {
   20412           0 :                 j2 = p2.ptr.p_int[j];
   20413           0 :                 v = b->y.ptr.p_double[j];
   20414           0 :                 b->y.ptr.p_double[j] = b->y.ptr.p_double[j2];
   20415           0 :                 b->y.ptr.p_double[j2] = v;
   20416           0 :                 v = b->w.ptr.p_double[j];
   20417           0 :                 b->w.ptr.p_double[j] = b->w.ptr.p_double[j2];
   20418           0 :                 b->w.ptr.p_double[j2] = v;
   20419             :             }
   20420           0 :             break;
   20421             :         }
   20422             :     }
   20423           0 :     ae_frame_leave(_state);
   20424           0 : }
   20425             : 
   20426             : 
   20427           0 : void _barycentricinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
   20428             : {
   20429           0 :     barycentricinterpolant *p = (barycentricinterpolant*)_p;
   20430           0 :     ae_touch_ptr((void*)p);
   20431           0 :     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
   20432           0 :     ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic);
   20433           0 :     ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic);
   20434           0 : }
   20435             : 
   20436             : 
   20437           0 : void _barycentricinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   20438             : {
   20439           0 :     barycentricinterpolant *dst = (barycentricinterpolant*)_dst;
   20440           0 :     barycentricinterpolant *src = (barycentricinterpolant*)_src;
   20441           0 :     dst->n = src->n;
   20442           0 :     dst->sy = src->sy;
   20443           0 :     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
   20444           0 :     ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic);
   20445           0 :     ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic);
   20446           0 : }
   20447             : 
   20448             : 
   20449           0 : void _barycentricinterpolant_clear(void* _p)
   20450             : {
   20451           0 :     barycentricinterpolant *p = (barycentricinterpolant*)_p;
   20452           0 :     ae_touch_ptr((void*)p);
   20453           0 :     ae_vector_clear(&p->x);
   20454           0 :     ae_vector_clear(&p->y);
   20455           0 :     ae_vector_clear(&p->w);
   20456           0 : }
   20457             : 
   20458             : 
   20459           0 : void _barycentricinterpolant_destroy(void* _p)
   20460             : {
   20461           0 :     barycentricinterpolant *p = (barycentricinterpolant*)_p;
   20462           0 :     ae_touch_ptr((void*)p);
   20463           0 :     ae_vector_destroy(&p->x);
   20464           0 :     ae_vector_destroy(&p->y);
   20465           0 :     ae_vector_destroy(&p->w);
   20466           0 : }
   20467             : 
   20468             : 
   20469             : #endif
   20470             : #if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD)
   20471             : 
   20472             : 
   20473             : /*************************************************************************
   20474             : Fits least squares (LS) circle (or NX-dimensional sphere) to data  (a  set
   20475             : of points in NX-dimensional space).
   20476             : 
   20477             : Least squares circle minimizes sum of squared deviations between distances
   20478             : from points to the center and  some  "candidate"  radius,  which  is  also
   20479             : fitted to the data.
   20480             : 
   20481             : INPUT PARAMETERS:
   20482             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
   20483             :                 One row = one point in NX-dimensional space.
   20484             :     NPoints -   dataset size, NPoints>0
   20485             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
   20486             : 
   20487             : OUTPUT PARAMETERS:
   20488             :     CX      -   central point for a sphere
   20489             :     R       -   radius
   20490             :                                     
   20491             :   -- ALGLIB --
   20492             :      Copyright 07.05.2018 by Bochkanov Sergey
   20493             : *************************************************************************/
   20494           0 : void fitspherels(/* Real    */ ae_matrix* xy,
   20495             :      ae_int_t npoints,
   20496             :      ae_int_t nx,
   20497             :      /* Real    */ ae_vector* cx,
   20498             :      double* r,
   20499             :      ae_state *_state)
   20500             : {
   20501             :     double dummy;
   20502             : 
   20503           0 :     ae_vector_clear(cx);
   20504           0 :     *r = 0;
   20505             : 
   20506           0 :     fitspherex(xy, npoints, nx, 0, 0.0, 0, 0.0, cx, &dummy, r, _state);
   20507           0 : }
   20508             : 
   20509             : 
   20510             : /*************************************************************************
   20511             : Fits minimum circumscribed (MC) circle (or NX-dimensional sphere) to  data
   20512             : (a set of points in NX-dimensional space).
   20513             : 
   20514             : INPUT PARAMETERS:
   20515             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
   20516             :                 One row = one point in NX-dimensional space.
   20517             :     NPoints -   dataset size, NPoints>0
   20518             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
   20519             : 
   20520             : OUTPUT PARAMETERS:
   20521             :     CX      -   central point for a sphere
   20522             :     RHi     -   radius
   20523             : 
   20524             : NOTE: this function is an easy-to-use wrapper around more powerful "expert"
   20525             :       function fitspherex().
   20526             :       
   20527             :       This  wrapper  is optimized  for  ease of use and stability - at the
   20528             :       cost of somewhat lower  performance  (we  have  to  use  very  tight
   20529             :       stopping criteria for inner optimizer because we want to  make  sure
   20530             :       that it will converge on any dataset).
   20531             :       
   20532             :       If you are ready to experiment with settings of  "expert"  function,
   20533             :       you can achieve ~2-4x speedup over standard "bulletproof" settings.
   20534             : 
   20535             :                                     
   20536             :   -- ALGLIB --
   20537             :      Copyright 14.04.2017 by Bochkanov Sergey
   20538             : *************************************************************************/
   20539           0 : void fitspheremc(/* Real    */ ae_matrix* xy,
   20540             :      ae_int_t npoints,
   20541             :      ae_int_t nx,
   20542             :      /* Real    */ ae_vector* cx,
   20543             :      double* rhi,
   20544             :      ae_state *_state)
   20545             : {
   20546             :     double dummy;
   20547             : 
   20548           0 :     ae_vector_clear(cx);
   20549           0 :     *rhi = 0;
   20550             : 
   20551           0 :     fitspherex(xy, npoints, nx, 1, 0.0, 0, 0.0, cx, &dummy, rhi, _state);
   20552           0 : }
   20553             : 
   20554             : 
   20555             : /*************************************************************************
   20556             : Fits maximum inscribed circle (or NX-dimensional sphere) to data (a set of
   20557             : points in NX-dimensional space).
   20558             : 
   20559             : INPUT PARAMETERS:
   20560             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
   20561             :                 One row = one point in NX-dimensional space.
   20562             :     NPoints -   dataset size, NPoints>0
   20563             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
   20564             : 
   20565             : OUTPUT PARAMETERS:
   20566             :     CX      -   central point for a sphere
   20567             :     RLo     -   radius
   20568             : 
   20569             : NOTE: this function is an easy-to-use wrapper around more powerful "expert"
   20570             :       function fitspherex().
   20571             :       
   20572             :       This  wrapper  is optimized  for  ease of use and stability - at the
   20573             :       cost of somewhat lower  performance  (we  have  to  use  very  tight
   20574             :       stopping criteria for inner optimizer because we want to  make  sure
   20575             :       that it will converge on any dataset).
   20576             :       
   20577             :       If you are ready to experiment with settings of  "expert"  function,
   20578             :       you can achieve ~2-4x speedup over standard "bulletproof" settings.
   20579             : 
   20580             :                                     
   20581             :   -- ALGLIB --
   20582             :      Copyright 14.04.2017 by Bochkanov Sergey
   20583             : *************************************************************************/
   20584           0 : void fitspheremi(/* Real    */ ae_matrix* xy,
   20585             :      ae_int_t npoints,
   20586             :      ae_int_t nx,
   20587             :      /* Real    */ ae_vector* cx,
   20588             :      double* rlo,
   20589             :      ae_state *_state)
   20590             : {
   20591             :     double dummy;
   20592             : 
   20593           0 :     ae_vector_clear(cx);
   20594           0 :     *rlo = 0;
   20595             : 
   20596           0 :     fitspherex(xy, npoints, nx, 2, 0.0, 0, 0.0, cx, rlo, &dummy, _state);
   20597           0 : }
   20598             : 
   20599             : 
   20600             : /*************************************************************************
   20601             : Fits minimum zone circle (or NX-dimensional sphere)  to  data  (a  set  of
   20602             : points in NX-dimensional space).
   20603             : 
   20604             : INPUT PARAMETERS:
   20605             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
   20606             :                 One row = one point in NX-dimensional space.
   20607             :     NPoints -   dataset size, NPoints>0
   20608             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
   20609             : 
   20610             : OUTPUT PARAMETERS:
   20611             :     CX      -   central point for a sphere
   20612             :     RLo     -   radius of inscribed circle
   20613             :     RHo     -   radius of circumscribed circle
   20614             : 
   20615             : NOTE: this function is an easy-to-use wrapper around more powerful "expert"
   20616             :       function fitspherex().
   20617             :       
   20618             :       This  wrapper  is optimized  for  ease of use and stability - at the
   20619             :       cost of somewhat lower  performance  (we  have  to  use  very  tight
   20620             :       stopping criteria for inner optimizer because we want to  make  sure
   20621             :       that it will converge on any dataset).
   20622             :       
   20623             :       If you are ready to experiment with settings of  "expert"  function,
   20624             :       you can achieve ~2-4x speedup over standard "bulletproof" settings.
   20625             : 
   20626             :                                     
   20627             :   -- ALGLIB --
   20628             :      Copyright 14.04.2017 by Bochkanov Sergey
   20629             : *************************************************************************/
   20630           0 : void fitspheremz(/* Real    */ ae_matrix* xy,
   20631             :      ae_int_t npoints,
   20632             :      ae_int_t nx,
   20633             :      /* Real    */ ae_vector* cx,
   20634             :      double* rlo,
   20635             :      double* rhi,
   20636             :      ae_state *_state)
   20637             : {
   20638             : 
   20639           0 :     ae_vector_clear(cx);
   20640           0 :     *rlo = 0;
   20641           0 :     *rhi = 0;
   20642             : 
   20643           0 :     fitspherex(xy, npoints, nx, 3, 0.0, 0, 0.0, cx, rlo, rhi, _state);
   20644           0 : }
   20645             : 
   20646             : 
   20647             : /*************************************************************************
   20648             : Fitting minimum circumscribed, maximum inscribed or minimum  zone  circles
   20649             : (or NX-dimensional spheres)  to  data  (a  set of points in NX-dimensional
   20650             : space).
   20651             : 
   20652             : This  is  expert  function  which  allows  to  tweak  many  parameters  of
   20653             : underlying nonlinear solver:
   20654             : * stopping criteria for inner iterations
   20655             : * number of outer iterations
   20656             : * penalty coefficient used to handle  nonlinear  constraints  (we  convert
   20657             :   unconstrained nonsmooth optimization problem ivolving max() and/or min()
   20658             :   operations to quadratically constrained smooth one).
   20659             : 
   20660             : You may tweak all these parameters or only some  of  them,  leaving  other
   20661             : ones at their default state - just specify zero  value,  and  solver  will
   20662             : fill it with appropriate default one.
   20663             : 
   20664             : These comments also include some discussion of  approach  used  to  handle
   20665             : such unusual fitting problem,  its  stability,  drawbacks  of  alternative
   20666             : methods, and convergence properties.
   20667             :   
   20668             : INPUT PARAMETERS:
   20669             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
   20670             :                 One row = one point in NX-dimensional space.
   20671             :     NPoints -   dataset size, NPoints>0
   20672             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
   20673             :     ProblemType-used to encode problem type:
   20674             :                 * 0 for least squares circle
   20675             :                 * 1 for minimum circumscribed circle/sphere fitting (MC)
   20676             :                 * 2 for  maximum inscribed circle/sphere fitting (MI)
   20677             :                 * 3 for minimum zone circle fitting (difference between
   20678             :                     Rhi and Rlo is minimized), denoted as MZ
   20679             :     EpsX    -   stopping condition for NLC optimizer:
   20680             :                 * must be non-negative
   20681             :                 * use 0 to choose default value (1.0E-12 is used by default)
   20682             :                 * you may specify larger values, up to 1.0E-6, if you want
   20683             :                   to   speed-up   solver;   NLC   solver  performs several
   20684             :                   preconditioned  outer  iterations,   so   final   result
   20685             :                   typically has precision much better than EpsX.
   20686             :     AULIts  -   number of outer iterations performed by NLC optimizer:
   20687             :                 * must be non-negative
   20688             :                 * use 0 to choose default value (20 is used by default)
   20689             :                 * you may specify values smaller than 20 if you want to
   20690             :                   speed up solver; 10 often results in good combination of
   20691             :                   precision and speed; sometimes you may get good results
   20692             :                   with just 6 outer iterations.
   20693             :                 Ignored for ProblemType=0.
   20694             :     Penalty -   penalty coefficient for NLC optimizer:
   20695             :                 * must be non-negative
   20696             :                 * use 0 to choose default value (1.0E6 in current version)
   20697             :                 * it should be really large, 1.0E6...1.0E7 is a good value
   20698             :                   to start from;
   20699             :                 * generally, default value is good enough
   20700             :                 Ignored for ProblemType=0.
   20701             : 
   20702             : OUTPUT PARAMETERS:
   20703             :     CX      -   central point for a sphere
   20704             :     RLo     -   radius:
   20705             :                 * for ProblemType=2,3, radius of the inscribed sphere
   20706             :                 * for ProblemType=0 - radius of the least squares sphere
   20707             :                 * for ProblemType=1 - zero
   20708             :     RHo     -   radius:
   20709             :                 * for ProblemType=1,3, radius of the circumscribed sphere
   20710             :                 * for ProblemType=0 - radius of the least squares sphere
   20711             :                 * for ProblemType=2 - zero
   20712             : 
   20713             : NOTE: ON THE UNIQUENESS OF SOLUTIONS
   20714             : 
   20715             : ALGLIB provides solution to several related circle fitting  problems:   MC
   20716             : (minimum circumscribed), MI (maximum inscribed)   and   MZ  (minimum zone)
   20717             : fitting, LS (least squares) fitting.
   20718             : 
   20719             : It  is  important  to  note  that  among these problems only MC and LS are
   20720             : convex and have unique solution independently from starting point.
   20721             : 
   20722             : As  for MI,  it  may (or  may  not, depending on dataset properties)  have
   20723             : multiple solutions, and it always  has  one degenerate solution C=infinity
   20724             : which corresponds to infinitely large radius. Thus, there are no guarantees
   20725             : that solution to  MI returned by this solver will be the best one (and  no
   20726             : one can provide you with such guarantee because problem is  NP-hard).  The
   20727             : only guarantee you have is that this solution is locally optimal, i.e.  it
   20728             : can not be improved by infinitesimally small tweaks in the parameters.
   20729             : 
   20730             : It  is  also  possible  to "run away" to infinity when  started  from  bad
   20731             : initial point located outside of point cloud (or when point cloud does not
   20732             : span entire circumference/surface of the sphere).
   20733             : 
   20734             : Finally,  MZ (minimum zone circle) stands somewhere between MC  and  MI in
   20735             : stability. It is somewhat regularized by "circumscribed" term of the merit
   20736             : function; however, solutions to  MZ may be non-unique, and in some unlucky
   20737             : cases it is also possible to "run away to infinity".
   20738             : 
   20739             : 
   20740             : NOTE: ON THE NONLINEARLY CONSTRAINED PROGRAMMING APPROACH
   20741             : 
   20742             : The problem formulation for MC  (minimum circumscribed   circle;  for  the
   20743             : sake of simplicity we omit MZ and MI here) is:
   20744             : 
   20745             :         [     [         ]2 ]
   20746             :     min [ max [ XY[i]-C ]  ]
   20747             :      C  [  i  [         ]  ]
   20748             : 
   20749             : i.e. it is unconstrained nonsmooth optimization problem of finding  "best"
   20750             : central point, with radius R being unambiguously  determined  from  C.  In
   20751             : order to move away from non-smoothness we use following reformulation:
   20752             : 
   20753             :         [   ]                  [         ]2
   20754             :     min [ R ] subject to R>=0, [ XY[i]-C ]  <= R^2
   20755             :     C,R [   ]                  [         ]
   20756             :     
   20757             : i.e. it becomes smooth quadratically constrained optimization problem with
   20758             : linear target function. Such problem statement is 100% equivalent  to  the
   20759             : original nonsmooth one, but much easier  to  approach.  We solve  it  with
   20760             : MinNLC solver provided by ALGLIB.
   20761             : 
   20762             : 
   20763             : NOTE: ON INSTABILITY OF SEQUENTIAL LINEARIZATION APPROACH
   20764             : 
   20765             : ALGLIB  has  nonlinearly  constrained  solver which proved to be stable on
   20766             : such problems. However, some authors proposed to linearize constraints  in
   20767             : the vicinity of current approximation (Ci,Ri) and to get next  approximate
   20768             : solution (Ci+1,Ri+1) as solution to linear programming problem. Obviously,
   20769             : LP problems are easier than nonlinearly constrained ones.
   20770             : 
   20771             : Indeed,  such approach  to   MC/MI/MZ   resulted   in  ~10-20x increase in
   20772             : performance (when compared with NLC solver). However, it turned  out  that
   20773             : in some cases linearized model fails to predict correct direction for next
   20774             : step and tells us that we converged to solution even when we are still 2-4
   20775             : digits of precision away from it.
   20776             : 
   20777             : It is important that it is not failure of LP solver - it is failure of the
   20778             : linear model;  even  when  solved  exactly,  it  fails  to  handle  subtle
   20779             : nonlinearities which arise near the solution. We validated it by comparing
   20780             : results returned by ALGLIB linear solver with that of MATLAB.
   20781             : 
   20782             : In our experiments with linearization:
   20783             : * MC failed most often, at both realistic and synthetic datasets
   20784             : * MI sometimes failed, but sometimes succeeded
   20785             : * MZ often  succeeded; our guess is that presence of two independent  sets
   20786             :   of constraints (one set for Rlo and another one for Rhi) and  two  terms
   20787             :   in the target function (Rlo and Rhi) regularizes task,  so  when  linear
   20788             :   model fails to handle nonlinearities from Rlo, it uses  Rhi  as  a  hint
   20789             :   (and vice versa).
   20790             :   
   20791             : Because linearization approach failed to achieve stable results, we do not
   20792             : include it in ALGLIB.
   20793             : 
   20794             :                                     
   20795             :   -- ALGLIB --
   20796             :      Copyright 14.04.2017 by Bochkanov Sergey
   20797             : *************************************************************************/
   20798           0 : void fitspherex(/* Real    */ ae_matrix* xy,
   20799             :      ae_int_t npoints,
   20800             :      ae_int_t nx,
   20801             :      ae_int_t problemtype,
   20802             :      double epsx,
   20803             :      ae_int_t aulits,
   20804             :      double penalty,
   20805             :      /* Real    */ ae_vector* cx,
   20806             :      double* rlo,
   20807             :      double* rhi,
   20808             :      ae_state *_state)
   20809             : {
   20810             :     ae_frame _frame_block;
   20811             :     fitsphereinternalreport rep;
   20812             : 
   20813           0 :     ae_frame_make(_state, &_frame_block);
   20814           0 :     memset(&rep, 0, sizeof(rep));
   20815           0 :     ae_vector_clear(cx);
   20816           0 :     *rlo = 0;
   20817           0 :     *rhi = 0;
   20818           0 :     _fitsphereinternalreport_init(&rep, _state, ae_true);
   20819             : 
   20820           0 :     ae_assert(ae_isfinite(penalty, _state)&&ae_fp_greater_eq(penalty,(double)(0)), "FitSphereX: Penalty<0 or is not finite", _state);
   20821           0 :     ae_assert(ae_isfinite(epsx, _state)&&ae_fp_greater_eq(epsx,(double)(0)), "FitSphereX: EpsX<0 or is not finite", _state);
   20822           0 :     ae_assert(aulits>=0, "FitSphereX: AULIts<0", _state);
   20823           0 :     fitsphereinternal(xy, npoints, nx, problemtype, 0, epsx, aulits, penalty, cx, rlo, rhi, &rep, _state);
   20824           0 :     ae_frame_leave(_state);
   20825           0 : }
   20826             : 
   20827             : 
   20828             : /*************************************************************************
   20829             : Fitting minimum circumscribed, maximum inscribed or minimum  zone  circles
   20830             : (or NX-dimensional spheres)  to  data  (a  set of points in NX-dimensional
   20831             : space).
   20832             : 
   20833             : Internal computational function.
   20834             : 
   20835             : INPUT PARAMETERS:
   20836             :     XY      -   array[NPoints,NX] (or larger), contains dataset.
   20837             :                 One row = one point in NX-dimensional space.
   20838             :     NPoints -   dataset size, NPoints>0
   20839             :     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
   20840             :     ProblemType-used to encode problem type:
   20841             :                 * 0 for least squares circle
   20842             :                 * 1 for minimum circumscribed circle/sphere fitting (MC)
   20843             :                 * 2 for  maximum inscribed circle/sphere fitting (MI)
   20844             :                 * 3 for minimum zone circle fitting (difference between
   20845             :                     Rhi and Rlo is minimized), denoted as MZ
   20846             :     SolverType- solver to use:
   20847             :                 * 0 use best solver available (1 in current version)
   20848             :                 * 1 use nonlinearly constrained optimization approach, AUL
   20849             :                     (it is roughly 10-20 times  slower  than  SPC-LIN, but
   20850             :                     much more stable)
   20851             :                 * 2 use special fast IMPRECISE solver, SPC-LIN  sequential
   20852             :                     linearization approach; SPC-LIN is fast, but sometimes
   20853             :                     fails to converge with more than 3 digits of precision;
   20854             :                     see comments below.
   20855             :                     NOT RECOMMENDED UNLESS YOU REALLY NEED HIGH PERFORMANCE
   20856             :                     AT THE COST OF SOME PRECISION.
   20857             :                 * 3 use nonlinearly constrained optimization approach, SLP
   20858             :                     (most robust one, but somewhat slower than AUL)
   20859             :                 Ignored for ProblemType=0.
   20860             :     EpsX    -   stopping criteria for SLP and NLC optimizers:
   20861             :                 * must be non-negative
   20862             :                 * use 0 to choose default value (1.0E-12 is used by default)
   20863             :                 * if you use SLP solver, you should use default values
   20864             :                 * if you use NLC solver, you may specify larger values, up
   20865             :                   to 1.0E-6, if you want to speed-up  solver;  NLC  solver
   20866             :                   performs several preconditioned outer iterations, so final
   20867             :                   result typically has precision much better than EpsX.
   20868             :     AULIts  -   number of iterations performed by NLC optimizer:
   20869             :                 * must be non-negative
   20870             :                 * use 0 to choose default value (20 is used by default)
   20871             :                 * you may specify values smaller than 20 if you want to
   20872             :                   speed up solver; 10 often results in good combination of
   20873             :                   precision and speed
   20874             :                 Ignored for ProblemType=0.
   20875             :     Penalty -   penalty coefficient for NLC optimizer (ignored  for  SLP):
   20876             :                 * must be non-negative
   20877             :                 * use 0 to choose default value (1.0E6 in current version)
   20878             :                 * it should be really large, 1.0E6...1.0E7 is a good value
   20879             :                   to start from;
   20880             :                 * generally, default value is good enough
   20881             :                 * ignored by SLP optimizer
   20882             :                 Ignored for ProblemType=0.
   20883             : 
   20884             : OUTPUT PARAMETERS:
   20885             :     CX      -   central point for a sphere
   20886             :     RLo     -   radius:
   20887             :                 * for ProblemType=2,3, radius of the inscribed sphere
   20888             :                 * for ProblemType=0 - radius of the least squares sphere
   20889             :                 * for ProblemType=1 - zero
   20890             :     RHo     -   radius:
   20891             :                 * for ProblemType=1,3, radius of the circumscribed sphere
   20892             :                 * for ProblemType=0 - radius of the least squares sphere
   20893             :                 * for ProblemType=2 - zero
   20894             :                                     
   20895             :   -- ALGLIB --
   20896             :      Copyright 14.04.2017 by Bochkanov Sergey
   20897             : *************************************************************************/
   20898           0 : void fitsphereinternal(/* Real    */ ae_matrix* xy,
   20899             :      ae_int_t npoints,
   20900             :      ae_int_t nx,
   20901             :      ae_int_t problemtype,
   20902             :      ae_int_t solvertype,
   20903             :      double epsx,
   20904             :      ae_int_t aulits,
   20905             :      double penalty,
   20906             :      /* Real    */ ae_vector* cx,
   20907             :      double* rlo,
   20908             :      double* rhi,
   20909             :      fitsphereinternalreport* rep,
   20910             :      ae_state *_state)
   20911             : {
   20912             :     ae_frame _frame_block;
   20913             :     ae_int_t i;
   20914             :     ae_int_t j;
   20915             :     double v;
   20916             :     double vv;
   20917             :     ae_int_t cpr;
   20918             :     ae_bool userlo;
   20919             :     ae_bool userhi;
   20920             :     double vlo;
   20921             :     double vhi;
   20922             :     ae_vector vmin;
   20923             :     ae_vector vmax;
   20924             :     double spread;
   20925             :     ae_vector pcr;
   20926             :     ae_vector scr;
   20927             :     ae_vector bl;
   20928             :     ae_vector bu;
   20929             :     ae_int_t suboffset;
   20930             :     ae_int_t dstrow;
   20931             :     minnlcstate nlcstate;
   20932             :     minnlcreport nlcrep;
   20933             :     ae_matrix cmatrix;
   20934             :     ae_vector ct;
   20935             :     ae_int_t outeridx;
   20936             :     ae_int_t maxouterits;
   20937             :     ae_int_t maxits;
   20938             :     double safeguard;
   20939             :     double bi;
   20940             :     minbleicstate blcstate;
   20941             :     minbleicreport blcrep;
   20942             :     ae_vector prevc;
   20943             :     minlmstate lmstate;
   20944             :     minlmreport lmrep;
   20945             : 
   20946           0 :     ae_frame_make(_state, &_frame_block);
   20947           0 :     memset(&vmin, 0, sizeof(vmin));
   20948           0 :     memset(&vmax, 0, sizeof(vmax));
   20949           0 :     memset(&pcr, 0, sizeof(pcr));
   20950           0 :     memset(&scr, 0, sizeof(scr));
   20951           0 :     memset(&bl, 0, sizeof(bl));
   20952           0 :     memset(&bu, 0, sizeof(bu));
   20953           0 :     memset(&nlcstate, 0, sizeof(nlcstate));
   20954           0 :     memset(&nlcrep, 0, sizeof(nlcrep));
   20955           0 :     memset(&cmatrix, 0, sizeof(cmatrix));
   20956           0 :     memset(&ct, 0, sizeof(ct));
   20957           0 :     memset(&blcstate, 0, sizeof(blcstate));
   20958           0 :     memset(&blcrep, 0, sizeof(blcrep));
   20959           0 :     memset(&prevc, 0, sizeof(prevc));
   20960           0 :     memset(&lmstate, 0, sizeof(lmstate));
   20961           0 :     memset(&lmrep, 0, sizeof(lmrep));
   20962           0 :     ae_vector_clear(cx);
   20963           0 :     *rlo = 0;
   20964           0 :     *rhi = 0;
   20965           0 :     _fitsphereinternalreport_clear(rep);
   20966           0 :     ae_vector_init(&vmin, 0, DT_REAL, _state, ae_true);
   20967           0 :     ae_vector_init(&vmax, 0, DT_REAL, _state, ae_true);
   20968           0 :     ae_vector_init(&pcr, 0, DT_REAL, _state, ae_true);
   20969           0 :     ae_vector_init(&scr, 0, DT_REAL, _state, ae_true);
   20970           0 :     ae_vector_init(&bl, 0, DT_REAL, _state, ae_true);
   20971           0 :     ae_vector_init(&bu, 0, DT_REAL, _state, ae_true);
   20972           0 :     _minnlcstate_init(&nlcstate, _state, ae_true);
   20973           0 :     _minnlcreport_init(&nlcrep, _state, ae_true);
   20974           0 :     ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true);
   20975           0 :     ae_vector_init(&ct, 0, DT_INT, _state, ae_true);
   20976           0 :     _minbleicstate_init(&blcstate, _state, ae_true);
   20977           0 :     _minbleicreport_init(&blcrep, _state, ae_true);
   20978           0 :     ae_vector_init(&prevc, 0, DT_REAL, _state, ae_true);
   20979           0 :     _minlmstate_init(&lmstate, _state, ae_true);
   20980           0 :     _minlmreport_init(&lmrep, _state, ae_true);
   20981             : 
   20982             :     
   20983             :     /*
   20984             :      * Check input parameters
   20985             :      */
   20986           0 :     ae_assert(npoints>0, "FitSphereX: NPoints<=0", _state);
   20987           0 :     ae_assert(nx>0, "FitSphereX: NX<=0", _state);
   20988           0 :     ae_assert(apservisfinitematrix(xy, npoints, nx, _state), "FitSphereX: XY contains infinite or NAN values", _state);
   20989           0 :     ae_assert(problemtype>=0&&problemtype<=3, "FitSphereX: ProblemType is neither 0, 1, 2 or 3", _state);
   20990           0 :     ae_assert(solvertype>=0&&solvertype<=3, "FitSphereX: ProblemType is neither 1, 2 or 3", _state);
   20991           0 :     ae_assert(ae_isfinite(penalty, _state)&&ae_fp_greater_eq(penalty,(double)(0)), "FitSphereX: Penalty<0 or is not finite", _state);
   20992           0 :     ae_assert(ae_isfinite(epsx, _state)&&ae_fp_greater_eq(epsx,(double)(0)), "FitSphereX: EpsX<0 or is not finite", _state);
   20993           0 :     ae_assert(aulits>=0, "FitSphereX: AULIts<0", _state);
   20994           0 :     if( solvertype==0 )
   20995             :     {
   20996           0 :         solvertype = 1;
   20997             :     }
   20998           0 :     if( ae_fp_eq(penalty,(double)(0)) )
   20999             :     {
   21000           0 :         penalty = 1.0E6;
   21001             :     }
   21002           0 :     if( ae_fp_eq(epsx,(double)(0)) )
   21003             :     {
   21004           0 :         epsx = 1.0E-12;
   21005             :     }
   21006           0 :     if( aulits==0 )
   21007             :     {
   21008           0 :         aulits = 20;
   21009             :     }
   21010           0 :     safeguard = (double)(10);
   21011           0 :     maxouterits = 10;
   21012           0 :     maxits = 10000;
   21013           0 :     rep->nfev = 0;
   21014           0 :     rep->iterationscount = 0;
   21015             :     
   21016             :     /*
   21017             :      * Determine initial values, initial estimates and spread of the points
   21018             :      */
   21019           0 :     ae_vector_set_length(&vmin, nx, _state);
   21020           0 :     ae_vector_set_length(&vmax, nx, _state);
   21021           0 :     ae_vector_set_length(cx, nx, _state);
   21022           0 :     for(j=0; j<=nx-1; j++)
   21023             :     {
   21024           0 :         vmin.ptr.p_double[j] = xy->ptr.pp_double[0][j];
   21025           0 :         vmax.ptr.p_double[j] = xy->ptr.pp_double[0][j];
   21026           0 :         cx->ptr.p_double[j] = (double)(0);
   21027             :     }
   21028           0 :     for(i=0; i<=npoints-1; i++)
   21029             :     {
   21030           0 :         for(j=0; j<=nx-1; j++)
   21031             :         {
   21032           0 :             cx->ptr.p_double[j] = cx->ptr.p_double[j]+xy->ptr.pp_double[i][j];
   21033           0 :             vmin.ptr.p_double[j] = ae_minreal(vmin.ptr.p_double[j], xy->ptr.pp_double[i][j], _state);
   21034           0 :             vmax.ptr.p_double[j] = ae_maxreal(vmax.ptr.p_double[j], xy->ptr.pp_double[i][j], _state);
   21035             :         }
   21036             :     }
   21037           0 :     spread = (double)(0);
   21038           0 :     for(j=0; j<=nx-1; j++)
   21039             :     {
   21040           0 :         cx->ptr.p_double[j] = cx->ptr.p_double[j]/npoints;
   21041           0 :         spread = ae_maxreal(spread, vmax.ptr.p_double[j]-vmin.ptr.p_double[j], _state);
   21042             :     }
   21043           0 :     *rlo = ae_maxrealnumber;
   21044           0 :     *rhi = (double)(0);
   21045           0 :     for(i=0; i<=npoints-1; i++)
   21046             :     {
   21047           0 :         v = (double)(0);
   21048           0 :         for(j=0; j<=nx-1; j++)
   21049             :         {
   21050           0 :             v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state);
   21051             :         }
   21052           0 :         v = ae_sqrt(v, _state);
   21053           0 :         *rhi = ae_maxreal(*rhi, v, _state);
   21054           0 :         *rlo = ae_minreal(*rlo, v, _state);
   21055             :     }
   21056             :     
   21057             :     /*
   21058             :      * Handle degenerate case of zero spread
   21059             :      */
   21060           0 :     if( ae_fp_eq(spread,(double)(0)) )
   21061             :     {
   21062           0 :         for(j=0; j<=nx-1; j++)
   21063             :         {
   21064           0 :             cx->ptr.p_double[j] = vmin.ptr.p_double[j];
   21065             :         }
   21066           0 :         *rhi = (double)(0);
   21067           0 :         *rlo = (double)(0);
   21068           0 :         ae_frame_leave(_state);
   21069           0 :         return;
   21070             :     }
   21071             :     
   21072             :     /*
   21073             :      * Prepare initial point for optimizer, scale vector and box constraints
   21074             :      */
   21075           0 :     ae_vector_set_length(&pcr, nx+2, _state);
   21076           0 :     ae_vector_set_length(&scr, nx+2, _state);
   21077           0 :     ae_vector_set_length(&bl, nx+2, _state);
   21078           0 :     ae_vector_set_length(&bu, nx+2, _state);
   21079           0 :     for(j=0; j<=nx-1; j++)
   21080             :     {
   21081           0 :         pcr.ptr.p_double[j] = cx->ptr.p_double[j];
   21082           0 :         scr.ptr.p_double[j] = 0.1*spread;
   21083           0 :         bl.ptr.p_double[j] = cx->ptr.p_double[j]-safeguard*spread;
   21084           0 :         bu.ptr.p_double[j] = cx->ptr.p_double[j]+safeguard*spread;
   21085             :     }
   21086           0 :     pcr.ptr.p_double[nx+0] = *rlo;
   21087           0 :     pcr.ptr.p_double[nx+1] = *rhi;
   21088           0 :     scr.ptr.p_double[nx+0] = 0.5*spread;
   21089           0 :     scr.ptr.p_double[nx+1] = 0.5*spread;
   21090           0 :     bl.ptr.p_double[nx+0] = (double)(0);
   21091           0 :     bl.ptr.p_double[nx+1] = (double)(0);
   21092           0 :     bu.ptr.p_double[nx+0] = safeguard*(*rhi);
   21093           0 :     bu.ptr.p_double[nx+1] = safeguard*(*rhi);
   21094             :     
   21095             :     /*
   21096             :      * First branch: least squares fitting vs MI/MC/MZ fitting
   21097             :      */
   21098           0 :     if( problemtype==0 )
   21099             :     {
   21100             :         
   21101             :         /*
   21102             :          * Solve problem with Levenberg-Marquardt algorithm
   21103             :          */
   21104           0 :         pcr.ptr.p_double[nx] = *rhi;
   21105           0 :         minlmcreatevj(nx+1, npoints, &pcr, &lmstate, _state);
   21106           0 :         minlmsetscale(&lmstate, &scr, _state);
   21107           0 :         minlmsetbc(&lmstate, &bl, &bu, _state);
   21108           0 :         minlmsetcond(&lmstate, epsx, maxits, _state);
   21109           0 :         while(minlmiteration(&lmstate, _state))
   21110             :         {
   21111           0 :             if( lmstate.needfij||lmstate.needfi )
   21112             :             {
   21113           0 :                 inc(&rep->nfev, _state);
   21114           0 :                 for(i=0; i<=npoints-1; i++)
   21115             :                 {
   21116           0 :                     v = (double)(0);
   21117           0 :                     for(j=0; j<=nx-1; j++)
   21118             :                     {
   21119           0 :                         v = v+ae_sqr(lmstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j], _state);
   21120             :                     }
   21121           0 :                     lmstate.fi.ptr.p_double[i] = ae_sqrt(v, _state)-lmstate.x.ptr.p_double[nx];
   21122           0 :                     if( lmstate.needfij )
   21123             :                     {
   21124           0 :                         for(j=0; j<=nx-1; j++)
   21125             :                         {
   21126           0 :                             lmstate.j.ptr.pp_double[i][j] = 0.5/(1.0E-9*spread+ae_sqrt(v, _state))*2*(lmstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j]);
   21127             :                         }
   21128           0 :                         lmstate.j.ptr.pp_double[i][nx] = (double)(-1);
   21129             :                     }
   21130             :                 }
   21131           0 :                 continue;
   21132             :             }
   21133           0 :             ae_assert(ae_false, "Assertion failed", _state);
   21134             :         }
   21135           0 :         minlmresults(&lmstate, &pcr, &lmrep, _state);
   21136           0 :         ae_assert(lmrep.terminationtype>0, "FitSphereX: unexpected failure of LM solver", _state);
   21137           0 :         rep->iterationscount = rep->iterationscount+lmrep.iterationscount;
   21138             :         
   21139             :         /*
   21140             :          * Offload center coordinates from PCR to CX,
   21141             :          * re-calculate exact value of RLo/RHi using CX.
   21142             :          */
   21143           0 :         for(j=0; j<=nx-1; j++)
   21144             :         {
   21145           0 :             cx->ptr.p_double[j] = pcr.ptr.p_double[j];
   21146             :         }
   21147           0 :         vv = (double)(0);
   21148           0 :         for(i=0; i<=npoints-1; i++)
   21149             :         {
   21150           0 :             v = (double)(0);
   21151           0 :             for(j=0; j<=nx-1; j++)
   21152             :             {
   21153           0 :                 v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state);
   21154             :             }
   21155           0 :             v = ae_sqrt(v, _state);
   21156           0 :             vv = vv+v/npoints;
   21157             :         }
   21158           0 :         *rlo = vv;
   21159           0 :         *rhi = vv;
   21160             :     }
   21161             :     else
   21162             :     {
   21163             :         
   21164             :         /*
   21165             :          * MI, MC, MZ fitting.
   21166             :          * Prepare problem metrics
   21167             :          */
   21168           0 :         userlo = problemtype==2||problemtype==3;
   21169           0 :         userhi = problemtype==1||problemtype==3;
   21170           0 :         if( userlo&&userhi )
   21171             :         {
   21172           0 :             cpr = 2;
   21173             :         }
   21174             :         else
   21175             :         {
   21176           0 :             cpr = 1;
   21177             :         }
   21178           0 :         if( userlo )
   21179             :         {
   21180           0 :             vlo = (double)(1);
   21181             :         }
   21182             :         else
   21183             :         {
   21184           0 :             vlo = (double)(0);
   21185             :         }
   21186           0 :         if( userhi )
   21187             :         {
   21188           0 :             vhi = (double)(1);
   21189             :         }
   21190             :         else
   21191             :         {
   21192           0 :             vhi = (double)(0);
   21193             :         }
   21194             :         
   21195             :         /*
   21196             :          * Solve with NLC solver; problem is treated as general nonlinearly constrained
   21197             :          * programming, with augmented Lagrangian solver or SLP being used.
   21198             :          */
   21199           0 :         if( solvertype==1||solvertype==3 )
   21200             :         {
   21201           0 :             minnlccreate(nx+2, &pcr, &nlcstate, _state);
   21202           0 :             minnlcsetscale(&nlcstate, &scr, _state);
   21203           0 :             minnlcsetbc(&nlcstate, &bl, &bu, _state);
   21204           0 :             minnlcsetnlc(&nlcstate, 0, cpr*npoints, _state);
   21205           0 :             minnlcsetcond(&nlcstate, epsx, maxits, _state);
   21206           0 :             minnlcsetprecexactrobust(&nlcstate, 5, _state);
   21207           0 :             minnlcsetstpmax(&nlcstate, 0.1, _state);
   21208           0 :             if( solvertype==1 )
   21209             :             {
   21210           0 :                 minnlcsetalgoaul(&nlcstate, penalty, aulits, _state);
   21211             :             }
   21212             :             else
   21213             :             {
   21214           0 :                 minnlcsetalgoslp(&nlcstate, _state);
   21215             :             }
   21216           0 :             minnlcrestartfrom(&nlcstate, &pcr, _state);
   21217           0 :             while(minnlciteration(&nlcstate, _state))
   21218             :             {
   21219           0 :                 if( nlcstate.needfij )
   21220             :                 {
   21221           0 :                     inc(&rep->nfev, _state);
   21222           0 :                     nlcstate.fi.ptr.p_double[0] = vhi*nlcstate.x.ptr.p_double[nx+1]-vlo*nlcstate.x.ptr.p_double[nx+0];
   21223           0 :                     for(j=0; j<=nx-1; j++)
   21224             :                     {
   21225           0 :                         nlcstate.j.ptr.pp_double[0][j] = (double)(0);
   21226             :                     }
   21227           0 :                     nlcstate.j.ptr.pp_double[0][nx+0] = -1*vlo;
   21228           0 :                     nlcstate.j.ptr.pp_double[0][nx+1] = 1*vhi;
   21229           0 :                     for(i=0; i<=npoints-1; i++)
   21230             :                     {
   21231           0 :                         suboffset = 0;
   21232           0 :                         if( userhi )
   21233             :                         {
   21234           0 :                             dstrow = 1+cpr*i+suboffset;
   21235           0 :                             v = (double)(0);
   21236           0 :                             for(j=0; j<=nx-1; j++)
   21237             :                             {
   21238           0 :                                 vv = nlcstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j];
   21239           0 :                                 v = v+vv*vv;
   21240           0 :                                 nlcstate.j.ptr.pp_double[dstrow][j] = 2*vv;
   21241             :                             }
   21242           0 :                             vv = nlcstate.x.ptr.p_double[nx+1];
   21243           0 :                             v = v-vv*vv;
   21244           0 :                             nlcstate.j.ptr.pp_double[dstrow][nx+0] = (double)(0);
   21245           0 :                             nlcstate.j.ptr.pp_double[dstrow][nx+1] = -2*vv;
   21246           0 :                             nlcstate.fi.ptr.p_double[dstrow] = v;
   21247           0 :                             inc(&suboffset, _state);
   21248             :                         }
   21249           0 :                         if( userlo )
   21250             :                         {
   21251           0 :                             dstrow = 1+cpr*i+suboffset;
   21252           0 :                             v = (double)(0);
   21253           0 :                             for(j=0; j<=nx-1; j++)
   21254             :                             {
   21255           0 :                                 vv = nlcstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j];
   21256           0 :                                 v = v-vv*vv;
   21257           0 :                                 nlcstate.j.ptr.pp_double[dstrow][j] = -2*vv;
   21258             :                             }
   21259           0 :                             vv = nlcstate.x.ptr.p_double[nx+0];
   21260           0 :                             v = v+vv*vv;
   21261           0 :                             nlcstate.j.ptr.pp_double[dstrow][nx+0] = 2*vv;
   21262           0 :                             nlcstate.j.ptr.pp_double[dstrow][nx+1] = (double)(0);
   21263           0 :                             nlcstate.fi.ptr.p_double[dstrow] = v;
   21264           0 :                             inc(&suboffset, _state);
   21265             :                         }
   21266           0 :                         ae_assert(suboffset==cpr, "Assertion failed", _state);
   21267             :                     }
   21268           0 :                     continue;
   21269             :                 }
   21270           0 :                 ae_assert(ae_false, "Assertion failed", _state);
   21271             :             }
   21272           0 :             minnlcresults(&nlcstate, &pcr, &nlcrep, _state);
   21273           0 :             ae_assert(nlcrep.terminationtype>0, "FitSphereX: unexpected failure of NLC solver", _state);
   21274           0 :             rep->iterationscount = rep->iterationscount+nlcrep.iterationscount;
   21275             :             
   21276             :             /*
   21277             :              * Offload center coordinates from PCR to CX,
   21278             :              * re-calculate exact value of RLo/RHi using CX.
   21279             :              */
   21280           0 :             for(j=0; j<=nx-1; j++)
   21281             :             {
   21282           0 :                 cx->ptr.p_double[j] = pcr.ptr.p_double[j];
   21283             :             }
   21284           0 :             *rlo = ae_maxrealnumber;
   21285           0 :             *rhi = (double)(0);
   21286           0 :             for(i=0; i<=npoints-1; i++)
   21287             :             {
   21288           0 :                 v = (double)(0);
   21289           0 :                 for(j=0; j<=nx-1; j++)
   21290             :                 {
   21291           0 :                     v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state);
   21292             :                 }
   21293           0 :                 v = ae_sqrt(v, _state);
   21294           0 :                 *rhi = ae_maxreal(*rhi, v, _state);
   21295           0 :                 *rlo = ae_minreal(*rlo, v, _state);
   21296             :             }
   21297           0 :             if( !userlo )
   21298             :             {
   21299           0 :                 *rlo = (double)(0);
   21300             :             }
   21301           0 :             if( !userhi )
   21302             :             {
   21303           0 :                 *rhi = (double)(0);
   21304             :             }
   21305           0 :             ae_frame_leave(_state);
   21306           0 :             return;
   21307             :         }
   21308             :         
   21309             :         /*
   21310             :          * Solve problem with SLP (sequential LP) approach; this approach
   21311             :          * is much faster than NLP, but often fails for MI and MC (for MZ
   21312             :          * it performs well enough).
   21313             :          *
   21314             :          * REFERENCE: "On a sequential linear programming approach to finding
   21315             :          *            the smallest circumscribed, largest inscribed, and minimum
   21316             :          *            zone circle or sphere", Helmuth Spath and G.A.Watson
   21317             :          */
   21318           0 :         if( solvertype==2 )
   21319             :         {
   21320           0 :             ae_matrix_set_length(&cmatrix, cpr*npoints, nx+3, _state);
   21321           0 :             ae_vector_set_length(&ct, cpr*npoints, _state);
   21322           0 :             ae_vector_set_length(&prevc, nx, _state);
   21323           0 :             minbleiccreate(nx+2, &pcr, &blcstate, _state);
   21324           0 :             minbleicsetscale(&blcstate, &scr, _state);
   21325           0 :             minbleicsetbc(&blcstate, &bl, &bu, _state);
   21326           0 :             minbleicsetcond(&blcstate, (double)(0), (double)(0), epsx, maxits, _state);
   21327           0 :             for(outeridx=0; outeridx<=maxouterits-1; outeridx++)
   21328             :             {
   21329             :                 
   21330             :                 /*
   21331             :                  * Prepare initial point for algorithm; center coordinates at
   21332             :                  * PCR are used to calculate RLo/RHi and update PCR with them.
   21333             :                  */
   21334           0 :                 *rlo = ae_maxrealnumber;
   21335           0 :                 *rhi = (double)(0);
   21336           0 :                 for(i=0; i<=npoints-1; i++)
   21337             :                 {
   21338           0 :                     v = (double)(0);
   21339           0 :                     for(j=0; j<=nx-1; j++)
   21340             :                     {
   21341           0 :                         v = v+ae_sqr(xy->ptr.pp_double[i][j]-pcr.ptr.p_double[j], _state);
   21342             :                     }
   21343           0 :                     v = ae_sqrt(v, _state);
   21344           0 :                     *rhi = ae_maxreal(*rhi, v, _state);
   21345           0 :                     *rlo = ae_minreal(*rlo, v, _state);
   21346             :                 }
   21347           0 :                 pcr.ptr.p_double[nx+0] = *rlo*0.99999;
   21348           0 :                 pcr.ptr.p_double[nx+1] = *rhi/0.99999;
   21349             :                 
   21350             :                 /*
   21351             :                  * Generate matrix of linear constraints
   21352             :                  */
   21353           0 :                 for(i=0; i<=npoints-1; i++)
   21354             :                 {
   21355           0 :                     v = (double)(0);
   21356           0 :                     for(j=0; j<=nx-1; j++)
   21357             :                     {
   21358           0 :                         v = v+ae_sqr(xy->ptr.pp_double[i][j], _state);
   21359             :                     }
   21360           0 :                     bi = -v/2;
   21361           0 :                     suboffset = 0;
   21362           0 :                     if( userhi )
   21363             :                     {
   21364           0 :                         dstrow = cpr*i+suboffset;
   21365           0 :                         for(j=0; j<=nx-1; j++)
   21366             :                         {
   21367           0 :                             cmatrix.ptr.pp_double[dstrow][j] = pcr.ptr.p_double[j]/2-xy->ptr.pp_double[i][j];
   21368             :                         }
   21369           0 :                         cmatrix.ptr.pp_double[dstrow][nx+0] = (double)(0);
   21370           0 :                         cmatrix.ptr.pp_double[dstrow][nx+1] = -*rhi/2;
   21371           0 :                         cmatrix.ptr.pp_double[dstrow][nx+2] = bi;
   21372           0 :                         ct.ptr.p_int[dstrow] = -1;
   21373           0 :                         inc(&suboffset, _state);
   21374             :                     }
   21375           0 :                     if( userlo )
   21376             :                     {
   21377           0 :                         dstrow = cpr*i+suboffset;
   21378           0 :                         for(j=0; j<=nx-1; j++)
   21379             :                         {
   21380           0 :                             cmatrix.ptr.pp_double[dstrow][j] = -(pcr.ptr.p_double[j]/2-xy->ptr.pp_double[i][j]);
   21381             :                         }
   21382           0 :                         cmatrix.ptr.pp_double[dstrow][nx+0] = *rlo/2;
   21383           0 :                         cmatrix.ptr.pp_double[dstrow][nx+1] = (double)(0);
   21384           0 :                         cmatrix.ptr.pp_double[dstrow][nx+2] = -bi;
   21385           0 :                         ct.ptr.p_int[dstrow] = -1;
   21386           0 :                         inc(&suboffset, _state);
   21387             :                     }
   21388           0 :                     ae_assert(suboffset==cpr, "Assertion failed", _state);
   21389             :                 }
   21390             :                 
   21391             :                 /*
   21392             :                  * Solve LP subproblem with MinBLEIC
   21393             :                  */
   21394           0 :                 for(j=0; j<=nx-1; j++)
   21395             :                 {
   21396           0 :                     prevc.ptr.p_double[j] = pcr.ptr.p_double[j];
   21397             :                 }
   21398           0 :                 minbleicsetlc(&blcstate, &cmatrix, &ct, cpr*npoints, _state);
   21399           0 :                 minbleicrestartfrom(&blcstate, &pcr, _state);
   21400           0 :                 while(minbleiciteration(&blcstate, _state))
   21401             :                 {
   21402           0 :                     if( blcstate.needfg )
   21403             :                     {
   21404           0 :                         inc(&rep->nfev, _state);
   21405           0 :                         blcstate.f = vhi*blcstate.x.ptr.p_double[nx+1]-vlo*blcstate.x.ptr.p_double[nx+0];
   21406           0 :                         for(j=0; j<=nx-1; j++)
   21407             :                         {
   21408           0 :                             blcstate.g.ptr.p_double[j] = (double)(0);
   21409             :                         }
   21410           0 :                         blcstate.g.ptr.p_double[nx+0] = -1*vlo;
   21411           0 :                         blcstate.g.ptr.p_double[nx+1] = 1*vhi;
   21412           0 :                         continue;
   21413             :                     }
   21414             :                 }
   21415           0 :                 minbleicresults(&blcstate, &pcr, &blcrep, _state);
   21416           0 :                 ae_assert(blcrep.terminationtype>0, "FitSphereX: unexpected failure of BLEIC solver", _state);
   21417           0 :                 rep->iterationscount = rep->iterationscount+blcrep.iterationscount;
   21418             :                 
   21419             :                 /*
   21420             :                  * Terminate iterations early if we converged
   21421             :                  */
   21422           0 :                 v = (double)(0);
   21423           0 :                 for(j=0; j<=nx-1; j++)
   21424             :                 {
   21425           0 :                     v = v+ae_sqr(prevc.ptr.p_double[j]-pcr.ptr.p_double[j], _state);
   21426             :                 }
   21427           0 :                 v = ae_sqrt(v, _state);
   21428           0 :                 if( ae_fp_less_eq(v,epsx) )
   21429             :                 {
   21430           0 :                     break;
   21431             :                 }
   21432             :             }
   21433             :             
   21434             :             /*
   21435             :              * Offload center coordinates from PCR to CX,
   21436             :              * re-calculate exact value of RLo/RHi using CX.
   21437             :              */
   21438           0 :             for(j=0; j<=nx-1; j++)
   21439             :             {
   21440           0 :                 cx->ptr.p_double[j] = pcr.ptr.p_double[j];
   21441             :             }
   21442           0 :             *rlo = ae_maxrealnumber;
   21443           0 :             *rhi = (double)(0);
   21444           0 :             for(i=0; i<=npoints-1; i++)
   21445             :             {
   21446           0 :                 v = (double)(0);
   21447           0 :                 for(j=0; j<=nx-1; j++)
   21448             :                 {
   21449           0 :                     v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state);
   21450             :                 }
   21451           0 :                 v = ae_sqrt(v, _state);
   21452           0 :                 *rhi = ae_maxreal(*rhi, v, _state);
   21453           0 :                 *rlo = ae_minreal(*rlo, v, _state);
   21454             :             }
   21455           0 :             if( !userlo )
   21456             :             {
   21457           0 :                 *rlo = (double)(0);
   21458             :             }
   21459           0 :             if( !userhi )
   21460             :             {
   21461           0 :                 *rhi = (double)(0);
   21462             :             }
   21463           0 :             ae_frame_leave(_state);
   21464           0 :             return;
   21465             :         }
   21466             :         
   21467             :         /*
   21468             :          * Oooops...!
   21469             :          */
   21470           0 :         ae_assert(ae_false, "FitSphereX: integrity check failed", _state);
   21471             :     }
   21472           0 :     ae_frame_leave(_state);
   21473             : }
   21474             : 
   21475             : 
   21476           0 : void _fitsphereinternalreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
   21477             : {
   21478           0 :     fitsphereinternalreport *p = (fitsphereinternalreport*)_p;
   21479           0 :     ae_touch_ptr((void*)p);
   21480           0 : }
   21481             : 
   21482             : 
   21483           0 : void _fitsphereinternalreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   21484             : {
   21485           0 :     fitsphereinternalreport *dst = (fitsphereinternalreport*)_dst;
   21486           0 :     fitsphereinternalreport *src = (fitsphereinternalreport*)_src;
   21487           0 :     dst->nfev = src->nfev;
   21488           0 :     dst->iterationscount = src->iterationscount;
   21489           0 : }
   21490             : 
   21491             : 
   21492           0 : void _fitsphereinternalreport_clear(void* _p)
   21493             : {
   21494           0 :     fitsphereinternalreport *p = (fitsphereinternalreport*)_p;
   21495           0 :     ae_touch_ptr((void*)p);
   21496           0 : }
   21497             : 
   21498             : 
   21499           0 : void _fitsphereinternalreport_destroy(void* _p)
   21500             : {
   21501           0 :     fitsphereinternalreport *p = (fitsphereinternalreport*)_p;
   21502           0 :     ae_touch_ptr((void*)p);
   21503           0 : }
   21504             : 
   21505             : 
   21506             : #endif
   21507             : #if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD)
   21508             : 
   21509             : 
   21510             : /*************************************************************************
   21511             : Internal subroutine: automatic scaling for LLS tasks.
   21512             : NEVER CALL IT DIRECTLY!
   21513             : 
   21514             : Maps abscissas to [-1,1], standartizes ordinates and correspondingly scales
   21515             : constraints. It also scales weights so that max(W[i])=1
   21516             : 
   21517             : Transformations performed:
   21518             : * X, XC         [XA,XB] => [-1,+1]
   21519             :                 transformation makes min(X)=-1, max(X)=+1
   21520             : 
   21521             : * Y             [SA,SB] => [0,1]
   21522             :                 transformation makes mean(Y)=0, stddev(Y)=1
   21523             :                 
   21524             : * YC            transformed accordingly to SA, SB, DC[I]
   21525             : 
   21526             :   -- ALGLIB PROJECT --
   21527             :      Copyright 08.09.2009 by Bochkanov Sergey
   21528             : *************************************************************************/
   21529           0 : void lsfitscalexy(/* Real    */ ae_vector* x,
   21530             :      /* Real    */ ae_vector* y,
   21531             :      /* Real    */ ae_vector* w,
   21532             :      ae_int_t n,
   21533             :      /* Real    */ ae_vector* xc,
   21534             :      /* Real    */ ae_vector* yc,
   21535             :      /* Integer */ ae_vector* dc,
   21536             :      ae_int_t k,
   21537             :      double* xa,
   21538             :      double* xb,
   21539             :      double* sa,
   21540             :      double* sb,
   21541             :      /* Real    */ ae_vector* xoriginal,
   21542             :      /* Real    */ ae_vector* yoriginal,
   21543             :      ae_state *_state)
   21544             : {
   21545             :     double xmin;
   21546             :     double xmax;
   21547             :     ae_int_t i;
   21548             :     double mx;
   21549             : 
   21550           0 :     *xa = 0;
   21551           0 :     *xb = 0;
   21552           0 :     *sa = 0;
   21553           0 :     *sb = 0;
   21554           0 :     ae_vector_clear(xoriginal);
   21555           0 :     ae_vector_clear(yoriginal);
   21556             : 
   21557           0 :     ae_assert(n>=1, "LSFitScaleXY: incorrect N", _state);
   21558           0 :     ae_assert(k>=0, "LSFitScaleXY: incorrect K", _state);
   21559           0 :     xmin = x->ptr.p_double[0];
   21560           0 :     xmax = x->ptr.p_double[0];
   21561           0 :     for(i=1; i<=n-1; i++)
   21562             :     {
   21563           0 :         xmin = ae_minreal(xmin, x->ptr.p_double[i], _state);
   21564           0 :         xmax = ae_maxreal(xmax, x->ptr.p_double[i], _state);
   21565             :     }
   21566           0 :     for(i=0; i<=k-1; i++)
   21567             :     {
   21568           0 :         xmin = ae_minreal(xmin, xc->ptr.p_double[i], _state);
   21569           0 :         xmax = ae_maxreal(xmax, xc->ptr.p_double[i], _state);
   21570             :     }
   21571           0 :     if( ae_fp_eq(xmin,xmax) )
   21572             :     {
   21573           0 :         if( ae_fp_eq(xmin,(double)(0)) )
   21574             :         {
   21575           0 :             xmin = (double)(-1);
   21576           0 :             xmax = (double)(1);
   21577             :         }
   21578             :         else
   21579             :         {
   21580           0 :             if( ae_fp_greater(xmin,(double)(0)) )
   21581             :             {
   21582           0 :                 xmin = 0.5*xmin;
   21583             :             }
   21584             :             else
   21585             :             {
   21586           0 :                 xmax = 0.5*xmax;
   21587             :             }
   21588             :         }
   21589             :     }
   21590           0 :     ae_vector_set_length(xoriginal, n, _state);
   21591           0 :     ae_v_move(&xoriginal->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
   21592           0 :     *xa = xmin;
   21593           0 :     *xb = xmax;
   21594           0 :     for(i=0; i<=n-1; i++)
   21595             :     {
   21596           0 :         x->ptr.p_double[i] = 2*(x->ptr.p_double[i]-0.5*(*xa+(*xb)))/(*xb-(*xa));
   21597             :     }
   21598           0 :     for(i=0; i<=k-1; i++)
   21599             :     {
   21600           0 :         ae_assert(dc->ptr.p_int[i]>=0, "LSFitScaleXY: internal error!", _state);
   21601           0 :         xc->ptr.p_double[i] = 2*(xc->ptr.p_double[i]-0.5*(*xa+(*xb)))/(*xb-(*xa));
   21602           0 :         yc->ptr.p_double[i] = yc->ptr.p_double[i]*ae_pow(0.5*(*xb-(*xa)), (double)(dc->ptr.p_int[i]), _state);
   21603             :     }
   21604           0 :     ae_vector_set_length(yoriginal, n, _state);
   21605           0 :     ae_v_move(&yoriginal->ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
   21606           0 :     *sa = (double)(0);
   21607           0 :     for(i=0; i<=n-1; i++)
   21608             :     {
   21609           0 :         *sa = *sa+y->ptr.p_double[i];
   21610             :     }
   21611           0 :     *sa = *sa/n;
   21612           0 :     *sb = (double)(0);
   21613           0 :     for(i=0; i<=n-1; i++)
   21614             :     {
   21615           0 :         *sb = *sb+ae_sqr(y->ptr.p_double[i]-(*sa), _state);
   21616             :     }
   21617           0 :     *sb = ae_sqrt(*sb/n, _state)+(*sa);
   21618           0 :     if( ae_fp_eq(*sb,*sa) )
   21619             :     {
   21620           0 :         *sb = 2*(*sa);
   21621             :     }
   21622           0 :     if( ae_fp_eq(*sb,*sa) )
   21623             :     {
   21624           0 :         *sb = *sa+1;
   21625             :     }
   21626           0 :     for(i=0; i<=n-1; i++)
   21627             :     {
   21628           0 :         y->ptr.p_double[i] = (y->ptr.p_double[i]-(*sa))/(*sb-(*sa));
   21629             :     }
   21630           0 :     for(i=0; i<=k-1; i++)
   21631             :     {
   21632           0 :         if( dc->ptr.p_int[i]==0 )
   21633             :         {
   21634           0 :             yc->ptr.p_double[i] = (yc->ptr.p_double[i]-(*sa))/(*sb-(*sa));
   21635             :         }
   21636             :         else
   21637             :         {
   21638           0 :             yc->ptr.p_double[i] = yc->ptr.p_double[i]/(*sb-(*sa));
   21639             :         }
   21640             :     }
   21641           0 :     mx = (double)(0);
   21642           0 :     for(i=0; i<=n-1; i++)
   21643             :     {
   21644           0 :         mx = ae_maxreal(mx, ae_fabs(w->ptr.p_double[i], _state), _state);
   21645             :     }
   21646           0 :     if( ae_fp_neq(mx,(double)(0)) )
   21647             :     {
   21648           0 :         for(i=0; i<=n-1; i++)
   21649             :         {
   21650           0 :             w->ptr.p_double[i] = w->ptr.p_double[i]/mx;
   21651             :         }
   21652             :     }
   21653           0 : }
   21654             : 
   21655             : 
   21656           0 : void buildpriorterm(/* Real    */ ae_matrix* xy,
   21657             :      ae_int_t n,
   21658             :      ae_int_t nx,
   21659             :      ae_int_t ny,
   21660             :      ae_int_t modeltype,
   21661             :      double priorval,
   21662             :      /* Real    */ ae_matrix* v,
   21663             :      ae_state *_state)
   21664             : {
   21665             :     ae_frame _frame_block;
   21666             :     ae_int_t i;
   21667             :     ae_int_t j;
   21668             :     ae_int_t j0;
   21669             :     ae_int_t j1;
   21670             :     double rj;
   21671             :     ae_matrix araw;
   21672             :     ae_matrix amod;
   21673             :     ae_matrix braw;
   21674             :     ae_vector tmp0;
   21675             :     double lambdareg;
   21676             :     ae_int_t rfsits;
   21677             : 
   21678           0 :     ae_frame_make(_state, &_frame_block);
   21679           0 :     memset(&araw, 0, sizeof(araw));
   21680           0 :     memset(&amod, 0, sizeof(amod));
   21681           0 :     memset(&braw, 0, sizeof(braw));
   21682           0 :     memset(&tmp0, 0, sizeof(tmp0));
   21683           0 :     ae_matrix_clear(v);
   21684           0 :     ae_matrix_init(&araw, 0, 0, DT_REAL, _state, ae_true);
   21685           0 :     ae_matrix_init(&amod, 0, 0, DT_REAL, _state, ae_true);
   21686           0 :     ae_matrix_init(&braw, 0, 0, DT_REAL, _state, ae_true);
   21687           0 :     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
   21688             : 
   21689           0 :     ae_assert(n>=0, "BuildPriorTerm: N<0", _state);
   21690           0 :     ae_assert(nx>0, "BuildPriorTerm: NX<=0", _state);
   21691           0 :     ae_assert(ny>0, "BuildPriorTerm: NY<=0", _state);
   21692           0 :     ae_matrix_set_length(v, ny, nx+1, _state);
   21693           0 :     for(i=0; i<=v->rows-1; i++)
   21694             :     {
   21695           0 :         for(j=0; j<=v->cols-1; j++)
   21696             :         {
   21697           0 :             v->ptr.pp_double[i][j] = (double)(0);
   21698             :         }
   21699             :     }
   21700           0 :     if( n==0 )
   21701             :     {
   21702           0 :         if( modeltype==0 )
   21703             :         {
   21704           0 :             for(i=0; i<=ny-1; i++)
   21705             :             {
   21706           0 :                 v->ptr.pp_double[i][nx] = priorval;
   21707             :             }
   21708           0 :             ae_frame_leave(_state);
   21709           0 :             return;
   21710             :         }
   21711           0 :         if( modeltype==1 )
   21712             :         {
   21713           0 :             ae_frame_leave(_state);
   21714           0 :             return;
   21715             :         }
   21716           0 :         if( modeltype==2 )
   21717             :         {
   21718           0 :             ae_frame_leave(_state);
   21719           0 :             return;
   21720             :         }
   21721           0 :         if( modeltype==3 )
   21722             :         {
   21723           0 :             ae_frame_leave(_state);
   21724           0 :             return;
   21725             :         }
   21726           0 :         ae_assert(ae_false, "BuildPriorTerm: unexpected model type", _state);
   21727             :     }
   21728           0 :     if( modeltype==0 )
   21729             :     {
   21730           0 :         for(i=0; i<=ny-1; i++)
   21731             :         {
   21732           0 :             v->ptr.pp_double[i][nx] = priorval;
   21733             :         }
   21734           0 :         for(i=0; i<=n-1; i++)
   21735             :         {
   21736           0 :             for(j=0; j<=ny-1; j++)
   21737             :             {
   21738           0 :                 xy->ptr.pp_double[i][nx+j] = xy->ptr.pp_double[i][nx+j]-priorval;
   21739             :             }
   21740             :         }
   21741           0 :         ae_frame_leave(_state);
   21742           0 :         return;
   21743             :     }
   21744           0 :     if( modeltype==2 )
   21745             :     {
   21746           0 :         for(i=0; i<=n-1; i++)
   21747             :         {
   21748           0 :             for(j=0; j<=ny-1; j++)
   21749             :             {
   21750           0 :                 v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]+xy->ptr.pp_double[i][nx+j];
   21751             :             }
   21752             :         }
   21753           0 :         for(j=0; j<=ny-1; j++)
   21754             :         {
   21755           0 :             v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]/coalesce((double)(n), (double)(1), _state);
   21756             :         }
   21757           0 :         for(i=0; i<=n-1; i++)
   21758             :         {
   21759           0 :             for(j=0; j<=ny-1; j++)
   21760             :             {
   21761           0 :                 xy->ptr.pp_double[i][nx+j] = xy->ptr.pp_double[i][nx+j]-v->ptr.pp_double[j][nx];
   21762             :             }
   21763             :         }
   21764           0 :         ae_frame_leave(_state);
   21765           0 :         return;
   21766             :     }
   21767           0 :     if( modeltype==3 )
   21768             :     {
   21769           0 :         ae_frame_leave(_state);
   21770           0 :         return;
   21771             :     }
   21772           0 :     ae_assert(modeltype==1, "BuildPriorTerm: unexpected model type", _state);
   21773           0 :     lambdareg = 0.0;
   21774           0 :     ae_matrix_set_length(&araw, nx+1, nx+1, _state);
   21775           0 :     ae_matrix_set_length(&braw, nx+1, ny, _state);
   21776           0 :     ae_vector_set_length(&tmp0, nx+1, _state);
   21777           0 :     ae_matrix_set_length(&amod, nx+1, nx+1, _state);
   21778           0 :     for(i=0; i<=nx; i++)
   21779             :     {
   21780           0 :         for(j=0; j<=nx; j++)
   21781             :         {
   21782           0 :             araw.ptr.pp_double[i][j] = (double)(0);
   21783             :         }
   21784             :     }
   21785           0 :     for(i=0; i<=n-1; i++)
   21786             :     {
   21787           0 :         for(j=0; j<=nx-1; j++)
   21788             :         {
   21789           0 :             tmp0.ptr.p_double[j] = xy->ptr.pp_double[i][j];
   21790             :         }
   21791           0 :         tmp0.ptr.p_double[nx] = 1.0;
   21792           0 :         for(j0=0; j0<=nx; j0++)
   21793             :         {
   21794           0 :             for(j1=0; j1<=nx; j1++)
   21795             :             {
   21796           0 :                 araw.ptr.pp_double[j0][j1] = araw.ptr.pp_double[j0][j1]+tmp0.ptr.p_double[j0]*tmp0.ptr.p_double[j1];
   21797             :             }
   21798             :         }
   21799             :     }
   21800           0 :     for(rfsits=1; rfsits<=3; rfsits++)
   21801             :     {
   21802           0 :         for(i=0; i<=nx; i++)
   21803             :         {
   21804           0 :             for(j=0; j<=ny-1; j++)
   21805             :             {
   21806           0 :                 braw.ptr.pp_double[i][j] = (double)(0);
   21807             :             }
   21808             :         }
   21809           0 :         for(i=0; i<=n-1; i++)
   21810             :         {
   21811           0 :             for(j=0; j<=nx-1; j++)
   21812             :             {
   21813           0 :                 tmp0.ptr.p_double[j] = xy->ptr.pp_double[i][j];
   21814             :             }
   21815           0 :             tmp0.ptr.p_double[nx] = 1.0;
   21816           0 :             for(j=0; j<=ny-1; j++)
   21817             :             {
   21818           0 :                 rj = xy->ptr.pp_double[i][nx+j];
   21819           0 :                 for(j0=0; j0<=nx; j0++)
   21820             :                 {
   21821           0 :                     rj = rj-tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0];
   21822             :                 }
   21823           0 :                 for(j0=0; j0<=nx; j0++)
   21824             :                 {
   21825           0 :                     braw.ptr.pp_double[j0][j] = braw.ptr.pp_double[j0][j]+rj*tmp0.ptr.p_double[j0];
   21826             :                 }
   21827             :             }
   21828             :         }
   21829             :         for(;;)
   21830             :         {
   21831           0 :             for(i=0; i<=nx; i++)
   21832             :             {
   21833           0 :                 for(j=0; j<=nx; j++)
   21834             :                 {
   21835           0 :                     amod.ptr.pp_double[i][j] = araw.ptr.pp_double[i][j];
   21836             :                 }
   21837           0 :                 amod.ptr.pp_double[i][i] = amod.ptr.pp_double[i][i]+lambdareg*coalesce(amod.ptr.pp_double[i][i], (double)(1), _state);
   21838             :             }
   21839           0 :             if( spdmatrixcholesky(&amod, nx+1, ae_true, _state) )
   21840             :             {
   21841           0 :                 break;
   21842             :             }
   21843           0 :             lambdareg = coalesce(10*lambdareg, 1.0E-12, _state);
   21844             :         }
   21845           0 :         rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 1, &braw, 0, 0, _state);
   21846           0 :         rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 0, &braw, 0, 0, _state);
   21847           0 :         for(i=0; i<=nx; i++)
   21848             :         {
   21849           0 :             for(j=0; j<=ny-1; j++)
   21850             :             {
   21851           0 :                 v->ptr.pp_double[j][i] = v->ptr.pp_double[j][i]+braw.ptr.pp_double[i][j];
   21852             :             }
   21853             :         }
   21854             :     }
   21855           0 :     for(i=0; i<=n-1; i++)
   21856             :     {
   21857           0 :         for(j=0; j<=nx-1; j++)
   21858             :         {
   21859           0 :             tmp0.ptr.p_double[j] = xy->ptr.pp_double[i][j];
   21860             :         }
   21861           0 :         tmp0.ptr.p_double[nx] = 1.0;
   21862           0 :         for(j=0; j<=ny-1; j++)
   21863             :         {
   21864           0 :             rj = 0.0;
   21865           0 :             for(j0=0; j0<=nx; j0++)
   21866             :             {
   21867           0 :                 rj = rj+tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0];
   21868             :             }
   21869           0 :             xy->ptr.pp_double[i][nx+j] = xy->ptr.pp_double[i][nx+j]-rj;
   21870             :         }
   21871             :     }
   21872           0 :     ae_frame_leave(_state);
   21873             : }
   21874             : 
   21875             : 
   21876           0 : void buildpriorterm1(/* Real    */ ae_vector* xy1,
   21877             :      ae_int_t n,
   21878             :      ae_int_t nx,
   21879             :      ae_int_t ny,
   21880             :      ae_int_t modeltype,
   21881             :      double priorval,
   21882             :      /* Real    */ ae_matrix* v,
   21883             :      ae_state *_state)
   21884             : {
   21885             :     ae_frame _frame_block;
   21886             :     ae_int_t i;
   21887             :     ae_int_t j;
   21888             :     ae_int_t j0;
   21889             :     ae_int_t j1;
   21890             :     ae_int_t ew;
   21891             :     double rj;
   21892             :     ae_matrix araw;
   21893             :     ae_matrix amod;
   21894             :     ae_matrix braw;
   21895             :     ae_vector tmp0;
   21896             :     double lambdareg;
   21897             :     ae_int_t rfsits;
   21898             : 
   21899           0 :     ae_frame_make(_state, &_frame_block);
   21900           0 :     memset(&araw, 0, sizeof(araw));
   21901           0 :     memset(&amod, 0, sizeof(amod));
   21902           0 :     memset(&braw, 0, sizeof(braw));
   21903           0 :     memset(&tmp0, 0, sizeof(tmp0));
   21904           0 :     ae_matrix_clear(v);
   21905           0 :     ae_matrix_init(&araw, 0, 0, DT_REAL, _state, ae_true);
   21906           0 :     ae_matrix_init(&amod, 0, 0, DT_REAL, _state, ae_true);
   21907           0 :     ae_matrix_init(&braw, 0, 0, DT_REAL, _state, ae_true);
   21908           0 :     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
   21909             : 
   21910           0 :     ae_assert(n>=0, "BuildPriorTerm: N<0", _state);
   21911           0 :     ae_assert(nx>0, "BuildPriorTerm: NX<=0", _state);
   21912           0 :     ae_assert(ny>0, "BuildPriorTerm: NY<=0", _state);
   21913           0 :     ew = nx+ny;
   21914           0 :     ae_matrix_set_length(v, ny, nx+1, _state);
   21915           0 :     for(i=0; i<=v->rows-1; i++)
   21916             :     {
   21917           0 :         for(j=0; j<=v->cols-1; j++)
   21918             :         {
   21919           0 :             v->ptr.pp_double[i][j] = (double)(0);
   21920             :         }
   21921             :     }
   21922           0 :     if( n==0 )
   21923             :     {
   21924           0 :         if( modeltype==0 )
   21925             :         {
   21926           0 :             for(i=0; i<=ny-1; i++)
   21927             :             {
   21928           0 :                 v->ptr.pp_double[i][nx] = priorval;
   21929             :             }
   21930           0 :             ae_frame_leave(_state);
   21931           0 :             return;
   21932             :         }
   21933           0 :         if( modeltype==1 )
   21934             :         {
   21935           0 :             ae_frame_leave(_state);
   21936           0 :             return;
   21937             :         }
   21938           0 :         if( modeltype==2 )
   21939             :         {
   21940           0 :             ae_frame_leave(_state);
   21941           0 :             return;
   21942             :         }
   21943           0 :         if( modeltype==3 )
   21944             :         {
   21945           0 :             ae_frame_leave(_state);
   21946           0 :             return;
   21947             :         }
   21948           0 :         ae_assert(ae_false, "BuildPriorTerm: unexpected model type", _state);
   21949             :     }
   21950           0 :     if( modeltype==0 )
   21951             :     {
   21952           0 :         for(i=0; i<=ny-1; i++)
   21953             :         {
   21954           0 :             v->ptr.pp_double[i][nx] = priorval;
   21955             :         }
   21956           0 :         for(i=0; i<=n-1; i++)
   21957             :         {
   21958           0 :             for(j=0; j<=ny-1; j++)
   21959             :             {
   21960           0 :                 xy1->ptr.p_double[i*ew+nx+j] = xy1->ptr.p_double[i*ew+nx+j]-priorval;
   21961             :             }
   21962             :         }
   21963           0 :         ae_frame_leave(_state);
   21964           0 :         return;
   21965             :     }
   21966           0 :     if( modeltype==2 )
   21967             :     {
   21968           0 :         for(i=0; i<=n-1; i++)
   21969             :         {
   21970           0 :             for(j=0; j<=ny-1; j++)
   21971             :             {
   21972           0 :                 v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]+xy1->ptr.p_double[i*ew+nx+j];
   21973             :             }
   21974             :         }
   21975           0 :         for(j=0; j<=ny-1; j++)
   21976             :         {
   21977           0 :             v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]/coalesce((double)(n), (double)(1), _state);
   21978             :         }
   21979           0 :         for(i=0; i<=n-1; i++)
   21980             :         {
   21981           0 :             for(j=0; j<=ny-1; j++)
   21982             :             {
   21983           0 :                 xy1->ptr.p_double[i*ew+nx+j] = xy1->ptr.p_double[i*ew+nx+j]-v->ptr.pp_double[j][nx];
   21984             :             }
   21985             :         }
   21986           0 :         ae_frame_leave(_state);
   21987           0 :         return;
   21988             :     }
   21989           0 :     if( modeltype==3 )
   21990             :     {
   21991           0 :         ae_frame_leave(_state);
   21992           0 :         return;
   21993             :     }
   21994           0 :     ae_assert(modeltype==1, "BuildPriorTerm: unexpected model type", _state);
   21995           0 :     lambdareg = 0.0;
   21996           0 :     ae_matrix_set_length(&araw, nx+1, nx+1, _state);
   21997           0 :     ae_matrix_set_length(&braw, nx+1, ny, _state);
   21998           0 :     ae_vector_set_length(&tmp0, nx+1, _state);
   21999           0 :     ae_matrix_set_length(&amod, nx+1, nx+1, _state);
   22000           0 :     for(i=0; i<=nx; i++)
   22001             :     {
   22002           0 :         for(j=0; j<=nx; j++)
   22003             :         {
   22004           0 :             araw.ptr.pp_double[i][j] = (double)(0);
   22005             :         }
   22006             :     }
   22007           0 :     for(i=0; i<=n-1; i++)
   22008             :     {
   22009           0 :         for(j=0; j<=nx-1; j++)
   22010             :         {
   22011           0 :             tmp0.ptr.p_double[j] = xy1->ptr.p_double[i*ew+j];
   22012             :         }
   22013           0 :         tmp0.ptr.p_double[nx] = 1.0;
   22014           0 :         for(j0=0; j0<=nx; j0++)
   22015             :         {
   22016           0 :             for(j1=0; j1<=nx; j1++)
   22017             :             {
   22018           0 :                 araw.ptr.pp_double[j0][j1] = araw.ptr.pp_double[j0][j1]+tmp0.ptr.p_double[j0]*tmp0.ptr.p_double[j1];
   22019             :             }
   22020             :         }
   22021             :     }
   22022           0 :     for(rfsits=1; rfsits<=3; rfsits++)
   22023             :     {
   22024           0 :         for(i=0; i<=nx; i++)
   22025             :         {
   22026           0 :             for(j=0; j<=ny-1; j++)
   22027             :             {
   22028           0 :                 braw.ptr.pp_double[i][j] = (double)(0);
   22029             :             }
   22030             :         }
   22031           0 :         for(i=0; i<=n-1; i++)
   22032             :         {
   22033           0 :             for(j=0; j<=nx-1; j++)
   22034             :             {
   22035           0 :                 tmp0.ptr.p_double[j] = xy1->ptr.p_double[i*ew+j];
   22036             :             }
   22037           0 :             tmp0.ptr.p_double[nx] = 1.0;
   22038           0 :             for(j=0; j<=ny-1; j++)
   22039             :             {
   22040           0 :                 rj = xy1->ptr.p_double[i*ew+nx+j];
   22041           0 :                 for(j0=0; j0<=nx; j0++)
   22042             :                 {
   22043           0 :                     rj = rj-tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0];
   22044             :                 }
   22045           0 :                 for(j0=0; j0<=nx; j0++)
   22046             :                 {
   22047           0 :                     braw.ptr.pp_double[j0][j] = braw.ptr.pp_double[j0][j]+rj*tmp0.ptr.p_double[j0];
   22048             :                 }
   22049             :             }
   22050             :         }
   22051             :         for(;;)
   22052             :         {
   22053           0 :             for(i=0; i<=nx; i++)
   22054             :             {
   22055           0 :                 for(j=0; j<=nx; j++)
   22056             :                 {
   22057           0 :                     amod.ptr.pp_double[i][j] = araw.ptr.pp_double[i][j];
   22058             :                 }
   22059           0 :                 amod.ptr.pp_double[i][i] = amod.ptr.pp_double[i][i]+lambdareg*coalesce(amod.ptr.pp_double[i][i], (double)(1), _state);
   22060             :             }
   22061           0 :             if( spdmatrixcholesky(&amod, nx+1, ae_true, _state) )
   22062             :             {
   22063           0 :                 break;
   22064             :             }
   22065           0 :             lambdareg = coalesce(10*lambdareg, 1.0E-12, _state);
   22066             :         }
   22067           0 :         rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 1, &braw, 0, 0, _state);
   22068           0 :         rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 0, &braw, 0, 0, _state);
   22069           0 :         for(i=0; i<=nx; i++)
   22070             :         {
   22071           0 :             for(j=0; j<=ny-1; j++)
   22072             :             {
   22073           0 :                 v->ptr.pp_double[j][i] = v->ptr.pp_double[j][i]+braw.ptr.pp_double[i][j];
   22074             :             }
   22075             :         }
   22076             :     }
   22077           0 :     for(i=0; i<=n-1; i++)
   22078             :     {
   22079           0 :         for(j=0; j<=nx-1; j++)
   22080             :         {
   22081           0 :             tmp0.ptr.p_double[j] = xy1->ptr.p_double[i*ew+j];
   22082             :         }
   22083           0 :         tmp0.ptr.p_double[nx] = 1.0;
   22084           0 :         for(j=0; j<=ny-1; j++)
   22085             :         {
   22086           0 :             rj = 0.0;
   22087           0 :             for(j0=0; j0<=nx; j0++)
   22088             :             {
   22089           0 :                 rj = rj+tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0];
   22090             :             }
   22091           0 :             xy1->ptr.p_double[i*ew+nx+j] = xy1->ptr.p_double[i*ew+nx+j]-rj;
   22092             :         }
   22093             :     }
   22094           0 :     ae_frame_leave(_state);
   22095             : }
   22096             : 
   22097             : 
   22098             : #endif
   22099             : #if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD)
   22100             : 
   22101             : 
   22102             : /*************************************************************************
   22103             : This subroutine builds linear spline interpolant
   22104             : 
   22105             : INPUT PARAMETERS:
   22106             :     X   -   spline nodes, array[0..N-1]
   22107             :     Y   -   function values, array[0..N-1]
   22108             :     N   -   points count (optional):
   22109             :             * N>=2
   22110             :             * if given, only first N points are used to build spline
   22111             :             * if not given, automatically detected from X/Y sizes
   22112             :               (len(X) must be equal to len(Y))
   22113             :     
   22114             : OUTPUT PARAMETERS:
   22115             :     C   -   spline interpolant
   22116             : 
   22117             : 
   22118             : ORDER OF POINTS
   22119             : 
   22120             : Subroutine automatically sorts points, so caller may pass unsorted array.
   22121             : 
   22122             :   -- ALGLIB PROJECT --
   22123             :      Copyright 24.06.2007 by Bochkanov Sergey
   22124             : *************************************************************************/
   22125           0 : void spline1dbuildlinear(/* Real    */ ae_vector* x,
   22126             :      /* Real    */ ae_vector* y,
   22127             :      ae_int_t n,
   22128             :      spline1dinterpolant* c,
   22129             :      ae_state *_state)
   22130             : {
   22131             :     ae_frame _frame_block;
   22132             :     ae_vector _x;
   22133             :     ae_vector _y;
   22134             :     ae_int_t i;
   22135             : 
   22136           0 :     ae_frame_make(_state, &_frame_block);
   22137           0 :     memset(&_x, 0, sizeof(_x));
   22138           0 :     memset(&_y, 0, sizeof(_y));
   22139           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   22140           0 :     x = &_x;
   22141           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   22142           0 :     y = &_y;
   22143           0 :     _spline1dinterpolant_clear(c);
   22144             : 
   22145           0 :     ae_assert(n>1, "Spline1DBuildLinear: N<2!", _state);
   22146           0 :     ae_assert(x->cnt>=n, "Spline1DBuildLinear: Length(X)<N!", _state);
   22147           0 :     ae_assert(y->cnt>=n, "Spline1DBuildLinear: Length(Y)<N!", _state);
   22148             :     
   22149             :     /*
   22150             :      * check and sort points
   22151             :      */
   22152           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildLinear: X contains infinite or NAN values!", _state);
   22153           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DBuildLinear: Y contains infinite or NAN values!", _state);
   22154           0 :     spline1d_heapsortpoints(x, y, n, _state);
   22155           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DBuildLinear: at least two consequent points are too close!", _state);
   22156             :     
   22157             :     /*
   22158             :      * Build
   22159             :      */
   22160           0 :     c->periodic = ae_false;
   22161           0 :     c->n = n;
   22162           0 :     c->k = 3;
   22163           0 :     c->continuity = 0;
   22164           0 :     ae_vector_set_length(&c->x, n, _state);
   22165           0 :     ae_vector_set_length(&c->c, 4*(n-1)+2, _state);
   22166           0 :     for(i=0; i<=n-1; i++)
   22167             :     {
   22168           0 :         c->x.ptr.p_double[i] = x->ptr.p_double[i];
   22169             :     }
   22170           0 :     for(i=0; i<=n-2; i++)
   22171             :     {
   22172           0 :         c->c.ptr.p_double[4*i+0] = y->ptr.p_double[i];
   22173           0 :         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]);
   22174           0 :         c->c.ptr.p_double[4*i+2] = (double)(0);
   22175           0 :         c->c.ptr.p_double[4*i+3] = (double)(0);
   22176             :     }
   22177           0 :     c->c.ptr.p_double[4*(n-1)+0] = y->ptr.p_double[n-1];
   22178           0 :     c->c.ptr.p_double[4*(n-1)+1] = c->c.ptr.p_double[4*(n-2)+1];
   22179           0 :     ae_frame_leave(_state);
   22180           0 : }
   22181             : 
   22182             : 
   22183             : /*************************************************************************
   22184             : This subroutine builds cubic spline interpolant.
   22185             : 
   22186             : INPUT PARAMETERS:
   22187             :     X           -   spline nodes, array[0..N-1].
   22188             :     Y           -   function values, array[0..N-1].
   22189             :     
   22190             : OPTIONAL PARAMETERS:
   22191             :     N           -   points count:
   22192             :                     * N>=2
   22193             :                     * if given, only first N points are used to build spline
   22194             :                     * if not given, automatically detected from X/Y sizes
   22195             :                       (len(X) must be equal to len(Y))
   22196             :     BoundLType  -   boundary condition type for the left boundary
   22197             :     BoundL      -   left boundary condition (first or second derivative,
   22198             :                     depending on the BoundLType)
   22199             :     BoundRType  -   boundary condition type for the right boundary
   22200             :     BoundR      -   right boundary condition (first or second derivative,
   22201             :                     depending on the BoundRType)
   22202             : 
   22203             : OUTPUT PARAMETERS:
   22204             :     C           -   spline interpolant
   22205             : 
   22206             : ORDER OF POINTS
   22207             : 
   22208             : Subroutine automatically sorts points, so caller may pass unsorted array.
   22209             : 
   22210             : SETTING BOUNDARY VALUES:
   22211             : 
   22212             : The BoundLType/BoundRType parameters can have the following values:
   22213             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
   22214             :           In this case:
   22215             :           * both BoundLType and BoundRType must be equal to -1.
   22216             :           * BoundL/BoundR are ignored
   22217             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
   22218             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
   22219             :           (BoundL and/or BoundR are ignored).
   22220             :     *  1, which corresponds to the first derivative boundary condition
   22221             :     *  2, which corresponds to the second derivative boundary condition
   22222             :     *  by default, BoundType=0 is used
   22223             : 
   22224             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
   22225             : 
   22226             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
   22227             : However, this subroutine doesn't require you to specify equal  values  for
   22228             : the first and last points - it automatically forces them  to  be  equal by
   22229             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
   22230             : Y[last_point]. However it is recommended to pass consistent values of Y[],
   22231             : i.e. to make Y[first_point]=Y[last_point].
   22232             : 
   22233             :   -- ALGLIB PROJECT --
   22234             :      Copyright 23.06.2007 by Bochkanov Sergey
   22235             : *************************************************************************/
   22236           0 : void spline1dbuildcubic(/* Real    */ ae_vector* x,
   22237             :      /* Real    */ ae_vector* y,
   22238             :      ae_int_t n,
   22239             :      ae_int_t boundltype,
   22240             :      double boundl,
   22241             :      ae_int_t boundrtype,
   22242             :      double boundr,
   22243             :      spline1dinterpolant* c,
   22244             :      ae_state *_state)
   22245             : {
   22246             :     ae_frame _frame_block;
   22247             :     ae_vector _x;
   22248             :     ae_vector _y;
   22249             :     ae_vector a1;
   22250             :     ae_vector a2;
   22251             :     ae_vector a3;
   22252             :     ae_vector b;
   22253             :     ae_vector dt;
   22254             :     ae_vector d;
   22255             :     ae_vector p;
   22256             :     ae_int_t ylen;
   22257             : 
   22258           0 :     ae_frame_make(_state, &_frame_block);
   22259           0 :     memset(&_x, 0, sizeof(_x));
   22260           0 :     memset(&_y, 0, sizeof(_y));
   22261           0 :     memset(&a1, 0, sizeof(a1));
   22262           0 :     memset(&a2, 0, sizeof(a2));
   22263           0 :     memset(&a3, 0, sizeof(a3));
   22264           0 :     memset(&b, 0, sizeof(b));
   22265           0 :     memset(&dt, 0, sizeof(dt));
   22266           0 :     memset(&d, 0, sizeof(d));
   22267           0 :     memset(&p, 0, sizeof(p));
   22268           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   22269           0 :     x = &_x;
   22270           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   22271           0 :     y = &_y;
   22272           0 :     _spline1dinterpolant_clear(c);
   22273           0 :     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
   22274           0 :     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
   22275           0 :     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
   22276           0 :     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
   22277           0 :     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
   22278           0 :     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
   22279           0 :     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
   22280             : 
   22281             :     
   22282             :     /*
   22283             :      * check correctness of boundary conditions
   22284             :      */
   22285           0 :     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DBuildCubic: incorrect BoundLType!", _state);
   22286           0 :     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DBuildCubic: incorrect BoundRType!", _state);
   22287           0 :     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DBuildCubic: incorrect BoundLType/BoundRType!", _state);
   22288           0 :     if( boundltype==1||boundltype==2 )
   22289             :     {
   22290           0 :         ae_assert(ae_isfinite(boundl, _state), "Spline1DBuildCubic: BoundL is infinite or NAN!", _state);
   22291             :     }
   22292           0 :     if( boundrtype==1||boundrtype==2 )
   22293             :     {
   22294           0 :         ae_assert(ae_isfinite(boundr, _state), "Spline1DBuildCubic: BoundR is infinite or NAN!", _state);
   22295             :     }
   22296             :     
   22297             :     /*
   22298             :      * check lengths of arguments
   22299             :      */
   22300           0 :     ae_assert(n>=2, "Spline1DBuildCubic: N<2!", _state);
   22301           0 :     ae_assert(x->cnt>=n, "Spline1DBuildCubic: Length(X)<N!", _state);
   22302           0 :     ae_assert(y->cnt>=n, "Spline1DBuildCubic: Length(Y)<N!", _state);
   22303             :     
   22304             :     /*
   22305             :      * check and sort points
   22306             :      */
   22307           0 :     ylen = n;
   22308           0 :     if( boundltype==-1 )
   22309             :     {
   22310           0 :         ylen = n-1;
   22311             :     }
   22312           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildCubic: X contains infinite or NAN values!", _state);
   22313           0 :     ae_assert(isfinitevector(y, ylen, _state), "Spline1DBuildCubic: Y contains infinite or NAN values!", _state);
   22314           0 :     spline1d_heapsortppoints(x, y, &p, n, _state);
   22315           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DBuildCubic: at least two consequent points are too close!", _state);
   22316             :     
   22317             :     /*
   22318             :      * Now we've checked and preordered everything,
   22319             :      * so we can call internal function to calculate derivatives,
   22320             :      * and then build Hermite spline using these derivatives
   22321             :      */
   22322           0 :     if( boundltype==-1||boundrtype==-1 )
   22323             :     {
   22324           0 :         y->ptr.p_double[n-1] = y->ptr.p_double[0];
   22325             :     }
   22326           0 :     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state);
   22327           0 :     spline1dbuildhermite(x, y, &d, n, c, _state);
   22328           0 :     c->periodic = boundltype==-1||boundrtype==-1;
   22329           0 :     c->continuity = 2;
   22330           0 :     ae_frame_leave(_state);
   22331           0 : }
   22332             : 
   22333             : 
   22334             : /*************************************************************************
   22335             : This function solves following problem: given table y[] of function values
   22336             : at nodes x[], it calculates and returns table of function derivatives  d[]
   22337             : (calculated at the same nodes x[]).
   22338             : 
   22339             : This function yields same result as Spline1DBuildCubic() call followed  by
   22340             : sequence of Spline1DDiff() calls, but it can be several times faster  when
   22341             : called for ordered X[] and X2[].
   22342             : 
   22343             : INPUT PARAMETERS:
   22344             :     X           -   spline nodes
   22345             :     Y           -   function values
   22346             : 
   22347             : OPTIONAL PARAMETERS:
   22348             :     N           -   points count:
   22349             :                     * N>=2
   22350             :                     * if given, only first N points are used
   22351             :                     * if not given, automatically detected from X/Y sizes
   22352             :                       (len(X) must be equal to len(Y))
   22353             :     BoundLType  -   boundary condition type for the left boundary
   22354             :     BoundL      -   left boundary condition (first or second derivative,
   22355             :                     depending on the BoundLType)
   22356             :     BoundRType  -   boundary condition type for the right boundary
   22357             :     BoundR      -   right boundary condition (first or second derivative,
   22358             :                     depending on the BoundRType)
   22359             : 
   22360             : OUTPUT PARAMETERS:
   22361             :     D           -   derivative values at X[]
   22362             : 
   22363             : ORDER OF POINTS
   22364             : 
   22365             : Subroutine automatically sorts points, so caller may pass unsorted array.
   22366             : Derivative values are correctly reordered on return, so  D[I]  is  always
   22367             : equal to S'(X[I]) independently of points order.
   22368             : 
   22369             : SETTING BOUNDARY VALUES:
   22370             : 
   22371             : The BoundLType/BoundRType parameters can have the following values:
   22372             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
   22373             :           In this case:
   22374             :           * both BoundLType and BoundRType must be equal to -1.
   22375             :           * BoundL/BoundR are ignored
   22376             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
   22377             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
   22378             :           (BoundL and/or BoundR are ignored).
   22379             :     *  1, which corresponds to the first derivative boundary condition
   22380             :     *  2, which corresponds to the second derivative boundary condition
   22381             :     *  by default, BoundType=0 is used
   22382             : 
   22383             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
   22384             : 
   22385             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
   22386             : However, this subroutine doesn't require you to specify equal  values  for
   22387             : the first and last points - it automatically forces them  to  be  equal by
   22388             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
   22389             : Y[last_point]. However it is recommended to pass consistent values of Y[],
   22390             : i.e. to make Y[first_point]=Y[last_point].
   22391             : 
   22392             :   -- ALGLIB PROJECT --
   22393             :      Copyright 03.09.2010 by Bochkanov Sergey
   22394             : *************************************************************************/
   22395           0 : void spline1dgriddiffcubic(/* Real    */ ae_vector* x,
   22396             :      /* Real    */ ae_vector* y,
   22397             :      ae_int_t n,
   22398             :      ae_int_t boundltype,
   22399             :      double boundl,
   22400             :      ae_int_t boundrtype,
   22401             :      double boundr,
   22402             :      /* Real    */ ae_vector* d,
   22403             :      ae_state *_state)
   22404             : {
   22405             :     ae_frame _frame_block;
   22406             :     ae_vector _x;
   22407             :     ae_vector _y;
   22408             :     ae_vector a1;
   22409             :     ae_vector a2;
   22410             :     ae_vector a3;
   22411             :     ae_vector b;
   22412             :     ae_vector dt;
   22413             :     ae_vector p;
   22414             :     ae_int_t i;
   22415             :     ae_int_t ylen;
   22416             : 
   22417           0 :     ae_frame_make(_state, &_frame_block);
   22418           0 :     memset(&_x, 0, sizeof(_x));
   22419           0 :     memset(&_y, 0, sizeof(_y));
   22420           0 :     memset(&a1, 0, sizeof(a1));
   22421           0 :     memset(&a2, 0, sizeof(a2));
   22422           0 :     memset(&a3, 0, sizeof(a3));
   22423           0 :     memset(&b, 0, sizeof(b));
   22424           0 :     memset(&dt, 0, sizeof(dt));
   22425           0 :     memset(&p, 0, sizeof(p));
   22426           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   22427           0 :     x = &_x;
   22428           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   22429           0 :     y = &_y;
   22430           0 :     ae_vector_clear(d);
   22431           0 :     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
   22432           0 :     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
   22433           0 :     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
   22434           0 :     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
   22435           0 :     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
   22436           0 :     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
   22437             : 
   22438             :     
   22439             :     /*
   22440             :      * check correctness of boundary conditions
   22441             :      */
   22442           0 :     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DGridDiffCubic: incorrect BoundLType!", _state);
   22443           0 :     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DGridDiffCubic: incorrect BoundRType!", _state);
   22444           0 :     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DGridDiffCubic: incorrect BoundLType/BoundRType!", _state);
   22445           0 :     if( boundltype==1||boundltype==2 )
   22446             :     {
   22447           0 :         ae_assert(ae_isfinite(boundl, _state), "Spline1DGridDiffCubic: BoundL is infinite or NAN!", _state);
   22448             :     }
   22449           0 :     if( boundrtype==1||boundrtype==2 )
   22450             :     {
   22451           0 :         ae_assert(ae_isfinite(boundr, _state), "Spline1DGridDiffCubic: BoundR is infinite or NAN!", _state);
   22452             :     }
   22453             :     
   22454             :     /*
   22455             :      * check lengths of arguments
   22456             :      */
   22457           0 :     ae_assert(n>=2, "Spline1DGridDiffCubic: N<2!", _state);
   22458           0 :     ae_assert(x->cnt>=n, "Spline1DGridDiffCubic: Length(X)<N!", _state);
   22459           0 :     ae_assert(y->cnt>=n, "Spline1DGridDiffCubic: Length(Y)<N!", _state);
   22460             :     
   22461             :     /*
   22462             :      * check and sort points
   22463             :      */
   22464           0 :     ylen = n;
   22465           0 :     if( boundltype==-1 )
   22466             :     {
   22467           0 :         ylen = n-1;
   22468             :     }
   22469           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DGridDiffCubic: X contains infinite or NAN values!", _state);
   22470           0 :     ae_assert(isfinitevector(y, ylen, _state), "Spline1DGridDiffCubic: Y contains infinite or NAN values!", _state);
   22471           0 :     spline1d_heapsortppoints(x, y, &p, n, _state);
   22472           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DGridDiffCubic: at least two consequent points are too close!", _state);
   22473             :     
   22474             :     /*
   22475             :      * Now we've checked and preordered everything,
   22476             :      * so we can call internal function.
   22477             :      */
   22478           0 :     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, d, &a1, &a2, &a3, &b, &dt, _state);
   22479             :     
   22480             :     /*
   22481             :      * Remember that HeapSortPPoints() call?
   22482             :      * Now we have to reorder them back.
   22483             :      */
   22484           0 :     if( dt.cnt<n )
   22485             :     {
   22486           0 :         ae_vector_set_length(&dt, n, _state);
   22487             :     }
   22488           0 :     for(i=0; i<=n-1; i++)
   22489             :     {
   22490           0 :         dt.ptr.p_double[p.ptr.p_int[i]] = d->ptr.p_double[i];
   22491             :     }
   22492           0 :     ae_v_move(&d->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1));
   22493           0 :     ae_frame_leave(_state);
   22494           0 : }
   22495             : 
   22496             : 
   22497             : /*************************************************************************
   22498             : This function solves following problem: given table y[] of function values
   22499             : at  nodes  x[],  it  calculates  and  returns  tables  of first and second
   22500             : function derivatives d1[] and d2[] (calculated at the same nodes x[]).
   22501             : 
   22502             : This function yields same result as Spline1DBuildCubic() call followed  by
   22503             : sequence of Spline1DDiff() calls, but it can be several times faster  when
   22504             : called for ordered X[] and X2[].
   22505             : 
   22506             : INPUT PARAMETERS:
   22507             :     X           -   spline nodes
   22508             :     Y           -   function values
   22509             : 
   22510             : OPTIONAL PARAMETERS:
   22511             :     N           -   points count:
   22512             :                     * N>=2
   22513             :                     * if given, only first N points are used
   22514             :                     * if not given, automatically detected from X/Y sizes
   22515             :                       (len(X) must be equal to len(Y))
   22516             :     BoundLType  -   boundary condition type for the left boundary
   22517             :     BoundL      -   left boundary condition (first or second derivative,
   22518             :                     depending on the BoundLType)
   22519             :     BoundRType  -   boundary condition type for the right boundary
   22520             :     BoundR      -   right boundary condition (first or second derivative,
   22521             :                     depending on the BoundRType)
   22522             : 
   22523             : OUTPUT PARAMETERS:
   22524             :     D1          -   S' values at X[]
   22525             :     D2          -   S'' values at X[]
   22526             : 
   22527             : ORDER OF POINTS
   22528             : 
   22529             : Subroutine automatically sorts points, so caller may pass unsorted array.
   22530             : Derivative values are correctly reordered on return, so  D[I]  is  always
   22531             : equal to S'(X[I]) independently of points order.
   22532             : 
   22533             : SETTING BOUNDARY VALUES:
   22534             : 
   22535             : The BoundLType/BoundRType parameters can have the following values:
   22536             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
   22537             :           In this case:
   22538             :           * both BoundLType and BoundRType must be equal to -1.
   22539             :           * BoundL/BoundR are ignored
   22540             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
   22541             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
   22542             :           (BoundL and/or BoundR are ignored).
   22543             :     *  1, which corresponds to the first derivative boundary condition
   22544             :     *  2, which corresponds to the second derivative boundary condition
   22545             :     *  by default, BoundType=0 is used
   22546             : 
   22547             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
   22548             : 
   22549             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
   22550             : However, this subroutine doesn't require you to specify equal  values  for
   22551             : the first and last points - it automatically forces them  to  be  equal by
   22552             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
   22553             : Y[last_point]. However it is recommended to pass consistent values of Y[],
   22554             : i.e. to make Y[first_point]=Y[last_point].
   22555             : 
   22556             :   -- ALGLIB PROJECT --
   22557             :      Copyright 03.09.2010 by Bochkanov Sergey
   22558             : *************************************************************************/
   22559           0 : void spline1dgriddiff2cubic(/* Real    */ ae_vector* x,
   22560             :      /* Real    */ ae_vector* y,
   22561             :      ae_int_t n,
   22562             :      ae_int_t boundltype,
   22563             :      double boundl,
   22564             :      ae_int_t boundrtype,
   22565             :      double boundr,
   22566             :      /* Real    */ ae_vector* d1,
   22567             :      /* Real    */ ae_vector* d2,
   22568             :      ae_state *_state)
   22569             : {
   22570             :     ae_frame _frame_block;
   22571             :     ae_vector _x;
   22572             :     ae_vector _y;
   22573             :     ae_vector a1;
   22574             :     ae_vector a2;
   22575             :     ae_vector a3;
   22576             :     ae_vector b;
   22577             :     ae_vector dt;
   22578             :     ae_vector p;
   22579             :     ae_int_t i;
   22580             :     ae_int_t ylen;
   22581             :     double delta;
   22582             :     double delta2;
   22583             :     double delta3;
   22584             :     double s2;
   22585             :     double s3;
   22586             : 
   22587           0 :     ae_frame_make(_state, &_frame_block);
   22588           0 :     memset(&_x, 0, sizeof(_x));
   22589           0 :     memset(&_y, 0, sizeof(_y));
   22590           0 :     memset(&a1, 0, sizeof(a1));
   22591           0 :     memset(&a2, 0, sizeof(a2));
   22592           0 :     memset(&a3, 0, sizeof(a3));
   22593           0 :     memset(&b, 0, sizeof(b));
   22594           0 :     memset(&dt, 0, sizeof(dt));
   22595           0 :     memset(&p, 0, sizeof(p));
   22596           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   22597           0 :     x = &_x;
   22598           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   22599           0 :     y = &_y;
   22600           0 :     ae_vector_clear(d1);
   22601           0 :     ae_vector_clear(d2);
   22602           0 :     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
   22603           0 :     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
   22604           0 :     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
   22605           0 :     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
   22606           0 :     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
   22607           0 :     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
   22608             : 
   22609             :     
   22610             :     /*
   22611             :      * check correctness of boundary conditions
   22612             :      */
   22613           0 :     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DGridDiff2Cubic: incorrect BoundLType!", _state);
   22614           0 :     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DGridDiff2Cubic: incorrect BoundRType!", _state);
   22615           0 :     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DGridDiff2Cubic: incorrect BoundLType/BoundRType!", _state);
   22616           0 :     if( boundltype==1||boundltype==2 )
   22617             :     {
   22618           0 :         ae_assert(ae_isfinite(boundl, _state), "Spline1DGridDiff2Cubic: BoundL is infinite or NAN!", _state);
   22619             :     }
   22620           0 :     if( boundrtype==1||boundrtype==2 )
   22621             :     {
   22622           0 :         ae_assert(ae_isfinite(boundr, _state), "Spline1DGridDiff2Cubic: BoundR is infinite or NAN!", _state);
   22623             :     }
   22624             :     
   22625             :     /*
   22626             :      * check lengths of arguments
   22627             :      */
   22628           0 :     ae_assert(n>=2, "Spline1DGridDiff2Cubic: N<2!", _state);
   22629           0 :     ae_assert(x->cnt>=n, "Spline1DGridDiff2Cubic: Length(X)<N!", _state);
   22630           0 :     ae_assert(y->cnt>=n, "Spline1DGridDiff2Cubic: Length(Y)<N!", _state);
   22631             :     
   22632             :     /*
   22633             :      * check and sort points
   22634             :      */
   22635           0 :     ylen = n;
   22636           0 :     if( boundltype==-1 )
   22637             :     {
   22638           0 :         ylen = n-1;
   22639             :     }
   22640           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DGridDiff2Cubic: X contains infinite or NAN values!", _state);
   22641           0 :     ae_assert(isfinitevector(y, ylen, _state), "Spline1DGridDiff2Cubic: Y contains infinite or NAN values!", _state);
   22642           0 :     spline1d_heapsortppoints(x, y, &p, n, _state);
   22643           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DGridDiff2Cubic: at least two consequent points are too close!", _state);
   22644             :     
   22645             :     /*
   22646             :      * Now we've checked and preordered everything,
   22647             :      * so we can call internal function.
   22648             :      *
   22649             :      * After this call we will calculate second derivatives
   22650             :      * (manually, by converting to the power basis)
   22651             :      */
   22652           0 :     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, d1, &a1, &a2, &a3, &b, &dt, _state);
   22653           0 :     ae_vector_set_length(d2, n, _state);
   22654           0 :     delta = (double)(0);
   22655           0 :     s2 = (double)(0);
   22656           0 :     s3 = (double)(0);
   22657           0 :     for(i=0; i<=n-2; i++)
   22658             :     {
   22659             :         
   22660             :         /*
   22661             :          * We convert from Hermite basis to the power basis.
   22662             :          * Si is coefficient before x^i.
   22663             :          *
   22664             :          * Inside this cycle we need just S2,
   22665             :          * because we calculate S'' exactly at spline node,
   22666             :          * (only x^2 matters at x=0), but after iterations
   22667             :          * will be over, we will need other coefficients
   22668             :          * to calculate spline value at the last node.
   22669             :          */
   22670           0 :         delta = x->ptr.p_double[i+1]-x->ptr.p_double[i];
   22671           0 :         delta2 = ae_sqr(delta, _state);
   22672           0 :         delta3 = delta*delta2;
   22673           0 :         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;
   22674           0 :         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;
   22675           0 :         d2->ptr.p_double[i] = 2*s2;
   22676             :     }
   22677           0 :     d2->ptr.p_double[n-1] = 2*s2+6*s3*delta;
   22678             :     
   22679             :     /*
   22680             :      * Remember that HeapSortPPoints() call?
   22681             :      * Now we have to reorder them back.
   22682             :      */
   22683           0 :     if( dt.cnt<n )
   22684             :     {
   22685           0 :         ae_vector_set_length(&dt, n, _state);
   22686             :     }
   22687           0 :     for(i=0; i<=n-1; i++)
   22688             :     {
   22689           0 :         dt.ptr.p_double[p.ptr.p_int[i]] = d1->ptr.p_double[i];
   22690             :     }
   22691           0 :     ae_v_move(&d1->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1));
   22692           0 :     for(i=0; i<=n-1; i++)
   22693             :     {
   22694           0 :         dt.ptr.p_double[p.ptr.p_int[i]] = d2->ptr.p_double[i];
   22695             :     }
   22696           0 :     ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1));
   22697           0 :     ae_frame_leave(_state);
   22698           0 : }
   22699             : 
   22700             : 
   22701             : /*************************************************************************
   22702             : This function solves following problem: given table y[] of function values
   22703             : at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
   22704             : function values y2[] (calculated at x2[]).
   22705             : 
   22706             : This function yields same result as Spline1DBuildCubic() call followed  by
   22707             : sequence of Spline1DDiff() calls, but it can be several times faster  when
   22708             : called for ordered X[] and X2[].
   22709             : 
   22710             : INPUT PARAMETERS:
   22711             :     X           -   old spline nodes
   22712             :     Y           -   function values
   22713             :     X2           -  new spline nodes
   22714             : 
   22715             : OPTIONAL PARAMETERS:
   22716             :     N           -   points count:
   22717             :                     * N>=2
   22718             :                     * if given, only first N points from X/Y are used
   22719             :                     * if not given, automatically detected from X/Y sizes
   22720             :                       (len(X) must be equal to len(Y))
   22721             :     BoundLType  -   boundary condition type for the left boundary
   22722             :     BoundL      -   left boundary condition (first or second derivative,
   22723             :                     depending on the BoundLType)
   22724             :     BoundRType  -   boundary condition type for the right boundary
   22725             :     BoundR      -   right boundary condition (first or second derivative,
   22726             :                     depending on the BoundRType)
   22727             :     N2          -   new points count:
   22728             :                     * N2>=2
   22729             :                     * if given, only first N2 points from X2 are used
   22730             :                     * if not given, automatically detected from X2 size
   22731             : 
   22732             : OUTPUT PARAMETERS:
   22733             :     F2          -   function values at X2[]
   22734             : 
   22735             : ORDER OF POINTS
   22736             : 
   22737             : Subroutine automatically sorts points, so caller  may pass unsorted array.
   22738             : Function  values  are correctly reordered on  return, so F2[I]  is  always
   22739             : equal to S(X2[I]) independently of points order.
   22740             : 
   22741             : SETTING BOUNDARY VALUES:
   22742             : 
   22743             : The BoundLType/BoundRType parameters can have the following values:
   22744             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
   22745             :           In this case:
   22746             :           * both BoundLType and BoundRType must be equal to -1.
   22747             :           * BoundL/BoundR are ignored
   22748             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
   22749             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
   22750             :           (BoundL and/or BoundR are ignored).
   22751             :     *  1, which corresponds to the first derivative boundary condition
   22752             :     *  2, which corresponds to the second derivative boundary condition
   22753             :     *  by default, BoundType=0 is used
   22754             : 
   22755             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
   22756             : 
   22757             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
   22758             : However, this subroutine doesn't require you to specify equal  values  for
   22759             : the first and last points - it automatically forces them  to  be  equal by
   22760             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
   22761             : Y[last_point]. However it is recommended to pass consistent values of Y[],
   22762             : i.e. to make Y[first_point]=Y[last_point].
   22763             : 
   22764             :   -- ALGLIB PROJECT --
   22765             :      Copyright 03.09.2010 by Bochkanov Sergey
   22766             : *************************************************************************/
   22767           0 : void spline1dconvcubic(/* Real    */ ae_vector* x,
   22768             :      /* Real    */ ae_vector* y,
   22769             :      ae_int_t n,
   22770             :      ae_int_t boundltype,
   22771             :      double boundl,
   22772             :      ae_int_t boundrtype,
   22773             :      double boundr,
   22774             :      /* Real    */ ae_vector* x2,
   22775             :      ae_int_t n2,
   22776             :      /* Real    */ ae_vector* y2,
   22777             :      ae_state *_state)
   22778             : {
   22779             :     ae_frame _frame_block;
   22780             :     ae_vector _x;
   22781             :     ae_vector _y;
   22782             :     ae_vector _x2;
   22783             :     ae_vector a1;
   22784             :     ae_vector a2;
   22785             :     ae_vector a3;
   22786             :     ae_vector b;
   22787             :     ae_vector d;
   22788             :     ae_vector dt;
   22789             :     ae_vector d1;
   22790             :     ae_vector d2;
   22791             :     ae_vector p;
   22792             :     ae_vector p2;
   22793             :     ae_int_t i;
   22794             :     ae_int_t ylen;
   22795             :     double t;
   22796             :     double t2;
   22797             : 
   22798           0 :     ae_frame_make(_state, &_frame_block);
   22799           0 :     memset(&_x, 0, sizeof(_x));
   22800           0 :     memset(&_y, 0, sizeof(_y));
   22801           0 :     memset(&_x2, 0, sizeof(_x2));
   22802           0 :     memset(&a1, 0, sizeof(a1));
   22803           0 :     memset(&a2, 0, sizeof(a2));
   22804           0 :     memset(&a3, 0, sizeof(a3));
   22805           0 :     memset(&b, 0, sizeof(b));
   22806           0 :     memset(&d, 0, sizeof(d));
   22807           0 :     memset(&dt, 0, sizeof(dt));
   22808           0 :     memset(&d1, 0, sizeof(d1));
   22809           0 :     memset(&d2, 0, sizeof(d2));
   22810           0 :     memset(&p, 0, sizeof(p));
   22811           0 :     memset(&p2, 0, sizeof(p2));
   22812           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   22813           0 :     x = &_x;
   22814           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   22815           0 :     y = &_y;
   22816           0 :     ae_vector_init_copy(&_x2, x2, _state, ae_true);
   22817           0 :     x2 = &_x2;
   22818           0 :     ae_vector_clear(y2);
   22819           0 :     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
   22820           0 :     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
   22821           0 :     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
   22822           0 :     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
   22823           0 :     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
   22824           0 :     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
   22825           0 :     ae_vector_init(&d1, 0, DT_REAL, _state, ae_true);
   22826           0 :     ae_vector_init(&d2, 0, DT_REAL, _state, ae_true);
   22827           0 :     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
   22828           0 :     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
   22829             : 
   22830             :     
   22831             :     /*
   22832             :      * check correctness of boundary conditions
   22833             :      */
   22834           0 :     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvCubic: incorrect BoundLType!", _state);
   22835           0 :     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvCubic: incorrect BoundRType!", _state);
   22836           0 :     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvCubic: incorrect BoundLType/BoundRType!", _state);
   22837           0 :     if( boundltype==1||boundltype==2 )
   22838             :     {
   22839           0 :         ae_assert(ae_isfinite(boundl, _state), "Spline1DConvCubic: BoundL is infinite or NAN!", _state);
   22840             :     }
   22841           0 :     if( boundrtype==1||boundrtype==2 )
   22842             :     {
   22843           0 :         ae_assert(ae_isfinite(boundr, _state), "Spline1DConvCubic: BoundR is infinite or NAN!", _state);
   22844             :     }
   22845             :     
   22846             :     /*
   22847             :      * check lengths of arguments
   22848             :      */
   22849           0 :     ae_assert(n>=2, "Spline1DConvCubic: N<2!", _state);
   22850           0 :     ae_assert(x->cnt>=n, "Spline1DConvCubic: Length(X)<N!", _state);
   22851           0 :     ae_assert(y->cnt>=n, "Spline1DConvCubic: Length(Y)<N!", _state);
   22852           0 :     ae_assert(n2>=2, "Spline1DConvCubic: N2<2!", _state);
   22853           0 :     ae_assert(x2->cnt>=n2, "Spline1DConvCubic: Length(X2)<N2!", _state);
   22854             :     
   22855             :     /*
   22856             :      * check and sort X/Y
   22857             :      */
   22858           0 :     ylen = n;
   22859           0 :     if( boundltype==-1 )
   22860             :     {
   22861           0 :         ylen = n-1;
   22862             :     }
   22863           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DConvCubic: X contains infinite or NAN values!", _state);
   22864           0 :     ae_assert(isfinitevector(y, ylen, _state), "Spline1DConvCubic: Y contains infinite or NAN values!", _state);
   22865           0 :     ae_assert(isfinitevector(x2, n2, _state), "Spline1DConvCubic: X2 contains infinite or NAN values!", _state);
   22866           0 :     spline1d_heapsortppoints(x, y, &p, n, _state);
   22867           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DConvCubic: at least two consequent points are too close!", _state);
   22868             :     
   22869             :     /*
   22870             :      * set up DT (we will need it below)
   22871             :      */
   22872           0 :     ae_vector_set_length(&dt, ae_maxint(n, n2, _state), _state);
   22873             :     
   22874             :     /*
   22875             :      * sort X2:
   22876             :      * * use fake array DT because HeapSortPPoints() needs both integer AND real arrays
   22877             :      * * if we have periodic problem, wrap points
   22878             :      * * sort them, store permutation at P2
   22879             :      */
   22880           0 :     if( boundrtype==-1&&boundltype==-1 )
   22881             :     {
   22882           0 :         for(i=0; i<=n2-1; i++)
   22883             :         {
   22884           0 :             t = x2->ptr.p_double[i];
   22885           0 :             apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state);
   22886           0 :             x2->ptr.p_double[i] = t;
   22887             :         }
   22888             :     }
   22889           0 :     spline1d_heapsortppoints(x2, &dt, &p2, n2, _state);
   22890             :     
   22891             :     /*
   22892             :      * Now we've checked and preordered everything, so we:
   22893             :      * * call internal GridDiff() function to get Hermite form of spline
   22894             :      * * convert using internal Conv() function
   22895             :      * * convert Y2 back to original order
   22896             :      */
   22897           0 :     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state);
   22898           0 :     spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, &d1, ae_false, &d2, ae_false, _state);
   22899           0 :     ae_assert(dt.cnt>=n2, "Spline1DConvCubic: internal error!", _state);
   22900           0 :     for(i=0; i<=n2-1; i++)
   22901             :     {
   22902           0 :         dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i];
   22903             :     }
   22904           0 :     ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
   22905           0 :     ae_frame_leave(_state);
   22906           0 : }
   22907             : 
   22908             : 
   22909             : /*************************************************************************
   22910             : This function solves following problem: given table y[] of function values
   22911             : at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
   22912             : function values y2[] and derivatives d2[] (calculated at x2[]).
   22913             : 
   22914             : This function yields same result as Spline1DBuildCubic() call followed  by
   22915             : sequence of Spline1DDiff() calls, but it can be several times faster  when
   22916             : called for ordered X[] and X2[].
   22917             : 
   22918             : INPUT PARAMETERS:
   22919             :     X           -   old spline nodes
   22920             :     Y           -   function values
   22921             :     X2           -  new spline nodes
   22922             : 
   22923             : OPTIONAL PARAMETERS:
   22924             :     N           -   points count:
   22925             :                     * N>=2
   22926             :                     * if given, only first N points from X/Y are used
   22927             :                     * if not given, automatically detected from X/Y sizes
   22928             :                       (len(X) must be equal to len(Y))
   22929             :     BoundLType  -   boundary condition type for the left boundary
   22930             :     BoundL      -   left boundary condition (first or second derivative,
   22931             :                     depending on the BoundLType)
   22932             :     BoundRType  -   boundary condition type for the right boundary
   22933             :     BoundR      -   right boundary condition (first or second derivative,
   22934             :                     depending on the BoundRType)
   22935             :     N2          -   new points count:
   22936             :                     * N2>=2
   22937             :                     * if given, only first N2 points from X2 are used
   22938             :                     * if not given, automatically detected from X2 size
   22939             : 
   22940             : OUTPUT PARAMETERS:
   22941             :     F2          -   function values at X2[]
   22942             :     D2          -   first derivatives at X2[]
   22943             : 
   22944             : ORDER OF POINTS
   22945             : 
   22946             : Subroutine automatically sorts points, so caller  may pass unsorted array.
   22947             : Function  values  are correctly reordered on  return, so F2[I]  is  always
   22948             : equal to S(X2[I]) independently of points order.
   22949             : 
   22950             : SETTING BOUNDARY VALUES:
   22951             : 
   22952             : The BoundLType/BoundRType parameters can have the following values:
   22953             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
   22954             :           In this case:
   22955             :           * both BoundLType and BoundRType must be equal to -1.
   22956             :           * BoundL/BoundR are ignored
   22957             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
   22958             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
   22959             :           (BoundL and/or BoundR are ignored).
   22960             :     *  1, which corresponds to the first derivative boundary condition
   22961             :     *  2, which corresponds to the second derivative boundary condition
   22962             :     *  by default, BoundType=0 is used
   22963             : 
   22964             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
   22965             : 
   22966             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
   22967             : However, this subroutine doesn't require you to specify equal  values  for
   22968             : the first and last points - it automatically forces them  to  be  equal by
   22969             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
   22970             : Y[last_point]. However it is recommended to pass consistent values of Y[],
   22971             : i.e. to make Y[first_point]=Y[last_point].
   22972             : 
   22973             :   -- ALGLIB PROJECT --
   22974             :      Copyright 03.09.2010 by Bochkanov Sergey
   22975             : *************************************************************************/
   22976           0 : void spline1dconvdiffcubic(/* Real    */ ae_vector* x,
   22977             :      /* Real    */ ae_vector* y,
   22978             :      ae_int_t n,
   22979             :      ae_int_t boundltype,
   22980             :      double boundl,
   22981             :      ae_int_t boundrtype,
   22982             :      double boundr,
   22983             :      /* Real    */ ae_vector* x2,
   22984             :      ae_int_t n2,
   22985             :      /* Real    */ ae_vector* y2,
   22986             :      /* Real    */ ae_vector* d2,
   22987             :      ae_state *_state)
   22988             : {
   22989             :     ae_frame _frame_block;
   22990             :     ae_vector _x;
   22991             :     ae_vector _y;
   22992             :     ae_vector _x2;
   22993             :     ae_vector a1;
   22994             :     ae_vector a2;
   22995             :     ae_vector a3;
   22996             :     ae_vector b;
   22997             :     ae_vector d;
   22998             :     ae_vector dt;
   22999             :     ae_vector rt1;
   23000             :     ae_vector p;
   23001             :     ae_vector p2;
   23002             :     ae_int_t i;
   23003             :     ae_int_t ylen;
   23004             :     double t;
   23005             :     double t2;
   23006             : 
   23007           0 :     ae_frame_make(_state, &_frame_block);
   23008           0 :     memset(&_x, 0, sizeof(_x));
   23009           0 :     memset(&_y, 0, sizeof(_y));
   23010           0 :     memset(&_x2, 0, sizeof(_x2));
   23011           0 :     memset(&a1, 0, sizeof(a1));
   23012           0 :     memset(&a2, 0, sizeof(a2));
   23013           0 :     memset(&a3, 0, sizeof(a3));
   23014           0 :     memset(&b, 0, sizeof(b));
   23015           0 :     memset(&d, 0, sizeof(d));
   23016           0 :     memset(&dt, 0, sizeof(dt));
   23017           0 :     memset(&rt1, 0, sizeof(rt1));
   23018           0 :     memset(&p, 0, sizeof(p));
   23019           0 :     memset(&p2, 0, sizeof(p2));
   23020           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   23021           0 :     x = &_x;
   23022           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   23023           0 :     y = &_y;
   23024           0 :     ae_vector_init_copy(&_x2, x2, _state, ae_true);
   23025           0 :     x2 = &_x2;
   23026           0 :     ae_vector_clear(y2);
   23027           0 :     ae_vector_clear(d2);
   23028           0 :     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
   23029           0 :     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
   23030           0 :     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
   23031           0 :     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
   23032           0 :     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
   23033           0 :     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
   23034           0 :     ae_vector_init(&rt1, 0, DT_REAL, _state, ae_true);
   23035           0 :     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
   23036           0 :     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
   23037             : 
   23038             :     
   23039             :     /*
   23040             :      * check correctness of boundary conditions
   23041             :      */
   23042           0 :     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvDiffCubic: incorrect BoundLType!", _state);
   23043           0 :     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvDiffCubic: incorrect BoundRType!", _state);
   23044           0 :     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvDiffCubic: incorrect BoundLType/BoundRType!", _state);
   23045           0 :     if( boundltype==1||boundltype==2 )
   23046             :     {
   23047           0 :         ae_assert(ae_isfinite(boundl, _state), "Spline1DConvDiffCubic: BoundL is infinite or NAN!", _state);
   23048             :     }
   23049           0 :     if( boundrtype==1||boundrtype==2 )
   23050             :     {
   23051           0 :         ae_assert(ae_isfinite(boundr, _state), "Spline1DConvDiffCubic: BoundR is infinite or NAN!", _state);
   23052             :     }
   23053             :     
   23054             :     /*
   23055             :      * check lengths of arguments
   23056             :      */
   23057           0 :     ae_assert(n>=2, "Spline1DConvDiffCubic: N<2!", _state);
   23058           0 :     ae_assert(x->cnt>=n, "Spline1DConvDiffCubic: Length(X)<N!", _state);
   23059           0 :     ae_assert(y->cnt>=n, "Spline1DConvDiffCubic: Length(Y)<N!", _state);
   23060           0 :     ae_assert(n2>=2, "Spline1DConvDiffCubic: N2<2!", _state);
   23061           0 :     ae_assert(x2->cnt>=n2, "Spline1DConvDiffCubic: Length(X2)<N2!", _state);
   23062             :     
   23063             :     /*
   23064             :      * check and sort X/Y
   23065             :      */
   23066           0 :     ylen = n;
   23067           0 :     if( boundltype==-1 )
   23068             :     {
   23069           0 :         ylen = n-1;
   23070             :     }
   23071           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DConvDiffCubic: X contains infinite or NAN values!", _state);
   23072           0 :     ae_assert(isfinitevector(y, ylen, _state), "Spline1DConvDiffCubic: Y contains infinite or NAN values!", _state);
   23073           0 :     ae_assert(isfinitevector(x2, n2, _state), "Spline1DConvDiffCubic: X2 contains infinite or NAN values!", _state);
   23074           0 :     spline1d_heapsortppoints(x, y, &p, n, _state);
   23075           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DConvDiffCubic: at least two consequent points are too close!", _state);
   23076             :     
   23077             :     /*
   23078             :      * set up DT (we will need it below)
   23079             :      */
   23080           0 :     ae_vector_set_length(&dt, ae_maxint(n, n2, _state), _state);
   23081             :     
   23082             :     /*
   23083             :      * sort X2:
   23084             :      * * use fake array DT because HeapSortPPoints() needs both integer AND real arrays
   23085             :      * * if we have periodic problem, wrap points
   23086             :      * * sort them, store permutation at P2
   23087             :      */
   23088           0 :     if( boundrtype==-1&&boundltype==-1 )
   23089             :     {
   23090           0 :         for(i=0; i<=n2-1; i++)
   23091             :         {
   23092           0 :             t = x2->ptr.p_double[i];
   23093           0 :             apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state);
   23094           0 :             x2->ptr.p_double[i] = t;
   23095             :         }
   23096             :     }
   23097           0 :     spline1d_heapsortppoints(x2, &dt, &p2, n2, _state);
   23098             :     
   23099             :     /*
   23100             :      * Now we've checked and preordered everything, so we:
   23101             :      * * call internal GridDiff() function to get Hermite form of spline
   23102             :      * * convert using internal Conv() function
   23103             :      * * convert Y2 back to original order
   23104             :      */
   23105           0 :     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state);
   23106           0 :     spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, d2, ae_true, &rt1, ae_false, _state);
   23107           0 :     ae_assert(dt.cnt>=n2, "Spline1DConvDiffCubic: internal error!", _state);
   23108           0 :     for(i=0; i<=n2-1; i++)
   23109             :     {
   23110           0 :         dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i];
   23111             :     }
   23112           0 :     ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
   23113           0 :     for(i=0; i<=n2-1; i++)
   23114             :     {
   23115           0 :         dt.ptr.p_double[p2.ptr.p_int[i]] = d2->ptr.p_double[i];
   23116             :     }
   23117           0 :     ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
   23118           0 :     ae_frame_leave(_state);
   23119           0 : }
   23120             : 
   23121             : 
   23122             : /*************************************************************************
   23123             : This function solves following problem: given table y[] of function values
   23124             : at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
   23125             : function  values  y2[],  first  and  second  derivatives  d2[]  and  dd2[]
   23126             : (calculated at x2[]).
   23127             : 
   23128             : This function yields same result as Spline1DBuildCubic() call followed  by
   23129             : sequence of Spline1DDiff() calls, but it can be several times faster  when
   23130             : called for ordered X[] and X2[].
   23131             : 
   23132             : INPUT PARAMETERS:
   23133             :     X           -   old spline nodes
   23134             :     Y           -   function values
   23135             :     X2           -  new spline nodes
   23136             : 
   23137             : OPTIONAL PARAMETERS:
   23138             :     N           -   points count:
   23139             :                     * N>=2
   23140             :                     * if given, only first N points from X/Y are used
   23141             :                     * if not given, automatically detected from X/Y sizes
   23142             :                       (len(X) must be equal to len(Y))
   23143             :     BoundLType  -   boundary condition type for the left boundary
   23144             :     BoundL      -   left boundary condition (first or second derivative,
   23145             :                     depending on the BoundLType)
   23146             :     BoundRType  -   boundary condition type for the right boundary
   23147             :     BoundR      -   right boundary condition (first or second derivative,
   23148             :                     depending on the BoundRType)
   23149             :     N2          -   new points count:
   23150             :                     * N2>=2
   23151             :                     * if given, only first N2 points from X2 are used
   23152             :                     * if not given, automatically detected from X2 size
   23153             : 
   23154             : OUTPUT PARAMETERS:
   23155             :     F2          -   function values at X2[]
   23156             :     D2          -   first derivatives at X2[]
   23157             :     DD2         -   second derivatives at X2[]
   23158             : 
   23159             : ORDER OF POINTS
   23160             : 
   23161             : Subroutine automatically sorts points, so caller  may pass unsorted array.
   23162             : Function  values  are correctly reordered on  return, so F2[I]  is  always
   23163             : equal to S(X2[I]) independently of points order.
   23164             : 
   23165             : SETTING BOUNDARY VALUES:
   23166             : 
   23167             : The BoundLType/BoundRType parameters can have the following values:
   23168             :     * -1, which corresonds to the periodic (cyclic) boundary conditions.
   23169             :           In this case:
   23170             :           * both BoundLType and BoundRType must be equal to -1.
   23171             :           * BoundL/BoundR are ignored
   23172             :           * Y[last] is ignored (it is assumed to be equal to Y[first]).
   23173             :     *  0, which  corresponds  to  the  parabolically   terminated  spline
   23174             :           (BoundL and/or BoundR are ignored).
   23175             :     *  1, which corresponds to the first derivative boundary condition
   23176             :     *  2, which corresponds to the second derivative boundary condition
   23177             :     *  by default, BoundType=0 is used
   23178             : 
   23179             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
   23180             : 
   23181             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
   23182             : However, this subroutine doesn't require you to specify equal  values  for
   23183             : the first and last points - it automatically forces them  to  be  equal by
   23184             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
   23185             : Y[last_point]. However it is recommended to pass consistent values of Y[],
   23186             : i.e. to make Y[first_point]=Y[last_point].
   23187             : 
   23188             :   -- ALGLIB PROJECT --
   23189             :      Copyright 03.09.2010 by Bochkanov Sergey
   23190             : *************************************************************************/
   23191           0 : void spline1dconvdiff2cubic(/* Real    */ ae_vector* x,
   23192             :      /* Real    */ ae_vector* y,
   23193             :      ae_int_t n,
   23194             :      ae_int_t boundltype,
   23195             :      double boundl,
   23196             :      ae_int_t boundrtype,
   23197             :      double boundr,
   23198             :      /* Real    */ ae_vector* x2,
   23199             :      ae_int_t n2,
   23200             :      /* Real    */ ae_vector* y2,
   23201             :      /* Real    */ ae_vector* d2,
   23202             :      /* Real    */ ae_vector* dd2,
   23203             :      ae_state *_state)
   23204             : {
   23205             :     ae_frame _frame_block;
   23206             :     ae_vector _x;
   23207             :     ae_vector _y;
   23208             :     ae_vector _x2;
   23209             :     ae_vector a1;
   23210             :     ae_vector a2;
   23211             :     ae_vector a3;
   23212             :     ae_vector b;
   23213             :     ae_vector d;
   23214             :     ae_vector dt;
   23215             :     ae_vector p;
   23216             :     ae_vector p2;
   23217             :     ae_int_t i;
   23218             :     ae_int_t ylen;
   23219             :     double t;
   23220             :     double t2;
   23221             : 
   23222           0 :     ae_frame_make(_state, &_frame_block);
   23223           0 :     memset(&_x, 0, sizeof(_x));
   23224           0 :     memset(&_y, 0, sizeof(_y));
   23225           0 :     memset(&_x2, 0, sizeof(_x2));
   23226           0 :     memset(&a1, 0, sizeof(a1));
   23227           0 :     memset(&a2, 0, sizeof(a2));
   23228           0 :     memset(&a3, 0, sizeof(a3));
   23229           0 :     memset(&b, 0, sizeof(b));
   23230           0 :     memset(&d, 0, sizeof(d));
   23231           0 :     memset(&dt, 0, sizeof(dt));
   23232           0 :     memset(&p, 0, sizeof(p));
   23233           0 :     memset(&p2, 0, sizeof(p2));
   23234           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   23235           0 :     x = &_x;
   23236           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   23237           0 :     y = &_y;
   23238           0 :     ae_vector_init_copy(&_x2, x2, _state, ae_true);
   23239           0 :     x2 = &_x2;
   23240           0 :     ae_vector_clear(y2);
   23241           0 :     ae_vector_clear(d2);
   23242           0 :     ae_vector_clear(dd2);
   23243           0 :     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
   23244           0 :     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
   23245           0 :     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
   23246           0 :     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
   23247           0 :     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
   23248           0 :     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
   23249           0 :     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
   23250           0 :     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
   23251             : 
   23252             :     
   23253             :     /*
   23254             :      * check correctness of boundary conditions
   23255             :      */
   23256           0 :     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvDiff2Cubic: incorrect BoundLType!", _state);
   23257           0 :     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvDiff2Cubic: incorrect BoundRType!", _state);
   23258           0 :     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvDiff2Cubic: incorrect BoundLType/BoundRType!", _state);
   23259           0 :     if( boundltype==1||boundltype==2 )
   23260             :     {
   23261           0 :         ae_assert(ae_isfinite(boundl, _state), "Spline1DConvDiff2Cubic: BoundL is infinite or NAN!", _state);
   23262             :     }
   23263           0 :     if( boundrtype==1||boundrtype==2 )
   23264             :     {
   23265           0 :         ae_assert(ae_isfinite(boundr, _state), "Spline1DConvDiff2Cubic: BoundR is infinite or NAN!", _state);
   23266             :     }
   23267             :     
   23268             :     /*
   23269             :      * check lengths of arguments
   23270             :      */
   23271           0 :     ae_assert(n>=2, "Spline1DConvDiff2Cubic: N<2!", _state);
   23272           0 :     ae_assert(x->cnt>=n, "Spline1DConvDiff2Cubic: Length(X)<N!", _state);
   23273           0 :     ae_assert(y->cnt>=n, "Spline1DConvDiff2Cubic: Length(Y)<N!", _state);
   23274           0 :     ae_assert(n2>=2, "Spline1DConvDiff2Cubic: N2<2!", _state);
   23275           0 :     ae_assert(x2->cnt>=n2, "Spline1DConvDiff2Cubic: Length(X2)<N2!", _state);
   23276             :     
   23277             :     /*
   23278             :      * check and sort X/Y
   23279             :      */
   23280           0 :     ylen = n;
   23281           0 :     if( boundltype==-1 )
   23282             :     {
   23283           0 :         ylen = n-1;
   23284             :     }
   23285           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DConvDiff2Cubic: X contains infinite or NAN values!", _state);
   23286           0 :     ae_assert(isfinitevector(y, ylen, _state), "Spline1DConvDiff2Cubic: Y contains infinite or NAN values!", _state);
   23287           0 :     ae_assert(isfinitevector(x2, n2, _state), "Spline1DConvDiff2Cubic: X2 contains infinite or NAN values!", _state);
   23288           0 :     spline1d_heapsortppoints(x, y, &p, n, _state);
   23289           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DConvDiff2Cubic: at least two consequent points are too close!", _state);
   23290             :     
   23291             :     /*
   23292             :      * set up DT (we will need it below)
   23293             :      */
   23294           0 :     ae_vector_set_length(&dt, ae_maxint(n, n2, _state), _state);
   23295             :     
   23296             :     /*
   23297             :      * sort X2:
   23298             :      * * use fake array DT because HeapSortPPoints() needs both integer AND real arrays
   23299             :      * * if we have periodic problem, wrap points
   23300             :      * * sort them, store permutation at P2
   23301             :      */
   23302           0 :     if( boundrtype==-1&&boundltype==-1 )
   23303             :     {
   23304           0 :         for(i=0; i<=n2-1; i++)
   23305             :         {
   23306           0 :             t = x2->ptr.p_double[i];
   23307           0 :             apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state);
   23308           0 :             x2->ptr.p_double[i] = t;
   23309             :         }
   23310             :     }
   23311           0 :     spline1d_heapsortppoints(x2, &dt, &p2, n2, _state);
   23312             :     
   23313             :     /*
   23314             :      * Now we've checked and preordered everything, so we:
   23315             :      * * call internal GridDiff() function to get Hermite form of spline
   23316             :      * * convert using internal Conv() function
   23317             :      * * convert Y2 back to original order
   23318             :      */
   23319           0 :     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state);
   23320           0 :     spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, d2, ae_true, dd2, ae_true, _state);
   23321           0 :     ae_assert(dt.cnt>=n2, "Spline1DConvDiff2Cubic: internal error!", _state);
   23322           0 :     for(i=0; i<=n2-1; i++)
   23323             :     {
   23324           0 :         dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i];
   23325             :     }
   23326           0 :     ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
   23327           0 :     for(i=0; i<=n2-1; i++)
   23328             :     {
   23329           0 :         dt.ptr.p_double[p2.ptr.p_int[i]] = d2->ptr.p_double[i];
   23330             :     }
   23331           0 :     ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
   23332           0 :     for(i=0; i<=n2-1; i++)
   23333             :     {
   23334           0 :         dt.ptr.p_double[p2.ptr.p_int[i]] = dd2->ptr.p_double[i];
   23335             :     }
   23336           0 :     ae_v_move(&dd2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
   23337           0 :     ae_frame_leave(_state);
   23338           0 : }
   23339             : 
   23340             : 
   23341             : /*************************************************************************
   23342             : This subroutine builds Catmull-Rom spline interpolant.
   23343             : 
   23344             : INPUT PARAMETERS:
   23345             :     X           -   spline nodes, array[0..N-1].
   23346             :     Y           -   function values, array[0..N-1].
   23347             :     
   23348             : OPTIONAL PARAMETERS:
   23349             :     N           -   points count:
   23350             :                     * N>=2
   23351             :                     * if given, only first N points are used to build spline
   23352             :                     * if not given, automatically detected from X/Y sizes
   23353             :                       (len(X) must be equal to len(Y))
   23354             :     BoundType   -   boundary condition type:
   23355             :                     * -1 for periodic boundary condition
   23356             :                     *  0 for parabolically terminated spline (default)
   23357             :     Tension     -   tension parameter:
   23358             :                     * tension=0   corresponds to classic Catmull-Rom spline (default)
   23359             :                     * 0<tension<1 corresponds to more general form - cardinal spline
   23360             : 
   23361             : OUTPUT PARAMETERS:
   23362             :     C           -   spline interpolant
   23363             : 
   23364             : 
   23365             : ORDER OF POINTS
   23366             : 
   23367             : Subroutine automatically sorts points, so caller may pass unsorted array.
   23368             : 
   23369             : PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
   23370             : 
   23371             : Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
   23372             : However, this subroutine doesn't require you to specify equal  values  for
   23373             : the first and last points - it automatically forces them  to  be  equal by
   23374             : copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
   23375             : Y[last_point]. However it is recommended to pass consistent values of Y[],
   23376             : i.e. to make Y[first_point]=Y[last_point].
   23377             : 
   23378             :   -- ALGLIB PROJECT --
   23379             :      Copyright 23.06.2007 by Bochkanov Sergey
   23380             : *************************************************************************/
   23381           0 : void spline1dbuildcatmullrom(/* Real    */ ae_vector* x,
   23382             :      /* Real    */ ae_vector* y,
   23383             :      ae_int_t n,
   23384             :      ae_int_t boundtype,
   23385             :      double tension,
   23386             :      spline1dinterpolant* c,
   23387             :      ae_state *_state)
   23388             : {
   23389             :     ae_frame _frame_block;
   23390             :     ae_vector _x;
   23391             :     ae_vector _y;
   23392             :     ae_vector d;
   23393             :     ae_int_t i;
   23394             : 
   23395           0 :     ae_frame_make(_state, &_frame_block);
   23396           0 :     memset(&_x, 0, sizeof(_x));
   23397           0 :     memset(&_y, 0, sizeof(_y));
   23398           0 :     memset(&d, 0, sizeof(d));
   23399           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   23400           0 :     x = &_x;
   23401           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   23402           0 :     y = &_y;
   23403           0 :     _spline1dinterpolant_clear(c);
   23404           0 :     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
   23405             : 
   23406           0 :     ae_assert(n>=2, "Spline1DBuildCatmullRom: N<2!", _state);
   23407           0 :     ae_assert(boundtype==-1||boundtype==0, "Spline1DBuildCatmullRom: incorrect BoundType!", _state);
   23408           0 :     ae_assert(ae_fp_greater_eq(tension,(double)(0)), "Spline1DBuildCatmullRom: Tension<0!", _state);
   23409           0 :     ae_assert(ae_fp_less_eq(tension,(double)(1)), "Spline1DBuildCatmullRom: Tension>1!", _state);
   23410           0 :     ae_assert(x->cnt>=n, "Spline1DBuildCatmullRom: Length(X)<N!", _state);
   23411           0 :     ae_assert(y->cnt>=n, "Spline1DBuildCatmullRom: Length(Y)<N!", _state);
   23412             :     
   23413             :     /*
   23414             :      * check and sort points
   23415             :      */
   23416           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildCatmullRom: X contains infinite or NAN values!", _state);
   23417           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DBuildCatmullRom: Y contains infinite or NAN values!", _state);
   23418           0 :     spline1d_heapsortpoints(x, y, n, _state);
   23419           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DBuildCatmullRom: at least two consequent points are too close!", _state);
   23420             :     
   23421             :     /*
   23422             :      * Special cases:
   23423             :      * * N=2, parabolic terminated boundary condition on both ends
   23424             :      * * N=2, periodic boundary condition
   23425             :      */
   23426           0 :     if( n==2&&boundtype==0 )
   23427             :     {
   23428             :         
   23429             :         /*
   23430             :          * Just linear spline
   23431             :          */
   23432           0 :         spline1dbuildlinear(x, y, n, c, _state);
   23433           0 :         ae_frame_leave(_state);
   23434           0 :         return;
   23435             :     }
   23436           0 :     if( n==2&&boundtype==-1 )
   23437             :     {
   23438             :         
   23439             :         /*
   23440             :          * Same as cubic spline with periodic conditions
   23441             :          */
   23442           0 :         spline1dbuildcubic(x, y, n, -1, 0.0, -1, 0.0, c, _state);
   23443           0 :         ae_frame_leave(_state);
   23444           0 :         return;
   23445             :     }
   23446             :     
   23447             :     /*
   23448             :      * Periodic or non-periodic boundary conditions
   23449             :      */
   23450           0 :     if( boundtype==-1 )
   23451             :     {
   23452             :         
   23453             :         /*
   23454             :          * Periodic boundary conditions
   23455             :          */
   23456           0 :         y->ptr.p_double[n-1] = y->ptr.p_double[0];
   23457           0 :         ae_vector_set_length(&d, n, _state);
   23458           0 :         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]));
   23459           0 :         for(i=1; i<=n-2; i++)
   23460             :         {
   23461           0 :             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]);
   23462             :         }
   23463           0 :         d.ptr.p_double[n-1] = d.ptr.p_double[0];
   23464             :         
   23465             :         /*
   23466             :          * Now problem is reduced to the cubic Hermite spline
   23467             :          */
   23468           0 :         spline1dbuildhermite(x, y, &d, n, c, _state);
   23469           0 :         c->periodic = ae_true;
   23470             :     }
   23471             :     else
   23472             :     {
   23473             :         
   23474             :         /*
   23475             :          * Non-periodic boundary conditions
   23476             :          */
   23477           0 :         ae_vector_set_length(&d, n, _state);
   23478           0 :         for(i=1; i<=n-2; i++)
   23479             :         {
   23480           0 :             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]);
   23481             :         }
   23482           0 :         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];
   23483           0 :         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];
   23484             :         
   23485             :         /*
   23486             :          * Now problem is reduced to the cubic Hermite spline
   23487             :          */
   23488           0 :         spline1dbuildhermite(x, y, &d, n, c, _state);
   23489             :     }
   23490           0 :     ae_frame_leave(_state);
   23491             : }
   23492             : 
   23493             : 
   23494             : /*************************************************************************
   23495             : This subroutine builds Hermite spline interpolant.
   23496             : 
   23497             : INPUT PARAMETERS:
   23498             :     X           -   spline nodes, array[0..N-1]
   23499             :     Y           -   function values, array[0..N-1]
   23500             :     D           -   derivatives, array[0..N-1]
   23501             :     N           -   points count (optional):
   23502             :                     * N>=2
   23503             :                     * if given, only first N points are used to build spline
   23504             :                     * if not given, automatically detected from X/Y sizes
   23505             :                       (len(X) must be equal to len(Y))
   23506             : 
   23507             : OUTPUT PARAMETERS:
   23508             :     C           -   spline interpolant.
   23509             : 
   23510             : 
   23511             : ORDER OF POINTS
   23512             : 
   23513             : Subroutine automatically sorts points, so caller may pass unsorted array.
   23514             : 
   23515             :   -- ALGLIB PROJECT --
   23516             :      Copyright 23.06.2007 by Bochkanov Sergey
   23517             : *************************************************************************/
   23518           0 : void spline1dbuildhermite(/* Real    */ ae_vector* x,
   23519             :      /* Real    */ ae_vector* y,
   23520             :      /* Real    */ ae_vector* d,
   23521             :      ae_int_t n,
   23522             :      spline1dinterpolant* c,
   23523             :      ae_state *_state)
   23524             : {
   23525             :     ae_frame _frame_block;
   23526             :     ae_vector _x;
   23527             :     ae_vector _y;
   23528             :     ae_vector _d;
   23529             :     ae_int_t i;
   23530             :     double delta;
   23531             :     double delta2;
   23532             :     double delta3;
   23533             : 
   23534           0 :     ae_frame_make(_state, &_frame_block);
   23535           0 :     memset(&_x, 0, sizeof(_x));
   23536           0 :     memset(&_y, 0, sizeof(_y));
   23537           0 :     memset(&_d, 0, sizeof(_d));
   23538           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   23539           0 :     x = &_x;
   23540           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   23541           0 :     y = &_y;
   23542           0 :     ae_vector_init_copy(&_d, d, _state, ae_true);
   23543           0 :     d = &_d;
   23544           0 :     _spline1dinterpolant_clear(c);
   23545             : 
   23546           0 :     ae_assert(n>=2, "Spline1DBuildHermite: N<2!", _state);
   23547           0 :     ae_assert(x->cnt>=n, "Spline1DBuildHermite: Length(X)<N!", _state);
   23548           0 :     ae_assert(y->cnt>=n, "Spline1DBuildHermite: Length(Y)<N!", _state);
   23549           0 :     ae_assert(d->cnt>=n, "Spline1DBuildHermite: Length(D)<N!", _state);
   23550             :     
   23551             :     /*
   23552             :      * check and sort points
   23553             :      */
   23554           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildHermite: X contains infinite or NAN values!", _state);
   23555           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DBuildHermite: Y contains infinite or NAN values!", _state);
   23556           0 :     ae_assert(isfinitevector(d, n, _state), "Spline1DBuildHermite: D contains infinite or NAN values!", _state);
   23557           0 :     heapsortdpoints(x, y, d, n, _state);
   23558           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DBuildHermite: at least two consequent points are too close!", _state);
   23559             :     
   23560             :     /*
   23561             :      * Build
   23562             :      */
   23563           0 :     ae_vector_set_length(&c->x, n, _state);
   23564           0 :     ae_vector_set_length(&c->c, 4*(n-1)+2, _state);
   23565           0 :     c->periodic = ae_false;
   23566           0 :     c->k = 3;
   23567           0 :     c->n = n;
   23568           0 :     c->continuity = 1;
   23569           0 :     for(i=0; i<=n-1; i++)
   23570             :     {
   23571           0 :         c->x.ptr.p_double[i] = x->ptr.p_double[i];
   23572             :     }
   23573           0 :     for(i=0; i<=n-2; i++)
   23574             :     {
   23575           0 :         delta = x->ptr.p_double[i+1]-x->ptr.p_double[i];
   23576           0 :         delta2 = ae_sqr(delta, _state);
   23577           0 :         delta3 = delta*delta2;
   23578           0 :         c->c.ptr.p_double[4*i+0] = y->ptr.p_double[i];
   23579           0 :         c->c.ptr.p_double[4*i+1] = d->ptr.p_double[i];
   23580           0 :         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;
   23581           0 :         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;
   23582             :     }
   23583           0 :     c->c.ptr.p_double[4*(n-1)+0] = y->ptr.p_double[n-1];
   23584           0 :     c->c.ptr.p_double[4*(n-1)+1] = d->ptr.p_double[n-1];
   23585           0 :     ae_frame_leave(_state);
   23586           0 : }
   23587             : 
   23588             : 
   23589             : /*************************************************************************
   23590             : This subroutine builds Akima spline interpolant
   23591             : 
   23592             : INPUT PARAMETERS:
   23593             :     X           -   spline nodes, array[0..N-1]
   23594             :     Y           -   function values, array[0..N-1]
   23595             :     N           -   points count (optional):
   23596             :                     * N>=2
   23597             :                     * if given, only first N points are used to build spline
   23598             :                     * if not given, automatically detected from X/Y sizes
   23599             :                       (len(X) must be equal to len(Y))
   23600             : 
   23601             : OUTPUT PARAMETERS:
   23602             :     C           -   spline interpolant
   23603             : 
   23604             : 
   23605             : ORDER OF POINTS
   23606             : 
   23607             : Subroutine automatically sorts points, so caller may pass unsorted array.
   23608             : 
   23609             :   -- ALGLIB PROJECT --
   23610             :      Copyright 24.06.2007 by Bochkanov Sergey
   23611             : *************************************************************************/
   23612           0 : void spline1dbuildakima(/* Real    */ ae_vector* x,
   23613             :      /* Real    */ ae_vector* y,
   23614             :      ae_int_t n,
   23615             :      spline1dinterpolant* c,
   23616             :      ae_state *_state)
   23617             : {
   23618             :     ae_frame _frame_block;
   23619             :     ae_vector _x;
   23620             :     ae_vector _y;
   23621             :     ae_int_t i;
   23622             :     ae_vector d;
   23623             :     ae_vector w;
   23624             :     ae_vector diff;
   23625             : 
   23626           0 :     ae_frame_make(_state, &_frame_block);
   23627           0 :     memset(&_x, 0, sizeof(_x));
   23628           0 :     memset(&_y, 0, sizeof(_y));
   23629           0 :     memset(&d, 0, sizeof(d));
   23630           0 :     memset(&w, 0, sizeof(w));
   23631           0 :     memset(&diff, 0, sizeof(diff));
   23632           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   23633           0 :     x = &_x;
   23634           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   23635           0 :     y = &_y;
   23636           0 :     _spline1dinterpolant_clear(c);
   23637           0 :     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
   23638           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   23639           0 :     ae_vector_init(&diff, 0, DT_REAL, _state, ae_true);
   23640             : 
   23641           0 :     ae_assert(n>=2, "Spline1DBuildAkima: N<2!", _state);
   23642           0 :     ae_assert(x->cnt>=n, "Spline1DBuildAkima: Length(X)<N!", _state);
   23643           0 :     ae_assert(y->cnt>=n, "Spline1DBuildAkima: Length(Y)<N!", _state);
   23644             :     
   23645             :     /*
   23646             :      * check and sort points
   23647             :      */
   23648           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildAkima: X contains infinite or NAN values!", _state);
   23649           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DBuildAkima: Y contains infinite or NAN values!", _state);
   23650           0 :     spline1d_heapsortpoints(x, y, n, _state);
   23651           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DBuildAkima: at least two consequent points are too close!", _state);
   23652             :     
   23653             :     /*
   23654             :      * Handle special cases: N=2, N=3, N=4
   23655             :      */
   23656           0 :     if( n<=4 )
   23657             :     {
   23658           0 :         spline1dbuildcubic(x, y, n, 0, 0.0, 0, 0.0, c, _state);
   23659           0 :         ae_frame_leave(_state);
   23660           0 :         return;
   23661             :     }
   23662             :     
   23663             :     /*
   23664             :      * Prepare W (weights), Diff (divided differences)
   23665             :      */
   23666           0 :     ae_vector_set_length(&w, n-1, _state);
   23667           0 :     ae_vector_set_length(&diff, n-1, _state);
   23668           0 :     for(i=0; i<=n-2; i++)
   23669             :     {
   23670           0 :         diff.ptr.p_double[i] = (y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i]);
   23671             :     }
   23672           0 :     for(i=1; i<=n-2; i++)
   23673             :     {
   23674           0 :         w.ptr.p_double[i] = ae_fabs(diff.ptr.p_double[i]-diff.ptr.p_double[i-1], _state);
   23675             :     }
   23676             :     
   23677             :     /*
   23678             :      * Prepare Hermite interpolation scheme
   23679             :      */
   23680           0 :     ae_vector_set_length(&d, n, _state);
   23681           0 :     for(i=2; i<=n-3; i++)
   23682             :     {
   23683           0 :         if( ae_fp_neq(ae_fabs(w.ptr.p_double[i-1], _state)+ae_fabs(w.ptr.p_double[i+1], _state),(double)(0)) )
   23684             :         {
   23685           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]);
   23686             :         }
   23687             :         else
   23688             :         {
   23689           0 :             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]);
   23690             :         }
   23691             :     }
   23692           0 :     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);
   23693           0 :     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);
   23694           0 :     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);
   23695           0 :     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);
   23696             :     
   23697             :     /*
   23698             :      * Build Akima spline using Hermite interpolation scheme
   23699             :      */
   23700           0 :     spline1dbuildhermite(x, y, &d, n, c, _state);
   23701           0 :     ae_frame_leave(_state);
   23702             : }
   23703             : 
   23704             : 
   23705             : /*************************************************************************
   23706             : This subroutine calculates the value of the spline at the given point X.
   23707             : 
   23708             : INPUT PARAMETERS:
   23709             :     C   -   spline interpolant
   23710             :     X   -   point
   23711             : 
   23712             : Result:
   23713             :     S(x)
   23714             : 
   23715             :   -- ALGLIB PROJECT --
   23716             :      Copyright 23.06.2007 by Bochkanov Sergey
   23717             : *************************************************************************/
   23718           0 : double spline1dcalc(spline1dinterpolant* c, double x, ae_state *_state)
   23719             : {
   23720             :     ae_int_t l;
   23721             :     ae_int_t r;
   23722             :     ae_int_t m;
   23723             :     double t;
   23724             :     double result;
   23725             : 
   23726             : 
   23727           0 :     ae_assert(c->k==3, "Spline1DCalc: internal error", _state);
   23728           0 :     ae_assert(!ae_isinf(x, _state), "Spline1DCalc: infinite X!", _state);
   23729             :     
   23730             :     /*
   23731             :      * special case: NaN
   23732             :      */
   23733           0 :     if( ae_isnan(x, _state) )
   23734             :     {
   23735           0 :         result = _state->v_nan;
   23736           0 :         return result;
   23737             :     }
   23738             :     
   23739             :     /*
   23740             :      * correct if periodic
   23741             :      */
   23742           0 :     if( c->periodic )
   23743             :     {
   23744           0 :         apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state);
   23745             :     }
   23746             :     
   23747             :     /*
   23748             :      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
   23749             :      */
   23750           0 :     l = 0;
   23751           0 :     r = c->n-2+1;
   23752           0 :     while(l!=r-1)
   23753             :     {
   23754           0 :         m = (l+r)/2;
   23755           0 :         if( c->x.ptr.p_double[m]>=x )
   23756             :         {
   23757           0 :             r = m;
   23758             :         }
   23759             :         else
   23760             :         {
   23761           0 :             l = m;
   23762             :         }
   23763             :     }
   23764             :     
   23765             :     /*
   23766             :      * Interpolation
   23767             :      */
   23768           0 :     x = x-c->x.ptr.p_double[l];
   23769           0 :     m = 4*l;
   23770           0 :     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]));
   23771           0 :     return result;
   23772             : }
   23773             : 
   23774             : 
   23775             : /*************************************************************************
   23776             : This subroutine differentiates the spline.
   23777             : 
   23778             : INPUT PARAMETERS:
   23779             :     C   -   spline interpolant.
   23780             :     X   -   point
   23781             : 
   23782             : Result:
   23783             :     S   -   S(x)
   23784             :     DS  -   S'(x)
   23785             :     D2S -   S''(x)
   23786             : 
   23787             :   -- ALGLIB PROJECT --
   23788             :      Copyright 24.06.2007 by Bochkanov Sergey
   23789             : *************************************************************************/
   23790           0 : void spline1ddiff(spline1dinterpolant* c,
   23791             :      double x,
   23792             :      double* s,
   23793             :      double* ds,
   23794             :      double* d2s,
   23795             :      ae_state *_state)
   23796             : {
   23797             :     ae_int_t l;
   23798             :     ae_int_t r;
   23799             :     ae_int_t m;
   23800             :     double t;
   23801             : 
   23802           0 :     *s = 0;
   23803           0 :     *ds = 0;
   23804           0 :     *d2s = 0;
   23805             : 
   23806           0 :     ae_assert(c->k==3, "Spline1DDiff: internal error", _state);
   23807           0 :     ae_assert(!ae_isinf(x, _state), "Spline1DDiff: infinite X!", _state);
   23808             :     
   23809             :     /*
   23810             :      * special case: NaN
   23811             :      */
   23812           0 :     if( ae_isnan(x, _state) )
   23813             :     {
   23814           0 :         *s = _state->v_nan;
   23815           0 :         *ds = _state->v_nan;
   23816           0 :         *d2s = _state->v_nan;
   23817           0 :         return;
   23818             :     }
   23819             :     
   23820             :     /*
   23821             :      * correct if periodic
   23822             :      */
   23823           0 :     if( c->periodic )
   23824             :     {
   23825           0 :         apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state);
   23826             :     }
   23827             :     
   23828             :     /*
   23829             :      * Binary search
   23830             :      */
   23831           0 :     l = 0;
   23832           0 :     r = c->n-2+1;
   23833           0 :     while(l!=r-1)
   23834             :     {
   23835           0 :         m = (l+r)/2;
   23836           0 :         if( c->x.ptr.p_double[m]>=x )
   23837             :         {
   23838           0 :             r = m;
   23839             :         }
   23840             :         else
   23841             :         {
   23842           0 :             l = m;
   23843             :         }
   23844             :     }
   23845             :     
   23846             :     /*
   23847             :      * Differentiation
   23848             :      */
   23849           0 :     x = x-c->x.ptr.p_double[l];
   23850           0 :     m = 4*l;
   23851           0 :     *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]));
   23852           0 :     *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];
   23853           0 :     *d2s = 2*c->c.ptr.p_double[m+2]+6*x*c->c.ptr.p_double[m+3];
   23854             : }
   23855             : 
   23856             : 
   23857             : /*************************************************************************
   23858             : This subroutine makes the copy of the spline.
   23859             : 
   23860             : INPUT PARAMETERS:
   23861             :     C   -   spline interpolant.
   23862             : 
   23863             : Result:
   23864             :     CC  -   spline copy
   23865             : 
   23866             :   -- ALGLIB PROJECT --
   23867             :      Copyright 29.06.2007 by Bochkanov Sergey
   23868             : *************************************************************************/
   23869           0 : void spline1dcopy(spline1dinterpolant* c,
   23870             :      spline1dinterpolant* cc,
   23871             :      ae_state *_state)
   23872             : {
   23873             :     ae_int_t s;
   23874             : 
   23875           0 :     _spline1dinterpolant_clear(cc);
   23876             : 
   23877           0 :     cc->periodic = c->periodic;
   23878           0 :     cc->n = c->n;
   23879           0 :     cc->k = c->k;
   23880           0 :     cc->continuity = c->continuity;
   23881           0 :     ae_vector_set_length(&cc->x, cc->n, _state);
   23882           0 :     ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1));
   23883           0 :     s = c->c.cnt;
   23884           0 :     ae_vector_set_length(&cc->c, s, _state);
   23885           0 :     ae_v_move(&cc->c.ptr.p_double[0], 1, &c->c.ptr.p_double[0], 1, ae_v_len(0,s-1));
   23886           0 : }
   23887             : 
   23888             : 
   23889             : /*************************************************************************
   23890             : This subroutine unpacks the spline into the coefficients table.
   23891             : 
   23892             : INPUT PARAMETERS:
   23893             :     C   -   spline interpolant.
   23894             :     X   -   point
   23895             : 
   23896             : OUTPUT PARAMETERS:
   23897             :     Tbl -   coefficients table, unpacked format, array[0..N-2, 0..5].
   23898             :             For I = 0...N-2:
   23899             :                 Tbl[I,0] = X[i]
   23900             :                 Tbl[I,1] = X[i+1]
   23901             :                 Tbl[I,2] = C0
   23902             :                 Tbl[I,3] = C1
   23903             :                 Tbl[I,4] = C2
   23904             :                 Tbl[I,5] = C3
   23905             :             On [x[i], x[i+1]] spline is equals to:
   23906             :                 S(x) = C0 + C1*t + C2*t^2 + C3*t^3
   23907             :                 t = x-x[i]
   23908             :                 
   23909             : NOTE:
   23910             :     You  can rebuild spline with  Spline1DBuildHermite()  function,  which
   23911             :     accepts as inputs function values and derivatives at nodes, which  are
   23912             :     easy to calculate when you have coefficients.
   23913             : 
   23914             :   -- ALGLIB PROJECT --
   23915             :      Copyright 29.06.2007 by Bochkanov Sergey
   23916             : *************************************************************************/
   23917           0 : void spline1dunpack(spline1dinterpolant* c,
   23918             :      ae_int_t* n,
   23919             :      /* Real    */ ae_matrix* tbl,
   23920             :      ae_state *_state)
   23921             : {
   23922             :     ae_int_t i;
   23923             :     ae_int_t j;
   23924             : 
   23925           0 :     *n = 0;
   23926           0 :     ae_matrix_clear(tbl);
   23927             : 
   23928           0 :     ae_matrix_set_length(tbl, c->n-2+1, 2+c->k+1, _state);
   23929           0 :     *n = c->n;
   23930             :     
   23931             :     /*
   23932             :      * Fill
   23933             :      */
   23934           0 :     for(i=0; i<=*n-2; i++)
   23935             :     {
   23936           0 :         tbl->ptr.pp_double[i][0] = c->x.ptr.p_double[i];
   23937           0 :         tbl->ptr.pp_double[i][1] = c->x.ptr.p_double[i+1];
   23938           0 :         for(j=0; j<=c->k; j++)
   23939             :         {
   23940           0 :             tbl->ptr.pp_double[i][2+j] = c->c.ptr.p_double[(c->k+1)*i+j];
   23941             :         }
   23942             :     }
   23943           0 : }
   23944             : 
   23945             : 
   23946             : /*************************************************************************
   23947             : This subroutine performs linear transformation of the spline argument.
   23948             : 
   23949             : INPUT PARAMETERS:
   23950             :     C   -   spline interpolant.
   23951             :     A, B-   transformation coefficients: x = A*t + B
   23952             : Result:
   23953             :     C   -   transformed spline
   23954             : 
   23955             :   -- ALGLIB PROJECT --
   23956             :      Copyright 30.06.2007 by Bochkanov Sergey
   23957             : *************************************************************************/
   23958           0 : void spline1dlintransx(spline1dinterpolant* c,
   23959             :      double a,
   23960             :      double b,
   23961             :      ae_state *_state)
   23962             : {
   23963             :     ae_frame _frame_block;
   23964             :     ae_int_t i;
   23965             :     ae_int_t n;
   23966             :     double v;
   23967             :     double dv;
   23968             :     double d2v;
   23969             :     ae_vector x;
   23970             :     ae_vector y;
   23971             :     ae_vector d;
   23972             :     ae_bool isperiodic;
   23973             :     ae_int_t contval;
   23974             : 
   23975           0 :     ae_frame_make(_state, &_frame_block);
   23976           0 :     memset(&x, 0, sizeof(x));
   23977           0 :     memset(&y, 0, sizeof(y));
   23978           0 :     memset(&d, 0, sizeof(d));
   23979           0 :     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
   23980           0 :     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
   23981           0 :     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
   23982             : 
   23983           0 :     ae_assert(c->k==3, "Spline1DLinTransX: internal error", _state);
   23984           0 :     n = c->n;
   23985           0 :     ae_vector_set_length(&x, n, _state);
   23986           0 :     ae_vector_set_length(&y, n, _state);
   23987           0 :     ae_vector_set_length(&d, n, _state);
   23988             :     
   23989             :     /*
   23990             :      * Unpack, X, Y, dY/dX.
   23991             :      * Scale and pack with Spline1DBuildHermite again.
   23992             :      */
   23993           0 :     if( ae_fp_eq(a,(double)(0)) )
   23994             :     {
   23995             :         
   23996             :         /*
   23997             :          * Special case: A=0
   23998             :          */
   23999           0 :         v = spline1dcalc(c, b, _state);
   24000           0 :         for(i=0; i<=n-1; i++)
   24001             :         {
   24002           0 :             x.ptr.p_double[i] = c->x.ptr.p_double[i];
   24003           0 :             y.ptr.p_double[i] = v;
   24004           0 :             d.ptr.p_double[i] = 0.0;
   24005             :         }
   24006             :     }
   24007             :     else
   24008             :     {
   24009             :         
   24010             :         /*
   24011             :          * General case, A<>0
   24012             :          */
   24013           0 :         for(i=0; i<=n-1; i++)
   24014             :         {
   24015           0 :             x.ptr.p_double[i] = c->x.ptr.p_double[i];
   24016           0 :             spline1ddiff(c, x.ptr.p_double[i], &v, &dv, &d2v, _state);
   24017           0 :             x.ptr.p_double[i] = (x.ptr.p_double[i]-b)/a;
   24018           0 :             y.ptr.p_double[i] = v;
   24019           0 :             d.ptr.p_double[i] = a*dv;
   24020             :         }
   24021             :     }
   24022           0 :     isperiodic = c->periodic;
   24023           0 :     contval = c->continuity;
   24024           0 :     if( contval>0 )
   24025             :     {
   24026           0 :         spline1dbuildhermite(&x, &y, &d, n, c, _state);
   24027             :     }
   24028             :     else
   24029             :     {
   24030           0 :         spline1dbuildlinear(&x, &y, n, c, _state);
   24031             :     }
   24032           0 :     c->periodic = isperiodic;
   24033           0 :     c->continuity = contval;
   24034           0 :     ae_frame_leave(_state);
   24035           0 : }
   24036             : 
   24037             : 
   24038             : /*************************************************************************
   24039             : This subroutine performs linear transformation of the spline.
   24040             : 
   24041             : INPUT PARAMETERS:
   24042             :     C   -   spline interpolant.
   24043             :     A, B-   transformation coefficients: S2(x) = A*S(x) + B
   24044             : Result:
   24045             :     C   -   transformed spline
   24046             : 
   24047             :   -- ALGLIB PROJECT --
   24048             :      Copyright 30.06.2007 by Bochkanov Sergey
   24049             : *************************************************************************/
   24050           0 : void spline1dlintransy(spline1dinterpolant* c,
   24051             :      double a,
   24052             :      double b,
   24053             :      ae_state *_state)
   24054             : {
   24055             :     ae_int_t i;
   24056             :     ae_int_t j;
   24057             :     ae_int_t n;
   24058             : 
   24059             : 
   24060           0 :     ae_assert(c->k==3, "Spline1DLinTransX: internal error", _state);
   24061           0 :     n = c->n;
   24062           0 :     for(i=0; i<=n-2; i++)
   24063             :     {
   24064           0 :         c->c.ptr.p_double[4*i] = a*c->c.ptr.p_double[4*i]+b;
   24065           0 :         for(j=1; j<=3; j++)
   24066             :         {
   24067           0 :             c->c.ptr.p_double[4*i+j] = a*c->c.ptr.p_double[4*i+j];
   24068             :         }
   24069             :     }
   24070           0 :     c->c.ptr.p_double[4*(n-1)+0] = a*c->c.ptr.p_double[4*(n-1)+0]+b;
   24071           0 :     c->c.ptr.p_double[4*(n-1)+1] = a*c->c.ptr.p_double[4*(n-1)+1];
   24072           0 : }
   24073             : 
   24074             : 
   24075             : /*************************************************************************
   24076             : This subroutine integrates the spline.
   24077             : 
   24078             : INPUT PARAMETERS:
   24079             :     C   -   spline interpolant.
   24080             :     X   -   right bound of the integration interval [a, x],
   24081             :             here 'a' denotes min(x[])
   24082             : Result:
   24083             :     integral(S(t)dt,a,x)
   24084             : 
   24085             :   -- ALGLIB PROJECT --
   24086             :      Copyright 23.06.2007 by Bochkanov Sergey
   24087             : *************************************************************************/
   24088           0 : double spline1dintegrate(spline1dinterpolant* c,
   24089             :      double x,
   24090             :      ae_state *_state)
   24091             : {
   24092             :     ae_int_t n;
   24093             :     ae_int_t i;
   24094             :     ae_int_t j;
   24095             :     ae_int_t l;
   24096             :     ae_int_t r;
   24097             :     ae_int_t m;
   24098             :     double w;
   24099             :     double v;
   24100             :     double t;
   24101             :     double intab;
   24102             :     double additionalterm;
   24103             :     double result;
   24104             : 
   24105             : 
   24106           0 :     n = c->n;
   24107             :     
   24108             :     /*
   24109             :      * Periodic splines require special treatment. We make
   24110             :      * following transformation:
   24111             :      *
   24112             :      *     integral(S(t)dt,A,X) = integral(S(t)dt,A,Z)+AdditionalTerm
   24113             :      *
   24114             :      * here X may lie outside of [A,B], Z lies strictly in [A,B],
   24115             :      * AdditionalTerm is equals to integral(S(t)dt,A,B) times some
   24116             :      * integer number (may be zero).
   24117             :      */
   24118           0 :     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])) )
   24119             :     {
   24120             :         
   24121             :         /*
   24122             :          * compute integral(S(x)dx,A,B)
   24123             :          */
   24124           0 :         intab = (double)(0);
   24125           0 :         for(i=0; i<=c->n-2; i++)
   24126             :         {
   24127           0 :             w = c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i];
   24128           0 :             m = (c->k+1)*i;
   24129           0 :             intab = intab+c->c.ptr.p_double[m]*w;
   24130           0 :             v = w;
   24131           0 :             for(j=1; j<=c->k; j++)
   24132             :             {
   24133           0 :                 v = v*w;
   24134           0 :                 intab = intab+c->c.ptr.p_double[m+j]*v/(j+1);
   24135             :             }
   24136             :         }
   24137             :         
   24138             :         /*
   24139             :          * map X into [A,B]
   24140             :          */
   24141           0 :         apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state);
   24142           0 :         additionalterm = t*intab;
   24143             :     }
   24144             :     else
   24145             :     {
   24146           0 :         additionalterm = (double)(0);
   24147             :     }
   24148             :     
   24149             :     /*
   24150             :      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
   24151             :      */
   24152           0 :     l = 0;
   24153           0 :     r = n-2+1;
   24154           0 :     while(l!=r-1)
   24155             :     {
   24156           0 :         m = (l+r)/2;
   24157           0 :         if( ae_fp_greater_eq(c->x.ptr.p_double[m],x) )
   24158             :         {
   24159           0 :             r = m;
   24160             :         }
   24161             :         else
   24162             :         {
   24163           0 :             l = m;
   24164             :         }
   24165             :     }
   24166             :     
   24167             :     /*
   24168             :      * Integration
   24169             :      */
   24170           0 :     result = (double)(0);
   24171           0 :     for(i=0; i<=l-1; i++)
   24172             :     {
   24173           0 :         w = c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i];
   24174           0 :         m = (c->k+1)*i;
   24175           0 :         result = result+c->c.ptr.p_double[m]*w;
   24176           0 :         v = w;
   24177           0 :         for(j=1; j<=c->k; j++)
   24178             :         {
   24179           0 :             v = v*w;
   24180           0 :             result = result+c->c.ptr.p_double[m+j]*v/(j+1);
   24181             :         }
   24182             :     }
   24183           0 :     w = x-c->x.ptr.p_double[l];
   24184           0 :     m = (c->k+1)*l;
   24185           0 :     v = w;
   24186           0 :     result = result+c->c.ptr.p_double[m]*w;
   24187           0 :     for(j=1; j<=c->k; j++)
   24188             :     {
   24189           0 :         v = v*w;
   24190           0 :         result = result+c->c.ptr.p_double[m+j]*v/(j+1);
   24191             :     }
   24192           0 :     result = result+additionalterm;
   24193           0 :     return result;
   24194             : }
   24195             : 
   24196             : 
   24197             : /*************************************************************************
   24198             : Fitting by smoothing (penalized) cubic spline.
   24199             : 
   24200             : This function approximates N scattered points (some of X[] may be equal to
   24201             : each other) by cubic spline with M  nodes  at  equidistant  grid  spanning
   24202             : interval [min(x,xc),max(x,xc)].
   24203             : 
   24204             : The problem is regularized by adding nonlinearity penalty to  usual  least
   24205             : squares penalty function:
   24206             : 
   24207             :     MERIT_FUNC = F_LS + F_NL
   24208             : 
   24209             : where F_LS is a least squares error  term,  and  F_NL  is  a  nonlinearity
   24210             : penalty which is roughly proportional to LambdaNS*integral{ S''(x)^2*dx }.
   24211             : Algorithm applies automatic renormalization of F_NL  which  makes  penalty
   24212             : term roughly invariant to scaling of X[] and changes in M.
   24213             : 
   24214             : This function is a new edition  of  penalized  regression  spline fitting,
   24215             : a fast and compact one which needs much less resources that  its  previous
   24216             : version: just O(maxMN) memory and O(maxMN*log(maxMN)) time.
   24217             : 
   24218             : NOTE: it is OK to run this function with both M<<N and M>>N;  say,  it  is
   24219             :       possible to process 100 points with 1000-node spline.
   24220             :            
   24221             : INPUT PARAMETERS:
   24222             :     X           -   points, array[0..N-1].
   24223             :     Y           -   function values, array[0..N-1].
   24224             :     N           -   number of points (optional):
   24225             :                     * N>0
   24226             :                     * if given, only first N elements of X/Y are processed
   24227             :                     * if not given, automatically determined from lengths
   24228             :     M           -   number of basis functions ( = number_of_nodes), M>=4.
   24229             :     LambdaNS    -   LambdaNS>=0, regularization  constant  passed by user.
   24230             :                     It penalizes nonlinearity in the regression spline.
   24231             :                     Possible values to start from are 0.00001, 0.1, 1
   24232             : 
   24233             : OUTPUT PARAMETERS:
   24234             :     S   -   spline interpolant.
   24235             :     Rep -   Following fields are set:
   24236             :             * RMSError      rms error on the (X,Y).
   24237             :             * AvgError      average error on the (X,Y).
   24238             :             * AvgRelError   average relative error on the non-zero Y
   24239             :             * MaxError      maximum error
   24240             : 
   24241             :   -- ALGLIB PROJECT --
   24242             :      Copyright 27.08.2019 by Bochkanov Sergey
   24243             : *************************************************************************/
   24244           0 : void spline1dfit(/* Real    */ ae_vector* x,
   24245             :      /* Real    */ ae_vector* y,
   24246             :      ae_int_t n,
   24247             :      ae_int_t m,
   24248             :      double lambdans,
   24249             :      spline1dinterpolant* s,
   24250             :      spline1dfitreport* rep,
   24251             :      ae_state *_state)
   24252             : {
   24253             :     ae_frame _frame_block;
   24254             :     ae_vector _x;
   24255             :     ae_vector _y;
   24256             :     ae_int_t bfrad;
   24257             :     double xa;
   24258             :     double xb;
   24259             :     ae_int_t i;
   24260             :     ae_int_t j;
   24261             :     ae_int_t k;
   24262             :     ae_int_t k0;
   24263             :     ae_int_t k1;
   24264             :     double v;
   24265             :     double dv;
   24266             :     double d2v;
   24267             :     ae_int_t gridexpansion;
   24268             :     ae_vector xywork;
   24269             :     ae_matrix vterm;
   24270             :     ae_vector sx;
   24271             :     ae_vector sy;
   24272             :     ae_vector sdy;
   24273             :     ae_vector tmpx;
   24274             :     ae_vector tmpy;
   24275             :     spline1dinterpolant basis1;
   24276             :     sparsematrix av;
   24277             :     sparsematrix ah;
   24278             :     sparsematrix ata;
   24279             :     ae_vector targets;
   24280             :     double meany;
   24281             :     ae_int_t lsqrcnt;
   24282             :     ae_int_t nrel;
   24283             :     double rss;
   24284             :     double tss;
   24285             :     ae_int_t arows;
   24286             :     ae_vector tmp0;
   24287             :     ae_vector tmp1;
   24288             :     linlsqrstate solver;
   24289             :     linlsqrreport srep;
   24290             :     double creg;
   24291             :     double mxata;
   24292             :     ae_int_t bw;
   24293             :     ae_vector nzidx;
   24294             :     ae_vector nzval;
   24295             :     ae_int_t nzcnt;
   24296             :     double scaletargetsby;
   24297             :     double scalepenaltyby;
   24298             : 
   24299           0 :     ae_frame_make(_state, &_frame_block);
   24300           0 :     memset(&_x, 0, sizeof(_x));
   24301           0 :     memset(&_y, 0, sizeof(_y));
   24302           0 :     memset(&xywork, 0, sizeof(xywork));
   24303           0 :     memset(&vterm, 0, sizeof(vterm));
   24304           0 :     memset(&sx, 0, sizeof(sx));
   24305           0 :     memset(&sy, 0, sizeof(sy));
   24306           0 :     memset(&sdy, 0, sizeof(sdy));
   24307           0 :     memset(&tmpx, 0, sizeof(tmpx));
   24308           0 :     memset(&tmpy, 0, sizeof(tmpy));
   24309           0 :     memset(&basis1, 0, sizeof(basis1));
   24310           0 :     memset(&av, 0, sizeof(av));
   24311           0 :     memset(&ah, 0, sizeof(ah));
   24312           0 :     memset(&ata, 0, sizeof(ata));
   24313           0 :     memset(&targets, 0, sizeof(targets));
   24314           0 :     memset(&tmp0, 0, sizeof(tmp0));
   24315           0 :     memset(&tmp1, 0, sizeof(tmp1));
   24316           0 :     memset(&solver, 0, sizeof(solver));
   24317           0 :     memset(&srep, 0, sizeof(srep));
   24318           0 :     memset(&nzidx, 0, sizeof(nzidx));
   24319           0 :     memset(&nzval, 0, sizeof(nzval));
   24320           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   24321           0 :     x = &_x;
   24322           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   24323           0 :     y = &_y;
   24324           0 :     _spline1dinterpolant_clear(s);
   24325           0 :     _spline1dfitreport_clear(rep);
   24326           0 :     ae_vector_init(&xywork, 0, DT_REAL, _state, ae_true);
   24327           0 :     ae_matrix_init(&vterm, 0, 0, DT_REAL, _state, ae_true);
   24328           0 :     ae_vector_init(&sx, 0, DT_REAL, _state, ae_true);
   24329           0 :     ae_vector_init(&sy, 0, DT_REAL, _state, ae_true);
   24330           0 :     ae_vector_init(&sdy, 0, DT_REAL, _state, ae_true);
   24331           0 :     ae_vector_init(&tmpx, 0, DT_REAL, _state, ae_true);
   24332           0 :     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
   24333           0 :     _spline1dinterpolant_init(&basis1, _state, ae_true);
   24334           0 :     _sparsematrix_init(&av, _state, ae_true);
   24335           0 :     _sparsematrix_init(&ah, _state, ae_true);
   24336           0 :     _sparsematrix_init(&ata, _state, ae_true);
   24337           0 :     ae_vector_init(&targets, 0, DT_REAL, _state, ae_true);
   24338           0 :     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
   24339           0 :     ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true);
   24340           0 :     _linlsqrstate_init(&solver, _state, ae_true);
   24341           0 :     _linlsqrreport_init(&srep, _state, ae_true);
   24342           0 :     ae_vector_init(&nzidx, 0, DT_INT, _state, ae_true);
   24343           0 :     ae_vector_init(&nzval, 0, DT_REAL, _state, ae_true);
   24344             : 
   24345           0 :     ae_assert(n>=1, "Spline1DFit: N<1!", _state);
   24346           0 :     ae_assert(m>=1, "Spline1DFit: M<1!", _state);
   24347           0 :     ae_assert(x->cnt>=n, "Spline1DFit: Length(X)<N!", _state);
   24348           0 :     ae_assert(y->cnt>=n, "Spline1DFit: Length(Y)<N!", _state);
   24349           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DFit: X contains infinite or NAN values!", _state);
   24350           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DFit: Y contains infinite or NAN values!", _state);
   24351           0 :     ae_assert(ae_isfinite(lambdans, _state), "Spline1DFit: LambdaNS is infinite!", _state);
   24352           0 :     ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline1DFit: LambdaNS<0!", _state);
   24353           0 :     bfrad = 2;
   24354           0 :     lsqrcnt = 10;
   24355             :     
   24356             :     /*
   24357             :      * Sort points.
   24358             :      * Determine actual area size, make sure that XA<XB
   24359             :      */
   24360           0 :     tagsortfastr(x, y, &tmpx, &tmpy, n, _state);
   24361           0 :     xa = x->ptr.p_double[0];
   24362           0 :     xb = x->ptr.p_double[n-1];
   24363           0 :     if( ae_fp_eq(xa,xb) )
   24364             :     {
   24365           0 :         v = xa;
   24366           0 :         if( ae_fp_greater_eq(v,(double)(0)) )
   24367             :         {
   24368           0 :             xa = v/2-1;
   24369           0 :             xb = v*2+1;
   24370             :         }
   24371             :         else
   24372             :         {
   24373           0 :             xa = v*2-1;
   24374           0 :             xb = v/2+1;
   24375             :         }
   24376             :     }
   24377           0 :     ae_assert(ae_fp_less(xa,xb), "Spline1DFit: integrity error", _state);
   24378             :     
   24379             :     /*
   24380             :      * Perform a grid correction according to current grid expansion size.
   24381             :      */
   24382           0 :     m = ae_maxint(m, 4, _state);
   24383           0 :     gridexpansion = 1;
   24384           0 :     v = (xb-xa)/m;
   24385           0 :     xa = xa-v*gridexpansion;
   24386           0 :     xb = xb+v*gridexpansion;
   24387           0 :     m = m+2*gridexpansion;
   24388             :     
   24389             :     /*
   24390             :      * Convert X/Y to work representation, remove linear trend (in
   24391             :      * order to improve condition number).
   24392             :      *
   24393             :      * Compute total-sum-of-squares (needed later for R2 coefficient).
   24394             :      */
   24395           0 :     ae_vector_set_length(&xywork, 2*n, _state);
   24396           0 :     for(i=0; i<=n-1; i++)
   24397             :     {
   24398           0 :         xywork.ptr.p_double[2*i+0] = (x->ptr.p_double[i]-xa)/(xb-xa);
   24399           0 :         xywork.ptr.p_double[2*i+1] = y->ptr.p_double[i];
   24400             :     }
   24401           0 :     buildpriorterm1(&xywork, n, 1, 1, 1, 0.0, &vterm, _state);
   24402           0 :     meany = (double)(0);
   24403           0 :     for(i=0; i<=n-1; i++)
   24404             :     {
   24405           0 :         meany = meany+y->ptr.p_double[i];
   24406             :     }
   24407           0 :     meany = meany/n;
   24408           0 :     tss = (double)(0);
   24409           0 :     for(i=0; i<=n-1; i++)
   24410             :     {
   24411           0 :         tss = tss+ae_sqr(y->ptr.p_double[i]-meany, _state);
   24412             :     }
   24413             :     
   24414             :     /*
   24415             :      * Build 1D compact basis function
   24416             :      * Generate design matrix AV ("vertical") and its transpose AH ("horizontal").
   24417             :      */
   24418           0 :     ae_vector_set_length(&tmpx, 7, _state);
   24419           0 :     ae_vector_set_length(&tmpy, 7, _state);
   24420           0 :     tmpx.ptr.p_double[0] = -(double)3/(double)(m-1);
   24421           0 :     tmpx.ptr.p_double[1] = -(double)2/(double)(m-1);
   24422           0 :     tmpx.ptr.p_double[2] = -(double)1/(double)(m-1);
   24423           0 :     tmpx.ptr.p_double[3] = (double)0/(double)(m-1);
   24424           0 :     tmpx.ptr.p_double[4] = (double)1/(double)(m-1);
   24425           0 :     tmpx.ptr.p_double[5] = (double)2/(double)(m-1);
   24426           0 :     tmpx.ptr.p_double[6] = (double)3/(double)(m-1);
   24427           0 :     tmpy.ptr.p_double[0] = (double)(0);
   24428           0 :     tmpy.ptr.p_double[1] = (double)(0);
   24429           0 :     tmpy.ptr.p_double[2] = (double)1/(double)12;
   24430           0 :     tmpy.ptr.p_double[3] = (double)2/(double)6;
   24431           0 :     tmpy.ptr.p_double[4] = (double)1/(double)12;
   24432           0 :     tmpy.ptr.p_double[5] = (double)(0);
   24433           0 :     tmpy.ptr.p_double[6] = (double)(0);
   24434           0 :     spline1dbuildcubic(&tmpx, &tmpy, tmpx.cnt, 2, 0.0, 2, 0.0, &basis1, _state);
   24435           0 :     arows = n+2*m;
   24436           0 :     sparsecreate(arows, m, 0, &av, _state);
   24437           0 :     setlengthzero(&targets, arows, _state);
   24438           0 :     scaletargetsby = 1/ae_sqrt((double)(n), _state);
   24439           0 :     scalepenaltyby = 1/ae_sqrt((double)(m), _state);
   24440           0 :     for(i=0; i<=n-1; i++)
   24441             :     {
   24442             :         
   24443             :         /*
   24444             :          * Generate design matrix row #I which corresponds to I-th dataset point
   24445             :          */
   24446           0 :         k = ae_ifloor(boundval(xywork.ptr.p_double[2*i+0]*(m-1), (double)(0), (double)(m-1), _state), _state);
   24447           0 :         k0 = ae_maxint(k-(bfrad-1), 0, _state);
   24448           0 :         k1 = ae_minint(k+bfrad, m-1, _state);
   24449           0 :         for(j=k0; j<=k1; j++)
   24450             :         {
   24451           0 :             sparseset(&av, i, j, spline1dcalc(&basis1, xywork.ptr.p_double[2*i+0]-(double)j/(double)(m-1), _state)*scaletargetsby, _state);
   24452             :         }
   24453           0 :         targets.ptr.p_double[i] = xywork.ptr.p_double[2*i+1]*scaletargetsby;
   24454             :     }
   24455           0 :     for(i=0; i<=m-1; i++)
   24456             :     {
   24457             :         
   24458             :         /*
   24459             :          * Generate design matrix row #(I+N) which corresponds to nonlinearity penalty at I-th node
   24460             :          */
   24461           0 :         k0 = ae_maxint(i-(bfrad-1), 0, _state);
   24462           0 :         k1 = ae_minint(i+(bfrad-1), m-1, _state);
   24463           0 :         for(j=k0; j<=k1; j++)
   24464             :         {
   24465           0 :             spline1ddiff(&basis1, (double)i/(double)(m-1)-(double)j/(double)(m-1), &v, &dv, &d2v, _state);
   24466           0 :             sparseset(&av, n+i, j, lambdans*d2v*scalepenaltyby, _state);
   24467             :         }
   24468             :     }
   24469           0 :     for(i=0; i<=m-1; i++)
   24470             :     {
   24471             :         
   24472             :         /*
   24473             :          * Generate design matrix row #(I+N+M) which corresponds to regularization for I-th coefficient
   24474             :          */
   24475           0 :         sparseset(&av, n+m+i, i, spline1d_lambdareg, _state);
   24476             :     }
   24477           0 :     sparseconverttocrs(&av, _state);
   24478           0 :     sparsecopytransposecrs(&av, &ah, _state);
   24479             :     
   24480             :     /*
   24481             :      * Build 7-diagonal (bandwidth=3) normal equations matrix and perform Cholesky
   24482             :      * decomposition (to be used later as preconditioner for LSQR iterations).
   24483             :      */
   24484           0 :     bw = 3;
   24485           0 :     sparsecreatesksband(m, m, bw, &ata, _state);
   24486           0 :     mxata = (double)(0);
   24487           0 :     for(i=0; i<=m-1; i++)
   24488             :     {
   24489           0 :         for(j=i; j<=ae_minint(i+bw, m-1, _state); j++)
   24490             :         {
   24491             :             
   24492             :             /*
   24493             :              * Get pattern of nonzeros in one of the rows (let it be I-th one)
   24494             :              * and compute dot product only for nonzero entries.
   24495             :              */
   24496           0 :             sparsegetcompressedrow(&ah, i, &nzidx, &nzval, &nzcnt, _state);
   24497           0 :             v = (double)(0);
   24498           0 :             for(k=0; k<=nzcnt-1; k++)
   24499             :             {
   24500           0 :                 v = v+sparseget(&ah, i, nzidx.ptr.p_int[k], _state)*sparseget(&ah, j, nzidx.ptr.p_int[k], _state);
   24501             :             }
   24502             :             
   24503             :             /*
   24504             :              * Update ATA and max(ATA)
   24505             :              */
   24506           0 :             sparseset(&ata, i, j, v, _state);
   24507           0 :             if( i==j )
   24508             :             {
   24509           0 :                 mxata = ae_maxreal(mxata, ae_fabs(v, _state), _state);
   24510             :             }
   24511             :         }
   24512             :     }
   24513           0 :     mxata = coalesce(mxata, 1.0, _state);
   24514           0 :     creg = spline1d_cholreg;
   24515             :     for(;;)
   24516             :     {
   24517             :         
   24518             :         /*
   24519             :          * Regularization
   24520             :          */
   24521           0 :         for(i=0; i<=m-1; i++)
   24522             :         {
   24523           0 :             sparseset(&ata, i, i, sparseget(&ata, i, i, _state)+mxata*creg, _state);
   24524             :         }
   24525             :         
   24526             :         /*
   24527             :          * Try Cholesky factorization.
   24528             :          */
   24529           0 :         if( !sparsecholeskyskyline(&ata, m, ae_true, _state) )
   24530             :         {
   24531             :             
   24532             :             /*
   24533             :              * Factorization failed, increase regularizer and repeat
   24534             :              */
   24535           0 :             creg = coalesce(10*creg, 1.0E-12, _state);
   24536           0 :             continue;
   24537             :         }
   24538           0 :         break;
   24539             :     }
   24540             :     
   24541             :     /*
   24542             :      * Solve with preconditioned LSQR:
   24543             :      *
   24544             :      * use Cholesky factor U of squared design matrix A'*A to
   24545             :      * transform min|A*x-b| to min|[A*inv(U)]*y-b| with y=U*x.
   24546             :      *
   24547             :      * Preconditioned problem is solved with LSQR solver, which
   24548             :      * gives superior results to normal equations approach. Due
   24549             :      * to Cholesky preconditioner being utilized we can solve
   24550             :      * problem in just a few iterations.
   24551             :      */
   24552           0 :     rvectorsetlengthatleast(&tmp0, arows, _state);
   24553           0 :     rvectorsetlengthatleast(&tmp1, m, _state);
   24554           0 :     linlsqrcreatebuf(arows, m, &solver, _state);
   24555           0 :     linlsqrsetb(&solver, &targets, _state);
   24556           0 :     linlsqrsetcond(&solver, 1.0E-14, 1.0E-14, lsqrcnt, _state);
   24557           0 :     while(linlsqriteration(&solver, _state))
   24558             :     {
   24559           0 :         if( solver.needmv )
   24560             :         {
   24561           0 :             for(i=0; i<=m-1; i++)
   24562             :             {
   24563           0 :                 tmp1.ptr.p_double[i] = solver.x.ptr.p_double[i];
   24564             :             }
   24565             :             
   24566             :             /*
   24567             :              * Use Cholesky factorization of the system matrix
   24568             :              * as preconditioner: solve TRSV(U,Solver.X)
   24569             :              */
   24570           0 :             sparsetrsv(&ata, ae_true, ae_false, 0, &tmp1, _state);
   24571             :             
   24572             :             /*
   24573             :              * After preconditioning is done, multiply by A
   24574             :              */
   24575           0 :             sparsemv(&av, &tmp1, &solver.mv, _state);
   24576             :         }
   24577           0 :         if( solver.needmtv )
   24578             :         {
   24579             :             
   24580             :             /*
   24581             :              * Multiply by design matrix A
   24582             :              */
   24583           0 :             sparsemtv(&av, &solver.x, &solver.mtv, _state);
   24584             :             
   24585             :             /*
   24586             :              * Multiply by preconditioner: solve TRSV(U',A*Solver.X)
   24587             :              */
   24588           0 :             sparsetrsv(&ata, ae_true, ae_false, 1, &solver.mtv, _state);
   24589             :         }
   24590             :     }
   24591           0 :     linlsqrresults(&solver, &tmp1, &srep, _state);
   24592           0 :     sparsetrsv(&ata, ae_true, ae_false, 0, &tmp1, _state);
   24593             :     
   24594             :     /*
   24595             :      * Generate output spline as a table of spline valued and first
   24596             :      * derivatives at nodes (used to build Hermite spline)
   24597             :      */
   24598           0 :     ae_vector_set_length(&sx, m, _state);
   24599           0 :     ae_vector_set_length(&sy, m, _state);
   24600           0 :     ae_vector_set_length(&sdy, m, _state);
   24601           0 :     for(i=0; i<=m-1; i++)
   24602             :     {
   24603           0 :         sx.ptr.p_double[i] = (double)i/(double)(m-1);
   24604           0 :         sy.ptr.p_double[i] = (double)(0);
   24605           0 :         sdy.ptr.p_double[i] = (double)(0);
   24606             :     }
   24607           0 :     for(i=0; i<=m-1; i++)
   24608             :     {
   24609           0 :         k0 = ae_maxint(i-(bfrad-1), 0, _state);
   24610           0 :         k1 = ae_minint(i+bfrad, m-1, _state);
   24611           0 :         for(j=k0; j<=k1; j++)
   24612             :         {
   24613           0 :             spline1ddiff(&basis1, (double)j/(double)(m-1)-(double)i/(double)(m-1), &v, &dv, &d2v, _state);
   24614           0 :             sy.ptr.p_double[j] = sy.ptr.p_double[j]+tmp1.ptr.p_double[i]*v;
   24615           0 :             sdy.ptr.p_double[j] = sdy.ptr.p_double[j]+tmp1.ptr.p_double[i]*dv;
   24616             :         }
   24617             :     }
   24618             :     
   24619             :     /*
   24620             :      * Calculate model values
   24621             :      */
   24622           0 :     sparsemv(&av, &tmp1, &tmp0, _state);
   24623           0 :     for(i=0; i<=n-1; i++)
   24624             :     {
   24625           0 :         tmp0.ptr.p_double[i] = tmp0.ptr.p_double[i]/scaletargetsby;
   24626             :     }
   24627           0 :     rss = 0.0;
   24628           0 :     nrel = 0;
   24629           0 :     rep->rmserror = (double)(0);
   24630           0 :     rep->maxerror = (double)(0);
   24631           0 :     rep->avgerror = (double)(0);
   24632           0 :     rep->avgrelerror = (double)(0);
   24633           0 :     for(i=0; i<=n-1; i++)
   24634             :     {
   24635           0 :         v = xywork.ptr.p_double[2*i+1]-tmp0.ptr.p_double[i];
   24636           0 :         rss = rss+v*v;
   24637           0 :         rep->rmserror = rep->rmserror+ae_sqr(v, _state);
   24638           0 :         rep->avgerror = rep->avgerror+ae_fabs(v, _state);
   24639           0 :         rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
   24640           0 :         if( ae_fp_neq(y->ptr.p_double[i],(double)(0)) )
   24641             :         {
   24642           0 :             rep->avgrelerror = rep->avgrelerror+ae_fabs(v/y->ptr.p_double[i], _state);
   24643           0 :             nrel = nrel+1;
   24644             :         }
   24645             :     }
   24646           0 :     rep->rmserror = ae_sqrt(rep->rmserror/n, _state);
   24647           0 :     rep->avgerror = rep->avgerror/n;
   24648           0 :     rep->avgrelerror = rep->avgrelerror/coalesce((double)(nrel), 1.0, _state);
   24649             :     
   24650             :     /*
   24651             :      * Append prior term.
   24652             :      * Transform spline to original coordinates.
   24653             :      * Output.
   24654             :      */
   24655           0 :     for(i=0; i<=m-1; i++)
   24656             :     {
   24657           0 :         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];
   24658           0 :         sdy.ptr.p_double[i] = sdy.ptr.p_double[i]+vterm.ptr.pp_double[0][0];
   24659             :     }
   24660           0 :     for(i=0; i<=m-1; i++)
   24661             :     {
   24662           0 :         sx.ptr.p_double[i] = sx.ptr.p_double[i]*(xb-xa)+xa;
   24663           0 :         sdy.ptr.p_double[i] = sdy.ptr.p_double[i]/(xb-xa);
   24664             :     }
   24665           0 :     spline1dbuildhermite(&sx, &sy, &sdy, m, s, _state);
   24666           0 :     ae_frame_leave(_state);
   24667           0 : }
   24668             : 
   24669             : 
   24670             : /*************************************************************************
   24671             : Internal version of Spline1DConvDiff
   24672             : 
   24673             : Converts from Hermite spline given by grid XOld to new grid X2
   24674             : 
   24675             : INPUT PARAMETERS:
   24676             :     XOld    -   old grid
   24677             :     YOld    -   values at old grid
   24678             :     DOld    -   first derivative at old grid
   24679             :     N       -   grid size
   24680             :     X2      -   new grid
   24681             :     N2      -   new grid size
   24682             :     Y       -   possibly preallocated output array
   24683             :                 (reallocate if too small)
   24684             :     NeedY   -   do we need Y?
   24685             :     D1      -   possibly preallocated output array
   24686             :                 (reallocate if too small)
   24687             :     NeedD1  -   do we need D1?
   24688             :     D2      -   possibly preallocated output array
   24689             :                 (reallocate if too small)
   24690             :     NeedD2  -   do we need D1?
   24691             : 
   24692             : OUTPUT ARRAYS:
   24693             :     Y       -   values, if needed
   24694             :     D1      -   first derivative, if needed
   24695             :     D2      -   second derivative, if needed
   24696             : 
   24697             :   -- ALGLIB PROJECT --
   24698             :      Copyright 03.09.2010 by Bochkanov Sergey
   24699             : *************************************************************************/
   24700           0 : void spline1dconvdiffinternal(/* Real    */ ae_vector* xold,
   24701             :      /* Real    */ ae_vector* yold,
   24702             :      /* Real    */ ae_vector* dold,
   24703             :      ae_int_t n,
   24704             :      /* Real    */ ae_vector* x2,
   24705             :      ae_int_t n2,
   24706             :      /* Real    */ ae_vector* y,
   24707             :      ae_bool needy,
   24708             :      /* Real    */ ae_vector* d1,
   24709             :      ae_bool needd1,
   24710             :      /* Real    */ ae_vector* d2,
   24711             :      ae_bool needd2,
   24712             :      ae_state *_state)
   24713             : {
   24714             :     ae_int_t intervalindex;
   24715             :     ae_int_t pointindex;
   24716             :     ae_bool havetoadvance;
   24717             :     double c0;
   24718             :     double c1;
   24719             :     double c2;
   24720             :     double c3;
   24721             :     double a;
   24722             :     double b;
   24723             :     double w;
   24724             :     double w2;
   24725             :     double w3;
   24726             :     double fa;
   24727             :     double fb;
   24728             :     double da;
   24729             :     double db;
   24730             :     double t;
   24731             : 
   24732             : 
   24733             :     
   24734             :     /*
   24735             :      * Prepare space
   24736             :      */
   24737           0 :     if( needy&&y->cnt<n2 )
   24738             :     {
   24739           0 :         ae_vector_set_length(y, n2, _state);
   24740             :     }
   24741           0 :     if( needd1&&d1->cnt<n2 )
   24742             :     {
   24743           0 :         ae_vector_set_length(d1, n2, _state);
   24744             :     }
   24745           0 :     if( needd2&&d2->cnt<n2 )
   24746             :     {
   24747           0 :         ae_vector_set_length(d2, n2, _state);
   24748             :     }
   24749             :     
   24750             :     /*
   24751             :      * These assignments aren't actually needed
   24752             :      * (variables are initialized in the loop below),
   24753             :      * but without them compiler will complain about uninitialized locals
   24754             :      */
   24755           0 :     c0 = (double)(0);
   24756           0 :     c1 = (double)(0);
   24757           0 :     c2 = (double)(0);
   24758           0 :     c3 = (double)(0);
   24759           0 :     a = (double)(0);
   24760           0 :     b = (double)(0);
   24761             :     
   24762             :     /*
   24763             :      * Cycle
   24764             :      */
   24765           0 :     intervalindex = -1;
   24766           0 :     pointindex = 0;
   24767             :     for(;;)
   24768             :     {
   24769             :         
   24770             :         /*
   24771             :          * are we ready to exit?
   24772             :          */
   24773           0 :         if( pointindex>=n2 )
   24774             :         {
   24775           0 :             break;
   24776             :         }
   24777           0 :         t = x2->ptr.p_double[pointindex];
   24778             :         
   24779             :         /*
   24780             :          * do we need to advance interval?
   24781             :          */
   24782           0 :         havetoadvance = ae_false;
   24783           0 :         if( intervalindex==-1 )
   24784             :         {
   24785           0 :             havetoadvance = ae_true;
   24786             :         }
   24787             :         else
   24788             :         {
   24789           0 :             if( intervalindex<n-2 )
   24790             :             {
   24791           0 :                 havetoadvance = ae_fp_greater_eq(t,b);
   24792             :             }
   24793             :         }
   24794           0 :         if( havetoadvance )
   24795             :         {
   24796           0 :             intervalindex = intervalindex+1;
   24797           0 :             a = xold->ptr.p_double[intervalindex];
   24798           0 :             b = xold->ptr.p_double[intervalindex+1];
   24799           0 :             w = b-a;
   24800           0 :             w2 = w*w;
   24801           0 :             w3 = w*w2;
   24802           0 :             fa = yold->ptr.p_double[intervalindex];
   24803           0 :             fb = yold->ptr.p_double[intervalindex+1];
   24804           0 :             da = dold->ptr.p_double[intervalindex];
   24805           0 :             db = dold->ptr.p_double[intervalindex+1];
   24806           0 :             c0 = fa;
   24807           0 :             c1 = da;
   24808           0 :             c2 = (3*(fb-fa)-2*da*w-db*w)/w2;
   24809           0 :             c3 = (2*(fa-fb)+da*w+db*w)/w3;
   24810           0 :             continue;
   24811             :         }
   24812             :         
   24813             :         /*
   24814             :          * Calculate spline and its derivatives using power basis
   24815             :          */
   24816           0 :         t = t-a;
   24817           0 :         if( needy )
   24818             :         {
   24819           0 :             y->ptr.p_double[pointindex] = c0+t*(c1+t*(c2+t*c3));
   24820             :         }
   24821           0 :         if( needd1 )
   24822             :         {
   24823           0 :             d1->ptr.p_double[pointindex] = c1+2*t*c2+3*t*t*c3;
   24824             :         }
   24825           0 :         if( needd2 )
   24826             :         {
   24827           0 :             d2->ptr.p_double[pointindex] = 2*c2+6*t*c3;
   24828             :         }
   24829           0 :         pointindex = pointindex+1;
   24830             :     }
   24831           0 : }
   24832             : 
   24833             : 
   24834             : /*************************************************************************
   24835             : This function finds all roots and extrema of the spline S(x)  defined  at
   24836             : [A,B] (interval which contains spline nodes).
   24837             : 
   24838             : It  does not extrapolates function, so roots and extrema located  outside 
   24839             : of [A,B] will not be found. It returns all isolated (including  multiple)
   24840             : roots and extrema.
   24841             : 
   24842             : INPUT PARAMETERS
   24843             :     C           -   spline interpolant
   24844             :     
   24845             : OUTPUT PARAMETERS
   24846             :     R           -   array[NR], contains roots of the spline. 
   24847             :                     In case there is no roots, this array has zero length.
   24848             :     NR          -   number of roots, >=0
   24849             :     DR          -   is set to True in case there is at least one interval
   24850             :                     where spline is just a zero constant. Such degenerate
   24851             :                     cases are not reported in the R/NR
   24852             :     E           -   array[NE], contains  extrema  (maximums/minimums)  of 
   24853             :                     the spline. In case there is no extrema,  this  array 
   24854             :                     has zero length.
   24855             :     ET          -   array[NE], extrema types:
   24856             :                     * ET[i]>0 in case I-th extrema is a minimum
   24857             :                     * ET[i]<0 in case I-th extrema is a maximum
   24858             :     NE          -   number of extrema, >=0
   24859             :     DE          -   is set to True in case there is at least one interval
   24860             :                     where spline is a constant. Such degenerate cases are  
   24861             :                     not reported in the E/NE.
   24862             :                     
   24863             : NOTES:
   24864             : 
   24865             : 1. This function does NOT report following kinds of roots:
   24866             :    * intervals where function is constantly zero
   24867             :    * roots which are outside of [A,B] (note: it CAN return A or B)
   24868             : 
   24869             : 2. This function does NOT report following kinds of extrema:
   24870             :    * intervals where function is a constant
   24871             :    * extrema which are outside of (A,B) (note: it WON'T return A or B)
   24872             :    
   24873             :  -- ALGLIB PROJECT --
   24874             :      Copyright 26.09.2011 by Bochkanov Sergey   
   24875             : *************************************************************************/
   24876           0 : void spline1drootsandextrema(spline1dinterpolant* c,
   24877             :      /* Real    */ ae_vector* r,
   24878             :      ae_int_t* nr,
   24879             :      ae_bool* dr,
   24880             :      /* Real    */ ae_vector* e,
   24881             :      /* Integer */ ae_vector* et,
   24882             :      ae_int_t* ne,
   24883             :      ae_bool* de,
   24884             :      ae_state *_state)
   24885             : {
   24886             :     ae_frame _frame_block;
   24887             :     double pl;
   24888             :     double ml;
   24889             :     double pll;
   24890             :     double pr;
   24891             :     double mr;
   24892             :     ae_vector tr;
   24893             :     ae_vector tmpr;
   24894             :     ae_vector tmpe;
   24895             :     ae_vector tmpet;
   24896             :     ae_vector tmpc;
   24897             :     double x0;
   24898             :     double x1;
   24899             :     double x2;
   24900             :     double ex0;
   24901             :     double ex1;
   24902             :     ae_int_t tne;
   24903             :     ae_int_t tnr;
   24904             :     ae_int_t i;
   24905             :     ae_int_t j;
   24906             :     ae_bool nstep;
   24907             : 
   24908           0 :     ae_frame_make(_state, &_frame_block);
   24909           0 :     memset(&tr, 0, sizeof(tr));
   24910           0 :     memset(&tmpr, 0, sizeof(tmpr));
   24911           0 :     memset(&tmpe, 0, sizeof(tmpe));
   24912           0 :     memset(&tmpet, 0, sizeof(tmpet));
   24913           0 :     memset(&tmpc, 0, sizeof(tmpc));
   24914           0 :     ae_vector_clear(r);
   24915           0 :     *nr = 0;
   24916           0 :     *dr = ae_false;
   24917           0 :     ae_vector_clear(e);
   24918           0 :     ae_vector_clear(et);
   24919           0 :     *ne = 0;
   24920           0 :     *de = ae_false;
   24921           0 :     ae_vector_init(&tr, 0, DT_REAL, _state, ae_true);
   24922           0 :     ae_vector_init(&tmpr, 0, DT_REAL, _state, ae_true);
   24923           0 :     ae_vector_init(&tmpe, 0, DT_REAL, _state, ae_true);
   24924           0 :     ae_vector_init(&tmpet, 0, DT_INT, _state, ae_true);
   24925           0 :     ae_vector_init(&tmpc, 0, DT_REAL, _state, ae_true);
   24926             : 
   24927             :     
   24928             :     /*
   24929             :      *exception handling
   24930             :      */
   24931           0 :     ae_assert(c->k==3, "Spline1DRootsAndExtrema : incorrect parameter C.K!", _state);
   24932           0 :     ae_assert(c->continuity>=0, "Spline1DRootsAndExtrema : parameter C.Continuity must not be less than 0!", _state);
   24933             :     
   24934             :     /*
   24935             :      *initialization of variable
   24936             :      */
   24937           0 :     *nr = 0;
   24938           0 :     *ne = 0;
   24939           0 :     *dr = ae_false;
   24940           0 :     *de = ae_false;
   24941           0 :     nstep = ae_true;
   24942             :     
   24943             :     /*
   24944             :      *consider case, when C.Continuty=0
   24945             :      */
   24946           0 :     if( c->continuity==0 )
   24947             :     {
   24948             :         
   24949             :         /*
   24950             :          *allocation for auxiliary arrays 
   24951             :          *'TmpR ' - it stores a time value for roots
   24952             :          *'TmpE ' - it stores a time value for extremums
   24953             :          *'TmpET '- it stores a time value for extremums type
   24954             :          */
   24955           0 :         rvectorsetlengthatleast(&tmpr, 3*(c->n-1), _state);
   24956           0 :         rvectorsetlengthatleast(&tmpe, 2*(c->n-1), _state);
   24957           0 :         ivectorsetlengthatleast(&tmpet, 2*(c->n-1), _state);
   24958             :         
   24959             :         /*
   24960             :          *start calculating
   24961             :          */
   24962           0 :         for(i=0; i<=c->n-2; i++)
   24963             :         {
   24964             :             
   24965             :             /*
   24966             :              *initialization pL, mL, pR, mR
   24967             :              */
   24968           0 :             pl = c->c.ptr.p_double[4*i];
   24969           0 :             ml = c->c.ptr.p_double[4*i+1];
   24970           0 :             pr = c->c.ptr.p_double[4*(i+1)];
   24971           0 :             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]);
   24972             :             
   24973             :             /*
   24974             :              *pre-searching roots and extremums
   24975             :              */
   24976           0 :             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);
   24977           0 :             *dr = *dr||tnr==-1;
   24978           0 :             *de = *de||tne==-1;
   24979             :             
   24980             :             /*
   24981             :              *searching of roots
   24982             :              */
   24983           0 :             if( tnr==1&&nstep )
   24984             :             {
   24985             :                 
   24986             :                 /*
   24987             :                  *is there roots?
   24988             :                  */
   24989           0 :                 if( *nr>0 )
   24990             :                 {
   24991             :                     
   24992             :                     /*
   24993             :                      *is a next root equal a previous root?
   24994             :                      *if is't, then write new root
   24995             :                      */
   24996           0 :                     if( ae_fp_neq(x0,tmpr.ptr.p_double[*nr-1]) )
   24997             :                     {
   24998           0 :                         tmpr.ptr.p_double[*nr] = x0;
   24999           0 :                         *nr = *nr+1;
   25000             :                     }
   25001             :                 }
   25002             :                 else
   25003             :                 {
   25004             :                     
   25005             :                     /*
   25006             :                      *write a first root
   25007             :                      */
   25008           0 :                     tmpr.ptr.p_double[*nr] = x0;
   25009           0 :                     *nr = *nr+1;
   25010             :                 }
   25011             :             }
   25012             :             else
   25013             :             {
   25014             :                 
   25015             :                 /*
   25016             :                  *case when function at a segment identically to zero
   25017             :                  *then we have to clear a root, if the one located on a 
   25018             :                  *constant segment
   25019             :                  */
   25020           0 :                 if( tnr==-1 )
   25021             :                 {
   25022             :                     
   25023             :                     /*
   25024             :                      *safe state variable as constant
   25025             :                      */
   25026           0 :                     if( nstep )
   25027             :                     {
   25028           0 :                         nstep = ae_false;
   25029             :                     }
   25030             :                     
   25031             :                     /*
   25032             :                      *clear the root, if there is
   25033             :                      */
   25034           0 :                     if( *nr>0 )
   25035             :                     {
   25036           0 :                         if( ae_fp_eq(c->x.ptr.p_double[i],tmpr.ptr.p_double[*nr-1]) )
   25037             :                         {
   25038           0 :                             *nr = *nr-1;
   25039             :                         }
   25040             :                     }
   25041             :                     
   25042             :                     /*
   25043             :                      *change state for 'DR'
   25044             :                      */
   25045           0 :                     if( !*dr )
   25046             :                     {
   25047           0 :                         *dr = ae_true;
   25048             :                     }
   25049             :                 }
   25050             :                 else
   25051             :                 {
   25052           0 :                     nstep = ae_true;
   25053             :                 }
   25054             :             }
   25055             :             
   25056             :             /*
   25057             :              *searching of extremums
   25058             :              */
   25059           0 :             if( i>0 )
   25060             :             {
   25061           0 :                 pll = c->c.ptr.p_double[4*(i-1)];
   25062             :                 
   25063             :                 /*
   25064             :                  *if pL=pLL or pL=pR then
   25065             :                  */
   25066           0 :                 if( tne==-1 )
   25067             :                 {
   25068           0 :                     if( !*de )
   25069             :                     {
   25070           0 :                         *de = ae_true;
   25071             :                     }
   25072             :                 }
   25073             :                 else
   25074             :                 {
   25075           0 :                     if( ae_fp_greater(pl,pll)&&ae_fp_greater(pl,pr) )
   25076             :                     {
   25077             :                         
   25078             :                         /*
   25079             :                          *maximum
   25080             :                          */
   25081           0 :                         tmpet.ptr.p_int[*ne] = -1;
   25082           0 :                         tmpe.ptr.p_double[*ne] = c->x.ptr.p_double[i];
   25083           0 :                         *ne = *ne+1;
   25084             :                     }
   25085             :                     else
   25086             :                     {
   25087           0 :                         if( ae_fp_less(pl,pll)&&ae_fp_less(pl,pr) )
   25088             :                         {
   25089             :                             
   25090             :                             /*
   25091             :                              *minimum
   25092             :                              */
   25093           0 :                             tmpet.ptr.p_int[*ne] = 1;
   25094           0 :                             tmpe.ptr.p_double[*ne] = c->x.ptr.p_double[i];
   25095           0 :                             *ne = *ne+1;
   25096             :                         }
   25097             :                     }
   25098             :                 }
   25099             :             }
   25100             :         }
   25101             :         
   25102             :         /*
   25103             :          *write final result
   25104             :          */
   25105           0 :         rvectorsetlengthatleast(r, *nr, _state);
   25106           0 :         rvectorsetlengthatleast(e, *ne, _state);
   25107           0 :         ivectorsetlengthatleast(et, *ne, _state);
   25108             :         
   25109             :         /*
   25110             :          *write roots
   25111             :          */
   25112           0 :         for(i=0; i<=*nr-1; i++)
   25113             :         {
   25114           0 :             r->ptr.p_double[i] = tmpr.ptr.p_double[i];
   25115             :         }
   25116             :         
   25117             :         /*
   25118             :          *write extremums and their types
   25119             :          */
   25120           0 :         for(i=0; i<=*ne-1; i++)
   25121             :         {
   25122           0 :             e->ptr.p_double[i] = tmpe.ptr.p_double[i];
   25123           0 :             et->ptr.p_int[i] = tmpet.ptr.p_int[i];
   25124             :         }
   25125             :     }
   25126             :     else
   25127             :     {
   25128             :         
   25129             :         /*
   25130             :          *case, when C.Continuity>=1 
   25131             :          *'TmpR ' - it stores a time value for roots
   25132             :          *'TmpC' - it stores a time value for extremums and 
   25133             :          *their function value (TmpC={EX0,F(EX0), EX1,F(EX1), ..., EXn,F(EXn)};)
   25134             :          *'TmpE' - it stores a time value for extremums only
   25135             :          *'TmpET'- it stores a time value for extremums type
   25136             :          */
   25137           0 :         rvectorsetlengthatleast(&tmpr, 2*c->n-1, _state);
   25138           0 :         rvectorsetlengthatleast(&tmpc, 4*c->n, _state);
   25139           0 :         rvectorsetlengthatleast(&tmpe, 2*c->n, _state);
   25140           0 :         ivectorsetlengthatleast(&tmpet, 2*c->n, _state);
   25141             :         
   25142             :         /*
   25143             :          *start calculating
   25144             :          */
   25145           0 :         for(i=0; i<=c->n-2; i++)
   25146             :         {
   25147             :             
   25148             :             /*
   25149             :              *we calculate pL,mL, pR,mR as Fi+1(F'i+1) at left border
   25150             :              */
   25151           0 :             pl = c->c.ptr.p_double[4*i];
   25152           0 :             ml = c->c.ptr.p_double[4*i+1];
   25153           0 :             pr = c->c.ptr.p_double[4*(i+1)];
   25154           0 :             mr = c->c.ptr.p_double[4*(i+1)+1];
   25155             :             
   25156             :             /*
   25157             :              *calculating roots and extremums at [X[i],X[i+1]]
   25158             :              */
   25159           0 :             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);
   25160             :             
   25161             :             /*
   25162             :              *searching roots
   25163             :              */
   25164           0 :             if( tnr>0 )
   25165             :             {
   25166             :                 
   25167             :                 /*
   25168             :                  *re-init tR
   25169             :                  */
   25170           0 :                 if( tnr>=1 )
   25171             :                 {
   25172           0 :                     tr.ptr.p_double[0] = x0;
   25173             :                 }
   25174           0 :                 if( tnr>=2 )
   25175             :                 {
   25176           0 :                     tr.ptr.p_double[1] = x1;
   25177             :                 }
   25178           0 :                 if( tnr==3 )
   25179             :                 {
   25180           0 :                     tr.ptr.p_double[2] = x2;
   25181             :                 }
   25182             :                 
   25183             :                 /*
   25184             :                  *start root selection
   25185             :                  */
   25186           0 :                 if( *nr>0 )
   25187             :                 {
   25188           0 :                     if( ae_fp_neq(tmpr.ptr.p_double[*nr-1],x0) )
   25189             :                     {
   25190             :                         
   25191             :                         /*
   25192             :                          *previous segment was't constant identical zero
   25193             :                          */
   25194           0 :                         if( nstep )
   25195             :                         {
   25196           0 :                             for(j=0; j<=tnr-1; j++)
   25197             :                             {
   25198           0 :                                 tmpr.ptr.p_double[*nr+j] = tr.ptr.p_double[j];
   25199             :                             }
   25200           0 :                             *nr = *nr+tnr;
   25201             :                         }
   25202             :                         else
   25203             :                         {
   25204             :                             
   25205             :                             /*
   25206             :                              *previous segment was constant identical zero
   25207             :                              *and we must ignore [NR+j-1] root
   25208             :                              */
   25209           0 :                             for(j=1; j<=tnr-1; j++)
   25210             :                             {
   25211           0 :                                 tmpr.ptr.p_double[*nr+j-1] = tr.ptr.p_double[j];
   25212             :                             }
   25213           0 :                             *nr = *nr+tnr-1;
   25214           0 :                             nstep = ae_true;
   25215             :                         }
   25216             :                     }
   25217             :                     else
   25218             :                     {
   25219           0 :                         for(j=1; j<=tnr-1; j++)
   25220             :                         {
   25221           0 :                             tmpr.ptr.p_double[*nr+j-1] = tr.ptr.p_double[j];
   25222             :                         }
   25223           0 :                         *nr = *nr+tnr-1;
   25224             :                     }
   25225             :                 }
   25226             :                 else
   25227             :                 {
   25228             :                     
   25229             :                     /*
   25230             :                      *write first root
   25231             :                      */
   25232           0 :                     for(j=0; j<=tnr-1; j++)
   25233             :                     {
   25234           0 :                         tmpr.ptr.p_double[*nr+j] = tr.ptr.p_double[j];
   25235             :                     }
   25236           0 :                     *nr = *nr+tnr;
   25237             :                 }
   25238             :             }
   25239             :             else
   25240             :             {
   25241           0 :                 if( tnr==-1 )
   25242             :                 {
   25243             :                     
   25244             :                     /*
   25245             :                      *decrement 'NR' if at previous step was writen a root
   25246             :                      *(previous segment identical zero)
   25247             :                      */
   25248           0 :                     if( *nr>0&&nstep )
   25249             :                     {
   25250           0 :                         *nr = *nr-1;
   25251             :                     }
   25252             :                     
   25253             :                     /*
   25254             :                      *previous segment is't constant
   25255             :                      */
   25256           0 :                     if( nstep )
   25257             :                     {
   25258           0 :                         nstep = ae_false;
   25259             :                     }
   25260             :                     
   25261             :                     /*
   25262             :                      *rewrite 'DR'
   25263             :                      */
   25264           0 :                     if( !*dr )
   25265             :                     {
   25266           0 :                         *dr = ae_true;
   25267             :                     }
   25268             :                 }
   25269             :             }
   25270             :             
   25271             :             /*
   25272             :              *searching extremums
   25273             :              *write all term like extremums
   25274             :              */
   25275           0 :             if( tne==1 )
   25276             :             {
   25277           0 :                 if( *ne>0 )
   25278             :                 {
   25279             :                     
   25280             :                     /*
   25281             :                      *just ignore identical extremums
   25282             :                      *because he must be one
   25283             :                      */
   25284           0 :                     if( ae_fp_neq(tmpc.ptr.p_double[*ne-2],ex0) )
   25285             :                     {
   25286           0 :                         tmpc.ptr.p_double[*ne] = ex0;
   25287           0 :                         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]);
   25288           0 :                         *ne = *ne+2;
   25289             :                     }
   25290             :                 }
   25291             :                 else
   25292             :                 {
   25293             :                     
   25294             :                     /*
   25295             :                      *write first extremum and it function value
   25296             :                      */
   25297           0 :                     tmpc.ptr.p_double[*ne] = ex0;
   25298           0 :                     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]);
   25299           0 :                     *ne = *ne+2;
   25300             :                 }
   25301             :             }
   25302             :             else
   25303             :             {
   25304           0 :                 if( tne==2 )
   25305             :                 {
   25306           0 :                     if( *ne>0 )
   25307             :                     {
   25308             :                         
   25309             :                         /*
   25310             :                          *ignore identical extremum
   25311             :                          */
   25312           0 :                         if( ae_fp_neq(tmpc.ptr.p_double[*ne-2],ex0) )
   25313             :                         {
   25314           0 :                             tmpc.ptr.p_double[*ne] = ex0;
   25315           0 :                             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]);
   25316           0 :                             *ne = *ne+2;
   25317             :                         }
   25318             :                     }
   25319             :                     else
   25320             :                     {
   25321             :                         
   25322             :                         /*
   25323             :                          *write first extremum
   25324             :                          */
   25325           0 :                         tmpc.ptr.p_double[*ne] = ex0;
   25326           0 :                         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]);
   25327           0 :                         *ne = *ne+2;
   25328             :                     }
   25329             :                     
   25330             :                     /*
   25331             :                      *write second extremum
   25332             :                      */
   25333           0 :                     tmpc.ptr.p_double[*ne] = ex1;
   25334           0 :                     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]);
   25335           0 :                     *ne = *ne+2;
   25336             :                 }
   25337             :                 else
   25338             :                 {
   25339           0 :                     if( tne==-1 )
   25340             :                     {
   25341           0 :                         if( !*de )
   25342             :                         {
   25343           0 :                             *de = ae_true;
   25344             :                         }
   25345             :                     }
   25346             :                 }
   25347             :             }
   25348             :         }
   25349             :         
   25350             :         /*
   25351             :          *checking of arrays
   25352             :          *get number of extremums (tNe=NE/2)
   25353             :          *initialize pL as value F0(X[0]) and
   25354             :          *initialize pR as value Fn-1(X[N])
   25355             :          */
   25356           0 :         tne = *ne/2;
   25357           0 :         *ne = 0;
   25358           0 :         pl = c->c.ptr.p_double[0];
   25359           0 :         pr = c->c.ptr.p_double[4*(c->n-1)];
   25360           0 :         for(i=0; i<=tne-1; i++)
   25361             :         {
   25362           0 :             if( i>0&&i<tne-1 )
   25363             :             {
   25364           0 :                 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],tmpc.ptr.p_double[2*(i+1)+1]) )
   25365             :                 {
   25366             :                     
   25367             :                     /*
   25368             :                      *maximum
   25369             :                      */
   25370           0 :                     tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
   25371           0 :                     tmpet.ptr.p_int[*ne] = -1;
   25372           0 :                     *ne = *ne+1;
   25373             :                 }
   25374             :                 else
   25375             :                 {
   25376           0 :                     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],tmpc.ptr.p_double[2*(i+1)+1]) )
   25377             :                     {
   25378             :                         
   25379             :                         /*
   25380             :                          *minimum
   25381             :                          */
   25382           0 :                         tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
   25383           0 :                         tmpet.ptr.p_int[*ne] = 1;
   25384           0 :                         *ne = *ne+1;
   25385             :                     }
   25386             :                 }
   25387             :             }
   25388             :             else
   25389             :             {
   25390           0 :                 if( i==0 )
   25391             :                 {
   25392           0 :                     if( ae_fp_neq(tmpc.ptr.p_double[2*i],c->x.ptr.p_double[0]) )
   25393             :                     {
   25394           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]) )
   25395             :                         {
   25396             :                             
   25397             :                             /*
   25398             :                              *maximum
   25399             :                              */
   25400           0 :                             tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
   25401           0 :                             tmpet.ptr.p_int[*ne] = -1;
   25402           0 :                             *ne = *ne+1;
   25403             :                         }
   25404             :                         else
   25405             :                         {
   25406           0 :                             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]) )
   25407             :                             {
   25408             :                                 
   25409             :                                 /*
   25410             :                                  *minimum
   25411             :                                  */
   25412           0 :                                 tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
   25413           0 :                                 tmpet.ptr.p_int[*ne] = 1;
   25414           0 :                                 *ne = *ne+1;
   25415             :                             }
   25416             :                         }
   25417             :                     }
   25418             :                 }
   25419             :                 else
   25420             :                 {
   25421           0 :                     if( i==tne-1 )
   25422             :                     {
   25423           0 :                         if( ae_fp_neq(tmpc.ptr.p_double[2*i],c->x.ptr.p_double[c->n-1]) )
   25424             :                         {
   25425           0 :                             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) )
   25426             :                             {
   25427             :                                 
   25428             :                                 /*
   25429             :                                  *maximum
   25430             :                                  */
   25431           0 :                                 tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
   25432           0 :                                 tmpet.ptr.p_int[*ne] = -1;
   25433           0 :                                 *ne = *ne+1;
   25434             :                             }
   25435             :                             else
   25436             :                             {
   25437           0 :                                 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) )
   25438             :                                 {
   25439             :                                     
   25440             :                                     /*
   25441             :                                      *minimum
   25442             :                                      */
   25443           0 :                                     tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
   25444           0 :                                     tmpet.ptr.p_int[*ne] = 1;
   25445           0 :                                     *ne = *ne+1;
   25446             :                                 }
   25447             :                             }
   25448             :                         }
   25449             :                     }
   25450             :                 }
   25451             :             }
   25452             :         }
   25453             :         
   25454             :         /*
   25455             :          *final results
   25456             :          *allocate R, E, ET
   25457             :          */
   25458           0 :         rvectorsetlengthatleast(r, *nr, _state);
   25459           0 :         rvectorsetlengthatleast(e, *ne, _state);
   25460           0 :         ivectorsetlengthatleast(et, *ne, _state);
   25461             :         
   25462             :         /*
   25463             :          *write result for extremus and their types
   25464             :          */
   25465           0 :         for(i=0; i<=*ne-1; i++)
   25466             :         {
   25467           0 :             e->ptr.p_double[i] = tmpe.ptr.p_double[i];
   25468           0 :             et->ptr.p_int[i] = tmpet.ptr.p_int[i];
   25469             :         }
   25470             :         
   25471             :         /*
   25472             :          *write result for roots
   25473             :          */
   25474           0 :         for(i=0; i<=*nr-1; i++)
   25475             :         {
   25476           0 :             r->ptr.p_double[i] = tmpr.ptr.p_double[i];
   25477             :         }
   25478             :     }
   25479           0 :     ae_frame_leave(_state);
   25480           0 : }
   25481             : 
   25482             : 
   25483             : /*************************************************************************
   25484             : Internal subroutine. Heap sort.
   25485             : *************************************************************************/
   25486           0 : void heapsortdpoints(/* Real    */ ae_vector* x,
   25487             :      /* Real    */ ae_vector* y,
   25488             :      /* Real    */ ae_vector* d,
   25489             :      ae_int_t n,
   25490             :      ae_state *_state)
   25491             : {
   25492             :     ae_frame _frame_block;
   25493             :     ae_vector rbuf;
   25494             :     ae_vector ibuf;
   25495             :     ae_vector rbuf2;
   25496             :     ae_vector ibuf2;
   25497             :     ae_int_t i;
   25498             : 
   25499           0 :     ae_frame_make(_state, &_frame_block);
   25500           0 :     memset(&rbuf, 0, sizeof(rbuf));
   25501           0 :     memset(&ibuf, 0, sizeof(ibuf));
   25502           0 :     memset(&rbuf2, 0, sizeof(rbuf2));
   25503           0 :     memset(&ibuf2, 0, sizeof(ibuf2));
   25504           0 :     ae_vector_init(&rbuf, 0, DT_REAL, _state, ae_true);
   25505           0 :     ae_vector_init(&ibuf, 0, DT_INT, _state, ae_true);
   25506           0 :     ae_vector_init(&rbuf2, 0, DT_REAL, _state, ae_true);
   25507           0 :     ae_vector_init(&ibuf2, 0, DT_INT, _state, ae_true);
   25508             : 
   25509           0 :     ae_vector_set_length(&ibuf, n, _state);
   25510           0 :     ae_vector_set_length(&rbuf, n, _state);
   25511           0 :     for(i=0; i<=n-1; i++)
   25512             :     {
   25513           0 :         ibuf.ptr.p_int[i] = i;
   25514             :     }
   25515           0 :     tagsortfasti(x, &ibuf, &rbuf2, &ibuf2, n, _state);
   25516           0 :     for(i=0; i<=n-1; i++)
   25517             :     {
   25518           0 :         rbuf.ptr.p_double[i] = y->ptr.p_double[ibuf.ptr.p_int[i]];
   25519             :     }
   25520           0 :     ae_v_move(&y->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1));
   25521           0 :     for(i=0; i<=n-1; i++)
   25522             :     {
   25523           0 :         rbuf.ptr.p_double[i] = d->ptr.p_double[ibuf.ptr.p_int[i]];
   25524             :     }
   25525           0 :     ae_v_move(&d->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1));
   25526           0 :     ae_frame_leave(_state);
   25527           0 : }
   25528             : 
   25529             : 
   25530             : /*************************************************************************
   25531             : This procedure search roots of an quadratic equation inside [0;1] and it number of roots.
   25532             : 
   25533             : INPUT PARAMETERS:
   25534             :     P0   -   value of a function at 0
   25535             :     M0   -   value of a derivative at 0
   25536             :     P1   -   value of a function at 1
   25537             :     M1   -   value of a derivative at 1
   25538             : 
   25539             : OUTPUT PARAMETERS:
   25540             :     X0   -  first root of an equation
   25541             :     X1   -  second root of an equation
   25542             :     NR   -  number of roots
   25543             :     
   25544             : RESTRICTIONS OF PARAMETERS:
   25545             : 
   25546             : Parameters for this procedure has't to be zero simultaneously. Is expected, 
   25547             : that input polinom is't degenerate or constant identicaly ZERO.
   25548             : 
   25549             : 
   25550             : REMARK:
   25551             : 
   25552             : The procedure always fill value for X1 and X2, even if it is't belongs to [0;1].
   25553             : But first true root(even if existing one) is in X1.
   25554             : Number of roots is NR.
   25555             : 
   25556             :  -- ALGLIB PROJECT --
   25557             :      Copyright 26.09.2011 by Bochkanov Sergey
   25558             : *************************************************************************/
   25559           0 : void solvepolinom2(double p0,
   25560             :      double m0,
   25561             :      double p1,
   25562             :      double m1,
   25563             :      double* x0,
   25564             :      double* x1,
   25565             :      ae_int_t* nr,
   25566             :      ae_state *_state)
   25567             : {
   25568             :     double a;
   25569             :     double b;
   25570             :     double c;
   25571             :     double dd;
   25572             :     double tmp;
   25573             :     double exf;
   25574             :     double extr;
   25575             : 
   25576           0 :     *x0 = 0;
   25577           0 :     *x1 = 0;
   25578           0 :     *nr = 0;
   25579             : 
   25580             :     
   25581             :     /*
   25582             :      *calculate parameters for equation: A, B  and C
   25583             :      */
   25584           0 :     a = 6*p0+3*m0-6*p1+3*m1;
   25585           0 :     b = -6*p0-4*m0+6*p1-2*m1;
   25586           0 :     c = m0;
   25587             :     
   25588             :     /*
   25589             :      *check case, when A=0
   25590             :      *we are considering the linear equation
   25591             :      */
   25592           0 :     if( ae_fp_eq(a,(double)(0)) )
   25593             :     {
   25594             :         
   25595             :         /*
   25596             :          *B<>0 and root inside [0;1]
   25597             :          *one root
   25598             :          */
   25599           0 :         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)) )
   25600             :         {
   25601           0 :             *x0 = -c/b;
   25602           0 :             *nr = 1;
   25603           0 :             return;
   25604             :         }
   25605             :         else
   25606             :         {
   25607           0 :             *nr = 0;
   25608           0 :             return;
   25609             :         }
   25610             :     }
   25611             :     
   25612             :     /*
   25613             :      *consider case, when extremumu outside (0;1)
   25614             :      *exist one root only
   25615             :      */
   25616           0 :     if( ae_fp_less_eq(ae_fabs(2*a, _state),ae_fabs(b, _state))||ae_sign(b, _state)*ae_sign(a, _state)>=0 )
   25617             :     {
   25618           0 :         if( ae_sign(m0, _state)*ae_sign(m1, _state)>0 )
   25619             :         {
   25620           0 :             *nr = 0;
   25621           0 :             return;
   25622             :         }
   25623             :         
   25624             :         /*
   25625             :          *consider case, when the one exist
   25626             :          *same sign of derivative
   25627             :          */
   25628           0 :         if( ae_sign(m0, _state)*ae_sign(m1, _state)<0 )
   25629             :         {
   25630           0 :             *nr = 1;
   25631           0 :             extr = -b/(2*a);
   25632           0 :             dd = b*b-4*a*c;
   25633           0 :             if( ae_fp_less(dd,(double)(0)) )
   25634             :             {
   25635           0 :                 return;
   25636             :             }
   25637           0 :             *x0 = (-b-ae_sqrt(dd, _state))/(2*a);
   25638           0 :             *x1 = (-b+ae_sqrt(dd, _state))/(2*a);
   25639           0 :             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)) )
   25640             :             {
   25641           0 :                 *x0 = *x1;
   25642             :             }
   25643           0 :             return;
   25644             :         }
   25645             :         
   25646             :         /*
   25647             :          *consider case, when the one is 0
   25648             :          */
   25649           0 :         if( ae_fp_eq(m0,(double)(0)) )
   25650             :         {
   25651           0 :             *x0 = (double)(0);
   25652           0 :             *nr = 1;
   25653           0 :             return;
   25654             :         }
   25655           0 :         if( ae_fp_eq(m1,(double)(0)) )
   25656             :         {
   25657           0 :             *x0 = (double)(1);
   25658           0 :             *nr = 1;
   25659           0 :             return;
   25660             :         }
   25661             :     }
   25662             :     else
   25663             :     {
   25664             :         
   25665             :         /*
   25666             :          *consider case, when both of derivatives is 0
   25667             :          */
   25668           0 :         if( ae_fp_eq(m0,(double)(0))&&ae_fp_eq(m1,(double)(0)) )
   25669             :         {
   25670           0 :             *x0 = (double)(0);
   25671           0 :             *x1 = (double)(1);
   25672           0 :             *nr = 2;
   25673           0 :             return;
   25674             :         }
   25675             :         
   25676             :         /*
   25677             :          *consider case, when derivative at 0 is 0, and derivative at 1 is't 0
   25678             :          */
   25679           0 :         if( ae_fp_eq(m0,(double)(0))&&ae_fp_neq(m1,(double)(0)) )
   25680             :         {
   25681           0 :             dd = b*b-4*a*c;
   25682           0 :             if( ae_fp_less(dd,(double)(0)) )
   25683             :             {
   25684           0 :                 *x0 = (double)(0);
   25685           0 :                 *nr = 1;
   25686           0 :                 return;
   25687             :             }
   25688           0 :             *x0 = (-b-ae_sqrt(dd, _state))/(2*a);
   25689           0 :             *x1 = (-b+ae_sqrt(dd, _state))/(2*a);
   25690           0 :             extr = -b/(2*a);
   25691           0 :             exf = a*extr*extr+b*extr+c;
   25692           0 :             if( ae_sign(exf, _state)*ae_sign(m1, _state)>0 )
   25693             :             {
   25694           0 :                 *x0 = (double)(0);
   25695           0 :                 *nr = 1;
   25696           0 :                 return;
   25697             :             }
   25698             :             else
   25699             :             {
   25700           0 :                 if( ae_fp_greater(extr,*x0) )
   25701             :                 {
   25702           0 :                     *x0 = (double)(0);
   25703             :                 }
   25704             :                 else
   25705             :                 {
   25706           0 :                     *x1 = (double)(0);
   25707             :                 }
   25708           0 :                 *nr = 2;
   25709             :                 
   25710             :                 /*
   25711             :                  *roots must placed ascending
   25712             :                  */
   25713           0 :                 if( ae_fp_greater(*x0,*x1) )
   25714             :                 {
   25715           0 :                     tmp = *x0;
   25716           0 :                     *x0 = *x1;
   25717           0 :                     *x1 = tmp;
   25718             :                 }
   25719           0 :                 return;
   25720             :             }
   25721             :         }
   25722           0 :         if( ae_fp_eq(m1,(double)(0))&&ae_fp_neq(m0,(double)(0)) )
   25723             :         {
   25724           0 :             dd = b*b-4*a*c;
   25725           0 :             if( ae_fp_less(dd,(double)(0)) )
   25726             :             {
   25727           0 :                 *x0 = (double)(1);
   25728           0 :                 *nr = 1;
   25729           0 :                 return;
   25730             :             }
   25731           0 :             *x0 = (-b-ae_sqrt(dd, _state))/(2*a);
   25732           0 :             *x1 = (-b+ae_sqrt(dd, _state))/(2*a);
   25733           0 :             extr = -b/(2*a);
   25734           0 :             exf = a*extr*extr+b*extr+c;
   25735           0 :             if( ae_sign(exf, _state)*ae_sign(m0, _state)>0 )
   25736             :             {
   25737           0 :                 *x0 = (double)(1);
   25738           0 :                 *nr = 1;
   25739           0 :                 return;
   25740             :             }
   25741             :             else
   25742             :             {
   25743           0 :                 if( ae_fp_less(extr,*x0) )
   25744             :                 {
   25745           0 :                     *x0 = (double)(1);
   25746             :                 }
   25747             :                 else
   25748             :                 {
   25749           0 :                     *x1 = (double)(1);
   25750             :                 }
   25751           0 :                 *nr = 2;
   25752             :                 
   25753             :                 /*
   25754             :                  *roots must placed ascending
   25755             :                  */
   25756           0 :                 if( ae_fp_greater(*x0,*x1) )
   25757             :                 {
   25758           0 :                     tmp = *x0;
   25759           0 :                     *x0 = *x1;
   25760           0 :                     *x1 = tmp;
   25761             :                 }
   25762           0 :                 return;
   25763             :             }
   25764             :         }
   25765             :         else
   25766             :         {
   25767           0 :             extr = -b/(2*a);
   25768           0 :             exf = a*extr*extr+b*extr+c;
   25769           0 :             if( ae_sign(exf, _state)*ae_sign(m0, _state)>0&&ae_sign(exf, _state)*ae_sign(m1, _state)>0 )
   25770             :             {
   25771           0 :                 *nr = 0;
   25772           0 :                 return;
   25773             :             }
   25774           0 :             dd = b*b-4*a*c;
   25775           0 :             if( ae_fp_less(dd,(double)(0)) )
   25776             :             {
   25777           0 :                 *nr = 0;
   25778           0 :                 return;
   25779             :             }
   25780           0 :             *x0 = (-b-ae_sqrt(dd, _state))/(2*a);
   25781           0 :             *x1 = (-b+ae_sqrt(dd, _state))/(2*a);
   25782             :             
   25783             :             /*
   25784             :              *if EXF and m0, EXF and m1 has different signs, then equation has two roots              
   25785             :              */
   25786           0 :             if( ae_sign(exf, _state)*ae_sign(m0, _state)<0&&ae_sign(exf, _state)*ae_sign(m1, _state)<0 )
   25787             :             {
   25788           0 :                 *nr = 2;
   25789             :                 
   25790             :                 /*
   25791             :                  *roots must placed ascending
   25792             :                  */
   25793           0 :                 if( ae_fp_greater(*x0,*x1) )
   25794             :                 {
   25795           0 :                     tmp = *x0;
   25796           0 :                     *x0 = *x1;
   25797           0 :                     *x1 = tmp;
   25798             :                 }
   25799           0 :                 return;
   25800             :             }
   25801             :             else
   25802             :             {
   25803           0 :                 *nr = 1;
   25804           0 :                 if( ae_sign(exf, _state)*ae_sign(m0, _state)<0 )
   25805             :                 {
   25806           0 :                     if( ae_fp_less(*x1,extr) )
   25807             :                     {
   25808           0 :                         *x0 = *x1;
   25809             :                     }
   25810           0 :                     return;
   25811             :                 }
   25812           0 :                 if( ae_sign(exf, _state)*ae_sign(m1, _state)<0 )
   25813             :                 {
   25814           0 :                     if( ae_fp_greater(*x1,extr) )
   25815             :                     {
   25816           0 :                         *x0 = *x1;
   25817             :                     }
   25818           0 :                     return;
   25819             :                 }
   25820             :             }
   25821             :         }
   25822             :     }
   25823             : }
   25824             : 
   25825             : 
   25826             : /*************************************************************************
   25827             : This procedure search roots of an cubic equation inside [A;B], it number of roots 
   25828             : and number of extremums.
   25829             : 
   25830             : INPUT PARAMETERS:
   25831             :     pA   -   value of a function at A
   25832             :     mA   -   value of a derivative at A
   25833             :     pB   -   value of a function at B
   25834             :     mB   -   value of a derivative at B
   25835             :     A0   -   left border [A0;B0]
   25836             :     B0   -   right border [A0;B0]
   25837             : 
   25838             : OUTPUT PARAMETERS:
   25839             :     X0   -  first root of an equation
   25840             :     X1   -  second root of an equation
   25841             :     X2   -  third root of an equation
   25842             :     EX0  -  first extremum of a function
   25843             :     EX0  -  second extremum of a function
   25844             :     NR   -  number of roots
   25845             :     NR   -  number of extrmums
   25846             :     
   25847             : RESTRICTIONS OF PARAMETERS:
   25848             : 
   25849             : Length of [A;B] must be positive and is't zero, i.e. A<>B and A<B.
   25850             : 
   25851             : 
   25852             : REMARK:
   25853             : 
   25854             : If 'NR' is -1 it's mean, than polinom has infiniti roots.
   25855             : If 'NE' is -1 it's mean, than polinom has infiniti extremums.
   25856             : 
   25857             :  -- ALGLIB PROJECT --
   25858             :      Copyright 26.09.2011 by Bochkanov Sergey
   25859             : *************************************************************************/
   25860           0 : void solvecubicpolinom(double pa,
   25861             :      double ma,
   25862             :      double pb,
   25863             :      double mb,
   25864             :      double a,
   25865             :      double b,
   25866             :      double* x0,
   25867             :      double* x1,
   25868             :      double* x2,
   25869             :      double* ex0,
   25870             :      double* ex1,
   25871             :      ae_int_t* nr,
   25872             :      ae_int_t* ne,
   25873             :      /* Real    */ ae_vector* tempdata,
   25874             :      ae_state *_state)
   25875             : {
   25876             :     ae_int_t i;
   25877             :     double tmpma;
   25878             :     double tmpmb;
   25879             :     double tex0;
   25880             :     double tex1;
   25881             : 
   25882           0 :     *x0 = 0;
   25883           0 :     *x1 = 0;
   25884           0 :     *x2 = 0;
   25885           0 :     *ex0 = 0;
   25886           0 :     *ex1 = 0;
   25887           0 :     *nr = 0;
   25888           0 :     *ne = 0;
   25889             : 
   25890           0 :     rvectorsetlengthatleast(tempdata, 3, _state);
   25891             :     
   25892             :     /*
   25893             :      *case, when A>B
   25894             :      */
   25895           0 :     ae_assert(ae_fp_less(a,b), "\nSolveCubicPolinom: incorrect borders for [A;B]!\n", _state);
   25896             :     
   25897             :     /*
   25898             :      *case 1    
   25899             :      *function can be identicaly to ZERO
   25900             :      */
   25901           0 :     if( ((ae_fp_eq(ma,(double)(0))&&ae_fp_eq(mb,(double)(0)))&&ae_fp_eq(pa,pb))&&ae_fp_eq(pa,(double)(0)) )
   25902             :     {
   25903           0 :         *nr = -1;
   25904           0 :         *ne = -1;
   25905           0 :         return;
   25906             :     }
   25907           0 :     if( (ae_fp_eq(ma,(double)(0))&&ae_fp_eq(mb,(double)(0)))&&ae_fp_eq(pa,pb) )
   25908             :     {
   25909           0 :         *nr = 0;
   25910           0 :         *ne = -1;
   25911           0 :         return;
   25912             :     }
   25913           0 :     tmpma = ma*(b-a);
   25914           0 :     tmpmb = mb*(b-a);
   25915           0 :     solvepolinom2(pa, tmpma, pb, tmpmb, ex0, ex1, ne, _state);
   25916           0 :     *ex0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *ex0, _state);
   25917           0 :     *ex1 = spline1d_rescaleval((double)(0), (double)(1), a, b, *ex1, _state);
   25918             :     
   25919             :     /*
   25920             :      *case 3.1
   25921             :      *no extremums at [A;B]
   25922             :      */
   25923           0 :     if( *ne==0 )
   25924             :     {
   25925           0 :         *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state);
   25926           0 :         if( *nr==1 )
   25927             :         {
   25928           0 :             *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state);
   25929             :         }
   25930           0 :         return;
   25931             :     }
   25932             :     
   25933             :     /*
   25934             :      *case 3.2
   25935             :      *one extremum
   25936             :      */
   25937           0 :     if( *ne==1 )
   25938             :     {
   25939           0 :         if( ae_fp_eq(*ex0,a)||ae_fp_eq(*ex0,b) )
   25940             :         {
   25941           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state);
   25942           0 :             if( *nr==1 )
   25943             :             {
   25944           0 :                 *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state);
   25945             :             }
   25946           0 :             return;
   25947             :         }
   25948             :         else
   25949             :         {
   25950           0 :             *nr = 0;
   25951           0 :             i = 0;
   25952           0 :             tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state);
   25953           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr);
   25954           0 :             if( *nr>i )
   25955             :             {
   25956           0 :                 tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state);
   25957           0 :                 i = i+1;
   25958             :             }
   25959           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, (double)(1), x0, _state)+(*nr);
   25960           0 :             if( *nr>i )
   25961             :             {
   25962           0 :                 *x0 = spline1d_rescaleval(tex0, (double)(1), *ex0, b, *x0, _state);
   25963           0 :                 if( i>0 )
   25964             :                 {
   25965           0 :                     if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) )
   25966             :                     {
   25967           0 :                         tempdata->ptr.p_double[i] = *x0;
   25968           0 :                         i = i+1;
   25969             :                     }
   25970             :                     else
   25971             :                     {
   25972           0 :                         *nr = *nr-1;
   25973             :                     }
   25974             :                 }
   25975             :                 else
   25976             :                 {
   25977           0 :                     tempdata->ptr.p_double[i] = *x0;
   25978           0 :                     i = i+1;
   25979             :                 }
   25980             :             }
   25981           0 :             if( *nr>0 )
   25982             :             {
   25983           0 :                 *x0 = tempdata->ptr.p_double[0];
   25984           0 :                 if( *nr>1 )
   25985             :                 {
   25986           0 :                     *x1 = tempdata->ptr.p_double[1];
   25987             :                 }
   25988           0 :                 return;
   25989             :             }
   25990             :         }
   25991           0 :         return;
   25992             :     }
   25993             :     else
   25994             :     {
   25995             :         
   25996             :         /*
   25997             :          *case 3.3
   25998             :          *two extremums(or more, but it's impossible)
   25999             :          *
   26000             :          *
   26001             :          *case 3.3.0
   26002             :          *both extremums at the border
   26003             :          */
   26004           0 :         if( ae_fp_eq(*ex0,a)&&ae_fp_eq(*ex1,b) )
   26005             :         {
   26006           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state);
   26007           0 :             if( *nr==1 )
   26008             :             {
   26009           0 :                 *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state);
   26010             :             }
   26011           0 :             return;
   26012             :         }
   26013           0 :         if( ae_fp_eq(*ex0,a)&&ae_fp_neq(*ex1,b) )
   26014             :         {
   26015           0 :             *nr = 0;
   26016           0 :             i = 0;
   26017           0 :             tex1 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex1, _state);
   26018           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex1, x0, _state)+(*nr);
   26019           0 :             if( *nr>i )
   26020             :             {
   26021           0 :                 tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex1, a, *ex1, *x0, _state);
   26022           0 :                 i = i+1;
   26023             :             }
   26024           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex1, (double)(1), x0, _state)+(*nr);
   26025           0 :             if( *nr>i )
   26026             :             {
   26027           0 :                 *x0 = spline1d_rescaleval(tex1, (double)(1), *ex1, b, *x0, _state);
   26028           0 :                 if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) )
   26029             :                 {
   26030           0 :                     tempdata->ptr.p_double[i] = *x0;
   26031           0 :                     i = i+1;
   26032             :                 }
   26033             :                 else
   26034             :                 {
   26035           0 :                     *nr = *nr-1;
   26036             :                 }
   26037             :             }
   26038           0 :             if( *nr>0 )
   26039             :             {
   26040           0 :                 *x0 = tempdata->ptr.p_double[0];
   26041           0 :                 if( *nr>1 )
   26042             :                 {
   26043           0 :                     *x1 = tempdata->ptr.p_double[1];
   26044             :                 }
   26045           0 :                 return;
   26046             :             }
   26047             :         }
   26048           0 :         if( ae_fp_eq(*ex1,b)&&ae_fp_neq(*ex0,a) )
   26049             :         {
   26050           0 :             *nr = 0;
   26051           0 :             i = 0;
   26052           0 :             tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state);
   26053           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr);
   26054           0 :             if( *nr>i )
   26055             :             {
   26056           0 :                 tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state);
   26057           0 :                 i = i+1;
   26058             :             }
   26059           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, (double)(1), x0, _state)+(*nr);
   26060           0 :             if( *nr>i )
   26061             :             {
   26062           0 :                 *x0 = spline1d_rescaleval(tex0, (double)(1), *ex0, b, *x0, _state);
   26063           0 :                 if( i>0 )
   26064             :                 {
   26065           0 :                     if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) )
   26066             :                     {
   26067           0 :                         tempdata->ptr.p_double[i] = *x0;
   26068           0 :                         i = i+1;
   26069             :                     }
   26070             :                     else
   26071             :                     {
   26072           0 :                         *nr = *nr-1;
   26073             :                     }
   26074             :                 }
   26075             :                 else
   26076             :                 {
   26077           0 :                     tempdata->ptr.p_double[i] = *x0;
   26078           0 :                     i = i+1;
   26079             :                 }
   26080             :             }
   26081           0 :             if( *nr>0 )
   26082             :             {
   26083           0 :                 *x0 = tempdata->ptr.p_double[0];
   26084           0 :                 if( *nr>1 )
   26085             :                 {
   26086           0 :                     *x1 = tempdata->ptr.p_double[1];
   26087             :                 }
   26088           0 :                 return;
   26089             :             }
   26090             :         }
   26091             :         else
   26092             :         {
   26093             :             
   26094             :             /*
   26095             :              *case 3.3.2
   26096             :              *both extremums inside (0;1)
   26097             :              */
   26098           0 :             *nr = 0;
   26099           0 :             i = 0;
   26100           0 :             tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state);
   26101           0 :             tex1 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex1, _state);
   26102           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr);
   26103           0 :             if( *nr>i )
   26104             :             {
   26105           0 :                 tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state);
   26106           0 :                 i = i+1;
   26107             :             }
   26108           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, tex1, x0, _state)+(*nr);
   26109           0 :             if( *nr>i )
   26110             :             {
   26111           0 :                 *x0 = spline1d_rescaleval(tex0, tex1, *ex0, *ex1, *x0, _state);
   26112           0 :                 if( i>0 )
   26113             :                 {
   26114           0 :                     if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) )
   26115             :                     {
   26116           0 :                         tempdata->ptr.p_double[i] = *x0;
   26117           0 :                         i = i+1;
   26118             :                     }
   26119             :                     else
   26120             :                     {
   26121           0 :                         *nr = *nr-1;
   26122             :                     }
   26123             :                 }
   26124             :                 else
   26125             :                 {
   26126           0 :                     tempdata->ptr.p_double[i] = *x0;
   26127           0 :                     i = i+1;
   26128             :                 }
   26129             :             }
   26130           0 :             *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex1, (double)(1), x0, _state)+(*nr);
   26131           0 :             if( *nr>i )
   26132             :             {
   26133           0 :                 *x0 = spline1d_rescaleval(tex1, (double)(1), *ex1, b, *x0, _state);
   26134           0 :                 if( i>0 )
   26135             :                 {
   26136           0 :                     if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) )
   26137             :                     {
   26138           0 :                         tempdata->ptr.p_double[i] = *x0;
   26139           0 :                         i = i+1;
   26140             :                     }
   26141             :                     else
   26142             :                     {
   26143           0 :                         *nr = *nr-1;
   26144             :                     }
   26145             :                 }
   26146             :                 else
   26147             :                 {
   26148           0 :                     tempdata->ptr.p_double[i] = *x0;
   26149           0 :                     i = i+1;
   26150             :                 }
   26151             :             }
   26152             :             
   26153             :             /*
   26154             :              *write are found roots
   26155             :              */
   26156           0 :             if( *nr>0 )
   26157             :             {
   26158           0 :                 *x0 = tempdata->ptr.p_double[0];
   26159           0 :                 if( *nr>1 )
   26160             :                 {
   26161           0 :                     *x1 = tempdata->ptr.p_double[1];
   26162             :                 }
   26163           0 :                 if( *nr>2 )
   26164             :                 {
   26165           0 :                     *x2 = tempdata->ptr.p_double[2];
   26166             :                 }
   26167           0 :                 return;
   26168             :             }
   26169             :         }
   26170             :     }
   26171             : }
   26172             : 
   26173             : 
   26174             : /*************************************************************************
   26175             : Function for searching a root at [A;B] by bisection method and return number of roots
   26176             : (0 or 1)
   26177             : 
   26178             : INPUT PARAMETERS:
   26179             :     pA   -   value of a function at A
   26180             :     mA   -   value of a derivative at A
   26181             :     pB   -   value of a function at B
   26182             :     mB   -   value of a derivative at B
   26183             :     A0   -   left border [A0;B0] 
   26184             :     B0   -   right border [A0;B0]
   26185             :     
   26186             : RESTRICTIONS OF PARAMETERS:
   26187             : 
   26188             : We assume, that B0>A0.
   26189             : 
   26190             : 
   26191             : REMARK:
   26192             : 
   26193             : Assume, that exist one root only at [A;B], else 
   26194             : function may be work incorrectly.
   26195             : The function dont check value A0,B0!
   26196             : 
   26197             :  -- ALGLIB PROJECT --
   26198             :      Copyright 26.09.2011 by Bochkanov Sergey
   26199             : *************************************************************************/
   26200           0 : ae_int_t bisectmethod(double pa,
   26201             :      double ma,
   26202             :      double pb,
   26203             :      double mb,
   26204             :      double a,
   26205             :      double b,
   26206             :      double* x,
   26207             :      ae_state *_state)
   26208             : {
   26209             :     double vacuum;
   26210             :     double eps;
   26211             :     double a0;
   26212             :     double b0;
   26213             :     double m;
   26214             :     double lf;
   26215             :     double rf;
   26216             :     double mf;
   26217             :     ae_int_t result;
   26218             : 
   26219           0 :     *x = 0;
   26220             : 
   26221             :     
   26222             :     /*
   26223             :      *accuracy
   26224             :      */
   26225           0 :     eps = 1000*(b-a)*ae_machineepsilon;
   26226             :     
   26227             :     /*
   26228             :      *initialization left and right borders
   26229             :      */
   26230           0 :     a0 = a;
   26231           0 :     b0 = b;
   26232             :     
   26233             :     /*
   26234             :      *initialize function value at 'A' and 'B'
   26235             :      */
   26236           0 :     spline1d_hermitecalc(pa, ma, pb, mb, a, &lf, &vacuum, _state);
   26237           0 :     spline1d_hermitecalc(pa, ma, pb, mb, b, &rf, &vacuum, _state);
   26238             :     
   26239             :     /*
   26240             :      *check, that 'A' and 'B' are't roots,
   26241             :      *and that root exist
   26242             :      */
   26243           0 :     if( ae_sign(lf, _state)*ae_sign(rf, _state)>0 )
   26244             :     {
   26245           0 :         result = 0;
   26246           0 :         return result;
   26247             :     }
   26248             :     else
   26249             :     {
   26250           0 :         if( ae_fp_eq(lf,(double)(0)) )
   26251             :         {
   26252           0 :             *x = a;
   26253           0 :             result = 1;
   26254           0 :             return result;
   26255             :         }
   26256             :         else
   26257             :         {
   26258           0 :             if( ae_fp_eq(rf,(double)(0)) )
   26259             :             {
   26260           0 :                 *x = b;
   26261           0 :                 result = 1;
   26262           0 :                 return result;
   26263             :             }
   26264             :         }
   26265             :     }
   26266             :     
   26267             :     /*
   26268             :      *searching a root
   26269             :      */
   26270           0 :     do
   26271             :     {
   26272           0 :         m = (b0+a0)/2;
   26273           0 :         spline1d_hermitecalc(pa, ma, pb, mb, a0, &lf, &vacuum, _state);
   26274           0 :         spline1d_hermitecalc(pa, ma, pb, mb, b0, &rf, &vacuum, _state);
   26275           0 :         spline1d_hermitecalc(pa, ma, pb, mb, m, &mf, &vacuum, _state);
   26276           0 :         if( ae_sign(mf, _state)*ae_sign(lf, _state)<0 )
   26277             :         {
   26278           0 :             b0 = m;
   26279             :         }
   26280             :         else
   26281             :         {
   26282           0 :             if( ae_sign(mf, _state)*ae_sign(rf, _state)<0 )
   26283             :             {
   26284           0 :                 a0 = m;
   26285             :             }
   26286             :             else
   26287             :             {
   26288           0 :                 if( ae_fp_eq(lf,(double)(0)) )
   26289             :                 {
   26290           0 :                     *x = a0;
   26291           0 :                     result = 1;
   26292           0 :                     return result;
   26293             :                 }
   26294           0 :                 if( ae_fp_eq(rf,(double)(0)) )
   26295             :                 {
   26296           0 :                     *x = b0;
   26297           0 :                     result = 1;
   26298           0 :                     return result;
   26299             :                 }
   26300           0 :                 if( ae_fp_eq(mf,(double)(0)) )
   26301             :                 {
   26302           0 :                     *x = m;
   26303           0 :                     result = 1;
   26304           0 :                     return result;
   26305             :                 }
   26306             :             }
   26307             :         }
   26308             :     }
   26309           0 :     while(ae_fp_greater_eq(ae_fabs(b0-a0, _state),eps));
   26310           0 :     *x = m;
   26311           0 :     result = 1;
   26312           0 :     return result;
   26313             : }
   26314             : 
   26315             : 
   26316             : /*************************************************************************
   26317             : This function builds monotone cubic Hermite interpolant. This interpolant
   26318             : is monotonic in [x(0),x(n-1)] and is constant outside of this interval.
   26319             : 
   26320             : In  case  y[]  form  non-monotonic  sequence,  interpolant  is  piecewise
   26321             : monotonic.  Say, for x=(0,1,2,3,4)  and  y=(0,1,2,1,0)  interpolant  will
   26322             : monotonically grow at [0..2] and monotonically decrease at [2..4].
   26323             : 
   26324             : INPUT PARAMETERS:
   26325             :     X           -   spline nodes, array[0..N-1]. Subroutine automatically
   26326             :                     sorts points, so caller may pass unsorted array.
   26327             :     Y           -   function values, array[0..N-1]
   26328             :     N           -   the number of points(N>=2).
   26329             : 
   26330             : OUTPUT PARAMETERS:
   26331             :     C           -   spline interpolant.
   26332             : 
   26333             :  -- ALGLIB PROJECT --
   26334             :      Copyright 21.06.2012 by Bochkanov Sergey
   26335             : *************************************************************************/
   26336           0 : void spline1dbuildmonotone(/* Real    */ ae_vector* x,
   26337             :      /* Real    */ ae_vector* y,
   26338             :      ae_int_t n,
   26339             :      spline1dinterpolant* c,
   26340             :      ae_state *_state)
   26341             : {
   26342             :     ae_frame _frame_block;
   26343             :     ae_vector _x;
   26344             :     ae_vector _y;
   26345             :     ae_vector d;
   26346             :     ae_vector ex;
   26347             :     ae_vector ey;
   26348             :     ae_vector p;
   26349             :     double delta;
   26350             :     double alpha;
   26351             :     double beta;
   26352             :     ae_int_t tmpn;
   26353             :     ae_int_t sn;
   26354             :     double ca;
   26355             :     double cb;
   26356             :     double epsilon;
   26357             :     ae_int_t i;
   26358             :     ae_int_t j;
   26359             : 
   26360           0 :     ae_frame_make(_state, &_frame_block);
   26361           0 :     memset(&_x, 0, sizeof(_x));
   26362           0 :     memset(&_y, 0, sizeof(_y));
   26363           0 :     memset(&d, 0, sizeof(d));
   26364           0 :     memset(&ex, 0, sizeof(ex));
   26365           0 :     memset(&ey, 0, sizeof(ey));
   26366           0 :     memset(&p, 0, sizeof(p));
   26367           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   26368           0 :     x = &_x;
   26369           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   26370           0 :     y = &_y;
   26371           0 :     _spline1dinterpolant_clear(c);
   26372           0 :     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
   26373           0 :     ae_vector_init(&ex, 0, DT_REAL, _state, ae_true);
   26374           0 :     ae_vector_init(&ey, 0, DT_REAL, _state, ae_true);
   26375           0 :     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
   26376             : 
   26377             :     
   26378             :     /*
   26379             :      * Check lengths of arguments
   26380             :      */
   26381           0 :     ae_assert(n>=2, "Spline1DBuildMonotone: N<2", _state);
   26382           0 :     ae_assert(x->cnt>=n, "Spline1DBuildMonotone: Length(X)<N", _state);
   26383           0 :     ae_assert(y->cnt>=n, "Spline1DBuildMonotone: Length(Y)<N", _state);
   26384             :     
   26385             :     /*
   26386             :      * Check and sort points
   26387             :      */
   26388           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildMonotone: X contains infinite or NAN values", _state);
   26389           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DBuildMonotone: Y contains infinite or NAN values", _state);
   26390           0 :     spline1d_heapsortppoints(x, y, &p, n, _state);
   26391           0 :     ae_assert(aredistinct(x, n, _state), "Spline1DBuildMonotone: at least two consequent points are too close", _state);
   26392           0 :     epsilon = ae_machineepsilon;
   26393           0 :     n = n+2;
   26394           0 :     ae_vector_set_length(&d, n, _state);
   26395           0 :     ae_vector_set_length(&ex, n, _state);
   26396           0 :     ae_vector_set_length(&ey, n, _state);
   26397           0 :     ex.ptr.p_double[0] = x->ptr.p_double[0]-ae_fabs(x->ptr.p_double[1]-x->ptr.p_double[0], _state);
   26398           0 :     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);
   26399           0 :     ey.ptr.p_double[0] = y->ptr.p_double[0];
   26400           0 :     ey.ptr.p_double[n-1] = y->ptr.p_double[n-3];
   26401           0 :     for(i=1; i<=n-2; i++)
   26402             :     {
   26403           0 :         ex.ptr.p_double[i] = x->ptr.p_double[i-1];
   26404           0 :         ey.ptr.p_double[i] = y->ptr.p_double[i-1];
   26405             :     }
   26406             :     
   26407             :     /*
   26408             :      * Init sign of the function for first segment
   26409             :      */
   26410           0 :     i = 0;
   26411           0 :     ca = (double)(0);
   26412           0 :     do
   26413             :     {
   26414           0 :         ca = ey.ptr.p_double[i+1]-ey.ptr.p_double[i];
   26415           0 :         i = i+1;
   26416             :     }
   26417           0 :     while(!(ae_fp_neq(ca,(double)(0))||i>n-2));
   26418           0 :     if( ae_fp_neq(ca,(double)(0)) )
   26419             :     {
   26420           0 :         ca = ca/ae_fabs(ca, _state);
   26421             :     }
   26422           0 :     i = 0;
   26423           0 :     while(i<n-1)
   26424             :     {
   26425             :         
   26426             :         /*
   26427             :          * Partition of the segment [X0;Xn]
   26428             :          */
   26429           0 :         tmpn = 1;
   26430           0 :         for(j=i; j<=n-2; j++)
   26431             :         {
   26432           0 :             cb = ey.ptr.p_double[j+1]-ey.ptr.p_double[j];
   26433           0 :             if( ae_fp_greater_eq(ca*cb,(double)(0)) )
   26434             :             {
   26435           0 :                 tmpn = tmpn+1;
   26436             :             }
   26437             :             else
   26438             :             {
   26439           0 :                 ca = cb/ae_fabs(cb, _state);
   26440           0 :                 break;
   26441             :             }
   26442             :         }
   26443           0 :         sn = i+tmpn;
   26444           0 :         ae_assert(tmpn>=2, "Spline1DBuildMonotone: internal error", _state);
   26445             :         
   26446             :         /*
   26447             :          * Calculate derivatives for current segment
   26448             :          */
   26449           0 :         d.ptr.p_double[i] = (double)(0);
   26450           0 :         d.ptr.p_double[sn-1] = (double)(0);
   26451           0 :         for(j=i+1; j<=sn-2; j++)
   26452             :         {
   26453           0 :             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;
   26454             :         }
   26455           0 :         for(j=i; j<=sn-2; j++)
   26456             :         {
   26457           0 :             delta = (ey.ptr.p_double[j+1]-ey.ptr.p_double[j])/(ex.ptr.p_double[j+1]-ex.ptr.p_double[j]);
   26458           0 :             if( ae_fp_less_eq(ae_fabs(delta, _state),epsilon) )
   26459             :             {
   26460           0 :                 d.ptr.p_double[j] = (double)(0);
   26461           0 :                 d.ptr.p_double[j+1] = (double)(0);
   26462             :             }
   26463             :             else
   26464             :             {
   26465           0 :                 alpha = d.ptr.p_double[j]/delta;
   26466           0 :                 beta = d.ptr.p_double[j+1]/delta;
   26467           0 :                 if( ae_fp_neq(alpha,(double)(0)) )
   26468             :                 {
   26469           0 :                     cb = alpha*ae_sqrt(1+ae_sqr(beta/alpha, _state), _state);
   26470             :                 }
   26471             :                 else
   26472             :                 {
   26473           0 :                     if( ae_fp_neq(beta,(double)(0)) )
   26474             :                     {
   26475           0 :                         cb = beta;
   26476             :                     }
   26477             :                     else
   26478             :                     {
   26479           0 :                         continue;
   26480             :                     }
   26481             :                 }
   26482           0 :                 if( ae_fp_greater(cb,(double)(3)) )
   26483             :                 {
   26484           0 :                     d.ptr.p_double[j] = 3*alpha*delta/cb;
   26485           0 :                     d.ptr.p_double[j+1] = 3*beta*delta/cb;
   26486             :                 }
   26487             :             }
   26488             :         }
   26489             :         
   26490             :         /*
   26491             :          * Transition to next segment
   26492             :          */
   26493           0 :         i = sn-1;
   26494             :     }
   26495           0 :     spline1dbuildhermite(&ex, &ey, &d, n, c, _state);
   26496           0 :     c->continuity = 2;
   26497           0 :     ae_frame_leave(_state);
   26498           0 : }
   26499             : 
   26500             : 
   26501             : /*************************************************************************
   26502             : Internal version of Spline1DGridDiffCubic.
   26503             : 
   26504             : Accepts pre-ordered X/Y, temporary arrays (which may be  preallocated,  if
   26505             : you want to save time, or not) and output array (which may be preallocated
   26506             : too).
   26507             : 
   26508             : Y is passed as var-parameter because we may need to force last element  to
   26509             : be equal to the first one (if periodic boundary conditions are specified).
   26510             : 
   26511             :   -- ALGLIB PROJECT --
   26512             :      Copyright 03.09.2010 by Bochkanov Sergey
   26513             : *************************************************************************/
   26514           0 : static void spline1d_spline1dgriddiffcubicinternal(/* Real    */ ae_vector* x,
   26515             :      /* Real    */ ae_vector* y,
   26516             :      ae_int_t n,
   26517             :      ae_int_t boundltype,
   26518             :      double boundl,
   26519             :      ae_int_t boundrtype,
   26520             :      double boundr,
   26521             :      /* Real    */ ae_vector* d,
   26522             :      /* Real    */ ae_vector* a1,
   26523             :      /* Real    */ ae_vector* a2,
   26524             :      /* Real    */ ae_vector* a3,
   26525             :      /* Real    */ ae_vector* b,
   26526             :      /* Real    */ ae_vector* dt,
   26527             :      ae_state *_state)
   26528             : {
   26529             :     ae_int_t i;
   26530             : 
   26531             : 
   26532             :     
   26533             :     /*
   26534             :      * allocate arrays
   26535             :      */
   26536           0 :     if( d->cnt<n )
   26537             :     {
   26538           0 :         ae_vector_set_length(d, n, _state);
   26539             :     }
   26540           0 :     if( a1->cnt<n )
   26541             :     {
   26542           0 :         ae_vector_set_length(a1, n, _state);
   26543             :     }
   26544           0 :     if( a2->cnt<n )
   26545             :     {
   26546           0 :         ae_vector_set_length(a2, n, _state);
   26547             :     }
   26548           0 :     if( a3->cnt<n )
   26549             :     {
   26550           0 :         ae_vector_set_length(a3, n, _state);
   26551             :     }
   26552           0 :     if( b->cnt<n )
   26553             :     {
   26554           0 :         ae_vector_set_length(b, n, _state);
   26555             :     }
   26556           0 :     if( dt->cnt<n )
   26557             :     {
   26558           0 :         ae_vector_set_length(dt, n, _state);
   26559             :     }
   26560             :     
   26561             :     /*
   26562             :      * Special cases:
   26563             :      * * N=2, parabolic terminated boundary condition on both ends
   26564             :      * * N=2, periodic boundary condition
   26565             :      */
   26566           0 :     if( (n==2&&boundltype==0)&&boundrtype==0 )
   26567             :     {
   26568           0 :         d->ptr.p_double[0] = (y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0]);
   26569           0 :         d->ptr.p_double[1] = d->ptr.p_double[0];
   26570           0 :         return;
   26571             :     }
   26572           0 :     if( (n==2&&boundltype==-1)&&boundrtype==-1 )
   26573             :     {
   26574           0 :         d->ptr.p_double[0] = (double)(0);
   26575           0 :         d->ptr.p_double[1] = (double)(0);
   26576           0 :         return;
   26577             :     }
   26578             :     
   26579             :     /*
   26580             :      * Periodic and non-periodic boundary conditions are
   26581             :      * two separate classes
   26582             :      */
   26583           0 :     if( boundrtype==-1&&boundltype==-1 )
   26584             :     {
   26585             :         
   26586             :         /*
   26587             :          * Periodic boundary conditions
   26588             :          */
   26589           0 :         y->ptr.p_double[n-1] = y->ptr.p_double[0];
   26590             :         
   26591             :         /*
   26592             :          * Boundary conditions at N-1 points
   26593             :          * (one point less because last point is the same as first point).
   26594             :          */
   26595           0 :         a1->ptr.p_double[0] = x->ptr.p_double[1]-x->ptr.p_double[0];
   26596           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]);
   26597           0 :         a3->ptr.p_double[0] = x->ptr.p_double[n-1]-x->ptr.p_double[n-2];
   26598           0 :         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]);
   26599           0 :         for(i=1; i<=n-2; i++)
   26600             :         {
   26601             :             
   26602             :             /*
   26603             :              * Altough last point is [N-2], we use X[N-1] and Y[N-1]
   26604             :              * (because of periodicity)
   26605             :              */
   26606           0 :             a1->ptr.p_double[i] = x->ptr.p_double[i+1]-x->ptr.p_double[i];
   26607           0 :             a2->ptr.p_double[i] = 2*(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]);
   26608           0 :             a3->ptr.p_double[i] = x->ptr.p_double[i]-x->ptr.p_double[i-1];
   26609           0 :             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]);
   26610             :         }
   26611             :         
   26612             :         /*
   26613             :          * Solve, add last point (with index N-1)
   26614             :          */
   26615           0 :         spline1d_solvecyclictridiagonal(a1, a2, a3, b, n-1, dt, _state);
   26616           0 :         ae_v_move(&d->ptr.p_double[0], 1, &dt->ptr.p_double[0], 1, ae_v_len(0,n-2));
   26617           0 :         d->ptr.p_double[n-1] = d->ptr.p_double[0];
   26618             :     }
   26619             :     else
   26620             :     {
   26621             :         
   26622             :         /*
   26623             :          * Non-periodic boundary condition.
   26624             :          * Left boundary conditions.
   26625             :          */
   26626           0 :         if( boundltype==0 )
   26627             :         {
   26628           0 :             a1->ptr.p_double[0] = (double)(0);
   26629           0 :             a2->ptr.p_double[0] = (double)(1);
   26630           0 :             a3->ptr.p_double[0] = (double)(1);
   26631           0 :             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]);
   26632             :         }
   26633           0 :         if( boundltype==1 )
   26634             :         {
   26635           0 :             a1->ptr.p_double[0] = (double)(0);
   26636           0 :             a2->ptr.p_double[0] = (double)(1);
   26637           0 :             a3->ptr.p_double[0] = (double)(0);
   26638           0 :             b->ptr.p_double[0] = boundl;
   26639             :         }
   26640           0 :         if( boundltype==2 )
   26641             :         {
   26642           0 :             a1->ptr.p_double[0] = (double)(0);
   26643           0 :             a2->ptr.p_double[0] = (double)(2);
   26644           0 :             a3->ptr.p_double[0] = (double)(1);
   26645           0 :             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]);
   26646             :         }
   26647             :         
   26648             :         /*
   26649             :          * Central conditions
   26650             :          */
   26651           0 :         for(i=1; i<=n-2; i++)
   26652             :         {
   26653           0 :             a1->ptr.p_double[i] = x->ptr.p_double[i+1]-x->ptr.p_double[i];
   26654           0 :             a2->ptr.p_double[i] = 2*(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]);
   26655           0 :             a3->ptr.p_double[i] = x->ptr.p_double[i]-x->ptr.p_double[i-1];
   26656           0 :             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]);
   26657             :         }
   26658             :         
   26659             :         /*
   26660             :          * Right boundary conditions
   26661             :          */
   26662           0 :         if( boundrtype==0 )
   26663             :         {
   26664           0 :             a1->ptr.p_double[n-1] = (double)(1);
   26665           0 :             a2->ptr.p_double[n-1] = (double)(1);
   26666           0 :             a3->ptr.p_double[n-1] = (double)(0);
   26667           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]);
   26668             :         }
   26669           0 :         if( boundrtype==1 )
   26670             :         {
   26671           0 :             a1->ptr.p_double[n-1] = (double)(0);
   26672           0 :             a2->ptr.p_double[n-1] = (double)(1);
   26673           0 :             a3->ptr.p_double[n-1] = (double)(0);
   26674           0 :             b->ptr.p_double[n-1] = boundr;
   26675             :         }
   26676           0 :         if( boundrtype==2 )
   26677             :         {
   26678           0 :             a1->ptr.p_double[n-1] = (double)(1);
   26679           0 :             a2->ptr.p_double[n-1] = (double)(2);
   26680           0 :             a3->ptr.p_double[n-1] = (double)(0);
   26681           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]);
   26682             :         }
   26683             :         
   26684             :         /*
   26685             :          * Solve
   26686             :          */
   26687           0 :         spline1d_solvetridiagonal(a1, a2, a3, b, n, d, _state);
   26688             :     }
   26689             : }
   26690             : 
   26691             : 
   26692             : /*************************************************************************
   26693             : Internal subroutine. Heap sort.
   26694             : *************************************************************************/
   26695           0 : static void spline1d_heapsortpoints(/* Real    */ ae_vector* x,
   26696             :      /* Real    */ ae_vector* y,
   26697             :      ae_int_t n,
   26698             :      ae_state *_state)
   26699             : {
   26700             :     ae_frame _frame_block;
   26701             :     ae_vector bufx;
   26702             :     ae_vector bufy;
   26703             : 
   26704           0 :     ae_frame_make(_state, &_frame_block);
   26705           0 :     memset(&bufx, 0, sizeof(bufx));
   26706           0 :     memset(&bufy, 0, sizeof(bufy));
   26707           0 :     ae_vector_init(&bufx, 0, DT_REAL, _state, ae_true);
   26708           0 :     ae_vector_init(&bufy, 0, DT_REAL, _state, ae_true);
   26709             : 
   26710           0 :     tagsortfastr(x, y, &bufx, &bufy, n, _state);
   26711           0 :     ae_frame_leave(_state);
   26712           0 : }
   26713             : 
   26714             : 
   26715             : /*************************************************************************
   26716             : Internal subroutine. Heap sort.
   26717             : 
   26718             : Accepts:
   26719             :     X, Y    -   points
   26720             :     P       -   empty or preallocated array
   26721             :     
   26722             : Returns:
   26723             :     X, Y    -   sorted by X
   26724             :     P       -   array of permutations; I-th position of output
   26725             :                 arrays X/Y contains (X[P[I]],Y[P[I]])
   26726             : *************************************************************************/
   26727           0 : static void spline1d_heapsortppoints(/* Real    */ ae_vector* x,
   26728             :      /* Real    */ ae_vector* y,
   26729             :      /* Integer */ ae_vector* p,
   26730             :      ae_int_t n,
   26731             :      ae_state *_state)
   26732             : {
   26733             :     ae_frame _frame_block;
   26734             :     ae_vector rbuf;
   26735             :     ae_vector ibuf;
   26736             :     ae_int_t i;
   26737             : 
   26738           0 :     ae_frame_make(_state, &_frame_block);
   26739           0 :     memset(&rbuf, 0, sizeof(rbuf));
   26740           0 :     memset(&ibuf, 0, sizeof(ibuf));
   26741           0 :     ae_vector_init(&rbuf, 0, DT_REAL, _state, ae_true);
   26742           0 :     ae_vector_init(&ibuf, 0, DT_INT, _state, ae_true);
   26743             : 
   26744           0 :     if( p->cnt<n )
   26745             :     {
   26746           0 :         ae_vector_set_length(p, n, _state);
   26747             :     }
   26748           0 :     ae_vector_set_length(&rbuf, n, _state);
   26749           0 :     for(i=0; i<=n-1; i++)
   26750             :     {
   26751           0 :         p->ptr.p_int[i] = i;
   26752             :     }
   26753           0 :     tagsortfasti(x, p, &rbuf, &ibuf, n, _state);
   26754           0 :     for(i=0; i<=n-1; i++)
   26755             :     {
   26756           0 :         rbuf.ptr.p_double[i] = y->ptr.p_double[p->ptr.p_int[i]];
   26757             :     }
   26758           0 :     ae_v_move(&y->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1));
   26759           0 :     ae_frame_leave(_state);
   26760           0 : }
   26761             : 
   26762             : 
   26763             : /*************************************************************************
   26764             : Internal subroutine. Tridiagonal solver. Solves
   26765             : 
   26766             : ( B[0] C[0]                      
   26767             : ( A[1] B[1] C[1]                 )
   26768             : (      A[2] B[2] C[2]            )
   26769             : (            ..........          ) * X = D
   26770             : (            ..........          )
   26771             : (           A[N-2] B[N-2] C[N-2] )
   26772             : (                  A[N-1] B[N-1] )
   26773             : 
   26774             : *************************************************************************/
   26775           0 : static void spline1d_solvetridiagonal(/* Real    */ ae_vector* a,
   26776             :      /* Real    */ ae_vector* b,
   26777             :      /* Real    */ ae_vector* c,
   26778             :      /* Real    */ ae_vector* d,
   26779             :      ae_int_t n,
   26780             :      /* Real    */ ae_vector* x,
   26781             :      ae_state *_state)
   26782             : {
   26783             :     ae_frame _frame_block;
   26784             :     ae_vector _b;
   26785             :     ae_vector _d;
   26786             :     ae_int_t k;
   26787             :     double t;
   26788             : 
   26789           0 :     ae_frame_make(_state, &_frame_block);
   26790           0 :     memset(&_b, 0, sizeof(_b));
   26791           0 :     memset(&_d, 0, sizeof(_d));
   26792           0 :     ae_vector_init_copy(&_b, b, _state, ae_true);
   26793           0 :     b = &_b;
   26794           0 :     ae_vector_init_copy(&_d, d, _state, ae_true);
   26795           0 :     d = &_d;
   26796             : 
   26797           0 :     if( x->cnt<n )
   26798             :     {
   26799           0 :         ae_vector_set_length(x, n, _state);
   26800             :     }
   26801           0 :     for(k=1; k<=n-1; k++)
   26802             :     {
   26803           0 :         t = a->ptr.p_double[k]/b->ptr.p_double[k-1];
   26804           0 :         b->ptr.p_double[k] = b->ptr.p_double[k]-t*c->ptr.p_double[k-1];
   26805           0 :         d->ptr.p_double[k] = d->ptr.p_double[k]-t*d->ptr.p_double[k-1];
   26806             :     }
   26807           0 :     x->ptr.p_double[n-1] = d->ptr.p_double[n-1]/b->ptr.p_double[n-1];
   26808           0 :     for(k=n-2; k>=0; k--)
   26809             :     {
   26810           0 :         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];
   26811             :     }
   26812           0 :     ae_frame_leave(_state);
   26813           0 : }
   26814             : 
   26815             : 
   26816             : /*************************************************************************
   26817             : Internal subroutine. Cyclic tridiagonal solver. Solves
   26818             : 
   26819             : ( B[0] C[0]                 A[0] )
   26820             : ( A[1] B[1] C[1]                 )
   26821             : (      A[2] B[2] C[2]            )
   26822             : (            ..........          ) * X = D
   26823             : (            ..........          )
   26824             : (           A[N-2] B[N-2] C[N-2] )
   26825             : ( C[N-1]           A[N-1] B[N-1] )
   26826             : *************************************************************************/
   26827           0 : static void spline1d_solvecyclictridiagonal(/* Real    */ ae_vector* a,
   26828             :      /* Real    */ ae_vector* b,
   26829             :      /* Real    */ ae_vector* c,
   26830             :      /* Real    */ ae_vector* d,
   26831             :      ae_int_t n,
   26832             :      /* Real    */ ae_vector* x,
   26833             :      ae_state *_state)
   26834             : {
   26835             :     ae_frame _frame_block;
   26836             :     ae_vector _b;
   26837             :     ae_int_t k;
   26838             :     double alpha;
   26839             :     double beta;
   26840             :     double gamma;
   26841             :     ae_vector y;
   26842             :     ae_vector z;
   26843             :     ae_vector u;
   26844             : 
   26845           0 :     ae_frame_make(_state, &_frame_block);
   26846           0 :     memset(&_b, 0, sizeof(_b));
   26847           0 :     memset(&y, 0, sizeof(y));
   26848           0 :     memset(&z, 0, sizeof(z));
   26849           0 :     memset(&u, 0, sizeof(u));
   26850           0 :     ae_vector_init_copy(&_b, b, _state, ae_true);
   26851           0 :     b = &_b;
   26852           0 :     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
   26853           0 :     ae_vector_init(&z, 0, DT_REAL, _state, ae_true);
   26854           0 :     ae_vector_init(&u, 0, DT_REAL, _state, ae_true);
   26855             : 
   26856           0 :     if( x->cnt<n )
   26857             :     {
   26858           0 :         ae_vector_set_length(x, n, _state);
   26859             :     }
   26860           0 :     beta = a->ptr.p_double[0];
   26861           0 :     alpha = c->ptr.p_double[n-1];
   26862           0 :     gamma = -b->ptr.p_double[0];
   26863           0 :     b->ptr.p_double[0] = 2*b->ptr.p_double[0];
   26864           0 :     b->ptr.p_double[n-1] = b->ptr.p_double[n-1]-alpha*beta/gamma;
   26865           0 :     ae_vector_set_length(&u, n, _state);
   26866           0 :     for(k=0; k<=n-1; k++)
   26867             :     {
   26868           0 :         u.ptr.p_double[k] = (double)(0);
   26869             :     }
   26870           0 :     u.ptr.p_double[0] = gamma;
   26871           0 :     u.ptr.p_double[n-1] = alpha;
   26872           0 :     spline1d_solvetridiagonal(a, b, c, d, n, &y, _state);
   26873           0 :     spline1d_solvetridiagonal(a, b, c, &u, n, &z, _state);
   26874           0 :     for(k=0; k<=n-1; k++)
   26875             :     {
   26876           0 :         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];
   26877             :     }
   26878           0 :     ae_frame_leave(_state);
   26879           0 : }
   26880             : 
   26881             : 
   26882             : /*************************************************************************
   26883             : Internal subroutine. Three-point differentiation
   26884             : *************************************************************************/
   26885           0 : static double spline1d_diffthreepoint(double t,
   26886             :      double x0,
   26887             :      double f0,
   26888             :      double x1,
   26889             :      double f1,
   26890             :      double x2,
   26891             :      double f2,
   26892             :      ae_state *_state)
   26893             : {
   26894             :     double a;
   26895             :     double b;
   26896             :     double result;
   26897             : 
   26898             : 
   26899           0 :     t = t-x0;
   26900           0 :     x1 = x1-x0;
   26901           0 :     x2 = x2-x0;
   26902           0 :     a = (f2-f0-x2/x1*(f1-f0))/(ae_sqr(x2, _state)-x1*x2);
   26903           0 :     b = (f1-f0-a*ae_sqr(x1, _state))/x1;
   26904           0 :     result = 2*a*t+b;
   26905           0 :     return result;
   26906             : }
   26907             : 
   26908             : 
   26909             : /*************************************************************************
   26910             : Procedure for calculating value of a function is providet in the form of
   26911             : Hermite polinom  
   26912             : 
   26913             : INPUT PARAMETERS:
   26914             :     P0   -   value of a function at 0
   26915             :     M0   -   value of a derivative at 0
   26916             :     P1   -   value of a function at 1
   26917             :     M1   -   value of a derivative at 1
   26918             :     T    -   point inside [0;1]
   26919             :     
   26920             : OUTPUT PARAMETERS:
   26921             :     S    -   value of a function at T
   26922             :     B0   -   value of a derivative function at T
   26923             :     
   26924             :  -- ALGLIB PROJECT --
   26925             :      Copyright 26.09.2011 by Bochkanov Sergey
   26926             : *************************************************************************/
   26927           0 : static void spline1d_hermitecalc(double p0,
   26928             :      double m0,
   26929             :      double p1,
   26930             :      double m1,
   26931             :      double t,
   26932             :      double* s,
   26933             :      double* ds,
   26934             :      ae_state *_state)
   26935             : {
   26936             : 
   26937           0 :     *s = 0;
   26938           0 :     *ds = 0;
   26939             : 
   26940           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);
   26941           0 :     *ds = -p0*6*t*(1-t)+m0*(1-t)*(1-3*t)+p1*6*t*(1-t)+m1*t*(3*t-2);
   26942           0 : }
   26943             : 
   26944             : 
   26945             : /*************************************************************************
   26946             : Function for mapping from [A0;B0] to [A1;B1]
   26947             : 
   26948             : INPUT PARAMETERS:
   26949             :     A0   -   left border [A0;B0]
   26950             :     B0   -   right border [A0;B0]
   26951             :     A1   -   left border [A1;B1]
   26952             :     B1   -   right border [A1;B1]
   26953             :     T    -   value inside [A0;B0]  
   26954             :     
   26955             : RESTRICTIONS OF PARAMETERS:
   26956             : 
   26957             : We assume, that B0>A0 and B1>A1. But we chech, that T is inside [A0;B0], 
   26958             : and if T<A0 then T become A1, if T>B0 then T - B1. 
   26959             : 
   26960             : INPUT PARAMETERS:
   26961             :         A0   -   left border for segment [A0;B0] from 'T' is converted to [A1;B1] 
   26962             :         B0   -   right border for segment [A0;B0] from 'T' is converted to [A1;B1] 
   26963             :         A1   -   left border for segment [A1;B1] to 'T' is converted from [A0;B0] 
   26964             :         B1   -   right border for segment [A1;B1] to 'T' is converted from [A0;B0] 
   26965             :         T    -   the parameter is mapped from [A0;B0] to [A1;B1] 
   26966             : 
   26967             : Result:
   26968             :     is converted value for 'T' from [A0;B0] to [A1;B1]
   26969             :          
   26970             : REMARK:
   26971             : 
   26972             : The function dont check value A0,B0 and A1,B1!
   26973             : 
   26974             :  -- ALGLIB PROJECT --
   26975             :      Copyright 26.09.2011 by Bochkanov Sergey
   26976             : *************************************************************************/
   26977           0 : static double spline1d_rescaleval(double a0,
   26978             :      double b0,
   26979             :      double a1,
   26980             :      double b1,
   26981             :      double t,
   26982             :      ae_state *_state)
   26983             : {
   26984             :     double result;
   26985             : 
   26986             : 
   26987             :     
   26988             :     /*
   26989             :      *return left border
   26990             :      */
   26991           0 :     if( ae_fp_less_eq(t,a0) )
   26992             :     {
   26993           0 :         result = a1;
   26994           0 :         return result;
   26995             :     }
   26996             :     
   26997             :     /*
   26998             :      *return right border
   26999             :      */
   27000           0 :     if( ae_fp_greater_eq(t,b0) )
   27001             :     {
   27002           0 :         result = b1;
   27003           0 :         return result;
   27004             :     }
   27005             :     
   27006             :     /*
   27007             :      *return value between left and right borders
   27008             :      */
   27009           0 :     result = (b1-a1)*(t-a0)/(b0-a0)+a1;
   27010           0 :     return result;
   27011             : }
   27012             : 
   27013             : 
   27014           0 : void _spline1dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
   27015             : {
   27016           0 :     spline1dinterpolant *p = (spline1dinterpolant*)_p;
   27017           0 :     ae_touch_ptr((void*)p);
   27018           0 :     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
   27019           0 :     ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic);
   27020           0 : }
   27021             : 
   27022             : 
   27023           0 : void _spline1dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   27024             : {
   27025           0 :     spline1dinterpolant *dst = (spline1dinterpolant*)_dst;
   27026           0 :     spline1dinterpolant *src = (spline1dinterpolant*)_src;
   27027           0 :     dst->periodic = src->periodic;
   27028           0 :     dst->n = src->n;
   27029           0 :     dst->k = src->k;
   27030           0 :     dst->continuity = src->continuity;
   27031           0 :     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
   27032           0 :     ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic);
   27033           0 : }
   27034             : 
   27035             : 
   27036           0 : void _spline1dinterpolant_clear(void* _p)
   27037             : {
   27038           0 :     spline1dinterpolant *p = (spline1dinterpolant*)_p;
   27039           0 :     ae_touch_ptr((void*)p);
   27040           0 :     ae_vector_clear(&p->x);
   27041           0 :     ae_vector_clear(&p->c);
   27042           0 : }
   27043             : 
   27044             : 
   27045           0 : void _spline1dinterpolant_destroy(void* _p)
   27046             : {
   27047           0 :     spline1dinterpolant *p = (spline1dinterpolant*)_p;
   27048           0 :     ae_touch_ptr((void*)p);
   27049           0 :     ae_vector_destroy(&p->x);
   27050           0 :     ae_vector_destroy(&p->c);
   27051           0 : }
   27052             : 
   27053             : 
   27054           0 : void _spline1dfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
   27055             : {
   27056           0 :     spline1dfitreport *p = (spline1dfitreport*)_p;
   27057           0 :     ae_touch_ptr((void*)p);
   27058           0 : }
   27059             : 
   27060             : 
   27061           0 : void _spline1dfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   27062             : {
   27063           0 :     spline1dfitreport *dst = (spline1dfitreport*)_dst;
   27064           0 :     spline1dfitreport *src = (spline1dfitreport*)_src;
   27065           0 :     dst->taskrcond = src->taskrcond;
   27066           0 :     dst->rmserror = src->rmserror;
   27067           0 :     dst->avgerror = src->avgerror;
   27068           0 :     dst->avgrelerror = src->avgrelerror;
   27069           0 :     dst->maxerror = src->maxerror;
   27070           0 : }
   27071             : 
   27072             : 
   27073           0 : void _spline1dfitreport_clear(void* _p)
   27074             : {
   27075           0 :     spline1dfitreport *p = (spline1dfitreport*)_p;
   27076           0 :     ae_touch_ptr((void*)p);
   27077           0 : }
   27078             : 
   27079             : 
   27080           0 : void _spline1dfitreport_destroy(void* _p)
   27081             : {
   27082           0 :     spline1dfitreport *p = (spline1dfitreport*)_p;
   27083           0 :     ae_touch_ptr((void*)p);
   27084           0 : }
   27085             : 
   27086             : 
   27087             : #endif
   27088             : #if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD)
   27089             : 
   27090             : 
   27091             : /*************************************************************************
   27092             : This function  builds  non-periodic 2-dimensional parametric spline  which
   27093             : starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]).
   27094             : 
   27095             : INPUT PARAMETERS:
   27096             :     XY  -   points, array[0..N-1,0..1].
   27097             :             XY[I,0:1] corresponds to the Ith point.
   27098             :             Order of points is important!
   27099             :     N   -   points count, N>=5 for Akima splines, N>=2 for other types  of
   27100             :             splines.
   27101             :     ST  -   spline type:
   27102             :             * 0     Akima spline
   27103             :             * 1     parabolically terminated Catmull-Rom spline (Tension=0)
   27104             :             * 2     parabolically terminated cubic spline
   27105             :     PT  -   parameterization type:
   27106             :             * 0     uniform
   27107             :             * 1     chord length
   27108             :             * 2     centripetal
   27109             : 
   27110             : OUTPUT PARAMETERS:
   27111             :     P   -   parametric spline interpolant
   27112             : 
   27113             : 
   27114             : NOTES:
   27115             : * this function  assumes  that  there all consequent points  are distinct.
   27116             :   I.e. (x0,y0)<>(x1,y1),  (x1,y1)<>(x2,y2),  (x2,y2)<>(x3,y3)  and  so on.
   27117             :   However, non-consequent points may coincide, i.e. we can  have  (x0,y0)=
   27118             :   =(x2,y2).
   27119             : 
   27120             :   -- ALGLIB PROJECT --
   27121             :      Copyright 28.05.2010 by Bochkanov Sergey
   27122             : *************************************************************************/
   27123           0 : void pspline2build(/* Real    */ ae_matrix* xy,
   27124             :      ae_int_t n,
   27125             :      ae_int_t st,
   27126             :      ae_int_t pt,
   27127             :      pspline2interpolant* p,
   27128             :      ae_state *_state)
   27129             : {
   27130             :     ae_frame _frame_block;
   27131             :     ae_matrix _xy;
   27132             :     ae_vector tmp;
   27133             : 
   27134           0 :     ae_frame_make(_state, &_frame_block);
   27135           0 :     memset(&_xy, 0, sizeof(_xy));
   27136           0 :     memset(&tmp, 0, sizeof(tmp));
   27137           0 :     ae_matrix_init_copy(&_xy, xy, _state, ae_true);
   27138           0 :     xy = &_xy;
   27139           0 :     _pspline2interpolant_clear(p);
   27140           0 :     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
   27141             : 
   27142           0 :     ae_assert(st>=0&&st<=2, "PSpline2Build: incorrect spline type!", _state);
   27143           0 :     ae_assert(pt>=0&&pt<=2, "PSpline2Build: incorrect parameterization type!", _state);
   27144           0 :     if( st==0 )
   27145             :     {
   27146           0 :         ae_assert(n>=5, "PSpline2Build: N<5 (minimum value for Akima splines)!", _state);
   27147             :     }
   27148             :     else
   27149             :     {
   27150           0 :         ae_assert(n>=2, "PSpline2Build: N<2!", _state);
   27151             :     }
   27152             :     
   27153             :     /*
   27154             :      * Prepare
   27155             :      */
   27156           0 :     p->n = n;
   27157           0 :     p->periodic = ae_false;
   27158           0 :     ae_vector_set_length(&tmp, n, _state);
   27159             :     
   27160             :     /*
   27161             :      * Build parameterization, check that all parameters are distinct
   27162             :      */
   27163           0 :     parametric_pspline2par(xy, n, pt, &p->p, _state);
   27164           0 :     ae_assert(aredistinct(&p->p, n, _state), "PSpline2Build: consequent points are too close!", _state);
   27165             :     
   27166             :     /*
   27167             :      * Build splines
   27168             :      */
   27169           0 :     if( st==0 )
   27170             :     {
   27171           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
   27172           0 :         spline1dbuildakima(&p->p, &tmp, n, &p->x, _state);
   27173           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
   27174           0 :         spline1dbuildakima(&p->p, &tmp, n, &p->y, _state);
   27175             :     }
   27176           0 :     if( st==1 )
   27177             :     {
   27178           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
   27179           0 :         spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->x, _state);
   27180           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
   27181           0 :         spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->y, _state);
   27182             :     }
   27183           0 :     if( st==2 )
   27184             :     {
   27185           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
   27186           0 :         spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->x, _state);
   27187           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
   27188           0 :         spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->y, _state);
   27189             :     }
   27190           0 :     ae_frame_leave(_state);
   27191           0 : }
   27192             : 
   27193             : 
   27194             : /*************************************************************************
   27195             : This function  builds  non-periodic 3-dimensional parametric spline  which
   27196             : starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]).
   27197             : 
   27198             : Same as PSpline2Build() function, but for 3D, so we  won't  duplicate  its
   27199             : description here.
   27200             : 
   27201             :   -- ALGLIB PROJECT --
   27202             :      Copyright 28.05.2010 by Bochkanov Sergey
   27203             : *************************************************************************/
   27204           0 : void pspline3build(/* Real    */ ae_matrix* xy,
   27205             :      ae_int_t n,
   27206             :      ae_int_t st,
   27207             :      ae_int_t pt,
   27208             :      pspline3interpolant* p,
   27209             :      ae_state *_state)
   27210             : {
   27211             :     ae_frame _frame_block;
   27212             :     ae_matrix _xy;
   27213             :     ae_vector tmp;
   27214             : 
   27215           0 :     ae_frame_make(_state, &_frame_block);
   27216           0 :     memset(&_xy, 0, sizeof(_xy));
   27217           0 :     memset(&tmp, 0, sizeof(tmp));
   27218           0 :     ae_matrix_init_copy(&_xy, xy, _state, ae_true);
   27219           0 :     xy = &_xy;
   27220           0 :     _pspline3interpolant_clear(p);
   27221           0 :     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
   27222             : 
   27223           0 :     ae_assert(st>=0&&st<=2, "PSpline3Build: incorrect spline type!", _state);
   27224           0 :     ae_assert(pt>=0&&pt<=2, "PSpline3Build: incorrect parameterization type!", _state);
   27225           0 :     if( st==0 )
   27226             :     {
   27227           0 :         ae_assert(n>=5, "PSpline3Build: N<5 (minimum value for Akima splines)!", _state);
   27228             :     }
   27229             :     else
   27230             :     {
   27231           0 :         ae_assert(n>=2, "PSpline3Build: N<2!", _state);
   27232             :     }
   27233             :     
   27234             :     /*
   27235             :      * Prepare
   27236             :      */
   27237           0 :     p->n = n;
   27238           0 :     p->periodic = ae_false;
   27239           0 :     ae_vector_set_length(&tmp, n, _state);
   27240             :     
   27241             :     /*
   27242             :      * Build parameterization, check that all parameters are distinct
   27243             :      */
   27244           0 :     parametric_pspline3par(xy, n, pt, &p->p, _state);
   27245           0 :     ae_assert(aredistinct(&p->p, n, _state), "PSpline3Build: consequent points are too close!", _state);
   27246             :     
   27247             :     /*
   27248             :      * Build splines
   27249             :      */
   27250           0 :     if( st==0 )
   27251             :     {
   27252           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
   27253           0 :         spline1dbuildakima(&p->p, &tmp, n, &p->x, _state);
   27254           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
   27255           0 :         spline1dbuildakima(&p->p, &tmp, n, &p->y, _state);
   27256           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1));
   27257           0 :         spline1dbuildakima(&p->p, &tmp, n, &p->z, _state);
   27258             :     }
   27259           0 :     if( st==1 )
   27260             :     {
   27261           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
   27262           0 :         spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->x, _state);
   27263           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
   27264           0 :         spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->y, _state);
   27265           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1));
   27266           0 :         spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->z, _state);
   27267             :     }
   27268           0 :     if( st==2 )
   27269             :     {
   27270           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
   27271           0 :         spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->x, _state);
   27272           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
   27273           0 :         spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->y, _state);
   27274           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1));
   27275           0 :         spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->z, _state);
   27276             :     }
   27277           0 :     ae_frame_leave(_state);
   27278           0 : }
   27279             : 
   27280             : 
   27281             : /*************************************************************************
   27282             : This  function  builds  periodic  2-dimensional  parametric  spline  which
   27283             : starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then
   27284             : back to (X[0],Y[0]).
   27285             : 
   27286             : INPUT PARAMETERS:
   27287             :     XY  -   points, array[0..N-1,0..1].
   27288             :             XY[I,0:1] corresponds to the Ith point.
   27289             :             XY[N-1,0:1] must be different from XY[0,0:1].
   27290             :             Order of points is important!
   27291             :     N   -   points count, N>=3 for other types of splines.
   27292             :     ST  -   spline type:
   27293             :             * 1     Catmull-Rom spline (Tension=0) with cyclic boundary conditions
   27294             :             * 2     cubic spline with cyclic boundary conditions
   27295             :     PT  -   parameterization type:
   27296             :             * 0     uniform
   27297             :             * 1     chord length
   27298             :             * 2     centripetal
   27299             : 
   27300             : OUTPUT PARAMETERS:
   27301             :     P   -   parametric spline interpolant
   27302             : 
   27303             : 
   27304             : NOTES:
   27305             : * this function  assumes  that there all consequent points  are  distinct.
   27306             :   I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2),  (x2,y2)<>(x3,y3)  and  so  on.
   27307             :   However, non-consequent points may coincide, i.e. we can  have  (x0,y0)=
   27308             :   =(x2,y2).
   27309             : * last point of sequence is NOT equal to the first  point.  You  shouldn't
   27310             :   make curve "explicitly periodic" by making them equal.
   27311             : 
   27312             :   -- ALGLIB PROJECT --
   27313             :      Copyright 28.05.2010 by Bochkanov Sergey
   27314             : *************************************************************************/
   27315           0 : void pspline2buildperiodic(/* Real    */ ae_matrix* xy,
   27316             :      ae_int_t n,
   27317             :      ae_int_t st,
   27318             :      ae_int_t pt,
   27319             :      pspline2interpolant* p,
   27320             :      ae_state *_state)
   27321             : {
   27322             :     ae_frame _frame_block;
   27323             :     ae_matrix _xy;
   27324             :     ae_matrix xyp;
   27325             :     ae_vector tmp;
   27326             : 
   27327           0 :     ae_frame_make(_state, &_frame_block);
   27328           0 :     memset(&_xy, 0, sizeof(_xy));
   27329           0 :     memset(&xyp, 0, sizeof(xyp));
   27330           0 :     memset(&tmp, 0, sizeof(tmp));
   27331           0 :     ae_matrix_init_copy(&_xy, xy, _state, ae_true);
   27332           0 :     xy = &_xy;
   27333           0 :     _pspline2interpolant_clear(p);
   27334           0 :     ae_matrix_init(&xyp, 0, 0, DT_REAL, _state, ae_true);
   27335           0 :     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
   27336             : 
   27337           0 :     ae_assert(st>=1&&st<=2, "PSpline2BuildPeriodic: incorrect spline type!", _state);
   27338           0 :     ae_assert(pt>=0&&pt<=2, "PSpline2BuildPeriodic: incorrect parameterization type!", _state);
   27339           0 :     ae_assert(n>=3, "PSpline2BuildPeriodic: N<3!", _state);
   27340             :     
   27341             :     /*
   27342             :      * Prepare
   27343             :      */
   27344           0 :     p->n = n;
   27345           0 :     p->periodic = ae_true;
   27346           0 :     ae_vector_set_length(&tmp, n+1, _state);
   27347           0 :     ae_matrix_set_length(&xyp, n+1, 2, _state);
   27348           0 :     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));
   27349           0 :     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));
   27350           0 :     ae_v_move(&xyp.ptr.pp_double[n][0], 1, &xy->ptr.pp_double[0][0], 1, ae_v_len(0,1));
   27351             :     
   27352             :     /*
   27353             :      * Build parameterization, check that all parameters are distinct
   27354             :      */
   27355           0 :     parametric_pspline2par(&xyp, n+1, pt, &p->p, _state);
   27356           0 :     ae_assert(aredistinct(&p->p, n+1, _state), "PSpline2BuildPeriodic: consequent (or first and last) points are too close!", _state);
   27357             :     
   27358             :     /*
   27359             :      * Build splines
   27360             :      */
   27361           0 :     if( st==1 )
   27362             :     {
   27363           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n));
   27364           0 :         spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->x, _state);
   27365           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n));
   27366           0 :         spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->y, _state);
   27367             :     }
   27368           0 :     if( st==2 )
   27369             :     {
   27370           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n));
   27371           0 :         spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->x, _state);
   27372           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n));
   27373           0 :         spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->y, _state);
   27374             :     }
   27375           0 :     ae_frame_leave(_state);
   27376           0 : }
   27377             : 
   27378             : 
   27379             : /*************************************************************************
   27380             : This  function  builds  periodic  3-dimensional  parametric  spline  which
   27381             : starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1])
   27382             : and then back to (X[0],Y[0],Z[0]).
   27383             : 
   27384             : Same as PSpline2Build() function, but for 3D, so we  won't  duplicate  its
   27385             : description here.
   27386             : 
   27387             :   -- ALGLIB PROJECT --
   27388             :      Copyright 28.05.2010 by Bochkanov Sergey
   27389             : *************************************************************************/
   27390           0 : void pspline3buildperiodic(/* Real    */ ae_matrix* xy,
   27391             :      ae_int_t n,
   27392             :      ae_int_t st,
   27393             :      ae_int_t pt,
   27394             :      pspline3interpolant* p,
   27395             :      ae_state *_state)
   27396             : {
   27397             :     ae_frame _frame_block;
   27398             :     ae_matrix _xy;
   27399             :     ae_matrix xyp;
   27400             :     ae_vector tmp;
   27401             : 
   27402           0 :     ae_frame_make(_state, &_frame_block);
   27403           0 :     memset(&_xy, 0, sizeof(_xy));
   27404           0 :     memset(&xyp, 0, sizeof(xyp));
   27405           0 :     memset(&tmp, 0, sizeof(tmp));
   27406           0 :     ae_matrix_init_copy(&_xy, xy, _state, ae_true);
   27407           0 :     xy = &_xy;
   27408           0 :     _pspline3interpolant_clear(p);
   27409           0 :     ae_matrix_init(&xyp, 0, 0, DT_REAL, _state, ae_true);
   27410           0 :     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
   27411             : 
   27412           0 :     ae_assert(st>=1&&st<=2, "PSpline3BuildPeriodic: incorrect spline type!", _state);
   27413           0 :     ae_assert(pt>=0&&pt<=2, "PSpline3BuildPeriodic: incorrect parameterization type!", _state);
   27414           0 :     ae_assert(n>=3, "PSpline3BuildPeriodic: N<3!", _state);
   27415             :     
   27416             :     /*
   27417             :      * Prepare
   27418             :      */
   27419           0 :     p->n = n;
   27420           0 :     p->periodic = ae_true;
   27421           0 :     ae_vector_set_length(&tmp, n+1, _state);
   27422           0 :     ae_matrix_set_length(&xyp, n+1, 3, _state);
   27423           0 :     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));
   27424           0 :     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));
   27425           0 :     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));
   27426           0 :     ae_v_move(&xyp.ptr.pp_double[n][0], 1, &xy->ptr.pp_double[0][0], 1, ae_v_len(0,2));
   27427             :     
   27428             :     /*
   27429             :      * Build parameterization, check that all parameters are distinct
   27430             :      */
   27431           0 :     parametric_pspline3par(&xyp, n+1, pt, &p->p, _state);
   27432           0 :     ae_assert(aredistinct(&p->p, n+1, _state), "PSplineBuild2Periodic: consequent (or first and last) points are too close!", _state);
   27433             :     
   27434             :     /*
   27435             :      * Build splines
   27436             :      */
   27437           0 :     if( st==1 )
   27438             :     {
   27439           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n));
   27440           0 :         spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->x, _state);
   27441           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n));
   27442           0 :         spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->y, _state);
   27443           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][2], xyp.stride, ae_v_len(0,n));
   27444           0 :         spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->z, _state);
   27445             :     }
   27446           0 :     if( st==2 )
   27447             :     {
   27448           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n));
   27449           0 :         spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->x, _state);
   27450           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n));
   27451           0 :         spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->y, _state);
   27452           0 :         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][2], xyp.stride, ae_v_len(0,n));
   27453           0 :         spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->z, _state);
   27454             :     }
   27455           0 :     ae_frame_leave(_state);
   27456           0 : }
   27457             : 
   27458             : 
   27459             : /*************************************************************************
   27460             : This function returns vector of parameter values correspoding to points.
   27461             : 
   27462             : I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P)  we
   27463             : have
   27464             :     (X[0],Y[0]) = PSpline2Calc(P,U[0]),
   27465             :     (X[1],Y[1]) = PSpline2Calc(P,U[1]),
   27466             :     (X[2],Y[2]) = PSpline2Calc(P,U[2]),
   27467             :     ...
   27468             : 
   27469             : INPUT PARAMETERS:
   27470             :     P   -   parametric spline interpolant
   27471             : 
   27472             : OUTPUT PARAMETERS:
   27473             :     N   -   array size
   27474             :     T   -   array[0..N-1]
   27475             : 
   27476             : 
   27477             : NOTES:
   27478             : * for non-periodic splines U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]=1
   27479             : * for periodic splines     U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]<1
   27480             : 
   27481             :   -- ALGLIB PROJECT --
   27482             :      Copyright 28.05.2010 by Bochkanov Sergey
   27483             : *************************************************************************/
   27484           0 : void pspline2parametervalues(pspline2interpolant* p,
   27485             :      ae_int_t* n,
   27486             :      /* Real    */ ae_vector* t,
   27487             :      ae_state *_state)
   27488             : {
   27489             : 
   27490           0 :     *n = 0;
   27491           0 :     ae_vector_clear(t);
   27492             : 
   27493           0 :     ae_assert(p->n>=2, "PSpline2ParameterValues: internal error!", _state);
   27494           0 :     *n = p->n;
   27495           0 :     ae_vector_set_length(t, *n, _state);
   27496           0 :     ae_v_move(&t->ptr.p_double[0], 1, &p->p.ptr.p_double[0], 1, ae_v_len(0,*n-1));
   27497           0 :     t->ptr.p_double[0] = (double)(0);
   27498           0 :     if( !p->periodic )
   27499             :     {
   27500           0 :         t->ptr.p_double[*n-1] = (double)(1);
   27501             :     }
   27502           0 : }
   27503             : 
   27504             : 
   27505             : /*************************************************************************
   27506             : This function returns vector of parameter values correspoding to points.
   27507             : 
   27508             : Same as PSpline2ParameterValues(), but for 3D.
   27509             : 
   27510             :   -- ALGLIB PROJECT --
   27511             :      Copyright 28.05.2010 by Bochkanov Sergey
   27512             : *************************************************************************/
   27513           0 : void pspline3parametervalues(pspline3interpolant* p,
   27514             :      ae_int_t* n,
   27515             :      /* Real    */ ae_vector* t,
   27516             :      ae_state *_state)
   27517             : {
   27518             : 
   27519           0 :     *n = 0;
   27520           0 :     ae_vector_clear(t);
   27521             : 
   27522           0 :     ae_assert(p->n>=2, "PSpline3ParameterValues: internal error!", _state);
   27523           0 :     *n = p->n;
   27524           0 :     ae_vector_set_length(t, *n, _state);
   27525           0 :     ae_v_move(&t->ptr.p_double[0], 1, &p->p.ptr.p_double[0], 1, ae_v_len(0,*n-1));
   27526           0 :     t->ptr.p_double[0] = (double)(0);
   27527           0 :     if( !p->periodic )
   27528             :     {
   27529           0 :         t->ptr.p_double[*n-1] = (double)(1);
   27530             :     }
   27531           0 : }
   27532             : 
   27533             : 
   27534             : /*************************************************************************
   27535             : This function  calculates  the value of the parametric spline for a  given
   27536             : value of parameter T
   27537             : 
   27538             : INPUT PARAMETERS:
   27539             :     P   -   parametric spline interpolant
   27540             :     T   -   point:
   27541             :             * T in [0,1] corresponds to interval spanned by points
   27542             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
   27543             :               the curve before the first (after the last) point
   27544             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
   27545             :               by making T=T-floor(T).
   27546             : 
   27547             : OUTPUT PARAMETERS:
   27548             :     X   -   X-position
   27549             :     Y   -   Y-position
   27550             : 
   27551             : 
   27552             :   -- ALGLIB PROJECT --
   27553             :      Copyright 28.05.2010 by Bochkanov Sergey
   27554             : *************************************************************************/
   27555           0 : void pspline2calc(pspline2interpolant* p,
   27556             :      double t,
   27557             :      double* x,
   27558             :      double* y,
   27559             :      ae_state *_state)
   27560             : {
   27561             : 
   27562           0 :     *x = 0;
   27563           0 :     *y = 0;
   27564             : 
   27565           0 :     if( p->periodic )
   27566             :     {
   27567           0 :         t = t-ae_ifloor(t, _state);
   27568             :     }
   27569           0 :     *x = spline1dcalc(&p->x, t, _state);
   27570           0 :     *y = spline1dcalc(&p->y, t, _state);
   27571           0 : }
   27572             : 
   27573             : 
   27574             : /*************************************************************************
   27575             : This function  calculates  the value of the parametric spline for a  given
   27576             : value of parameter T.
   27577             : 
   27578             : INPUT PARAMETERS:
   27579             :     P   -   parametric spline interpolant
   27580             :     T   -   point:
   27581             :             * T in [0,1] corresponds to interval spanned by points
   27582             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
   27583             :               the curve before the first (after the last) point
   27584             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
   27585             :               by making T=T-floor(T).
   27586             : 
   27587             : OUTPUT PARAMETERS:
   27588             :     X   -   X-position
   27589             :     Y   -   Y-position
   27590             :     Z   -   Z-position
   27591             : 
   27592             : 
   27593             :   -- ALGLIB PROJECT --
   27594             :      Copyright 28.05.2010 by Bochkanov Sergey
   27595             : *************************************************************************/
   27596           0 : void pspline3calc(pspline3interpolant* p,
   27597             :      double t,
   27598             :      double* x,
   27599             :      double* y,
   27600             :      double* z,
   27601             :      ae_state *_state)
   27602             : {
   27603             : 
   27604           0 :     *x = 0;
   27605           0 :     *y = 0;
   27606           0 :     *z = 0;
   27607             : 
   27608           0 :     if( p->periodic )
   27609             :     {
   27610           0 :         t = t-ae_ifloor(t, _state);
   27611             :     }
   27612           0 :     *x = spline1dcalc(&p->x, t, _state);
   27613           0 :     *y = spline1dcalc(&p->y, t, _state);
   27614           0 :     *z = spline1dcalc(&p->z, t, _state);
   27615           0 : }
   27616             : 
   27617             : 
   27618             : /*************************************************************************
   27619             : This function  calculates  tangent vector for a given value of parameter T
   27620             : 
   27621             : INPUT PARAMETERS:
   27622             :     P   -   parametric spline interpolant
   27623             :     T   -   point:
   27624             :             * T in [0,1] corresponds to interval spanned by points
   27625             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
   27626             :               the curve before the first (after the last) point
   27627             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
   27628             :               by making T=T-floor(T).
   27629             : 
   27630             : OUTPUT PARAMETERS:
   27631             :     X    -   X-component of tangent vector (normalized)
   27632             :     Y    -   Y-component of tangent vector (normalized)
   27633             :     
   27634             : NOTE:
   27635             :     X^2+Y^2 is either 1 (for non-zero tangent vector) or 0.
   27636             : 
   27637             : 
   27638             :   -- ALGLIB PROJECT --
   27639             :      Copyright 28.05.2010 by Bochkanov Sergey
   27640             : *************************************************************************/
   27641           0 : void pspline2tangent(pspline2interpolant* p,
   27642             :      double t,
   27643             :      double* x,
   27644             :      double* y,
   27645             :      ae_state *_state)
   27646             : {
   27647             :     double v;
   27648             :     double v0;
   27649             :     double v1;
   27650             : 
   27651           0 :     *x = 0;
   27652           0 :     *y = 0;
   27653             : 
   27654           0 :     if( p->periodic )
   27655             :     {
   27656           0 :         t = t-ae_ifloor(t, _state);
   27657             :     }
   27658           0 :     pspline2diff(p, t, &v0, x, &v1, y, _state);
   27659           0 :     if( ae_fp_neq(*x,(double)(0))||ae_fp_neq(*y,(double)(0)) )
   27660             :     {
   27661             :         
   27662             :         /*
   27663             :          * this code is a bit more complex than X^2+Y^2 to avoid
   27664             :          * overflow for large values of X and Y.
   27665             :          */
   27666           0 :         v = safepythag2(*x, *y, _state);
   27667           0 :         *x = *x/v;
   27668           0 :         *y = *y/v;
   27669             :     }
   27670           0 : }
   27671             : 
   27672             : 
   27673             : /*************************************************************************
   27674             : This function  calculates  tangent vector for a given value of parameter T
   27675             : 
   27676             : INPUT PARAMETERS:
   27677             :     P   -   parametric spline interpolant
   27678             :     T   -   point:
   27679             :             * T in [0,1] corresponds to interval spanned by points
   27680             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
   27681             :               the curve before the first (after the last) point
   27682             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
   27683             :               by making T=T-floor(T).
   27684             : 
   27685             : OUTPUT PARAMETERS:
   27686             :     X    -   X-component of tangent vector (normalized)
   27687             :     Y    -   Y-component of tangent vector (normalized)
   27688             :     Z    -   Z-component of tangent vector (normalized)
   27689             : 
   27690             : NOTE:
   27691             :     X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0.
   27692             : 
   27693             : 
   27694             :   -- ALGLIB PROJECT --
   27695             :      Copyright 28.05.2010 by Bochkanov Sergey
   27696             : *************************************************************************/
   27697           0 : void pspline3tangent(pspline3interpolant* p,
   27698             :      double t,
   27699             :      double* x,
   27700             :      double* y,
   27701             :      double* z,
   27702             :      ae_state *_state)
   27703             : {
   27704             :     double v;
   27705             :     double v0;
   27706             :     double v1;
   27707             :     double v2;
   27708             : 
   27709           0 :     *x = 0;
   27710           0 :     *y = 0;
   27711           0 :     *z = 0;
   27712             : 
   27713           0 :     if( p->periodic )
   27714             :     {
   27715           0 :         t = t-ae_ifloor(t, _state);
   27716             :     }
   27717           0 :     pspline3diff(p, t, &v0, x, &v1, y, &v2, z, _state);
   27718           0 :     if( (ae_fp_neq(*x,(double)(0))||ae_fp_neq(*y,(double)(0)))||ae_fp_neq(*z,(double)(0)) )
   27719             :     {
   27720           0 :         v = safepythag3(*x, *y, *z, _state);
   27721           0 :         *x = *x/v;
   27722           0 :         *y = *y/v;
   27723           0 :         *z = *z/v;
   27724             :     }
   27725           0 : }
   27726             : 
   27727             : 
   27728             : /*************************************************************************
   27729             : This function calculates derivative, i.e. it returns (dX/dT,dY/dT).
   27730             : 
   27731             : INPUT PARAMETERS:
   27732             :     P   -   parametric spline interpolant
   27733             :     T   -   point:
   27734             :             * T in [0,1] corresponds to interval spanned by points
   27735             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
   27736             :               the curve before the first (after the last) point
   27737             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
   27738             :               by making T=T-floor(T).
   27739             : 
   27740             : OUTPUT PARAMETERS:
   27741             :     X   -   X-value
   27742             :     DX  -   X-derivative
   27743             :     Y   -   Y-value
   27744             :     DY  -   Y-derivative
   27745             : 
   27746             : 
   27747             :   -- ALGLIB PROJECT --
   27748             :      Copyright 28.05.2010 by Bochkanov Sergey
   27749             : *************************************************************************/
   27750           0 : void pspline2diff(pspline2interpolant* p,
   27751             :      double t,
   27752             :      double* x,
   27753             :      double* dx,
   27754             :      double* y,
   27755             :      double* dy,
   27756             :      ae_state *_state)
   27757             : {
   27758             :     double d2s;
   27759             : 
   27760           0 :     *x = 0;
   27761           0 :     *dx = 0;
   27762           0 :     *y = 0;
   27763           0 :     *dy = 0;
   27764             : 
   27765           0 :     if( p->periodic )
   27766             :     {
   27767           0 :         t = t-ae_ifloor(t, _state);
   27768             :     }
   27769           0 :     spline1ddiff(&p->x, t, x, dx, &d2s, _state);
   27770           0 :     spline1ddiff(&p->y, t, y, dy, &d2s, _state);
   27771           0 : }
   27772             : 
   27773             : 
   27774             : /*************************************************************************
   27775             : This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT).
   27776             : 
   27777             : INPUT PARAMETERS:
   27778             :     P   -   parametric spline interpolant
   27779             :     T   -   point:
   27780             :             * T in [0,1] corresponds to interval spanned by points
   27781             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
   27782             :               the curve before the first (after the last) point
   27783             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
   27784             :               by making T=T-floor(T).
   27785             : 
   27786             : OUTPUT PARAMETERS:
   27787             :     X   -   X-value
   27788             :     DX  -   X-derivative
   27789             :     Y   -   Y-value
   27790             :     DY  -   Y-derivative
   27791             :     Z   -   Z-value
   27792             :     DZ  -   Z-derivative
   27793             : 
   27794             : 
   27795             :   -- ALGLIB PROJECT --
   27796             :      Copyright 28.05.2010 by Bochkanov Sergey
   27797             : *************************************************************************/
   27798           0 : void pspline3diff(pspline3interpolant* p,
   27799             :      double t,
   27800             :      double* x,
   27801             :      double* dx,
   27802             :      double* y,
   27803             :      double* dy,
   27804             :      double* z,
   27805             :      double* dz,
   27806             :      ae_state *_state)
   27807             : {
   27808             :     double d2s;
   27809             : 
   27810           0 :     *x = 0;
   27811           0 :     *dx = 0;
   27812           0 :     *y = 0;
   27813           0 :     *dy = 0;
   27814           0 :     *z = 0;
   27815           0 :     *dz = 0;
   27816             : 
   27817           0 :     if( p->periodic )
   27818             :     {
   27819           0 :         t = t-ae_ifloor(t, _state);
   27820             :     }
   27821           0 :     spline1ddiff(&p->x, t, x, dx, &d2s, _state);
   27822           0 :     spline1ddiff(&p->y, t, y, dy, &d2s, _state);
   27823           0 :     spline1ddiff(&p->z, t, z, dz, &d2s, _state);
   27824           0 : }
   27825             : 
   27826             : 
   27827             : /*************************************************************************
   27828             : This function calculates first and second derivative with respect to T.
   27829             : 
   27830             : INPUT PARAMETERS:
   27831             :     P   -   parametric spline interpolant
   27832             :     T   -   point:
   27833             :             * T in [0,1] corresponds to interval spanned by points
   27834             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
   27835             :               the curve before the first (after the last) point
   27836             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
   27837             :               by making T=T-floor(T).
   27838             : 
   27839             : OUTPUT PARAMETERS:
   27840             :     X   -   X-value
   27841             :     DX  -   derivative
   27842             :     D2X -   second derivative
   27843             :     Y   -   Y-value
   27844             :     DY  -   derivative
   27845             :     D2Y -   second derivative
   27846             : 
   27847             : 
   27848             :   -- ALGLIB PROJECT --
   27849             :      Copyright 28.05.2010 by Bochkanov Sergey
   27850             : *************************************************************************/
   27851           0 : void pspline2diff2(pspline2interpolant* p,
   27852             :      double t,
   27853             :      double* x,
   27854             :      double* dx,
   27855             :      double* d2x,
   27856             :      double* y,
   27857             :      double* dy,
   27858             :      double* d2y,
   27859             :      ae_state *_state)
   27860             : {
   27861             : 
   27862           0 :     *x = 0;
   27863           0 :     *dx = 0;
   27864           0 :     *d2x = 0;
   27865           0 :     *y = 0;
   27866           0 :     *dy = 0;
   27867           0 :     *d2y = 0;
   27868             : 
   27869           0 :     if( p->periodic )
   27870             :     {
   27871           0 :         t = t-ae_ifloor(t, _state);
   27872             :     }
   27873           0 :     spline1ddiff(&p->x, t, x, dx, d2x, _state);
   27874           0 :     spline1ddiff(&p->y, t, y, dy, d2y, _state);
   27875           0 : }
   27876             : 
   27877             : 
   27878             : /*************************************************************************
   27879             : This function calculates first and second derivative with respect to T.
   27880             : 
   27881             : INPUT PARAMETERS:
   27882             :     P   -   parametric spline interpolant
   27883             :     T   -   point:
   27884             :             * T in [0,1] corresponds to interval spanned by points
   27885             :             * for non-periodic splines T<0 (or T>1) correspond to parts of
   27886             :               the curve before the first (after the last) point
   27887             :             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
   27888             :               by making T=T-floor(T).
   27889             : 
   27890             : OUTPUT PARAMETERS:
   27891             :     X   -   X-value
   27892             :     DX  -   derivative
   27893             :     D2X -   second derivative
   27894             :     Y   -   Y-value
   27895             :     DY  -   derivative
   27896             :     D2Y -   second derivative
   27897             :     Z   -   Z-value
   27898             :     DZ  -   derivative
   27899             :     D2Z -   second derivative
   27900             : 
   27901             : 
   27902             :   -- ALGLIB PROJECT --
   27903             :      Copyright 28.05.2010 by Bochkanov Sergey
   27904             : *************************************************************************/
   27905           0 : void pspline3diff2(pspline3interpolant* p,
   27906             :      double t,
   27907             :      double* x,
   27908             :      double* dx,
   27909             :      double* d2x,
   27910             :      double* y,
   27911             :      double* dy,
   27912             :      double* d2y,
   27913             :      double* z,
   27914             :      double* dz,
   27915             :      double* d2z,
   27916             :      ae_state *_state)
   27917             : {
   27918             : 
   27919           0 :     *x = 0;
   27920           0 :     *dx = 0;
   27921           0 :     *d2x = 0;
   27922           0 :     *y = 0;
   27923           0 :     *dy = 0;
   27924           0 :     *d2y = 0;
   27925           0 :     *z = 0;
   27926           0 :     *dz = 0;
   27927           0 :     *d2z = 0;
   27928             : 
   27929           0 :     if( p->periodic )
   27930             :     {
   27931           0 :         t = t-ae_ifloor(t, _state);
   27932             :     }
   27933           0 :     spline1ddiff(&p->x, t, x, dx, d2x, _state);
   27934           0 :     spline1ddiff(&p->y, t, y, dy, d2y, _state);
   27935           0 :     spline1ddiff(&p->z, t, z, dz, d2z, _state);
   27936           0 : }
   27937             : 
   27938             : 
   27939             : /*************************************************************************
   27940             : This function  calculates  arc length, i.e. length of  curve  between  t=a
   27941             : and t=b.
   27942             : 
   27943             : INPUT PARAMETERS:
   27944             :     P   -   parametric spline interpolant
   27945             :     A,B -   parameter values corresponding to arc ends:
   27946             :             * B>A will result in positive length returned
   27947             :             * B<A will result in negative length returned
   27948             : 
   27949             : RESULT:
   27950             :     length of arc starting at T=A and ending at T=B.
   27951             : 
   27952             : 
   27953             :   -- ALGLIB PROJECT --
   27954             :      Copyright 30.05.2010 by Bochkanov Sergey
   27955             : *************************************************************************/
   27956           0 : double pspline2arclength(pspline2interpolant* p,
   27957             :      double a,
   27958             :      double b,
   27959             :      ae_state *_state)
   27960             : {
   27961             :     ae_frame _frame_block;
   27962             :     autogkstate state;
   27963             :     autogkreport rep;
   27964             :     double sx;
   27965             :     double dsx;
   27966             :     double d2sx;
   27967             :     double sy;
   27968             :     double dsy;
   27969             :     double d2sy;
   27970             :     double result;
   27971             : 
   27972           0 :     ae_frame_make(_state, &_frame_block);
   27973           0 :     memset(&state, 0, sizeof(state));
   27974           0 :     memset(&rep, 0, sizeof(rep));
   27975           0 :     _autogkstate_init(&state, _state, ae_true);
   27976           0 :     _autogkreport_init(&rep, _state, ae_true);
   27977             : 
   27978           0 :     autogksmooth(a, b, &state, _state);
   27979           0 :     while(autogkiteration(&state, _state))
   27980             :     {
   27981           0 :         spline1ddiff(&p->x, state.x, &sx, &dsx, &d2sx, _state);
   27982           0 :         spline1ddiff(&p->y, state.x, &sy, &dsy, &d2sy, _state);
   27983           0 :         state.f = safepythag2(dsx, dsy, _state);
   27984             :     }
   27985           0 :     autogkresults(&state, &result, &rep, _state);
   27986           0 :     ae_assert(rep.terminationtype>0, "PSpline2ArcLength: internal error!", _state);
   27987           0 :     ae_frame_leave(_state);
   27988           0 :     return result;
   27989             : }
   27990             : 
   27991             : 
   27992             : /*************************************************************************
   27993             : This function  calculates  arc length, i.e. length of  curve  between  t=a
   27994             : and t=b.
   27995             : 
   27996             : INPUT PARAMETERS:
   27997             :     P   -   parametric spline interpolant
   27998             :     A,B -   parameter values corresponding to arc ends:
   27999             :             * B>A will result in positive length returned
   28000             :             * B<A will result in negative length returned
   28001             : 
   28002             : RESULT:
   28003             :     length of arc starting at T=A and ending at T=B.
   28004             : 
   28005             : 
   28006             :   -- ALGLIB PROJECT --
   28007             :      Copyright 30.05.2010 by Bochkanov Sergey
   28008             : *************************************************************************/
   28009           0 : double pspline3arclength(pspline3interpolant* p,
   28010             :      double a,
   28011             :      double b,
   28012             :      ae_state *_state)
   28013             : {
   28014             :     ae_frame _frame_block;
   28015             :     autogkstate state;
   28016             :     autogkreport rep;
   28017             :     double sx;
   28018             :     double dsx;
   28019             :     double d2sx;
   28020             :     double sy;
   28021             :     double dsy;
   28022             :     double d2sy;
   28023             :     double sz;
   28024             :     double dsz;
   28025             :     double d2sz;
   28026             :     double result;
   28027             : 
   28028           0 :     ae_frame_make(_state, &_frame_block);
   28029           0 :     memset(&state, 0, sizeof(state));
   28030           0 :     memset(&rep, 0, sizeof(rep));
   28031           0 :     _autogkstate_init(&state, _state, ae_true);
   28032           0 :     _autogkreport_init(&rep, _state, ae_true);
   28033             : 
   28034           0 :     autogksmooth(a, b, &state, _state);
   28035           0 :     while(autogkiteration(&state, _state))
   28036             :     {
   28037           0 :         spline1ddiff(&p->x, state.x, &sx, &dsx, &d2sx, _state);
   28038           0 :         spline1ddiff(&p->y, state.x, &sy, &dsy, &d2sy, _state);
   28039           0 :         spline1ddiff(&p->z, state.x, &sz, &dsz, &d2sz, _state);
   28040           0 :         state.f = safepythag3(dsx, dsy, dsz, _state);
   28041             :     }
   28042           0 :     autogkresults(&state, &result, &rep, _state);
   28043           0 :     ae_assert(rep.terminationtype>0, "PSpline3ArcLength: internal error!", _state);
   28044           0 :     ae_frame_leave(_state);
   28045           0 :     return result;
   28046             : }
   28047             : 
   28048             : 
   28049             : /*************************************************************************
   28050             : This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
   28051             : Peucker algorithm. This  function  performs PARAMETRIC fit, i.e. it can be
   28052             : used to fit curves like circles.
   28053             : 
   28054             : On  input  it  accepts dataset which describes parametric multidimensional
   28055             : curve X(t), with X being vector, and t taking values in [0,N), where N  is
   28056             : a number of points in dataset. As result, it returns reduced  dataset  X2,
   28057             : which can be used to build  parametric  curve  X2(t),  which  approximates
   28058             : X(t) with desired precision (or has specified number of sections).
   28059             : 
   28060             : 
   28061             : INPUT PARAMETERS:
   28062             :     X       -   array of multidimensional points:
   28063             :                 * at least N elements, leading N elements are used if more
   28064             :                   than N elements were specified
   28065             :                 * order of points is IMPORTANT because  it  is  parametric
   28066             :                   fit
   28067             :                 * each row of array is one point which has D coordinates
   28068             :     N       -   number of elements in X
   28069             :     D       -   number of dimensions (elements per row of X)
   28070             :     StopM   -   stopping condition - desired number of sections:
   28071             :                 * at most M sections are generated by this function
   28072             :                 * less than M sections can be generated if we have N<M
   28073             :                   (or some X are non-distinct).
   28074             :                 * zero StopM means that algorithm does not stop after
   28075             :                   achieving some pre-specified section count
   28076             :     StopEps -   stopping condition - desired precision:
   28077             :                 * algorithm stops after error in each section is at most Eps
   28078             :                 * zero Eps means that algorithm does not stop after
   28079             :                   achieving some pre-specified precision
   28080             : 
   28081             : OUTPUT PARAMETERS:
   28082             :     X2      -   array of corner points for piecewise approximation,
   28083             :                 has length NSections+1 or zero (for NSections=0).
   28084             :     Idx2    -   array of indexes (parameter values):
   28085             :                 * has length NSections+1 or zero (for NSections=0).
   28086             :                 * each element of Idx2 corresponds to same-numbered
   28087             :                   element of X2
   28088             :                 * each element of Idx2 is index of  corresponding  element
   28089             :                   of X2 at original array X, i.e. I-th  row  of  X2  is
   28090             :                   Idx2[I]-th row of X.
   28091             :                 * elements of Idx2 can be treated as parameter values
   28092             :                   which should be used when building new parametric curve
   28093             :                 * Idx2[0]=0, Idx2[NSections]=N-1
   28094             :     NSections-  number of sections found by algorithm, NSections<=M,
   28095             :                 NSections can be zero for degenerate datasets
   28096             :                 (N<=1 or all X[] are non-distinct).
   28097             : 
   28098             : NOTE: algorithm stops after:
   28099             :       a) dividing curve into StopM sections 
   28100             :       b) achieving required precision StopEps
   28101             :       c) dividing curve into N-1 sections
   28102             :       If both StopM and StopEps are non-zero, algorithm is stopped by  the
   28103             :       FIRST criterion which is satisfied. In case both StopM  and  StopEps
   28104             :       are zero, algorithm stops because of (c).
   28105             :                 
   28106             :   -- ALGLIB --
   28107             :      Copyright 02.10.2014 by Bochkanov Sergey
   28108             : *************************************************************************/
   28109           0 : void parametricrdpfixed(/* Real    */ ae_matrix* x,
   28110             :      ae_int_t n,
   28111             :      ae_int_t d,
   28112             :      ae_int_t stopm,
   28113             :      double stopeps,
   28114             :      /* Real    */ ae_matrix* x2,
   28115             :      /* Integer */ ae_vector* idx2,
   28116             :      ae_int_t* nsections,
   28117             :      ae_state *_state)
   28118             : {
   28119             :     ae_frame _frame_block;
   28120             :     ae_int_t i;
   28121             :     ae_int_t j;
   28122             :     ae_int_t k;
   28123             :     ae_bool allsame;
   28124             :     ae_int_t k0;
   28125             :     ae_int_t k1;
   28126             :     ae_int_t k2;
   28127             :     double e0;
   28128             :     double e1;
   28129             :     ae_int_t idx0;
   28130             :     ae_int_t idx1;
   28131             :     ae_int_t worstidx;
   28132             :     double worsterror;
   28133             :     ae_matrix sections;
   28134             :     ae_vector heaperrors;
   28135             :     ae_vector heaptags;
   28136             :     ae_vector buf0;
   28137             :     ae_vector buf1;
   28138             : 
   28139           0 :     ae_frame_make(_state, &_frame_block);
   28140           0 :     memset(&sections, 0, sizeof(sections));
   28141           0 :     memset(&heaperrors, 0, sizeof(heaperrors));
   28142           0 :     memset(&heaptags, 0, sizeof(heaptags));
   28143           0 :     memset(&buf0, 0, sizeof(buf0));
   28144           0 :     memset(&buf1, 0, sizeof(buf1));
   28145           0 :     ae_matrix_clear(x2);
   28146           0 :     ae_vector_clear(idx2);
   28147           0 :     *nsections = 0;
   28148           0 :     ae_matrix_init(&sections, 0, 0, DT_REAL, _state, ae_true);
   28149           0 :     ae_vector_init(&heaperrors, 0, DT_REAL, _state, ae_true);
   28150           0 :     ae_vector_init(&heaptags, 0, DT_INT, _state, ae_true);
   28151           0 :     ae_vector_init(&buf0, 0, DT_REAL, _state, ae_true);
   28152           0 :     ae_vector_init(&buf1, 0, DT_REAL, _state, ae_true);
   28153             : 
   28154           0 :     ae_assert(n>=0, "LSTFitPiecewiseLinearParametricRDP: N<0", _state);
   28155           0 :     ae_assert(d>=1, "LSTFitPiecewiseLinearParametricRDP: D<=0", _state);
   28156           0 :     ae_assert(stopm>=0, "LSTFitPiecewiseLinearParametricRDP: StopM<1", _state);
   28157           0 :     ae_assert(ae_isfinite(stopeps, _state)&&ae_fp_greater_eq(stopeps,(double)(0)), "LSTFitPiecewiseLinearParametricRDP: StopEps<0 or is infinite", _state);
   28158           0 :     ae_assert(x->rows>=n, "LSTFitPiecewiseLinearParametricRDP: Rows(X)<N", _state);
   28159           0 :     ae_assert(x->cols>=d, "LSTFitPiecewiseLinearParametricRDP: Cols(X)<D", _state);
   28160           0 :     ae_assert(apservisfinitematrix(x, n, d, _state), "LSTFitPiecewiseLinearParametricRDP: X contains infinite/NAN values", _state);
   28161             :     
   28162             :     /*
   28163             :      * Handle degenerate cases
   28164             :      */
   28165           0 :     if( n<=1 )
   28166             :     {
   28167           0 :         *nsections = 0;
   28168           0 :         ae_frame_leave(_state);
   28169           0 :         return;
   28170             :     }
   28171           0 :     allsame = ae_true;
   28172           0 :     for(i=1; i<=n-1; i++)
   28173             :     {
   28174           0 :         for(j=0; j<=d-1; j++)
   28175             :         {
   28176           0 :             allsame = allsame&&ae_fp_eq(x->ptr.pp_double[i][j],x->ptr.pp_double[0][j]);
   28177             :         }
   28178             :     }
   28179           0 :     if( allsame )
   28180             :     {
   28181           0 :         *nsections = 0;
   28182           0 :         ae_frame_leave(_state);
   28183           0 :         return;
   28184             :     }
   28185             :     
   28186             :     /*
   28187             :      * Prepare first section
   28188             :      */
   28189           0 :     parametric_rdpanalyzesectionpar(x, 0, n-1, d, &worstidx, &worsterror, _state);
   28190           0 :     ae_matrix_set_length(&sections, n, 4, _state);
   28191           0 :     ae_vector_set_length(&heaperrors, n, _state);
   28192           0 :     ae_vector_set_length(&heaptags, n, _state);
   28193           0 :     *nsections = 1;
   28194           0 :     sections.ptr.pp_double[0][0] = (double)(0);
   28195           0 :     sections.ptr.pp_double[0][1] = (double)(n-1);
   28196           0 :     sections.ptr.pp_double[0][2] = (double)(worstidx);
   28197           0 :     sections.ptr.pp_double[0][3] = worsterror;
   28198           0 :     heaperrors.ptr.p_double[0] = worsterror;
   28199           0 :     heaptags.ptr.p_int[0] = 0;
   28200           0 :     ae_assert(ae_fp_eq(sections.ptr.pp_double[0][1],(double)(n-1)), "RDP algorithm: integrity check failed", _state);
   28201             :     
   28202             :     /*
   28203             :      * Main loop.
   28204             :      * Repeatedly find section with worst error and divide it.
   28205             :      * Terminate after M-th section, or because of other reasons (see loop internals).
   28206             :      */
   28207             :     for(;;)
   28208             :     {
   28209             :         
   28210             :         /*
   28211             :          * Break loop if one of the stopping conditions was met.
   28212             :          * Store index of worst section to K.
   28213             :          */
   28214           0 :         if( ae_fp_eq(heaperrors.ptr.p_double[0],(double)(0)) )
   28215             :         {
   28216           0 :             break;
   28217             :         }
   28218           0 :         if( ae_fp_greater(stopeps,(double)(0))&&ae_fp_less_eq(heaperrors.ptr.p_double[0],stopeps) )
   28219             :         {
   28220           0 :             break;
   28221             :         }
   28222           0 :         if( stopm>0&&*nsections>=stopm )
   28223             :         {
   28224           0 :             break;
   28225             :         }
   28226           0 :         k = heaptags.ptr.p_int[0];
   28227             :         
   28228             :         /*
   28229             :          * K-th section is divided in two:
   28230             :          * * first  one spans interval from X[Sections[K,0]] to X[Sections[K,2]]
   28231             :          * * second one spans interval from X[Sections[K,2]] to X[Sections[K,1]]
   28232             :          *
   28233             :          * First section is stored at K-th position, second one is appended to the table.
   28234             :          * Then we update heap which stores pairs of (error,section_index)
   28235             :          */
   28236           0 :         k0 = ae_round(sections.ptr.pp_double[k][0], _state);
   28237           0 :         k1 = ae_round(sections.ptr.pp_double[k][1], _state);
   28238           0 :         k2 = ae_round(sections.ptr.pp_double[k][2], _state);
   28239           0 :         parametric_rdpanalyzesectionpar(x, k0, k2, d, &idx0, &e0, _state);
   28240           0 :         parametric_rdpanalyzesectionpar(x, k2, k1, d, &idx1, &e1, _state);
   28241           0 :         sections.ptr.pp_double[k][0] = (double)(k0);
   28242           0 :         sections.ptr.pp_double[k][1] = (double)(k2);
   28243           0 :         sections.ptr.pp_double[k][2] = (double)(idx0);
   28244           0 :         sections.ptr.pp_double[k][3] = e0;
   28245           0 :         tagheapreplacetopi(&heaperrors, &heaptags, *nsections, e0, k, _state);
   28246           0 :         sections.ptr.pp_double[*nsections][0] = (double)(k2);
   28247           0 :         sections.ptr.pp_double[*nsections][1] = (double)(k1);
   28248           0 :         sections.ptr.pp_double[*nsections][2] = (double)(idx1);
   28249           0 :         sections.ptr.pp_double[*nsections][3] = e1;
   28250           0 :         tagheappushi(&heaperrors, &heaptags, nsections, e1, *nsections, _state);
   28251             :     }
   28252             :     
   28253             :     /*
   28254             :      * Convert from sections to indexes
   28255             :      */
   28256           0 :     ae_vector_set_length(&buf0, *nsections+1, _state);
   28257           0 :     for(i=0; i<=*nsections-1; i++)
   28258             :     {
   28259           0 :         buf0.ptr.p_double[i] = (double)(ae_round(sections.ptr.pp_double[i][0], _state));
   28260             :     }
   28261           0 :     buf0.ptr.p_double[*nsections] = (double)(n-1);
   28262           0 :     tagsortfast(&buf0, &buf1, *nsections+1, _state);
   28263           0 :     ae_vector_set_length(idx2, *nsections+1, _state);
   28264           0 :     for(i=0; i<=*nsections; i++)
   28265             :     {
   28266           0 :         idx2->ptr.p_int[i] = ae_round(buf0.ptr.p_double[i], _state);
   28267             :     }
   28268           0 :     ae_assert(idx2->ptr.p_int[0]==0, "RDP algorithm: integrity check failed", _state);
   28269           0 :     ae_assert(idx2->ptr.p_int[*nsections]==n-1, "RDP algorithm: integrity check failed", _state);
   28270             :     
   28271             :     /*
   28272             :      * Output sections:
   28273             :      * * first NSection elements of X2/Y2 are filled by x/y at left boundaries of sections
   28274             :      * * last element of X2/Y2 is filled by right boundary of rightmost section
   28275             :      * * X2/Y2 is sorted by ascending of X2
   28276             :      */
   28277           0 :     ae_matrix_set_length(x2, *nsections+1, d, _state);
   28278           0 :     for(i=0; i<=*nsections; i++)
   28279             :     {
   28280           0 :         for(j=0; j<=d-1; j++)
   28281             :         {
   28282           0 :             x2->ptr.pp_double[i][j] = x->ptr.pp_double[idx2->ptr.p_int[i]][j];
   28283             :         }
   28284             :     }
   28285           0 :     ae_frame_leave(_state);
   28286             : }
   28287             : 
   28288             : 
   28289             : /*************************************************************************
   28290             : Builds non-periodic parameterization for 2-dimensional spline
   28291             : *************************************************************************/
   28292           0 : static void parametric_pspline2par(/* Real    */ ae_matrix* xy,
   28293             :      ae_int_t n,
   28294             :      ae_int_t pt,
   28295             :      /* Real    */ ae_vector* p,
   28296             :      ae_state *_state)
   28297             : {
   28298             :     double v;
   28299             :     ae_int_t i;
   28300             : 
   28301           0 :     ae_vector_clear(p);
   28302             : 
   28303           0 :     ae_assert(pt>=0&&pt<=2, "PSpline2Par: internal error!", _state);
   28304             :     
   28305             :     /*
   28306             :      * Build parameterization:
   28307             :      * * fill by non-normalized values
   28308             :      * * normalize them so we have P[0]=0, P[N-1]=1.
   28309             :      */
   28310           0 :     ae_vector_set_length(p, n, _state);
   28311           0 :     if( pt==0 )
   28312             :     {
   28313           0 :         for(i=0; i<=n-1; i++)
   28314             :         {
   28315           0 :             p->ptr.p_double[i] = (double)(i);
   28316             :         }
   28317             :     }
   28318           0 :     if( pt==1 )
   28319             :     {
   28320           0 :         p->ptr.p_double[0] = (double)(0);
   28321           0 :         for(i=1; i<=n-1; i++)
   28322             :         {
   28323           0 :             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);
   28324             :         }
   28325             :     }
   28326           0 :     if( pt==2 )
   28327             :     {
   28328           0 :         p->ptr.p_double[0] = (double)(0);
   28329           0 :         for(i=1; i<=n-1; i++)
   28330             :         {
   28331           0 :             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);
   28332             :         }
   28333             :     }
   28334           0 :     v = 1/p->ptr.p_double[n-1];
   28335           0 :     ae_v_muld(&p->ptr.p_double[0], 1, ae_v_len(0,n-1), v);
   28336           0 : }
   28337             : 
   28338             : 
   28339             : /*************************************************************************
   28340             : Builds non-periodic parameterization for 3-dimensional spline
   28341             : *************************************************************************/
   28342           0 : static void parametric_pspline3par(/* Real    */ ae_matrix* xy,
   28343             :      ae_int_t n,
   28344             :      ae_int_t pt,
   28345             :      /* Real    */ ae_vector* p,
   28346             :      ae_state *_state)
   28347             : {
   28348             :     double v;
   28349             :     ae_int_t i;
   28350             : 
   28351           0 :     ae_vector_clear(p);
   28352             : 
   28353           0 :     ae_assert(pt>=0&&pt<=2, "PSpline3Par: internal error!", _state);
   28354             :     
   28355             :     /*
   28356             :      * Build parameterization:
   28357             :      * * fill by non-normalized values
   28358             :      * * normalize them so we have P[0]=0, P[N-1]=1.
   28359             :      */
   28360           0 :     ae_vector_set_length(p, n, _state);
   28361           0 :     if( pt==0 )
   28362             :     {
   28363           0 :         for(i=0; i<=n-1; i++)
   28364             :         {
   28365           0 :             p->ptr.p_double[i] = (double)(i);
   28366             :         }
   28367             :     }
   28368           0 :     if( pt==1 )
   28369             :     {
   28370           0 :         p->ptr.p_double[0] = (double)(0);
   28371           0 :         for(i=1; i<=n-1; i++)
   28372             :         {
   28373           0 :             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);
   28374             :         }
   28375             :     }
   28376           0 :     if( pt==2 )
   28377             :     {
   28378           0 :         p->ptr.p_double[0] = (double)(0);
   28379           0 :         for(i=1; i<=n-1; i++)
   28380             :         {
   28381           0 :             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);
   28382             :         }
   28383             :     }
   28384           0 :     v = 1/p->ptr.p_double[n-1];
   28385           0 :     ae_v_muld(&p->ptr.p_double[0], 1, ae_v_len(0,n-1), v);
   28386           0 : }
   28387             : 
   28388             : 
   28389             : /*************************************************************************
   28390             : This function analyzes section of curve for processing by RDP algorithm:
   28391             : given set of points X,Y with indexes [I0,I1] it returns point with
   28392             : worst deviation from linear model (PARAMETRIC version which sees curve
   28393             : as X(t) with vector X).
   28394             : 
   28395             : Input parameters:
   28396             :     XY          -   array
   28397             :     I0,I1       -   interval (boundaries included) to process
   28398             :     D           -   number of dimensions
   28399             :     
   28400             : OUTPUT PARAMETERS:
   28401             :     WorstIdx    -   index of worst point
   28402             :     WorstError  -   error at worst point
   28403             :     
   28404             : NOTE: this function guarantees that it returns exactly zero for a section
   28405             :       with less than 3 points.
   28406             : 
   28407             :   -- ALGLIB PROJECT --
   28408             :      Copyright 02.10.2014 by Bochkanov Sergey
   28409             : *************************************************************************/
   28410           0 : static void parametric_rdpanalyzesectionpar(/* Real    */ ae_matrix* xy,
   28411             :      ae_int_t i0,
   28412             :      ae_int_t i1,
   28413             :      ae_int_t d,
   28414             :      ae_int_t* worstidx,
   28415             :      double* worsterror,
   28416             :      ae_state *_state)
   28417             : {
   28418             :     ae_int_t i;
   28419             :     ae_int_t j;
   28420             :     double v;
   28421             :     double d2;
   28422             :     double ts;
   28423             :     double vv;
   28424             : 
   28425           0 :     *worstidx = 0;
   28426           0 :     *worsterror = 0;
   28427             : 
   28428             :     
   28429             :     /*
   28430             :      * Quick exit for 0, 1, 2 points
   28431             :      */
   28432           0 :     if( i1-i0+1<3 )
   28433             :     {
   28434           0 :         *worstidx = i0;
   28435           0 :         *worsterror = 0.0;
   28436           0 :         return;
   28437             :     }
   28438             :     
   28439             :     /*
   28440             :      * Estimate D2 - squared distance between XY[I1] and XY[I0].
   28441             :      * In case D2=0 handle it as special case.
   28442             :      */
   28443           0 :     d2 = 0.0;
   28444           0 :     for(j=0; j<=d-1; j++)
   28445             :     {
   28446           0 :         d2 = d2+ae_sqr(xy->ptr.pp_double[i1][j]-xy->ptr.pp_double[i0][j], _state);
   28447             :     }
   28448           0 :     if( ae_fp_eq(d2,(double)(0)) )
   28449             :     {
   28450             :         
   28451             :         /*
   28452             :          * First and last points are equal, interval evaluation is
   28453             :          * trivial - we just calculate distance from all points to
   28454             :          * the first/last one.
   28455             :          */
   28456           0 :         *worstidx = i0;
   28457           0 :         *worsterror = 0.0;
   28458           0 :         for(i=i0+1; i<=i1-1; i++)
   28459             :         {
   28460           0 :             vv = 0.0;
   28461           0 :             for(j=0; j<=d-1; j++)
   28462             :             {
   28463           0 :                 v = xy->ptr.pp_double[i][j]-xy->ptr.pp_double[i0][j];
   28464           0 :                 vv = vv+v*v;
   28465             :             }
   28466           0 :             vv = ae_sqrt(vv, _state);
   28467           0 :             if( ae_fp_greater(vv,*worsterror) )
   28468             :             {
   28469           0 :                 *worsterror = vv;
   28470           0 :                 *worstidx = i;
   28471             :             }
   28472             :         }
   28473           0 :         return;
   28474             :     }
   28475             :     
   28476             :     /*
   28477             :      * General case
   28478             :      *
   28479             :      * Current section of curve is modeled as x(t) = d*t+c, where
   28480             :      *     d = XY[I1]-XY[I0]
   28481             :      *     c = XY[I0]
   28482             :      *     t is in [0,1]
   28483             :      */
   28484           0 :     *worstidx = i0;
   28485           0 :     *worsterror = 0.0;
   28486           0 :     for(i=i0+1; i<=i1-1; i++)
   28487             :     {
   28488             :         
   28489             :         /*
   28490             :          * Determine t_s - parameter value for projected point.
   28491             :          */
   28492           0 :         ts = (double)(i-i0)/(double)(i1-i0);
   28493             :         
   28494             :         /*
   28495             :          * Estimate error norm
   28496             :          */
   28497           0 :         vv = 0.0;
   28498           0 :         for(j=0; j<=d-1; j++)
   28499             :         {
   28500           0 :             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]);
   28501           0 :             vv = vv+ae_sqr(v, _state);
   28502             :         }
   28503           0 :         vv = ae_sqrt(vv, _state);
   28504           0 :         if( ae_fp_greater(vv,*worsterror) )
   28505             :         {
   28506           0 :             *worsterror = vv;
   28507           0 :             *worstidx = i;
   28508             :         }
   28509             :     }
   28510             : }
   28511             : 
   28512             : 
   28513           0 : void _pspline2interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
   28514             : {
   28515           0 :     pspline2interpolant *p = (pspline2interpolant*)_p;
   28516           0 :     ae_touch_ptr((void*)p);
   28517           0 :     ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic);
   28518           0 :     _spline1dinterpolant_init(&p->x, _state, make_automatic);
   28519           0 :     _spline1dinterpolant_init(&p->y, _state, make_automatic);
   28520           0 : }
   28521             : 
   28522             : 
   28523           0 : void _pspline2interpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   28524             : {
   28525           0 :     pspline2interpolant *dst = (pspline2interpolant*)_dst;
   28526           0 :     pspline2interpolant *src = (pspline2interpolant*)_src;
   28527           0 :     dst->n = src->n;
   28528           0 :     dst->periodic = src->periodic;
   28529           0 :     ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic);
   28530           0 :     _spline1dinterpolant_init_copy(&dst->x, &src->x, _state, make_automatic);
   28531           0 :     _spline1dinterpolant_init_copy(&dst->y, &src->y, _state, make_automatic);
   28532           0 : }
   28533             : 
   28534             : 
   28535           0 : void _pspline2interpolant_clear(void* _p)
   28536             : {
   28537           0 :     pspline2interpolant *p = (pspline2interpolant*)_p;
   28538           0 :     ae_touch_ptr((void*)p);
   28539           0 :     ae_vector_clear(&p->p);
   28540           0 :     _spline1dinterpolant_clear(&p->x);
   28541           0 :     _spline1dinterpolant_clear(&p->y);
   28542           0 : }
   28543             : 
   28544             : 
   28545           0 : void _pspline2interpolant_destroy(void* _p)
   28546             : {
   28547           0 :     pspline2interpolant *p = (pspline2interpolant*)_p;
   28548           0 :     ae_touch_ptr((void*)p);
   28549           0 :     ae_vector_destroy(&p->p);
   28550           0 :     _spline1dinterpolant_destroy(&p->x);
   28551           0 :     _spline1dinterpolant_destroy(&p->y);
   28552           0 : }
   28553             : 
   28554             : 
   28555           0 : void _pspline3interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
   28556             : {
   28557           0 :     pspline3interpolant *p = (pspline3interpolant*)_p;
   28558           0 :     ae_touch_ptr((void*)p);
   28559           0 :     ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic);
   28560           0 :     _spline1dinterpolant_init(&p->x, _state, make_automatic);
   28561           0 :     _spline1dinterpolant_init(&p->y, _state, make_automatic);
   28562           0 :     _spline1dinterpolant_init(&p->z, _state, make_automatic);
   28563           0 : }
   28564             : 
   28565             : 
   28566           0 : void _pspline3interpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   28567             : {
   28568           0 :     pspline3interpolant *dst = (pspline3interpolant*)_dst;
   28569           0 :     pspline3interpolant *src = (pspline3interpolant*)_src;
   28570           0 :     dst->n = src->n;
   28571           0 :     dst->periodic = src->periodic;
   28572           0 :     ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic);
   28573           0 :     _spline1dinterpolant_init_copy(&dst->x, &src->x, _state, make_automatic);
   28574           0 :     _spline1dinterpolant_init_copy(&dst->y, &src->y, _state, make_automatic);
   28575           0 :     _spline1dinterpolant_init_copy(&dst->z, &src->z, _state, make_automatic);
   28576           0 : }
   28577             : 
   28578             : 
   28579           0 : void _pspline3interpolant_clear(void* _p)
   28580             : {
   28581           0 :     pspline3interpolant *p = (pspline3interpolant*)_p;
   28582           0 :     ae_touch_ptr((void*)p);
   28583           0 :     ae_vector_clear(&p->p);
   28584           0 :     _spline1dinterpolant_clear(&p->x);
   28585           0 :     _spline1dinterpolant_clear(&p->y);
   28586           0 :     _spline1dinterpolant_clear(&p->z);
   28587           0 : }
   28588             : 
   28589             : 
   28590           0 : void _pspline3interpolant_destroy(void* _p)
   28591             : {
   28592           0 :     pspline3interpolant *p = (pspline3interpolant*)_p;
   28593           0 :     ae_touch_ptr((void*)p);
   28594           0 :     ae_vector_destroy(&p->p);
   28595           0 :     _spline1dinterpolant_destroy(&p->x);
   28596           0 :     _spline1dinterpolant_destroy(&p->y);
   28597           0 :     _spline1dinterpolant_destroy(&p->z);
   28598           0 : }
   28599             : 
   28600             : 
   28601             : #endif
   28602             : #if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD)
   28603             : 
   28604             : 
   28605             : /*************************************************************************
   28606             : This subroutine calculates the value of the trilinear or tricubic spline at
   28607             : the given point (X,Y,Z).
   28608             : 
   28609             : INPUT PARAMETERS:
   28610             :     C   -   coefficients table.
   28611             :             Built by BuildBilinearSpline or BuildBicubicSpline.
   28612             :     X, Y,
   28613             :     Z   -   point
   28614             : 
   28615             : Result:
   28616             :     S(x,y,z)
   28617             : 
   28618             :   -- ALGLIB PROJECT --
   28619             :      Copyright 26.04.2012 by Bochkanov Sergey
   28620             : *************************************************************************/
   28621           0 : double spline3dcalc(spline3dinterpolant* c,
   28622             :      double x,
   28623             :      double y,
   28624             :      double z,
   28625             :      ae_state *_state)
   28626             : {
   28627             :     double v;
   28628             :     double vx;
   28629             :     double vy;
   28630             :     double vxy;
   28631             :     double result;
   28632             : 
   28633             : 
   28634           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalc: incorrect C (incorrect parameter C.SType)", _state);
   28635           0 :     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);
   28636           0 :     if( c->d!=1 )
   28637             :     {
   28638           0 :         result = (double)(0);
   28639           0 :         return result;
   28640             :     }
   28641           0 :     spline3d_spline3ddiff(c, x, y, z, &v, &vx, &vy, &vxy, _state);
   28642           0 :     result = v;
   28643           0 :     return result;
   28644             : }
   28645             : 
   28646             : 
   28647             : /*************************************************************************
   28648             : This subroutine performs linear transformation of the spline argument.
   28649             : 
   28650             : INPUT PARAMETERS:
   28651             :     C       -   spline interpolant
   28652             :     AX, BX  -   transformation coefficients: x = A*u + B
   28653             :     AY, BY  -   transformation coefficients: y = A*v + B
   28654             :     AZ, BZ  -   transformation coefficients: z = A*w + B
   28655             :     
   28656             : OUTPUT PARAMETERS:
   28657             :     C   -   transformed spline
   28658             : 
   28659             :   -- ALGLIB PROJECT --
   28660             :      Copyright 26.04.2012 by Bochkanov Sergey
   28661             : *************************************************************************/
   28662           0 : void spline3dlintransxyz(spline3dinterpolant* c,
   28663             :      double ax,
   28664             :      double bx,
   28665             :      double ay,
   28666             :      double by,
   28667             :      double az,
   28668             :      double bz,
   28669             :      ae_state *_state)
   28670             : {
   28671             :     ae_frame _frame_block;
   28672             :     ae_vector x;
   28673             :     ae_vector y;
   28674             :     ae_vector z;
   28675             :     ae_vector f;
   28676             :     ae_vector v;
   28677             :     ae_int_t i;
   28678             :     ae_int_t j;
   28679             :     ae_int_t k;
   28680             :     ae_int_t di;
   28681             : 
   28682           0 :     ae_frame_make(_state, &_frame_block);
   28683           0 :     memset(&x, 0, sizeof(x));
   28684           0 :     memset(&y, 0, sizeof(y));
   28685           0 :     memset(&z, 0, sizeof(z));
   28686           0 :     memset(&f, 0, sizeof(f));
   28687           0 :     memset(&v, 0, sizeof(v));
   28688           0 :     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
   28689           0 :     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
   28690           0 :     ae_vector_init(&z, 0, DT_REAL, _state, ae_true);
   28691           0 :     ae_vector_init(&f, 0, DT_REAL, _state, ae_true);
   28692           0 :     ae_vector_init(&v, 0, DT_REAL, _state, ae_true);
   28693             : 
   28694           0 :     ae_assert(c->stype==-3||c->stype==-1, "Spline3DLinTransXYZ: incorrect C (incorrect parameter C.SType)", _state);
   28695           0 :     ae_vector_set_length(&x, c->n, _state);
   28696           0 :     ae_vector_set_length(&y, c->m, _state);
   28697           0 :     ae_vector_set_length(&z, c->l, _state);
   28698           0 :     ae_vector_set_length(&f, c->m*c->n*c->l*c->d, _state);
   28699           0 :     for(j=0; j<=c->n-1; j++)
   28700             :     {
   28701           0 :         x.ptr.p_double[j] = c->x.ptr.p_double[j];
   28702             :     }
   28703           0 :     for(i=0; i<=c->m-1; i++)
   28704             :     {
   28705           0 :         y.ptr.p_double[i] = c->y.ptr.p_double[i];
   28706             :     }
   28707           0 :     for(i=0; i<=c->l-1; i++)
   28708             :     {
   28709           0 :         z.ptr.p_double[i] = c->z.ptr.p_double[i];
   28710             :     }
   28711             :     
   28712             :     /*
   28713             :      * Handle different combinations of zero/nonzero AX/AY/AZ
   28714             :      */
   28715           0 :     if( (ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) )
   28716             :     {
   28717           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));
   28718             :     }
   28719           0 :     if( (ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) )
   28720             :     {
   28721           0 :         for(i=0; i<=c->m-1; i++)
   28722             :         {
   28723           0 :             for(j=0; j<=c->l-1; j++)
   28724             :             {
   28725           0 :                 spline3dcalcv(c, bx, y.ptr.p_double[i], z.ptr.p_double[j], &v, _state);
   28726           0 :                 for(k=0; k<=c->n-1; k++)
   28727             :                 {
   28728           0 :                     for(di=0; di<=c->d-1; di++)
   28729             :                     {
   28730           0 :                         f.ptr.p_double[c->d*(c->n*(c->m*j+i)+k)+di] = v.ptr.p_double[di];
   28731             :                     }
   28732             :                 }
   28733             :             }
   28734             :         }
   28735           0 :         ax = (double)(1);
   28736           0 :         bx = (double)(0);
   28737             :     }
   28738           0 :     if( (ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) )
   28739             :     {
   28740           0 :         for(i=0; i<=c->n-1; i++)
   28741             :         {
   28742           0 :             for(j=0; j<=c->l-1; j++)
   28743             :             {
   28744           0 :                 spline3dcalcv(c, x.ptr.p_double[i], by, z.ptr.p_double[j], &v, _state);
   28745           0 :                 for(k=0; k<=c->m-1; k++)
   28746             :                 {
   28747           0 :                     for(di=0; di<=c->d-1; di++)
   28748             :                     {
   28749           0 :                         f.ptr.p_double[c->d*(c->n*(c->m*j+k)+i)+di] = v.ptr.p_double[di];
   28750             :                     }
   28751             :                 }
   28752             :             }
   28753             :         }
   28754           0 :         ay = (double)(1);
   28755           0 :         by = (double)(0);
   28756             :     }
   28757           0 :     if( (ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) )
   28758             :     {
   28759           0 :         for(i=0; i<=c->n-1; i++)
   28760             :         {
   28761           0 :             for(j=0; j<=c->m-1; j++)
   28762             :             {
   28763           0 :                 spline3dcalcv(c, x.ptr.p_double[i], y.ptr.p_double[j], bz, &v, _state);
   28764           0 :                 for(k=0; k<=c->l-1; k++)
   28765             :                 {
   28766           0 :                     for(di=0; di<=c->d-1; di++)
   28767             :                     {
   28768           0 :                         f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di];
   28769             :                     }
   28770             :                 }
   28771             :             }
   28772             :         }
   28773           0 :         az = (double)(1);
   28774           0 :         bz = (double)(0);
   28775             :     }
   28776           0 :     if( (ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) )
   28777             :     {
   28778           0 :         for(i=0; i<=c->l-1; i++)
   28779             :         {
   28780           0 :             spline3dcalcv(c, bx, by, z.ptr.p_double[i], &v, _state);
   28781           0 :             for(k=0; k<=c->m-1; k++)
   28782             :             {
   28783           0 :                 for(j=0; j<=c->n-1; j++)
   28784             :                 {
   28785           0 :                     for(di=0; di<=c->d-1; di++)
   28786             :                     {
   28787           0 :                         f.ptr.p_double[c->d*(c->n*(c->m*i+k)+j)+di] = v.ptr.p_double[di];
   28788             :                     }
   28789             :                 }
   28790             :             }
   28791             :         }
   28792           0 :         ax = (double)(1);
   28793           0 :         bx = (double)(0);
   28794           0 :         ay = (double)(1);
   28795           0 :         by = (double)(0);
   28796             :     }
   28797           0 :     if( (ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) )
   28798             :     {
   28799           0 :         for(i=0; i<=c->m-1; i++)
   28800             :         {
   28801           0 :             spline3dcalcv(c, bx, y.ptr.p_double[i], bz, &v, _state);
   28802           0 :             for(k=0; k<=c->l-1; k++)
   28803             :             {
   28804           0 :                 for(j=0; j<=c->n-1; j++)
   28805             :                 {
   28806           0 :                     for(di=0; di<=c->d-1; di++)
   28807             :                     {
   28808           0 :                         f.ptr.p_double[c->d*(c->n*(c->m*k+i)+j)+di] = v.ptr.p_double[di];
   28809             :                     }
   28810             :                 }
   28811             :             }
   28812             :         }
   28813           0 :         ax = (double)(1);
   28814           0 :         bx = (double)(0);
   28815           0 :         az = (double)(1);
   28816           0 :         bz = (double)(0);
   28817             :     }
   28818           0 :     if( (ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) )
   28819             :     {
   28820           0 :         for(i=0; i<=c->n-1; i++)
   28821             :         {
   28822           0 :             spline3dcalcv(c, x.ptr.p_double[i], by, bz, &v, _state);
   28823           0 :             for(k=0; k<=c->l-1; k++)
   28824             :             {
   28825           0 :                 for(j=0; j<=c->m-1; j++)
   28826             :                 {
   28827           0 :                     for(di=0; di<=c->d-1; di++)
   28828             :                     {
   28829           0 :                         f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di];
   28830             :                     }
   28831             :                 }
   28832             :             }
   28833             :         }
   28834           0 :         ay = (double)(1);
   28835           0 :         by = (double)(0);
   28836           0 :         az = (double)(1);
   28837           0 :         bz = (double)(0);
   28838             :     }
   28839           0 :     if( (ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) )
   28840             :     {
   28841           0 :         spline3dcalcv(c, bx, by, bz, &v, _state);
   28842           0 :         for(k=0; k<=c->l-1; k++)
   28843             :         {
   28844           0 :             for(j=0; j<=c->m-1; j++)
   28845             :             {
   28846           0 :                 for(i=0; i<=c->n-1; i++)
   28847             :                 {
   28848           0 :                     for(di=0; di<=c->d-1; di++)
   28849             :                     {
   28850           0 :                         f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di];
   28851             :                     }
   28852             :                 }
   28853             :             }
   28854             :         }
   28855           0 :         ax = (double)(1);
   28856           0 :         bx = (double)(0);
   28857           0 :         ay = (double)(1);
   28858           0 :         by = (double)(0);
   28859           0 :         az = (double)(1);
   28860           0 :         bz = (double)(0);
   28861             :     }
   28862             :     
   28863             :     /*
   28864             :      * General case: AX<>0, AY<>0, AZ<>0
   28865             :      * Unpack, scale and pack again.
   28866             :      */
   28867           0 :     for(i=0; i<=c->n-1; i++)
   28868             :     {
   28869           0 :         x.ptr.p_double[i] = (x.ptr.p_double[i]-bx)/ax;
   28870             :     }
   28871           0 :     for(i=0; i<=c->m-1; i++)
   28872             :     {
   28873           0 :         y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay;
   28874             :     }
   28875           0 :     for(i=0; i<=c->l-1; i++)
   28876             :     {
   28877           0 :         z.ptr.p_double[i] = (z.ptr.p_double[i]-bz)/az;
   28878             :     }
   28879           0 :     if( c->stype==-1 )
   28880             :     {
   28881           0 :         spline3dbuildtrilinearv(&x, c->n, &y, c->m, &z, c->l, &f, c->d, c, _state);
   28882             :     }
   28883           0 :     ae_frame_leave(_state);
   28884           0 : }
   28885             : 
   28886             : 
   28887             : /*************************************************************************
   28888             : This subroutine performs linear transformation of the spline.
   28889             : 
   28890             : INPUT PARAMETERS:
   28891             :     C   -   spline interpolant.
   28892             :     A, B-   transformation coefficients: S2(x,y) = A*S(x,y,z) + B
   28893             :     
   28894             : OUTPUT PARAMETERS:
   28895             :     C   -   transformed spline
   28896             : 
   28897             :   -- ALGLIB PROJECT --
   28898             :      Copyright 26.04.2012 by Bochkanov Sergey
   28899             : *************************************************************************/
   28900           0 : void spline3dlintransf(spline3dinterpolant* c,
   28901             :      double a,
   28902             :      double b,
   28903             :      ae_state *_state)
   28904             : {
   28905             :     ae_frame _frame_block;
   28906             :     ae_vector x;
   28907             :     ae_vector y;
   28908             :     ae_vector z;
   28909             :     ae_vector f;
   28910             :     ae_int_t i;
   28911             :     ae_int_t j;
   28912             : 
   28913           0 :     ae_frame_make(_state, &_frame_block);
   28914           0 :     memset(&x, 0, sizeof(x));
   28915           0 :     memset(&y, 0, sizeof(y));
   28916           0 :     memset(&z, 0, sizeof(z));
   28917           0 :     memset(&f, 0, sizeof(f));
   28918           0 :     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
   28919           0 :     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
   28920           0 :     ae_vector_init(&z, 0, DT_REAL, _state, ae_true);
   28921           0 :     ae_vector_init(&f, 0, DT_REAL, _state, ae_true);
   28922             : 
   28923           0 :     ae_assert(c->stype==-3||c->stype==-1, "Spline3DLinTransF: incorrect C (incorrect parameter C.SType)", _state);
   28924           0 :     ae_vector_set_length(&x, c->n, _state);
   28925           0 :     ae_vector_set_length(&y, c->m, _state);
   28926           0 :     ae_vector_set_length(&z, c->l, _state);
   28927           0 :     ae_vector_set_length(&f, c->m*c->n*c->l*c->d, _state);
   28928           0 :     for(j=0; j<=c->n-1; j++)
   28929             :     {
   28930           0 :         x.ptr.p_double[j] = c->x.ptr.p_double[j];
   28931             :     }
   28932           0 :     for(i=0; i<=c->m-1; i++)
   28933             :     {
   28934           0 :         y.ptr.p_double[i] = c->y.ptr.p_double[i];
   28935             :     }
   28936           0 :     for(i=0; i<=c->l-1; i++)
   28937             :     {
   28938           0 :         z.ptr.p_double[i] = c->z.ptr.p_double[i];
   28939             :     }
   28940           0 :     for(i=0; i<=c->m*c->n*c->l*c->d-1; i++)
   28941             :     {
   28942           0 :         f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b;
   28943             :     }
   28944           0 :     if( c->stype==-1 )
   28945             :     {
   28946           0 :         spline3dbuildtrilinearv(&x, c->n, &y, c->m, &z, c->l, &f, c->d, c, _state);
   28947             :     }
   28948           0 :     ae_frame_leave(_state);
   28949           0 : }
   28950             : 
   28951             : 
   28952             : /*************************************************************************
   28953             : This subroutine makes the copy of the spline model.
   28954             : 
   28955             : INPUT PARAMETERS:
   28956             :     C   -   spline interpolant
   28957             : 
   28958             : OUTPUT PARAMETERS:
   28959             :     CC  -   spline copy
   28960             : 
   28961             :   -- ALGLIB PROJECT --
   28962             :      Copyright 26.04.2012 by Bochkanov Sergey
   28963             : *************************************************************************/
   28964           0 : void spline3dcopy(spline3dinterpolant* c,
   28965             :      spline3dinterpolant* cc,
   28966             :      ae_state *_state)
   28967             : {
   28968             :     ae_int_t tblsize;
   28969             : 
   28970           0 :     _spline3dinterpolant_clear(cc);
   28971             : 
   28972           0 :     ae_assert(c->k==1||c->k==3, "Spline3DCopy: incorrect C (incorrect parameter C.K)", _state);
   28973           0 :     cc->k = c->k;
   28974           0 :     cc->n = c->n;
   28975           0 :     cc->m = c->m;
   28976           0 :     cc->l = c->l;
   28977           0 :     cc->d = c->d;
   28978           0 :     tblsize = c->n*c->m*c->l*c->d;
   28979           0 :     cc->stype = c->stype;
   28980           0 :     ae_vector_set_length(&cc->x, cc->n, _state);
   28981           0 :     ae_vector_set_length(&cc->y, cc->m, _state);
   28982           0 :     ae_vector_set_length(&cc->z, cc->l, _state);
   28983           0 :     ae_vector_set_length(&cc->f, tblsize, _state);
   28984           0 :     ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1));
   28985           0 :     ae_v_move(&cc->y.ptr.p_double[0], 1, &c->y.ptr.p_double[0], 1, ae_v_len(0,cc->m-1));
   28986           0 :     ae_v_move(&cc->z.ptr.p_double[0], 1, &c->z.ptr.p_double[0], 1, ae_v_len(0,cc->l-1));
   28987           0 :     ae_v_move(&cc->f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,tblsize-1));
   28988           0 : }
   28989             : 
   28990             : 
   28991             : /*************************************************************************
   28992             : Trilinear spline resampling
   28993             : 
   28994             : INPUT PARAMETERS:
   28995             :     A           -   array[0..OldXCount*OldYCount*OldZCount-1], function
   28996             :                     values at the old grid, :
   28997             :                         A[0]        x=0,y=0,z=0
   28998             :                         A[1]        x=1,y=0,z=0
   28999             :                         A[..]       ...
   29000             :                         A[..]       x=oldxcount-1,y=0,z=0
   29001             :                         A[..]       x=0,y=1,z=0
   29002             :                         A[..]       ...
   29003             :                         ...
   29004             :     OldZCount   -   old Z-count, OldZCount>1
   29005             :     OldYCount   -   old Y-count, OldYCount>1
   29006             :     OldXCount   -   old X-count, OldXCount>1
   29007             :     NewZCount   -   new Z-count, NewZCount>1
   29008             :     NewYCount   -   new Y-count, NewYCount>1
   29009             :     NewXCount   -   new X-count, NewXCount>1
   29010             : 
   29011             : OUTPUT PARAMETERS:
   29012             :     B           -   array[0..NewXCount*NewYCount*NewZCount-1], function
   29013             :                     values at the new grid:
   29014             :                         B[0]        x=0,y=0,z=0
   29015             :                         B[1]        x=1,y=0,z=0
   29016             :                         B[..]       ...
   29017             :                         B[..]       x=newxcount-1,y=0,z=0
   29018             :                         B[..]       x=0,y=1,z=0
   29019             :                         B[..]       ...
   29020             :                         ...
   29021             : 
   29022             :   -- ALGLIB routine --
   29023             :      26.04.2012
   29024             :      Copyright by Bochkanov Sergey
   29025             : *************************************************************************/
   29026           0 : void spline3dresampletrilinear(/* Real    */ ae_vector* a,
   29027             :      ae_int_t oldzcount,
   29028             :      ae_int_t oldycount,
   29029             :      ae_int_t oldxcount,
   29030             :      ae_int_t newzcount,
   29031             :      ae_int_t newycount,
   29032             :      ae_int_t newxcount,
   29033             :      /* Real    */ ae_vector* b,
   29034             :      ae_state *_state)
   29035             : {
   29036             :     double xd;
   29037             :     double yd;
   29038             :     double zd;
   29039             :     double c0;
   29040             :     double c1;
   29041             :     double c2;
   29042             :     double c3;
   29043             :     ae_int_t ix;
   29044             :     ae_int_t iy;
   29045             :     ae_int_t iz;
   29046             :     ae_int_t i;
   29047             :     ae_int_t j;
   29048             :     ae_int_t k;
   29049             : 
   29050           0 :     ae_vector_clear(b);
   29051             : 
   29052           0 :     ae_assert((oldycount>1&&oldzcount>1)&&oldxcount>1, "Spline3DResampleTrilinear: length/width/height less than 1", _state);
   29053           0 :     ae_assert((newycount>1&&newzcount>1)&&newxcount>1, "Spline3DResampleTrilinear: length/width/height less than 1", _state);
   29054           0 :     ae_assert(a->cnt>=oldycount*oldzcount*oldxcount, "Spline3DResampleTrilinear: length/width/height less than 1", _state);
   29055           0 :     ae_vector_set_length(b, newxcount*newycount*newzcount, _state);
   29056           0 :     for(i=0; i<=newxcount-1; i++)
   29057             :     {
   29058           0 :         for(j=0; j<=newycount-1; j++)
   29059             :         {
   29060           0 :             for(k=0; k<=newzcount-1; k++)
   29061             :             {
   29062           0 :                 ix = i*(oldxcount-1)/(newxcount-1);
   29063           0 :                 if( ix==oldxcount-1 )
   29064             :                 {
   29065           0 :                     ix = oldxcount-2;
   29066             :                 }
   29067           0 :                 xd = (double)(i*(oldxcount-1))/(double)(newxcount-1)-ix;
   29068           0 :                 iy = j*(oldycount-1)/(newycount-1);
   29069           0 :                 if( iy==oldycount-1 )
   29070             :                 {
   29071           0 :                     iy = oldycount-2;
   29072             :                 }
   29073           0 :                 yd = (double)(j*(oldycount-1))/(double)(newycount-1)-iy;
   29074           0 :                 iz = k*(oldzcount-1)/(newzcount-1);
   29075           0 :                 if( iz==oldzcount-1 )
   29076             :                 {
   29077           0 :                     iz = oldzcount-2;
   29078             :                 }
   29079           0 :                 zd = (double)(k*(oldzcount-1))/(double)(newzcount-1)-iz;
   29080           0 :                 c0 = a->ptr.p_double[oldxcount*(oldycount*iz+iy)+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*iz+iy)+(ix+1)]*xd;
   29081           0 :                 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;
   29082           0 :                 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;
   29083           0 :                 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;
   29084           0 :                 c0 = c0*(1-yd)+c1*yd;
   29085           0 :                 c1 = c2*(1-yd)+c3*yd;
   29086           0 :                 b->ptr.p_double[newxcount*(newycount*k+j)+i] = c0*(1-zd)+c1*zd;
   29087             :             }
   29088             :         }
   29089             :     }
   29090           0 : }
   29091             : 
   29092             : 
   29093             : /*************************************************************************
   29094             : This subroutine builds trilinear vector-valued spline.
   29095             : 
   29096             : INPUT PARAMETERS:
   29097             :     X   -   spline abscissas,  array[0..N-1]
   29098             :     Y   -   spline ordinates,  array[0..M-1]
   29099             :     Z   -   spline applicates, array[0..L-1] 
   29100             :     F   -   function values, array[0..M*N*L*D-1]:
   29101             :             * first D elements store D values at (X[0],Y[0],Z[0])
   29102             :             * next D elements store D values at (X[1],Y[0],Z[0])
   29103             :             * next D elements store D values at (X[2],Y[0],Z[0])
   29104             :             * ...
   29105             :             * next D elements store D values at (X[0],Y[1],Z[0])
   29106             :             * next D elements store D values at (X[1],Y[1],Z[0])
   29107             :             * next D elements store D values at (X[2],Y[1],Z[0])
   29108             :             * ...
   29109             :             * next D elements store D values at (X[0],Y[0],Z[1])
   29110             :             * next D elements store D values at (X[1],Y[0],Z[1])
   29111             :             * next D elements store D values at (X[2],Y[0],Z[1])
   29112             :             * ...
   29113             :             * general form - D function values at (X[i],Y[j]) are stored
   29114             :               at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1].
   29115             :     M,N,
   29116             :     L   -   grid size, M>=2, N>=2, L>=2
   29117             :     D   -   vector dimension, D>=1
   29118             : 
   29119             : OUTPUT PARAMETERS:
   29120             :     C   -   spline interpolant
   29121             : 
   29122             :   -- ALGLIB PROJECT --
   29123             :      Copyright 26.04.2012 by Bochkanov Sergey
   29124             : *************************************************************************/
   29125           0 : void spline3dbuildtrilinearv(/* Real    */ ae_vector* x,
   29126             :      ae_int_t n,
   29127             :      /* Real    */ ae_vector* y,
   29128             :      ae_int_t m,
   29129             :      /* Real    */ ae_vector* z,
   29130             :      ae_int_t l,
   29131             :      /* Real    */ ae_vector* f,
   29132             :      ae_int_t d,
   29133             :      spline3dinterpolant* c,
   29134             :      ae_state *_state)
   29135             : {
   29136             :     double t;
   29137             :     ae_int_t tblsize;
   29138             :     ae_int_t i;
   29139             :     ae_int_t j;
   29140             :     ae_int_t k;
   29141             :     ae_int_t i0;
   29142             :     ae_int_t j0;
   29143             : 
   29144           0 :     _spline3dinterpolant_clear(c);
   29145             : 
   29146           0 :     ae_assert(m>=2, "Spline3DBuildTrilinearV: M<2", _state);
   29147           0 :     ae_assert(n>=2, "Spline3DBuildTrilinearV: N<2", _state);
   29148           0 :     ae_assert(l>=2, "Spline3DBuildTrilinearV: L<2", _state);
   29149           0 :     ae_assert(d>=1, "Spline3DBuildTrilinearV: D<1", _state);
   29150           0 :     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)<N/M/L)", _state);
   29151           0 :     ae_assert((isfinitevector(x, n, _state)&&isfinitevector(y, m, _state))&&isfinitevector(z, l, _state), "Spline3DBuildTrilinearV: X, Y or Z contains NaN or Infinite value", _state);
   29152           0 :     tblsize = n*m*l*d;
   29153           0 :     ae_assert(f->cnt>=tblsize, "Spline3DBuildTrilinearV: length of F is too short (Length(F)<N*M*L*D)", _state);
   29154           0 :     ae_assert(isfinitevector(f, tblsize, _state), "Spline3DBuildTrilinearV: F contains NaN or Infinite value", _state);
   29155             :     
   29156             :     /*
   29157             :      * Fill interpolant
   29158             :      */
   29159           0 :     c->k = 1;
   29160           0 :     c->n = n;
   29161           0 :     c->m = m;
   29162           0 :     c->l = l;
   29163           0 :     c->d = d;
   29164           0 :     c->stype = -1;
   29165           0 :     ae_vector_set_length(&c->x, c->n, _state);
   29166           0 :     ae_vector_set_length(&c->y, c->m, _state);
   29167           0 :     ae_vector_set_length(&c->z, c->l, _state);
   29168           0 :     ae_vector_set_length(&c->f, tblsize, _state);
   29169           0 :     for(i=0; i<=c->n-1; i++)
   29170             :     {
   29171           0 :         c->x.ptr.p_double[i] = x->ptr.p_double[i];
   29172             :     }
   29173           0 :     for(i=0; i<=c->m-1; i++)
   29174             :     {
   29175           0 :         c->y.ptr.p_double[i] = y->ptr.p_double[i];
   29176             :     }
   29177           0 :     for(i=0; i<=c->l-1; i++)
   29178             :     {
   29179           0 :         c->z.ptr.p_double[i] = z->ptr.p_double[i];
   29180             :     }
   29181           0 :     for(i=0; i<=tblsize-1; i++)
   29182             :     {
   29183           0 :         c->f.ptr.p_double[i] = f->ptr.p_double[i];
   29184             :     }
   29185             :     
   29186             :     /*
   29187             :      * Sort points:
   29188             :      *  * sort x;
   29189             :      *  * sort y;
   29190             :      *  * sort z.
   29191             :      */
   29192           0 :     for(j=0; j<=c->n-1; j++)
   29193             :     {
   29194           0 :         k = j;
   29195           0 :         for(i=j+1; i<=c->n-1; i++)
   29196             :         {
   29197           0 :             if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) )
   29198             :             {
   29199           0 :                 k = i;
   29200             :             }
   29201             :         }
   29202           0 :         if( k!=j )
   29203             :         {
   29204           0 :             for(i=0; i<=c->m-1; i++)
   29205             :             {
   29206           0 :                 for(j0=0; j0<=c->l-1; j0++)
   29207             :                 {
   29208           0 :                     for(i0=0; i0<=c->d-1; i0++)
   29209             :                     {
   29210           0 :                         t = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0];
   29211           0 :                         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];
   29212           0 :                         c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+k)+i0] = t;
   29213             :                     }
   29214             :                 }
   29215             :             }
   29216           0 :             t = c->x.ptr.p_double[j];
   29217           0 :             c->x.ptr.p_double[j] = c->x.ptr.p_double[k];
   29218           0 :             c->x.ptr.p_double[k] = t;
   29219             :         }
   29220             :     }
   29221           0 :     for(i=0; i<=c->m-1; i++)
   29222             :     {
   29223           0 :         k = i;
   29224           0 :         for(j=i+1; j<=c->m-1; j++)
   29225             :         {
   29226           0 :             if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) )
   29227             :             {
   29228           0 :                 k = j;
   29229             :             }
   29230             :         }
   29231           0 :         if( k!=i )
   29232             :         {
   29233           0 :             for(j=0; j<=c->n-1; j++)
   29234             :             {
   29235           0 :                 for(j0=0; j0<=c->l-1; j0++)
   29236             :                 {
   29237           0 :                     for(i0=0; i0<=c->d-1; i0++)
   29238             :                     {
   29239           0 :                         t = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0];
   29240           0 :                         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];
   29241           0 :                         c->f.ptr.p_double[c->d*(c->n*(c->m*j0+k)+j)+i0] = t;
   29242             :                     }
   29243             :                 }
   29244             :             }
   29245           0 :             t = c->y.ptr.p_double[i];
   29246           0 :             c->y.ptr.p_double[i] = c->y.ptr.p_double[k];
   29247           0 :             c->y.ptr.p_double[k] = t;
   29248             :         }
   29249             :     }
   29250           0 :     for(k=0; k<=c->l-1; k++)
   29251             :     {
   29252           0 :         i = k;
   29253           0 :         for(j=i+1; j<=c->l-1; j++)
   29254             :         {
   29255           0 :             if( ae_fp_less(c->z.ptr.p_double[j],c->z.ptr.p_double[i]) )
   29256             :             {
   29257           0 :                 i = j;
   29258             :             }
   29259             :         }
   29260           0 :         if( i!=k )
   29261             :         {
   29262           0 :             for(j=0; j<=c->m-1; j++)
   29263             :             {
   29264           0 :                 for(j0=0; j0<=c->n-1; j0++)
   29265             :                 {
   29266           0 :                     for(i0=0; i0<=c->d-1; i0++)
   29267             :                     {
   29268           0 :                         t = c->f.ptr.p_double[c->d*(c->n*(c->m*k+j)+j0)+i0];
   29269           0 :                         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];
   29270           0 :                         c->f.ptr.p_double[c->d*(c->n*(c->m*i+j)+j0)+i0] = t;
   29271             :                     }
   29272             :                 }
   29273             :             }
   29274           0 :             t = c->z.ptr.p_double[k];
   29275           0 :             c->z.ptr.p_double[k] = c->z.ptr.p_double[i];
   29276           0 :             c->z.ptr.p_double[i] = t;
   29277             :         }
   29278             :     }
   29279           0 : }
   29280             : 
   29281             : 
   29282             : /*************************************************************************
   29283             : This subroutine calculates bilinear or bicubic vector-valued spline at the
   29284             : given point (X,Y,Z).
   29285             : 
   29286             : INPUT PARAMETERS:
   29287             :     C   -   spline interpolant.
   29288             :     X, Y,
   29289             :     Z   -   point
   29290             :     F   -   output buffer, possibly preallocated array. In case array size
   29291             :             is large enough to store result, it is not reallocated.  Array
   29292             :             which is too short will be reallocated
   29293             : 
   29294             : OUTPUT PARAMETERS:
   29295             :     F   -   array[D] (or larger) which stores function values
   29296             : 
   29297             :   -- ALGLIB PROJECT --
   29298             :      Copyright 26.04.2012 by Bochkanov Sergey
   29299             : *************************************************************************/
   29300           0 : void spline3dcalcvbuf(spline3dinterpolant* c,
   29301             :      double x,
   29302             :      double y,
   29303             :      double z,
   29304             :      /* Real    */ ae_vector* f,
   29305             :      ae_state *_state)
   29306             : {
   29307             :     double xd;
   29308             :     double yd;
   29309             :     double zd;
   29310             :     double c0;
   29311             :     double c1;
   29312             :     double c2;
   29313             :     double c3;
   29314             :     ae_int_t ix;
   29315             :     ae_int_t iy;
   29316             :     ae_int_t iz;
   29317             :     ae_int_t l;
   29318             :     ae_int_t r;
   29319             :     ae_int_t h;
   29320             :     ae_int_t i;
   29321             : 
   29322             : 
   29323           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalcVBuf: incorrect C (incorrect parameter C.SType)", _state);
   29324           0 :     ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalcVBuf: X, Y or Z contains NaN/Infinite", _state);
   29325           0 :     rvectorsetlengthatleast(f, c->d, _state);
   29326             :     
   29327             :     /*
   29328             :      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
   29329             :      */
   29330           0 :     l = 0;
   29331           0 :     r = c->n-1;
   29332           0 :     while(l!=r-1)
   29333             :     {
   29334           0 :         h = (l+r)/2;
   29335           0 :         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
   29336             :         {
   29337           0 :             r = h;
   29338             :         }
   29339             :         else
   29340             :         {
   29341           0 :             l = h;
   29342             :         }
   29343             :     }
   29344           0 :     ix = l;
   29345             :     
   29346             :     /*
   29347             :      * Binary search in the [ y[0], ..., y[n-2] ] (y[n-1] is not included)
   29348             :      */
   29349           0 :     l = 0;
   29350           0 :     r = c->m-1;
   29351           0 :     while(l!=r-1)
   29352             :     {
   29353           0 :         h = (l+r)/2;
   29354           0 :         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
   29355             :         {
   29356           0 :             r = h;
   29357             :         }
   29358             :         else
   29359             :         {
   29360           0 :             l = h;
   29361             :         }
   29362             :     }
   29363           0 :     iy = l;
   29364             :     
   29365             :     /*
   29366             :      * Binary search in the [ z[0], ..., z[n-2] ] (z[n-1] is not included)
   29367             :      */
   29368           0 :     l = 0;
   29369           0 :     r = c->l-1;
   29370           0 :     while(l!=r-1)
   29371             :     {
   29372           0 :         h = (l+r)/2;
   29373           0 :         if( ae_fp_greater_eq(c->z.ptr.p_double[h],z) )
   29374             :         {
   29375           0 :             r = h;
   29376             :         }
   29377             :         else
   29378             :         {
   29379           0 :             l = h;
   29380             :         }
   29381             :     }
   29382           0 :     iz = l;
   29383           0 :     xd = (x-c->x.ptr.p_double[ix])/(c->x.ptr.p_double[ix+1]-c->x.ptr.p_double[ix]);
   29384           0 :     yd = (y-c->y.ptr.p_double[iy])/(c->y.ptr.p_double[iy+1]-c->y.ptr.p_double[iy]);
   29385           0 :     zd = (z-c->z.ptr.p_double[iz])/(c->z.ptr.p_double[iz+1]-c->z.ptr.p_double[iz]);
   29386           0 :     for(i=0; i<=c->d-1; i++)
   29387             :     {
   29388             :         
   29389             :         /*
   29390             :          * Trilinear interpolation
   29391             :          */
   29392           0 :         if( c->stype==-1 )
   29393             :         {
   29394           0 :             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;
   29395           0 :             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;
   29396           0 :             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;
   29397           0 :             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;
   29398           0 :             c0 = c0*(1-yd)+c1*yd;
   29399           0 :             c1 = c2*(1-yd)+c3*yd;
   29400           0 :             f->ptr.p_double[i] = c0*(1-zd)+c1*zd;
   29401             :         }
   29402             :     }
   29403           0 : }
   29404             : 
   29405             : 
   29406             : /*************************************************************************
   29407             : This subroutine calculates trilinear or tricubic vector-valued spline at the
   29408             : given point (X,Y,Z).
   29409             : 
   29410             : INPUT PARAMETERS:
   29411             :     C   -   spline interpolant.
   29412             :     X, Y,
   29413             :     Z   -   point
   29414             : 
   29415             : OUTPUT PARAMETERS:
   29416             :     F   -   array[D] which stores function values.  F is out-parameter and
   29417             :             it  is  reallocated  after  call to this function. In case you
   29418             :             want  to    reuse  previously  allocated  F,   you   may   use
   29419             :             Spline2DCalcVBuf(),  which  reallocates  F only when it is too
   29420             :             small.
   29421             : 
   29422             :   -- ALGLIB PROJECT --
   29423             :      Copyright 26.04.2012 by Bochkanov Sergey
   29424             : *************************************************************************/
   29425           0 : void spline3dcalcv(spline3dinterpolant* c,
   29426             :      double x,
   29427             :      double y,
   29428             :      double z,
   29429             :      /* Real    */ ae_vector* f,
   29430             :      ae_state *_state)
   29431             : {
   29432             : 
   29433           0 :     ae_vector_clear(f);
   29434             : 
   29435           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalcV: incorrect C (incorrect parameter C.SType)", _state);
   29436           0 :     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);
   29437           0 :     ae_vector_set_length(f, c->d, _state);
   29438           0 :     spline3dcalcvbuf(c, x, y, z, f, _state);
   29439           0 : }
   29440             : 
   29441             : 
   29442             : /*************************************************************************
   29443             : This subroutine unpacks tri-dimensional spline into the coefficients table
   29444             : 
   29445             : INPUT PARAMETERS:
   29446             :     C   -   spline interpolant.
   29447             : 
   29448             : Result:
   29449             :     N   -   grid size (X)
   29450             :     M   -   grid size (Y)
   29451             :     L   -   grid size (Z)
   29452             :     D   -   number of components
   29453             :     SType-  spline type. Currently, only one spline type is supported:
   29454             :             trilinear spline, as indicated by SType=1.
   29455             :     Tbl -   spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13].
   29456             :             For T=0..D-1 (component index), I = 0...N-2 (x index),
   29457             :             J=0..M-2 (y index), K=0..L-2 (z index):
   29458             :                 Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1),
   29459             :                 
   29460             :                 Q-th row stores decomposition for T-th component of the
   29461             :                 vector-valued function
   29462             :                 
   29463             :                 Tbl[Q,0] = X[i]
   29464             :                 Tbl[Q,1] = X[i+1]
   29465             :                 Tbl[Q,2] = Y[j]
   29466             :                 Tbl[Q,3] = Y[j+1]
   29467             :                 Tbl[Q,4] = Z[k]
   29468             :                 Tbl[Q,5] = Z[k+1]
   29469             :                 
   29470             :                 Tbl[Q,6] = C000
   29471             :                 Tbl[Q,7] = C100
   29472             :                 Tbl[Q,8] = C010
   29473             :                 Tbl[Q,9] = C110
   29474             :                 Tbl[Q,10]= C001
   29475             :                 Tbl[Q,11]= C101
   29476             :                 Tbl[Q,12]= C011
   29477             :                 Tbl[Q,13]= C111
   29478             :             On each grid square spline is equals to:
   29479             :                 S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1)
   29480             :                 t = x-x[j]
   29481             :                 u = y-y[i]
   29482             :                 v = z-z[k]
   29483             :             
   29484             :             NOTE: format of Tbl is given for SType=1. Future versions of
   29485             :                   ALGLIB can use different formats for different values of
   29486             :                   SType.
   29487             : 
   29488             :   -- ALGLIB PROJECT --
   29489             :      Copyright 26.04.2012 by Bochkanov Sergey
   29490             : *************************************************************************/
   29491           0 : void spline3dunpackv(spline3dinterpolant* c,
   29492             :      ae_int_t* n,
   29493             :      ae_int_t* m,
   29494             :      ae_int_t* l,
   29495             :      ae_int_t* d,
   29496             :      ae_int_t* stype,
   29497             :      /* Real    */ ae_matrix* tbl,
   29498             :      ae_state *_state)
   29499             : {
   29500             :     ae_int_t p;
   29501             :     ae_int_t ci;
   29502             :     ae_int_t cj;
   29503             :     ae_int_t ck;
   29504             :     double du;
   29505             :     double dv;
   29506             :     double dw;
   29507             :     ae_int_t i;
   29508             :     ae_int_t j;
   29509             :     ae_int_t k;
   29510             :     ae_int_t di;
   29511             :     ae_int_t i0;
   29512             : 
   29513           0 :     *n = 0;
   29514           0 :     *m = 0;
   29515           0 :     *l = 0;
   29516           0 :     *d = 0;
   29517           0 :     *stype = 0;
   29518           0 :     ae_matrix_clear(tbl);
   29519             : 
   29520           0 :     ae_assert(c->stype==-1, "Spline3DUnpackV: incorrect C (incorrect parameter C.SType)", _state);
   29521           0 :     *n = c->n;
   29522           0 :     *m = c->m;
   29523           0 :     *l = c->l;
   29524           0 :     *d = c->d;
   29525           0 :     *stype = ae_iabs(c->stype, _state);
   29526           0 :     ae_matrix_set_length(tbl, (*n-1)*(*m-1)*(*l-1)*(*d), 14, _state);
   29527             :     
   29528             :     /*
   29529             :      * Fill
   29530             :      */
   29531           0 :     for(i=0; i<=*n-2; i++)
   29532             :     {
   29533           0 :         for(j=0; j<=*m-2; j++)
   29534             :         {
   29535           0 :             for(k=0; k<=*l-2; k++)
   29536             :             {
   29537           0 :                 for(di=0; di<=*d-1; di++)
   29538             :                 {
   29539           0 :                     p = *d*((*n-1)*((*m-1)*k+j)+i)+di;
   29540           0 :                     tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[i];
   29541           0 :                     tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[i+1];
   29542           0 :                     tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[j];
   29543           0 :                     tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[j+1];
   29544           0 :                     tbl->ptr.pp_double[p][4] = c->z.ptr.p_double[k];
   29545           0 :                     tbl->ptr.pp_double[p][5] = c->z.ptr.p_double[k+1];
   29546           0 :                     du = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]);
   29547           0 :                     dv = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]);
   29548           0 :                     dw = 1/(tbl->ptr.pp_double[p][5]-tbl->ptr.pp_double[p][4]);
   29549             :                     
   29550             :                     /*
   29551             :                      * Trilinear interpolation
   29552             :                      */
   29553           0 :                     if( c->stype==-1 )
   29554             :                     {
   29555           0 :                         for(i0=6; i0<=13; i0++)
   29556             :                         {
   29557           0 :                             tbl->ptr.pp_double[p][i0] = (double)(0);
   29558             :                         }
   29559           0 :                         tbl->ptr.pp_double[p][6+2*(2*0+0)+0] = c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di];
   29560           0 :                         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];
   29561           0 :                         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];
   29562           0 :                         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];
   29563           0 :                         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];
   29564           0 :                         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];
   29565           0 :                         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];
   29566           0 :                         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];
   29567             :                     }
   29568             :                     
   29569             :                     /*
   29570             :                      * Rescale Cij
   29571             :                      */
   29572           0 :                     for(ci=0; ci<=1; ci++)
   29573             :                     {
   29574           0 :                         for(cj=0; cj<=1; cj++)
   29575             :                         {
   29576           0 :                             for(ck=0; ck<=1; ck++)
   29577             :                             {
   29578           0 :                                 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);
   29579             :                             }
   29580             :                         }
   29581             :                     }
   29582             :                 }
   29583             :             }
   29584             :         }
   29585             :     }
   29586           0 : }
   29587             : 
   29588             : 
   29589             : /*************************************************************************
   29590             : This subroutine calculates the value of the trilinear(or tricubic;possible
   29591             : will be later) spline  at the given point X(and its derivatives; possible
   29592             : will be later).
   29593             : 
   29594             : INPUT PARAMETERS:
   29595             :     C       -   spline interpolant.
   29596             :     X, Y, Z -   point
   29597             : 
   29598             : OUTPUT PARAMETERS:
   29599             :     F   -   S(x,y,z)
   29600             :     FX  -   dS(x,y,z)/dX
   29601             :     FY  -   dS(x,y,z)/dY
   29602             :     FXY -   d2S(x,y,z)/dXdY
   29603             : 
   29604             :   -- ALGLIB PROJECT --
   29605             :      Copyright 26.04.2012 by Bochkanov Sergey
   29606             : *************************************************************************/
   29607           0 : static void spline3d_spline3ddiff(spline3dinterpolant* c,
   29608             :      double x,
   29609             :      double y,
   29610             :      double z,
   29611             :      double* f,
   29612             :      double* fx,
   29613             :      double* fy,
   29614             :      double* fxy,
   29615             :      ae_state *_state)
   29616             : {
   29617             :     double xd;
   29618             :     double yd;
   29619             :     double zd;
   29620             :     double c0;
   29621             :     double c1;
   29622             :     double c2;
   29623             :     double c3;
   29624             :     ae_int_t ix;
   29625             :     ae_int_t iy;
   29626             :     ae_int_t iz;
   29627             :     ae_int_t l;
   29628             :     ae_int_t r;
   29629             :     ae_int_t h;
   29630             : 
   29631           0 :     *f = 0;
   29632           0 :     *fx = 0;
   29633           0 :     *fy = 0;
   29634           0 :     *fxy = 0;
   29635             : 
   29636           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline3DDiff: incorrect C (incorrect parameter C.SType)", _state);
   29637           0 :     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline3DDiff: X or Y contains NaN or Infinite value", _state);
   29638             :     
   29639             :     /*
   29640             :      * Prepare F, dF/dX, dF/dY, d2F/dXdY
   29641             :      */
   29642           0 :     *f = (double)(0);
   29643           0 :     *fx = (double)(0);
   29644           0 :     *fy = (double)(0);
   29645           0 :     *fxy = (double)(0);
   29646           0 :     if( c->d!=1 )
   29647             :     {
   29648           0 :         return;
   29649             :     }
   29650             :     
   29651             :     /*
   29652             :      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
   29653             :      */
   29654           0 :     l = 0;
   29655           0 :     r = c->n-1;
   29656           0 :     while(l!=r-1)
   29657             :     {
   29658           0 :         h = (l+r)/2;
   29659           0 :         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
   29660             :         {
   29661           0 :             r = h;
   29662             :         }
   29663             :         else
   29664             :         {
   29665           0 :             l = h;
   29666             :         }
   29667             :     }
   29668           0 :     ix = l;
   29669             :     
   29670             :     /*
   29671             :      * Binary search in the [ y[0], ..., y[n-2] ] (y[n-1] is not included)
   29672             :      */
   29673           0 :     l = 0;
   29674           0 :     r = c->m-1;
   29675           0 :     while(l!=r-1)
   29676             :     {
   29677           0 :         h = (l+r)/2;
   29678           0 :         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
   29679             :         {
   29680           0 :             r = h;
   29681             :         }
   29682             :         else
   29683             :         {
   29684           0 :             l = h;
   29685             :         }
   29686             :     }
   29687           0 :     iy = l;
   29688             :     
   29689             :     /*
   29690             :      * Binary search in the [ z[0], ..., z[n-2] ] (z[n-1] is not included)
   29691             :      */
   29692           0 :     l = 0;
   29693           0 :     r = c->l-1;
   29694           0 :     while(l!=r-1)
   29695             :     {
   29696           0 :         h = (l+r)/2;
   29697           0 :         if( ae_fp_greater_eq(c->z.ptr.p_double[h],z) )
   29698             :         {
   29699           0 :             r = h;
   29700             :         }
   29701             :         else
   29702             :         {
   29703           0 :             l = h;
   29704             :         }
   29705             :     }
   29706           0 :     iz = l;
   29707           0 :     xd = (x-c->x.ptr.p_double[ix])/(c->x.ptr.p_double[ix+1]-c->x.ptr.p_double[ix]);
   29708           0 :     yd = (y-c->y.ptr.p_double[iy])/(c->y.ptr.p_double[iy+1]-c->y.ptr.p_double[iy]);
   29709           0 :     zd = (z-c->z.ptr.p_double[iz])/(c->z.ptr.p_double[iz+1]-c->z.ptr.p_double[iz]);
   29710             :     
   29711             :     /*
   29712             :      * Trilinear interpolation
   29713             :      */
   29714           0 :     if( c->stype==-1 )
   29715             :     {
   29716           0 :         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;
   29717           0 :         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;
   29718           0 :         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;
   29719           0 :         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;
   29720           0 :         c0 = c0*(1-yd)+c1*yd;
   29721           0 :         c1 = c2*(1-yd)+c3*yd;
   29722           0 :         *f = c0*(1-zd)+c1*zd;
   29723             :     }
   29724             : }
   29725             : 
   29726             : 
   29727           0 : void _spline3dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
   29728             : {
   29729           0 :     spline3dinterpolant *p = (spline3dinterpolant*)_p;
   29730           0 :     ae_touch_ptr((void*)p);
   29731           0 :     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
   29732           0 :     ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic);
   29733           0 :     ae_vector_init(&p->z, 0, DT_REAL, _state, make_automatic);
   29734           0 :     ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic);
   29735           0 : }
   29736             : 
   29737             : 
   29738           0 : void _spline3dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   29739             : {
   29740           0 :     spline3dinterpolant *dst = (spline3dinterpolant*)_dst;
   29741           0 :     spline3dinterpolant *src = (spline3dinterpolant*)_src;
   29742           0 :     dst->k = src->k;
   29743           0 :     dst->stype = src->stype;
   29744           0 :     dst->n = src->n;
   29745           0 :     dst->m = src->m;
   29746           0 :     dst->l = src->l;
   29747           0 :     dst->d = src->d;
   29748           0 :     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
   29749           0 :     ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic);
   29750           0 :     ae_vector_init_copy(&dst->z, &src->z, _state, make_automatic);
   29751           0 :     ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic);
   29752           0 : }
   29753             : 
   29754             : 
   29755           0 : void _spline3dinterpolant_clear(void* _p)
   29756             : {
   29757           0 :     spline3dinterpolant *p = (spline3dinterpolant*)_p;
   29758           0 :     ae_touch_ptr((void*)p);
   29759           0 :     ae_vector_clear(&p->x);
   29760           0 :     ae_vector_clear(&p->y);
   29761           0 :     ae_vector_clear(&p->z);
   29762           0 :     ae_vector_clear(&p->f);
   29763           0 : }
   29764             : 
   29765             : 
   29766           0 : void _spline3dinterpolant_destroy(void* _p)
   29767             : {
   29768           0 :     spline3dinterpolant *p = (spline3dinterpolant*)_p;
   29769           0 :     ae_touch_ptr((void*)p);
   29770           0 :     ae_vector_destroy(&p->x);
   29771           0 :     ae_vector_destroy(&p->y);
   29772           0 :     ae_vector_destroy(&p->z);
   29773           0 :     ae_vector_destroy(&p->f);
   29774           0 : }
   29775             : 
   29776             : 
   29777             : #endif
   29778             : #if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD)
   29779             : 
   29780             : 
   29781             : /*************************************************************************
   29782             : Conversion from barycentric representation to Chebyshev basis.
   29783             : This function has O(N^2) complexity.
   29784             : 
   29785             : INPUT PARAMETERS:
   29786             :     P   -   polynomial in barycentric form
   29787             :     A,B -   base interval for Chebyshev polynomials (see below)
   29788             :             A<>B
   29789             : 
   29790             : OUTPUT PARAMETERS
   29791             :     T   -   coefficients of Chebyshev representation;
   29792             :             P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 },
   29793             :             where Ti - I-th Chebyshev polynomial.
   29794             : 
   29795             : NOTES:
   29796             :     barycentric interpolant passed as P may be either polynomial  obtained
   29797             :     from  polynomial  interpolation/ fitting or rational function which is
   29798             :     NOT polynomial. We can't distinguish between these two cases, and this
   29799             :     algorithm just tries to work assuming that P IS a polynomial.  If not,
   29800             :     algorithm will return results, but they won't have any meaning.
   29801             : 
   29802             :   -- ALGLIB --
   29803             :      Copyright 30.09.2010 by Bochkanov Sergey
   29804             : *************************************************************************/
   29805           0 : void polynomialbar2cheb(barycentricinterpolant* p,
   29806             :      double a,
   29807             :      double b,
   29808             :      /* Real    */ ae_vector* t,
   29809             :      ae_state *_state)
   29810             : {
   29811             :     ae_frame _frame_block;
   29812             :     ae_int_t i;
   29813             :     ae_int_t k;
   29814             :     ae_vector vp;
   29815             :     ae_vector vx;
   29816             :     ae_vector tk;
   29817             :     ae_vector tk1;
   29818             :     double v;
   29819             : 
   29820           0 :     ae_frame_make(_state, &_frame_block);
   29821           0 :     memset(&vp, 0, sizeof(vp));
   29822           0 :     memset(&vx, 0, sizeof(vx));
   29823           0 :     memset(&tk, 0, sizeof(tk));
   29824           0 :     memset(&tk1, 0, sizeof(tk1));
   29825           0 :     ae_vector_clear(t);
   29826           0 :     ae_vector_init(&vp, 0, DT_REAL, _state, ae_true);
   29827           0 :     ae_vector_init(&vx, 0, DT_REAL, _state, ae_true);
   29828           0 :     ae_vector_init(&tk, 0, DT_REAL, _state, ae_true);
   29829           0 :     ae_vector_init(&tk1, 0, DT_REAL, _state, ae_true);
   29830             : 
   29831           0 :     ae_assert(ae_isfinite(a, _state), "PolynomialBar2Cheb: A is not finite!", _state);
   29832           0 :     ae_assert(ae_isfinite(b, _state), "PolynomialBar2Cheb: B is not finite!", _state);
   29833           0 :     ae_assert(ae_fp_neq(a,b), "PolynomialBar2Cheb: A=B!", _state);
   29834           0 :     ae_assert(p->n>0, "PolynomialBar2Cheb: P is not correctly initialized barycentric interpolant!", _state);
   29835             :     
   29836             :     /*
   29837             :      * Calculate function values on a Chebyshev grid
   29838             :      */
   29839           0 :     ae_vector_set_length(&vp, p->n, _state);
   29840           0 :     ae_vector_set_length(&vx, p->n, _state);
   29841           0 :     for(i=0; i<=p->n-1; i++)
   29842             :     {
   29843           0 :         vx.ptr.p_double[i] = ae_cos(ae_pi*(i+0.5)/p->n, _state);
   29844           0 :         vp.ptr.p_double[i] = barycentriccalc(p, 0.5*(vx.ptr.p_double[i]+1)*(b-a)+a, _state);
   29845             :     }
   29846             :     
   29847             :     /*
   29848             :      * T[0]
   29849             :      */
   29850           0 :     ae_vector_set_length(t, p->n, _state);
   29851           0 :     v = (double)(0);
   29852           0 :     for(i=0; i<=p->n-1; i++)
   29853             :     {
   29854           0 :         v = v+vp.ptr.p_double[i];
   29855             :     }
   29856           0 :     t->ptr.p_double[0] = v/p->n;
   29857             :     
   29858             :     /*
   29859             :      * other T's.
   29860             :      *
   29861             :      * NOTES:
   29862             :      * 1. TK stores T{k} on VX, TK1 stores T{k-1} on VX
   29863             :      * 2. we can do same calculations with fast DCT, but it
   29864             :      *    * adds dependencies
   29865             :      *    * still leaves us with O(N^2) algorithm because
   29866             :      *      preparation of function values is O(N^2) process
   29867             :      */
   29868           0 :     if( p->n>1 )
   29869             :     {
   29870           0 :         ae_vector_set_length(&tk, p->n, _state);
   29871           0 :         ae_vector_set_length(&tk1, p->n, _state);
   29872           0 :         for(i=0; i<=p->n-1; i++)
   29873             :         {
   29874           0 :             tk.ptr.p_double[i] = vx.ptr.p_double[i];
   29875           0 :             tk1.ptr.p_double[i] = (double)(1);
   29876             :         }
   29877           0 :         for(k=1; k<=p->n-1; k++)
   29878             :         {
   29879             :             
   29880             :             /*
   29881             :              * calculate discrete product of function vector and TK
   29882             :              */
   29883           0 :             v = ae_v_dotproduct(&tk.ptr.p_double[0], 1, &vp.ptr.p_double[0], 1, ae_v_len(0,p->n-1));
   29884           0 :             t->ptr.p_double[k] = v/(0.5*p->n);
   29885             :             
   29886             :             /*
   29887             :              * Update TK and TK1
   29888             :              */
   29889           0 :             for(i=0; i<=p->n-1; i++)
   29890             :             {
   29891           0 :                 v = 2*vx.ptr.p_double[i]*tk.ptr.p_double[i]-tk1.ptr.p_double[i];
   29892           0 :                 tk1.ptr.p_double[i] = tk.ptr.p_double[i];
   29893           0 :                 tk.ptr.p_double[i] = v;
   29894             :             }
   29895             :         }
   29896             :     }
   29897           0 :     ae_frame_leave(_state);
   29898           0 : }
   29899             : 
   29900             : 
   29901             : /*************************************************************************
   29902             : Conversion from Chebyshev basis to barycentric representation.
   29903             : This function has O(N^2) complexity.
   29904             : 
   29905             : INPUT PARAMETERS:
   29906             :     T   -   coefficients of Chebyshev representation;
   29907             :             P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N },
   29908             :             where Ti - I-th Chebyshev polynomial.
   29909             :     N   -   number of coefficients:
   29910             :             * if given, only leading N elements of T are used
   29911             :             * if not given, automatically determined from size of T
   29912             :     A,B -   base interval for Chebyshev polynomials (see above)
   29913             :             A<B
   29914             : 
   29915             : OUTPUT PARAMETERS
   29916             :     P   -   polynomial in barycentric form
   29917             : 
   29918             :   -- ALGLIB --
   29919             :      Copyright 30.09.2010 by Bochkanov Sergey
   29920             : *************************************************************************/
   29921           0 : void polynomialcheb2bar(/* Real    */ ae_vector* t,
   29922             :      ae_int_t n,
   29923             :      double a,
   29924             :      double b,
   29925             :      barycentricinterpolant* p,
   29926             :      ae_state *_state)
   29927             : {
   29928             :     ae_frame _frame_block;
   29929             :     ae_int_t i;
   29930             :     ae_int_t k;
   29931             :     ae_vector y;
   29932             :     double tk;
   29933             :     double tk1;
   29934             :     double vx;
   29935             :     double vy;
   29936             :     double v;
   29937             : 
   29938           0 :     ae_frame_make(_state, &_frame_block);
   29939           0 :     memset(&y, 0, sizeof(y));
   29940           0 :     _barycentricinterpolant_clear(p);
   29941           0 :     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
   29942             : 
   29943           0 :     ae_assert(ae_isfinite(a, _state), "PolynomialBar2Cheb: A is not finite!", _state);
   29944           0 :     ae_assert(ae_isfinite(b, _state), "PolynomialBar2Cheb: B is not finite!", _state);
   29945           0 :     ae_assert(ae_fp_neq(a,b), "PolynomialBar2Cheb: A=B!", _state);
   29946           0 :     ae_assert(n>=1, "PolynomialBar2Cheb: N<1", _state);
   29947           0 :     ae_assert(t->cnt>=n, "PolynomialBar2Cheb: Length(T)<N", _state);
   29948           0 :     ae_assert(isfinitevector(t, n, _state), "PolynomialBar2Cheb: T[] contains INF or NAN", _state);
   29949             :     
   29950             :     /*
   29951             :      * Calculate function values on a Chebyshev grid spanning [-1,+1]
   29952             :      */
   29953           0 :     ae_vector_set_length(&y, n, _state);
   29954           0 :     for(i=0; i<=n-1; i++)
   29955             :     {
   29956             :         
   29957             :         /*
   29958             :          * Calculate value on a grid spanning [-1,+1]
   29959             :          */
   29960           0 :         vx = ae_cos(ae_pi*(i+0.5)/n, _state);
   29961           0 :         vy = t->ptr.p_double[0];
   29962           0 :         tk1 = (double)(1);
   29963           0 :         tk = vx;
   29964           0 :         for(k=1; k<=n-1; k++)
   29965             :         {
   29966           0 :             vy = vy+t->ptr.p_double[k]*tk;
   29967           0 :             v = 2*vx*tk-tk1;
   29968           0 :             tk1 = tk;
   29969           0 :             tk = v;
   29970             :         }
   29971           0 :         y.ptr.p_double[i] = vy;
   29972             :     }
   29973             :     
   29974             :     /*
   29975             :      * Build barycentric interpolant, map grid from [-1,+1] to [A,B]
   29976             :      */
   29977           0 :     polynomialbuildcheb1(a, b, &y, n, p, _state);
   29978           0 :     ae_frame_leave(_state);
   29979           0 : }
   29980             : 
   29981             : 
   29982             : /*************************************************************************
   29983             : Conversion from barycentric representation to power basis.
   29984             : This function has O(N^2) complexity.
   29985             : 
   29986             : INPUT PARAMETERS:
   29987             :     P   -   polynomial in barycentric form
   29988             :     C   -   offset (see below); 0.0 is used as default value.
   29989             :     S   -   scale (see below);  1.0 is used as default value. S<>0.
   29990             : 
   29991             : OUTPUT PARAMETERS
   29992             :     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
   29993             :     N   -   number of coefficients (polynomial degree plus 1)
   29994             : 
   29995             : NOTES:
   29996             : 1.  this function accepts offset and scale, which can be  set  to  improve
   29997             :     numerical properties of polynomial. For example, if P was obtained  as
   29998             :     result of interpolation on [-1,+1],  you  can  set  C=0  and  S=1  and
   29999             :     represent  P  as sum of 1, x, x^2, x^3 and so on. In most cases you it
   30000             :     is exactly what you need.
   30001             : 
   30002             :     However, if your interpolation model was built on [999,1001], you will
   30003             :     see significant growth of numerical errors when using {1, x, x^2, x^3}
   30004             :     as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3
   30005             :     will be better option. Such representation can be  obtained  by  using
   30006             :     1000.0 as offset C and 1.0 as scale S.
   30007             : 
   30008             : 2.  power basis is ill-conditioned and tricks described above can't  solve
   30009             :     this problem completely. This function  will  return  coefficients  in
   30010             :     any  case,  but  for  N>8  they  will  become unreliable. However, N's
   30011             :     less than 5 are pretty safe.
   30012             :     
   30013             : 3.  barycentric interpolant passed as P may be either polynomial  obtained
   30014             :     from  polynomial  interpolation/ fitting or rational function which is
   30015             :     NOT polynomial. We can't distinguish between these two cases, and this
   30016             :     algorithm just tries to work assuming that P IS a polynomial.  If not,
   30017             :     algorithm will return results, but they won't have any meaning.
   30018             : 
   30019             :   -- ALGLIB --
   30020             :      Copyright 30.09.2010 by Bochkanov Sergey
   30021             : *************************************************************************/
   30022           0 : void polynomialbar2pow(barycentricinterpolant* p,
   30023             :      double c,
   30024             :      double s,
   30025             :      /* Real    */ ae_vector* a,
   30026             :      ae_state *_state)
   30027             : {
   30028             :     ae_frame _frame_block;
   30029             :     ae_int_t i;
   30030             :     ae_int_t k;
   30031             :     double e;
   30032             :     double d;
   30033             :     ae_vector vp;
   30034             :     ae_vector vx;
   30035             :     ae_vector tk;
   30036             :     ae_vector tk1;
   30037             :     ae_vector t;
   30038             :     double v;
   30039             :     double c0;
   30040             :     double s0;
   30041             :     double va;
   30042             :     double vb;
   30043             :     ae_vector vai;
   30044             :     ae_vector vbi;
   30045             :     double minx;
   30046             :     double maxx;
   30047             : 
   30048           0 :     ae_frame_make(_state, &_frame_block);
   30049           0 :     memset(&vp, 0, sizeof(vp));
   30050           0 :     memset(&vx, 0, sizeof(vx));
   30051           0 :     memset(&tk, 0, sizeof(tk));
   30052           0 :     memset(&tk1, 0, sizeof(tk1));
   30053           0 :     memset(&t, 0, sizeof(t));
   30054           0 :     memset(&vai, 0, sizeof(vai));
   30055           0 :     memset(&vbi, 0, sizeof(vbi));
   30056           0 :     ae_vector_clear(a);
   30057           0 :     ae_vector_init(&vp, 0, DT_REAL, _state, ae_true);
   30058           0 :     ae_vector_init(&vx, 0, DT_REAL, _state, ae_true);
   30059           0 :     ae_vector_init(&tk, 0, DT_REAL, _state, ae_true);
   30060           0 :     ae_vector_init(&tk1, 0, DT_REAL, _state, ae_true);
   30061           0 :     ae_vector_init(&t, 0, DT_REAL, _state, ae_true);
   30062           0 :     ae_vector_init(&vai, 0, DT_REAL, _state, ae_true);
   30063           0 :     ae_vector_init(&vbi, 0, DT_REAL, _state, ae_true);
   30064             : 
   30065             :     
   30066             :     /*
   30067             :      * We have barycentric model built using set of points X[], and we
   30068             :      * want to convert it to power basis centered about point  C  with
   30069             :      * scale S: I-th basis function is ((X-C)/S)^i.
   30070             :      *
   30071             :      * We use following three-stage algorithm:
   30072             :      *
   30073             :      * 1. we build Chebyshev representation of polynomial using
   30074             :      *    intermediate center C0 and scale S0, which are derived from X[]:
   30075             :      *    C0 = 0.5*(min(X)+max(X)), S0 = 0.5*(max(X)-min(X)). Chebyshev
   30076             :      *    representation is built by sampling points around center C0,
   30077             :      *    with typical distance between them proportional to S0.
   30078             :      * 2. then we transform form Chebyshev basis to intermediate power
   30079             :      *    basis, using same center/scale C0/S0.
   30080             :      * 3. after that, we apply linear transformation to intermediate
   30081             :      *    power basis which moves it to final center/scale C/S.
   30082             :      *
   30083             :      * The idea of such multi-stage algorithm is that it is much easier to
   30084             :      * transform barycentric model to Chebyshev basis, and only later to
   30085             :      * power basis, than transforming it directly to power basis. It is
   30086             :      * also more numerically stable to sample points using intermediate C0/S0,
   30087             :      * which are derived from user-supplied model, than using "final" C/S,
   30088             :      * which may be unsuitable for sampling (say, if S=1, we may have stability
   30089             :      * problems when working with models built from dataset with non-unit
   30090             :      * scale of abscissas).
   30091             :      */
   30092           0 :     ae_assert(ae_isfinite(c, _state), "PolynomialBar2Pow: C is not finite!", _state);
   30093           0 :     ae_assert(ae_isfinite(s, _state), "PolynomialBar2Pow: S is not finite!", _state);
   30094           0 :     ae_assert(ae_fp_neq(s,(double)(0)), "PolynomialBar2Pow: S=0!", _state);
   30095           0 :     ae_assert(p->n>0, "PolynomialBar2Pow: P is not correctly initialized barycentric interpolant!", _state);
   30096             :     
   30097             :     /*
   30098             :      * Select intermediate center/scale
   30099             :      */
   30100           0 :     minx = p->x.ptr.p_double[0];
   30101           0 :     maxx = p->x.ptr.p_double[0];
   30102           0 :     for(i=1; i<=p->n-1; i++)
   30103             :     {
   30104           0 :         minx = ae_minreal(minx, p->x.ptr.p_double[i], _state);
   30105           0 :         maxx = ae_maxreal(maxx, p->x.ptr.p_double[i], _state);
   30106             :     }
   30107           0 :     if( ae_fp_eq(minx,maxx) )
   30108             :     {
   30109           0 :         c0 = minx;
   30110           0 :         s0 = 1.0;
   30111             :     }
   30112             :     else
   30113             :     {
   30114           0 :         c0 = 0.5*(maxx+minx);
   30115           0 :         s0 = 0.5*(maxx-minx);
   30116             :     }
   30117             :     
   30118             :     /*
   30119             :      * Calculate function values on a Chebyshev grid using intermediate C0/S0
   30120             :      */
   30121           0 :     ae_vector_set_length(&vp, p->n+1, _state);
   30122           0 :     ae_vector_set_length(&vx, p->n, _state);
   30123           0 :     for(i=0; i<=p->n-1; i++)
   30124             :     {
   30125           0 :         vx.ptr.p_double[i] = ae_cos(ae_pi*(i+0.5)/p->n, _state);
   30126           0 :         vp.ptr.p_double[i] = barycentriccalc(p, s0*vx.ptr.p_double[i]+c0, _state);
   30127             :     }
   30128             :     
   30129             :     /*
   30130             :      * T[0]
   30131             :      */
   30132           0 :     ae_vector_set_length(&t, p->n, _state);
   30133           0 :     v = (double)(0);
   30134           0 :     for(i=0; i<=p->n-1; i++)
   30135             :     {
   30136           0 :         v = v+vp.ptr.p_double[i];
   30137             :     }
   30138           0 :     t.ptr.p_double[0] = v/p->n;
   30139             :     
   30140             :     /*
   30141             :      * other T's.
   30142             :      *
   30143             :      * NOTES:
   30144             :      * 1. TK stores T{k} on VX, TK1 stores T{k-1} on VX
   30145             :      * 2. we can do same calculations with fast DCT, but it
   30146             :      *    * adds dependencies
   30147             :      *    * still leaves us with O(N^2) algorithm because
   30148             :      *      preparation of function values is O(N^2) process
   30149             :      */
   30150           0 :     if( p->n>1 )
   30151             :     {
   30152           0 :         ae_vector_set_length(&tk, p->n, _state);
   30153           0 :         ae_vector_set_length(&tk1, p->n, _state);
   30154           0 :         for(i=0; i<=p->n-1; i++)
   30155             :         {
   30156           0 :             tk.ptr.p_double[i] = vx.ptr.p_double[i];
   30157           0 :             tk1.ptr.p_double[i] = (double)(1);
   30158             :         }
   30159           0 :         for(k=1; k<=p->n-1; k++)
   30160             :         {
   30161             :             
   30162             :             /*
   30163             :              * calculate discrete product of function vector and TK
   30164             :              */
   30165           0 :             v = ae_v_dotproduct(&tk.ptr.p_double[0], 1, &vp.ptr.p_double[0], 1, ae_v_len(0,p->n-1));
   30166           0 :             t.ptr.p_double[k] = v/(0.5*p->n);
   30167             :             
   30168             :             /*
   30169             :              * Update TK and TK1
   30170             :              */
   30171           0 :             for(i=0; i<=p->n-1; i++)
   30172             :             {
   30173           0 :                 v = 2*vx.ptr.p_double[i]*tk.ptr.p_double[i]-tk1.ptr.p_double[i];
   30174           0 :                 tk1.ptr.p_double[i] = tk.ptr.p_double[i];
   30175           0 :                 tk.ptr.p_double[i] = v;
   30176             :             }
   30177             :         }
   30178             :     }
   30179             :     
   30180             :     /*
   30181             :      * Convert from Chebyshev basis to power basis
   30182             :      */
   30183           0 :     ae_vector_set_length(a, p->n, _state);
   30184           0 :     for(i=0; i<=p->n-1; i++)
   30185             :     {
   30186           0 :         a->ptr.p_double[i] = (double)(0);
   30187             :     }
   30188           0 :     d = (double)(0);
   30189           0 :     for(i=0; i<=p->n-1; i++)
   30190             :     {
   30191           0 :         for(k=i; k<=p->n-1; k++)
   30192             :         {
   30193           0 :             e = a->ptr.p_double[k];
   30194           0 :             a->ptr.p_double[k] = (double)(0);
   30195           0 :             if( i<=1&&k==i )
   30196             :             {
   30197           0 :                 a->ptr.p_double[k] = (double)(1);
   30198             :             }
   30199             :             else
   30200             :             {
   30201           0 :                 if( i!=0 )
   30202             :                 {
   30203           0 :                     a->ptr.p_double[k] = 2*d;
   30204             :                 }
   30205           0 :                 if( k>i+1 )
   30206             :                 {
   30207           0 :                     a->ptr.p_double[k] = a->ptr.p_double[k]-a->ptr.p_double[k-2];
   30208             :                 }
   30209             :             }
   30210           0 :             d = e;
   30211             :         }
   30212           0 :         d = a->ptr.p_double[i];
   30213           0 :         e = (double)(0);
   30214           0 :         k = i;
   30215           0 :         while(k<=p->n-1)
   30216             :         {
   30217           0 :             e = e+a->ptr.p_double[k]*t.ptr.p_double[k];
   30218           0 :             k = k+2;
   30219             :         }
   30220           0 :         a->ptr.p_double[i] = e;
   30221             :     }
   30222             :     
   30223             :     /*
   30224             :      * Apply linear transformation which converts basis from intermediate
   30225             :      * one Fi=((x-C0)/S0)^i to final one Fi=((x-C)/S)^i.
   30226             :      *
   30227             :      * We have y=(x-C0)/S0, z=(x-C)/S, and coefficients A[] for basis Fi(y).
   30228             :      * Because we have y=A*z+B, for A=s/s0 and B=c/s0-c0/s0, we can perform
   30229             :      * substitution and get coefficients A_new[] in basis Fi(z).
   30230             :      */
   30231           0 :     ae_assert(vp.cnt>=p->n+1, "PolynomialBar2Pow: internal error", _state);
   30232           0 :     ae_assert(t.cnt>=p->n, "PolynomialBar2Pow: internal error", _state);
   30233           0 :     for(i=0; i<=p->n-1; i++)
   30234             :     {
   30235           0 :         t.ptr.p_double[i] = 0.0;
   30236             :     }
   30237           0 :     va = s/s0;
   30238           0 :     vb = c/s0-c0/s0;
   30239           0 :     ae_vector_set_length(&vai, p->n, _state);
   30240           0 :     ae_vector_set_length(&vbi, p->n, _state);
   30241           0 :     vai.ptr.p_double[0] = (double)(1);
   30242           0 :     vbi.ptr.p_double[0] = (double)(1);
   30243           0 :     for(k=1; k<=p->n-1; k++)
   30244             :     {
   30245           0 :         vai.ptr.p_double[k] = vai.ptr.p_double[k-1]*va;
   30246           0 :         vbi.ptr.p_double[k] = vbi.ptr.p_double[k-1]*vb;
   30247             :     }
   30248           0 :     for(k=0; k<=p->n-1; k++)
   30249             :     {
   30250             :         
   30251             :         /*
   30252             :          * Generate set of binomial coefficients in VP[]
   30253             :          */
   30254           0 :         if( k>0 )
   30255             :         {
   30256           0 :             vp.ptr.p_double[k] = (double)(1);
   30257           0 :             for(i=k-1; i>=1; i--)
   30258             :             {
   30259           0 :                 vp.ptr.p_double[i] = vp.ptr.p_double[i]+vp.ptr.p_double[i-1];
   30260             :             }
   30261           0 :             vp.ptr.p_double[0] = (double)(1);
   30262             :         }
   30263             :         else
   30264             :         {
   30265           0 :             vp.ptr.p_double[0] = (double)(1);
   30266             :         }
   30267             :         
   30268             :         /*
   30269             :          * Update T[] with expansion of K-th basis function
   30270             :          */
   30271           0 :         for(i=0; i<=k; i++)
   30272             :         {
   30273           0 :             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];
   30274             :         }
   30275             :     }
   30276           0 :     for(k=0; k<=p->n-1; k++)
   30277             :     {
   30278           0 :         a->ptr.p_double[k] = t.ptr.p_double[k];
   30279             :     }
   30280           0 :     ae_frame_leave(_state);
   30281           0 : }
   30282             : 
   30283             : 
   30284             : /*************************************************************************
   30285             : Conversion from power basis to barycentric representation.
   30286             : This function has O(N^2) complexity.
   30287             : 
   30288             : INPUT PARAMETERS:
   30289             :     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
   30290             :     N   -   number of coefficients (polynomial degree plus 1)
   30291             :             * if given, only leading N elements of A are used
   30292             :             * if not given, automatically determined from size of A
   30293             :     C   -   offset (see below); 0.0 is used as default value.
   30294             :     S   -   scale (see below);  1.0 is used as default value. S<>0.
   30295             : 
   30296             : OUTPUT PARAMETERS
   30297             :     P   -   polynomial in barycentric form
   30298             : 
   30299             : 
   30300             : NOTES:
   30301             : 1.  this function accepts offset and scale, which can be  set  to  improve
   30302             :     numerical properties of polynomial. For example, if you interpolate on
   30303             :     [-1,+1],  you  can  set C=0 and S=1 and convert from sum of 1, x, x^2,
   30304             :     x^3 and so on. In most cases you it is exactly what you need.
   30305             : 
   30306             :     However, if your interpolation model was built on [999,1001], you will
   30307             :     see significant growth of numerical errors when using {1, x, x^2, x^3}
   30308             :     as  input  basis.  Converting  from  sum  of  1, (x-1000), (x-1000)^2,
   30309             :     (x-1000)^3 will be better option (you have to specify 1000.0 as offset
   30310             :     C and 1.0 as scale S).
   30311             : 
   30312             : 2.  power basis is ill-conditioned and tricks described above can't  solve
   30313             :     this problem completely. This function  will  return barycentric model
   30314             :     in any case, but for N>8 accuracy well degrade. However, N's less than
   30315             :     5 are pretty safe.
   30316             : 
   30317             :   -- ALGLIB --
   30318             :      Copyright 30.09.2010 by Bochkanov Sergey
   30319             : *************************************************************************/
   30320           0 : void polynomialpow2bar(/* Real    */ ae_vector* a,
   30321             :      ae_int_t n,
   30322             :      double c,
   30323             :      double s,
   30324             :      barycentricinterpolant* p,
   30325             :      ae_state *_state)
   30326             : {
   30327             :     ae_frame _frame_block;
   30328             :     ae_int_t i;
   30329             :     ae_int_t k;
   30330             :     ae_vector y;
   30331             :     double vx;
   30332             :     double vy;
   30333             :     double px;
   30334             : 
   30335           0 :     ae_frame_make(_state, &_frame_block);
   30336           0 :     memset(&y, 0, sizeof(y));
   30337           0 :     _barycentricinterpolant_clear(p);
   30338           0 :     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
   30339             : 
   30340           0 :     ae_assert(ae_isfinite(c, _state), "PolynomialPow2Bar: C is not finite!", _state);
   30341           0 :     ae_assert(ae_isfinite(s, _state), "PolynomialPow2Bar: S is not finite!", _state);
   30342           0 :     ae_assert(ae_fp_neq(s,(double)(0)), "PolynomialPow2Bar: S is zero!", _state);
   30343           0 :     ae_assert(n>=1, "PolynomialPow2Bar: N<1", _state);
   30344           0 :     ae_assert(a->cnt>=n, "PolynomialPow2Bar: Length(A)<N", _state);
   30345           0 :     ae_assert(isfinitevector(a, n, _state), "PolynomialPow2Bar: A[] contains INF or NAN", _state);
   30346             :     
   30347             :     /*
   30348             :      * Calculate function values on a Chebyshev grid spanning [-1,+1]
   30349             :      */
   30350           0 :     ae_vector_set_length(&y, n, _state);
   30351           0 :     for(i=0; i<=n-1; i++)
   30352             :     {
   30353             :         
   30354             :         /*
   30355             :          * Calculate value on a grid spanning [-1,+1]
   30356             :          */
   30357           0 :         vx = ae_cos(ae_pi*(i+0.5)/n, _state);
   30358           0 :         vy = a->ptr.p_double[0];
   30359           0 :         px = vx;
   30360           0 :         for(k=1; k<=n-1; k++)
   30361             :         {
   30362           0 :             vy = vy+px*a->ptr.p_double[k];
   30363           0 :             px = px*vx;
   30364             :         }
   30365           0 :         y.ptr.p_double[i] = vy;
   30366             :     }
   30367             :     
   30368             :     /*
   30369             :      * Build barycentric interpolant, map grid from [-1,+1] to [A,B]
   30370             :      */
   30371           0 :     polynomialbuildcheb1(c-s, c+s, &y, n, p, _state);
   30372           0 :     ae_frame_leave(_state);
   30373           0 : }
   30374             : 
   30375             : 
   30376             : /*************************************************************************
   30377             : Lagrange intepolant: generation of the model on the general grid.
   30378             : This function has O(N^2) complexity.
   30379             : 
   30380             : INPUT PARAMETERS:
   30381             :     X   -   abscissas, array[0..N-1]
   30382             :     Y   -   function values, array[0..N-1]
   30383             :     N   -   number of points, N>=1
   30384             : 
   30385             : OUTPUT PARAMETERS
   30386             :     P   -   barycentric model which represents Lagrange interpolant
   30387             :             (see ratint unit info and BarycentricCalc() description for
   30388             :             more information).
   30389             : 
   30390             :   -- ALGLIB --
   30391             :      Copyright 02.12.2009 by Bochkanov Sergey
   30392             : *************************************************************************/
   30393           0 : void polynomialbuild(/* Real    */ ae_vector* x,
   30394             :      /* Real    */ ae_vector* y,
   30395             :      ae_int_t n,
   30396             :      barycentricinterpolant* p,
   30397             :      ae_state *_state)
   30398             : {
   30399             :     ae_frame _frame_block;
   30400             :     ae_vector _x;
   30401             :     ae_vector _y;
   30402             :     ae_int_t j;
   30403             :     ae_int_t k;
   30404             :     ae_vector w;
   30405             :     double b;
   30406             :     double a;
   30407             :     double v;
   30408             :     double mx;
   30409             :     ae_vector sortrbuf;
   30410             :     ae_vector sortrbuf2;
   30411             : 
   30412           0 :     ae_frame_make(_state, &_frame_block);
   30413           0 :     memset(&_x, 0, sizeof(_x));
   30414           0 :     memset(&_y, 0, sizeof(_y));
   30415           0 :     memset(&w, 0, sizeof(w));
   30416           0 :     memset(&sortrbuf, 0, sizeof(sortrbuf));
   30417           0 :     memset(&sortrbuf2, 0, sizeof(sortrbuf2));
   30418           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   30419           0 :     x = &_x;
   30420           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   30421           0 :     y = &_y;
   30422           0 :     _barycentricinterpolant_clear(p);
   30423           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   30424           0 :     ae_vector_init(&sortrbuf, 0, DT_REAL, _state, ae_true);
   30425           0 :     ae_vector_init(&sortrbuf2, 0, DT_REAL, _state, ae_true);
   30426             : 
   30427           0 :     ae_assert(n>0, "PolynomialBuild: N<=0!", _state);
   30428           0 :     ae_assert(x->cnt>=n, "PolynomialBuild: Length(X)<N!", _state);
   30429           0 :     ae_assert(y->cnt>=n, "PolynomialBuild: Length(Y)<N!", _state);
   30430           0 :     ae_assert(isfinitevector(x, n, _state), "PolynomialBuild: X contains infinite or NaN values!", _state);
   30431           0 :     ae_assert(isfinitevector(y, n, _state), "PolynomialBuild: Y contains infinite or NaN values!", _state);
   30432           0 :     tagsortfastr(x, y, &sortrbuf, &sortrbuf2, n, _state);
   30433           0 :     ae_assert(aredistinct(x, n, _state), "PolynomialBuild: at least two consequent points are too close!", _state);
   30434             :     
   30435             :     /*
   30436             :      * calculate W[j]
   30437             :      * multi-pass algorithm is used to avoid overflow
   30438             :      */
   30439           0 :     ae_vector_set_length(&w, n, _state);
   30440           0 :     a = x->ptr.p_double[0];
   30441           0 :     b = x->ptr.p_double[0];
   30442           0 :     for(j=0; j<=n-1; j++)
   30443             :     {
   30444           0 :         w.ptr.p_double[j] = (double)(1);
   30445           0 :         a = ae_minreal(a, x->ptr.p_double[j], _state);
   30446           0 :         b = ae_maxreal(b, x->ptr.p_double[j], _state);
   30447             :     }
   30448           0 :     for(k=0; k<=n-1; k++)
   30449             :     {
   30450             :         
   30451             :         /*
   30452             :          * W[K] is used instead of 0.0 because
   30453             :          * cycle on J does not touch K-th element
   30454             :          * and we MUST get maximum from ALL elements
   30455             :          */
   30456           0 :         mx = ae_fabs(w.ptr.p_double[k], _state);
   30457           0 :         for(j=0; j<=n-1; j++)
   30458             :         {
   30459           0 :             if( j!=k )
   30460             :             {
   30461           0 :                 v = (b-a)/(x->ptr.p_double[j]-x->ptr.p_double[k]);
   30462           0 :                 w.ptr.p_double[j] = w.ptr.p_double[j]*v;
   30463           0 :                 mx = ae_maxreal(mx, ae_fabs(w.ptr.p_double[j], _state), _state);
   30464             :             }
   30465             :         }
   30466           0 :         if( k%5==0 )
   30467             :         {
   30468             :             
   30469             :             /*
   30470             :              * every 5-th run we renormalize W[]
   30471             :              */
   30472           0 :             v = 1/mx;
   30473           0 :             ae_v_muld(&w.ptr.p_double[0], 1, ae_v_len(0,n-1), v);
   30474             :         }
   30475             :     }
   30476           0 :     barycentricbuildxyw(x, y, &w, n, p, _state);
   30477           0 :     ae_frame_leave(_state);
   30478           0 : }
   30479             : 
   30480             : 
   30481             : /*************************************************************************
   30482             : Lagrange intepolant: generation of the model on equidistant grid.
   30483             : This function has O(N) complexity.
   30484             : 
   30485             : INPUT PARAMETERS:
   30486             :     A   -   left boundary of [A,B]
   30487             :     B   -   right boundary of [A,B]
   30488             :     Y   -   function values at the nodes, array[0..N-1]
   30489             :     N   -   number of points, N>=1
   30490             :             for N=1 a constant model is constructed.
   30491             : 
   30492             : OUTPUT PARAMETERS
   30493             :     P   -   barycentric model which represents Lagrange interpolant
   30494             :             (see ratint unit info and BarycentricCalc() description for
   30495             :             more information).
   30496             : 
   30497             :   -- ALGLIB --
   30498             :      Copyright 03.12.2009 by Bochkanov Sergey
   30499             : *************************************************************************/
   30500           0 : void polynomialbuildeqdist(double a,
   30501             :      double b,
   30502             :      /* Real    */ ae_vector* y,
   30503             :      ae_int_t n,
   30504             :      barycentricinterpolant* p,
   30505             :      ae_state *_state)
   30506             : {
   30507             :     ae_frame _frame_block;
   30508             :     ae_int_t i;
   30509             :     ae_vector w;
   30510             :     ae_vector x;
   30511             :     double v;
   30512             : 
   30513           0 :     ae_frame_make(_state, &_frame_block);
   30514           0 :     memset(&w, 0, sizeof(w));
   30515           0 :     memset(&x, 0, sizeof(x));
   30516           0 :     _barycentricinterpolant_clear(p);
   30517           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   30518           0 :     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
   30519             : 
   30520           0 :     ae_assert(n>0, "PolynomialBuildEqDist: N<=0!", _state);
   30521           0 :     ae_assert(y->cnt>=n, "PolynomialBuildEqDist: Length(Y)<N!", _state);
   30522           0 :     ae_assert(ae_isfinite(a, _state), "PolynomialBuildEqDist: A is infinite or NaN!", _state);
   30523           0 :     ae_assert(ae_isfinite(b, _state), "PolynomialBuildEqDist: B is infinite or NaN!", _state);
   30524           0 :     ae_assert(isfinitevector(y, n, _state), "PolynomialBuildEqDist: Y contains infinite or NaN values!", _state);
   30525           0 :     ae_assert(ae_fp_neq(b,a), "PolynomialBuildEqDist: B=A!", _state);
   30526           0 :     ae_assert(ae_fp_neq(a+(b-a)/n,a), "PolynomialBuildEqDist: B is too close to A!", _state);
   30527             :     
   30528             :     /*
   30529             :      * Special case: N=1
   30530             :      */
   30531           0 :     if( n==1 )
   30532             :     {
   30533           0 :         ae_vector_set_length(&x, 1, _state);
   30534           0 :         ae_vector_set_length(&w, 1, _state);
   30535           0 :         x.ptr.p_double[0] = 0.5*(b+a);
   30536           0 :         w.ptr.p_double[0] = (double)(1);
   30537           0 :         barycentricbuildxyw(&x, y, &w, 1, p, _state);
   30538           0 :         ae_frame_leave(_state);
   30539           0 :         return;
   30540             :     }
   30541             :     
   30542             :     /*
   30543             :      * general case
   30544             :      */
   30545           0 :     ae_vector_set_length(&x, n, _state);
   30546           0 :     ae_vector_set_length(&w, n, _state);
   30547           0 :     v = (double)(1);
   30548           0 :     for(i=0; i<=n-1; i++)
   30549             :     {
   30550           0 :         w.ptr.p_double[i] = v;
   30551           0 :         x.ptr.p_double[i] = a+(b-a)*i/(n-1);
   30552           0 :         v = -v*(n-1-i);
   30553           0 :         v = v/(i+1);
   30554             :     }
   30555           0 :     barycentricbuildxyw(&x, y, &w, n, p, _state);
   30556           0 :     ae_frame_leave(_state);
   30557             : }
   30558             : 
   30559             : 
   30560             : /*************************************************************************
   30561             : Lagrange intepolant on Chebyshev grid (first kind).
   30562             : This function has O(N) complexity.
   30563             : 
   30564             : INPUT PARAMETERS:
   30565             :     A   -   left boundary of [A,B]
   30566             :     B   -   right boundary of [A,B]
   30567             :     Y   -   function values at the nodes, array[0..N-1],
   30568             :             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)))
   30569             :     N   -   number of points, N>=1
   30570             :             for N=1 a constant model is constructed.
   30571             : 
   30572             : OUTPUT PARAMETERS
   30573             :     P   -   barycentric model which represents Lagrange interpolant
   30574             :             (see ratint unit info and BarycentricCalc() description for
   30575             :             more information).
   30576             : 
   30577             :   -- ALGLIB --
   30578             :      Copyright 03.12.2009 by Bochkanov Sergey
   30579             : *************************************************************************/
   30580           0 : void polynomialbuildcheb1(double a,
   30581             :      double b,
   30582             :      /* Real    */ ae_vector* y,
   30583             :      ae_int_t n,
   30584             :      barycentricinterpolant* p,
   30585             :      ae_state *_state)
   30586             : {
   30587             :     ae_frame _frame_block;
   30588             :     ae_int_t i;
   30589             :     ae_vector w;
   30590             :     ae_vector x;
   30591             :     double v;
   30592             :     double t;
   30593             : 
   30594           0 :     ae_frame_make(_state, &_frame_block);
   30595           0 :     memset(&w, 0, sizeof(w));
   30596           0 :     memset(&x, 0, sizeof(x));
   30597           0 :     _barycentricinterpolant_clear(p);
   30598           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   30599           0 :     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
   30600             : 
   30601           0 :     ae_assert(n>0, "PolynomialBuildCheb1: N<=0!", _state);
   30602           0 :     ae_assert(y->cnt>=n, "PolynomialBuildCheb1: Length(Y)<N!", _state);
   30603           0 :     ae_assert(ae_isfinite(a, _state), "PolynomialBuildCheb1: A is infinite or NaN!", _state);
   30604           0 :     ae_assert(ae_isfinite(b, _state), "PolynomialBuildCheb1: B is infinite or NaN!", _state);
   30605           0 :     ae_assert(isfinitevector(y, n, _state), "PolynomialBuildCheb1: Y contains infinite or NaN values!", _state);
   30606           0 :     ae_assert(ae_fp_neq(b,a), "PolynomialBuildCheb1: B=A!", _state);
   30607             :     
   30608             :     /*
   30609             :      * Special case: N=1
   30610             :      */
   30611           0 :     if( n==1 )
   30612             :     {
   30613           0 :         ae_vector_set_length(&x, 1, _state);
   30614           0 :         ae_vector_set_length(&w, 1, _state);
   30615           0 :         x.ptr.p_double[0] = 0.5*(b+a);
   30616           0 :         w.ptr.p_double[0] = (double)(1);
   30617           0 :         barycentricbuildxyw(&x, y, &w, 1, p, _state);
   30618           0 :         ae_frame_leave(_state);
   30619           0 :         return;
   30620             :     }
   30621             :     
   30622             :     /*
   30623             :      * general case
   30624             :      */
   30625           0 :     ae_vector_set_length(&x, n, _state);
   30626           0 :     ae_vector_set_length(&w, n, _state);
   30627           0 :     v = (double)(1);
   30628           0 :     for(i=0; i<=n-1; i++)
   30629             :     {
   30630           0 :         t = ae_tan(0.5*ae_pi*(2*i+1)/(2*n), _state);
   30631           0 :         w.ptr.p_double[i] = 2*v*t/(1+ae_sqr(t, _state));
   30632           0 :         x.ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*(1-ae_sqr(t, _state))/(1+ae_sqr(t, _state));
   30633           0 :         v = -v;
   30634             :     }
   30635           0 :     barycentricbuildxyw(&x, y, &w, n, p, _state);
   30636           0 :     ae_frame_leave(_state);
   30637             : }
   30638             : 
   30639             : 
   30640             : /*************************************************************************
   30641             : Lagrange intepolant on Chebyshev grid (second kind).
   30642             : This function has O(N) complexity.
   30643             : 
   30644             : INPUT PARAMETERS:
   30645             :     A   -   left boundary of [A,B]
   30646             :     B   -   right boundary of [A,B]
   30647             :     Y   -   function values at the nodes, array[0..N-1],
   30648             :             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)))
   30649             :     N   -   number of points, N>=1
   30650             :             for N=1 a constant model is constructed.
   30651             : 
   30652             : OUTPUT PARAMETERS
   30653             :     P   -   barycentric model which represents Lagrange interpolant
   30654             :             (see ratint unit info and BarycentricCalc() description for
   30655             :             more information).
   30656             : 
   30657             :   -- ALGLIB --
   30658             :      Copyright 03.12.2009 by Bochkanov Sergey
   30659             : *************************************************************************/
   30660           0 : void polynomialbuildcheb2(double a,
   30661             :      double b,
   30662             :      /* Real    */ ae_vector* y,
   30663             :      ae_int_t n,
   30664             :      barycentricinterpolant* p,
   30665             :      ae_state *_state)
   30666             : {
   30667             :     ae_frame _frame_block;
   30668             :     ae_int_t i;
   30669             :     ae_vector w;
   30670             :     ae_vector x;
   30671             :     double v;
   30672             : 
   30673           0 :     ae_frame_make(_state, &_frame_block);
   30674           0 :     memset(&w, 0, sizeof(w));
   30675           0 :     memset(&x, 0, sizeof(x));
   30676           0 :     _barycentricinterpolant_clear(p);
   30677           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   30678           0 :     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
   30679             : 
   30680           0 :     ae_assert(n>0, "PolynomialBuildCheb2: N<=0!", _state);
   30681           0 :     ae_assert(y->cnt>=n, "PolynomialBuildCheb2: Length(Y)<N!", _state);
   30682           0 :     ae_assert(ae_isfinite(a, _state), "PolynomialBuildCheb2: A is infinite or NaN!", _state);
   30683           0 :     ae_assert(ae_isfinite(b, _state), "PolynomialBuildCheb2: B is infinite or NaN!", _state);
   30684           0 :     ae_assert(ae_fp_neq(b,a), "PolynomialBuildCheb2: B=A!", _state);
   30685           0 :     ae_assert(isfinitevector(y, n, _state), "PolynomialBuildCheb2: Y contains infinite or NaN values!", _state);
   30686             :     
   30687             :     /*
   30688             :      * Special case: N=1
   30689             :      */
   30690           0 :     if( n==1 )
   30691             :     {
   30692           0 :         ae_vector_set_length(&x, 1, _state);
   30693           0 :         ae_vector_set_length(&w, 1, _state);
   30694           0 :         x.ptr.p_double[0] = 0.5*(b+a);
   30695           0 :         w.ptr.p_double[0] = (double)(1);
   30696           0 :         barycentricbuildxyw(&x, y, &w, 1, p, _state);
   30697           0 :         ae_frame_leave(_state);
   30698           0 :         return;
   30699             :     }
   30700             :     
   30701             :     /*
   30702             :      * general case
   30703             :      */
   30704           0 :     ae_vector_set_length(&x, n, _state);
   30705           0 :     ae_vector_set_length(&w, n, _state);
   30706           0 :     v = (double)(1);
   30707           0 :     for(i=0; i<=n-1; i++)
   30708             :     {
   30709           0 :         if( i==0||i==n-1 )
   30710             :         {
   30711           0 :             w.ptr.p_double[i] = v*0.5;
   30712             :         }
   30713             :         else
   30714             :         {
   30715           0 :             w.ptr.p_double[i] = v;
   30716             :         }
   30717           0 :         x.ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*i/(n-1), _state);
   30718           0 :         v = -v;
   30719             :     }
   30720           0 :     barycentricbuildxyw(&x, y, &w, n, p, _state);
   30721           0 :     ae_frame_leave(_state);
   30722             : }
   30723             : 
   30724             : 
   30725             : /*************************************************************************
   30726             : Fast equidistant polynomial interpolation function with O(N) complexity
   30727             : 
   30728             : INPUT PARAMETERS:
   30729             :     A   -   left boundary of [A,B]
   30730             :     B   -   right boundary of [A,B]
   30731             :     F   -   function values, array[0..N-1]
   30732             :     N   -   number of points on equidistant grid, N>=1
   30733             :             for N=1 a constant model is constructed.
   30734             :     T   -   position where P(x) is calculated
   30735             : 
   30736             : RESULT
   30737             :     value of the Lagrange interpolant at T
   30738             :     
   30739             : IMPORTANT
   30740             :     this function provides fast interface which is not overflow-safe
   30741             :     nor it is very precise.
   30742             :     the best option is to use  PolynomialBuildEqDist()/BarycentricCalc()
   30743             :     subroutines unless you are pretty sure that your data will not result
   30744             :     in overflow.
   30745             : 
   30746             :   -- ALGLIB --
   30747             :      Copyright 02.12.2009 by Bochkanov Sergey
   30748             : *************************************************************************/
   30749           0 : double polynomialcalceqdist(double a,
   30750             :      double b,
   30751             :      /* Real    */ ae_vector* f,
   30752             :      ae_int_t n,
   30753             :      double t,
   30754             :      ae_state *_state)
   30755             : {
   30756             :     double s1;
   30757             :     double s2;
   30758             :     double v;
   30759             :     double threshold;
   30760             :     double s;
   30761             :     double h;
   30762             :     ae_int_t i;
   30763             :     ae_int_t j;
   30764             :     double w;
   30765             :     double x;
   30766             :     double result;
   30767             : 
   30768             : 
   30769           0 :     ae_assert(n>0, "PolynomialCalcEqDist: N<=0!", _state);
   30770           0 :     ae_assert(f->cnt>=n, "PolynomialCalcEqDist: Length(F)<N!", _state);
   30771           0 :     ae_assert(ae_isfinite(a, _state), "PolynomialCalcEqDist: A is infinite or NaN!", _state);
   30772           0 :     ae_assert(ae_isfinite(b, _state), "PolynomialCalcEqDist: B is infinite or NaN!", _state);
   30773           0 :     ae_assert(isfinitevector(f, n, _state), "PolynomialCalcEqDist: F contains infinite or NaN values!", _state);
   30774           0 :     ae_assert(ae_fp_neq(b,a), "PolynomialCalcEqDist: B=A!", _state);
   30775           0 :     ae_assert(!ae_isinf(t, _state), "PolynomialCalcEqDist: T is infinite!", _state);
   30776             :     
   30777             :     /*
   30778             :      * Special case: T is NAN
   30779             :      */
   30780           0 :     if( ae_isnan(t, _state) )
   30781             :     {
   30782           0 :         result = _state->v_nan;
   30783           0 :         return result;
   30784             :     }
   30785             :     
   30786             :     /*
   30787             :      * Special case: N=1
   30788             :      */
   30789           0 :     if( n==1 )
   30790             :     {
   30791           0 :         result = f->ptr.p_double[0];
   30792           0 :         return result;
   30793             :     }
   30794             :     
   30795             :     /*
   30796             :      * First, decide: should we use "safe" formula (guarded
   30797             :      * against overflow) or fast one?
   30798             :      */
   30799           0 :     threshold = ae_sqrt(ae_minrealnumber, _state);
   30800           0 :     j = 0;
   30801           0 :     s = t-a;
   30802           0 :     for(i=1; i<=n-1; i++)
   30803             :     {
   30804           0 :         x = a+(double)i/(double)(n-1)*(b-a);
   30805           0 :         if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) )
   30806             :         {
   30807           0 :             s = t-x;
   30808           0 :             j = i;
   30809             :         }
   30810             :     }
   30811           0 :     if( ae_fp_eq(s,(double)(0)) )
   30812             :     {
   30813           0 :         result = f->ptr.p_double[j];
   30814           0 :         return result;
   30815             :     }
   30816           0 :     if( ae_fp_greater(ae_fabs(s, _state),threshold) )
   30817             :     {
   30818             :         
   30819             :         /*
   30820             :          * use fast formula
   30821             :          */
   30822           0 :         j = -1;
   30823           0 :         s = 1.0;
   30824             :     }
   30825             :     
   30826             :     /*
   30827             :      * Calculate using safe or fast barycentric formula
   30828             :      */
   30829           0 :     s1 = (double)(0);
   30830           0 :     s2 = (double)(0);
   30831           0 :     w = 1.0;
   30832           0 :     h = (b-a)/(n-1);
   30833           0 :     for(i=0; i<=n-1; i++)
   30834             :     {
   30835           0 :         if( i!=j )
   30836             :         {
   30837           0 :             v = s*w/(t-(a+i*h));
   30838           0 :             s1 = s1+v*f->ptr.p_double[i];
   30839           0 :             s2 = s2+v;
   30840             :         }
   30841             :         else
   30842             :         {
   30843           0 :             v = w;
   30844           0 :             s1 = s1+v*f->ptr.p_double[i];
   30845           0 :             s2 = s2+v;
   30846             :         }
   30847           0 :         w = -w*(n-1-i);
   30848           0 :         w = w/(i+1);
   30849             :     }
   30850           0 :     result = s1/s2;
   30851           0 :     return result;
   30852             : }
   30853             : 
   30854             : 
   30855             : /*************************************************************************
   30856             : Fast polynomial interpolation function on Chebyshev points (first kind)
   30857             : with O(N) complexity.
   30858             : 
   30859             : INPUT PARAMETERS:
   30860             :     A   -   left boundary of [A,B]
   30861             :     B   -   right boundary of [A,B]
   30862             :     F   -   function values, array[0..N-1]
   30863             :     N   -   number of points on Chebyshev grid (first kind),
   30864             :             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))
   30865             :             for N=1 a constant model is constructed.
   30866             :     T   -   position where P(x) is calculated
   30867             : 
   30868             : RESULT
   30869             :     value of the Lagrange interpolant at T
   30870             : 
   30871             : IMPORTANT
   30872             :     this function provides fast interface which is not overflow-safe
   30873             :     nor it is very precise.
   30874             :     the best option is to use  PolIntBuildCheb1()/BarycentricCalc()
   30875             :     subroutines unless you are pretty sure that your data will not result
   30876             :     in overflow.
   30877             : 
   30878             :   -- ALGLIB --
   30879             :      Copyright 02.12.2009 by Bochkanov Sergey
   30880             : *************************************************************************/
   30881           0 : double polynomialcalccheb1(double a,
   30882             :      double b,
   30883             :      /* Real    */ ae_vector* f,
   30884             :      ae_int_t n,
   30885             :      double t,
   30886             :      ae_state *_state)
   30887             : {
   30888             :     double s1;
   30889             :     double s2;
   30890             :     double v;
   30891             :     double threshold;
   30892             :     double s;
   30893             :     ae_int_t i;
   30894             :     ae_int_t j;
   30895             :     double a0;
   30896             :     double delta;
   30897             :     double alpha;
   30898             :     double beta;
   30899             :     double ca;
   30900             :     double sa;
   30901             :     double tempc;
   30902             :     double temps;
   30903             :     double x;
   30904             :     double w;
   30905             :     double p1;
   30906             :     double result;
   30907             : 
   30908             : 
   30909           0 :     ae_assert(n>0, "PolynomialCalcCheb1: N<=0!", _state);
   30910           0 :     ae_assert(f->cnt>=n, "PolynomialCalcCheb1: Length(F)<N!", _state);
   30911           0 :     ae_assert(ae_isfinite(a, _state), "PolynomialCalcCheb1: A is infinite or NaN!", _state);
   30912           0 :     ae_assert(ae_isfinite(b, _state), "PolynomialCalcCheb1: B is infinite or NaN!", _state);
   30913           0 :     ae_assert(isfinitevector(f, n, _state), "PolynomialCalcCheb1: F contains infinite or NaN values!", _state);
   30914           0 :     ae_assert(ae_fp_neq(b,a), "PolynomialCalcCheb1: B=A!", _state);
   30915           0 :     ae_assert(!ae_isinf(t, _state), "PolynomialCalcCheb1: T is infinite!", _state);
   30916             :     
   30917             :     /*
   30918             :      * Special case: T is NAN
   30919             :      */
   30920           0 :     if( ae_isnan(t, _state) )
   30921             :     {
   30922           0 :         result = _state->v_nan;
   30923           0 :         return result;
   30924             :     }
   30925             :     
   30926             :     /*
   30927             :      * Special case: N=1
   30928             :      */
   30929           0 :     if( n==1 )
   30930             :     {
   30931           0 :         result = f->ptr.p_double[0];
   30932           0 :         return result;
   30933             :     }
   30934             :     
   30935             :     /*
   30936             :      * Prepare information for the recurrence formula
   30937             :      * used to calculate sin(pi*(2j+1)/(2n+2)) and
   30938             :      * cos(pi*(2j+1)/(2n+2)):
   30939             :      *
   30940             :      * A0    = pi/(2n+2)
   30941             :      * Delta = pi/(n+1)
   30942             :      * Alpha = 2 sin^2 (Delta/2)
   30943             :      * Beta  = sin(Delta)
   30944             :      *
   30945             :      * so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta).
   30946             :      * Then we use
   30947             :      *
   30948             :      * sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x))
   30949             :      * cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x))
   30950             :      *
   30951             :      * to repeatedly calculate sin(..) and cos(..).
   30952             :      */
   30953           0 :     threshold = ae_sqrt(ae_minrealnumber, _state);
   30954           0 :     t = (t-0.5*(a+b))/(0.5*(b-a));
   30955           0 :     a0 = ae_pi/(2*(n-1)+2);
   30956           0 :     delta = 2*ae_pi/(2*(n-1)+2);
   30957           0 :     alpha = 2*ae_sqr(ae_sin(delta/2, _state), _state);
   30958           0 :     beta = ae_sin(delta, _state);
   30959             :     
   30960             :     /*
   30961             :      * First, decide: should we use "safe" formula (guarded
   30962             :      * against overflow) or fast one?
   30963             :      */
   30964           0 :     ca = ae_cos(a0, _state);
   30965           0 :     sa = ae_sin(a0, _state);
   30966           0 :     j = 0;
   30967           0 :     x = ca;
   30968           0 :     s = t-x;
   30969           0 :     for(i=1; i<=n-1; i++)
   30970             :     {
   30971             :         
   30972             :         /*
   30973             :          * Next X[i]
   30974             :          */
   30975           0 :         temps = sa-(alpha*sa-beta*ca);
   30976           0 :         tempc = ca-(alpha*ca+beta*sa);
   30977           0 :         sa = temps;
   30978           0 :         ca = tempc;
   30979           0 :         x = ca;
   30980             :         
   30981             :         /*
   30982             :          * Use X[i]
   30983             :          */
   30984           0 :         if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) )
   30985             :         {
   30986           0 :             s = t-x;
   30987           0 :             j = i;
   30988             :         }
   30989             :     }
   30990           0 :     if( ae_fp_eq(s,(double)(0)) )
   30991             :     {
   30992           0 :         result = f->ptr.p_double[j];
   30993           0 :         return result;
   30994             :     }
   30995           0 :     if( ae_fp_greater(ae_fabs(s, _state),threshold) )
   30996             :     {
   30997             :         
   30998             :         /*
   30999             :          * use fast formula
   31000             :          */
   31001           0 :         j = -1;
   31002           0 :         s = 1.0;
   31003             :     }
   31004             :     
   31005             :     /*
   31006             :      * Calculate using safe or fast barycentric formula
   31007             :      */
   31008           0 :     s1 = (double)(0);
   31009           0 :     s2 = (double)(0);
   31010           0 :     ca = ae_cos(a0, _state);
   31011           0 :     sa = ae_sin(a0, _state);
   31012           0 :     p1 = 1.0;
   31013           0 :     for(i=0; i<=n-1; i++)
   31014             :     {
   31015             :         
   31016             :         /*
   31017             :          * Calculate X[i], W[i]
   31018             :          */
   31019           0 :         x = ca;
   31020           0 :         w = p1*sa;
   31021             :         
   31022             :         /*
   31023             :          * Proceed
   31024             :          */
   31025           0 :         if( i!=j )
   31026             :         {
   31027           0 :             v = s*w/(t-x);
   31028           0 :             s1 = s1+v*f->ptr.p_double[i];
   31029           0 :             s2 = s2+v;
   31030             :         }
   31031             :         else
   31032             :         {
   31033           0 :             v = w;
   31034           0 :             s1 = s1+v*f->ptr.p_double[i];
   31035           0 :             s2 = s2+v;
   31036             :         }
   31037             :         
   31038             :         /*
   31039             :          * Next CA, SA, P1
   31040             :          */
   31041           0 :         temps = sa-(alpha*sa-beta*ca);
   31042           0 :         tempc = ca-(alpha*ca+beta*sa);
   31043           0 :         sa = temps;
   31044           0 :         ca = tempc;
   31045           0 :         p1 = -p1;
   31046             :     }
   31047           0 :     result = s1/s2;
   31048           0 :     return result;
   31049             : }
   31050             : 
   31051             : 
   31052             : /*************************************************************************
   31053             : Fast polynomial interpolation function on Chebyshev points (second kind)
   31054             : with O(N) complexity.
   31055             : 
   31056             : INPUT PARAMETERS:
   31057             :     A   -   left boundary of [A,B]
   31058             :     B   -   right boundary of [A,B]
   31059             :     F   -   function values, array[0..N-1]
   31060             :     N   -   number of points on Chebyshev grid (second kind),
   31061             :             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))
   31062             :             for N=1 a constant model is constructed.
   31063             :     T   -   position where P(x) is calculated
   31064             : 
   31065             : RESULT
   31066             :     value of the Lagrange interpolant at T
   31067             : 
   31068             : IMPORTANT
   31069             :     this function provides fast interface which is not overflow-safe
   31070             :     nor it is very precise.
   31071             :     the best option is to use PolIntBuildCheb2()/BarycentricCalc()
   31072             :     subroutines unless you are pretty sure that your data will not result
   31073             :     in overflow.
   31074             : 
   31075             :   -- ALGLIB --
   31076             :      Copyright 02.12.2009 by Bochkanov Sergey
   31077             : *************************************************************************/
   31078           0 : double polynomialcalccheb2(double a,
   31079             :      double b,
   31080             :      /* Real    */ ae_vector* f,
   31081             :      ae_int_t n,
   31082             :      double t,
   31083             :      ae_state *_state)
   31084             : {
   31085             :     double s1;
   31086             :     double s2;
   31087             :     double v;
   31088             :     double threshold;
   31089             :     double s;
   31090             :     ae_int_t i;
   31091             :     ae_int_t j;
   31092             :     double a0;
   31093             :     double delta;
   31094             :     double alpha;
   31095             :     double beta;
   31096             :     double ca;
   31097             :     double sa;
   31098             :     double tempc;
   31099             :     double temps;
   31100             :     double x;
   31101             :     double w;
   31102             :     double p1;
   31103             :     double result;
   31104             : 
   31105             : 
   31106           0 :     ae_assert(n>0, "PolynomialCalcCheb2: N<=0!", _state);
   31107           0 :     ae_assert(f->cnt>=n, "PolynomialCalcCheb2: Length(F)<N!", _state);
   31108           0 :     ae_assert(ae_isfinite(a, _state), "PolynomialCalcCheb2: A is infinite or NaN!", _state);
   31109           0 :     ae_assert(ae_isfinite(b, _state), "PolynomialCalcCheb2: B is infinite or NaN!", _state);
   31110           0 :     ae_assert(ae_fp_neq(b,a), "PolynomialCalcCheb2: B=A!", _state);
   31111           0 :     ae_assert(isfinitevector(f, n, _state), "PolynomialCalcCheb2: F contains infinite or NaN values!", _state);
   31112           0 :     ae_assert(!ae_isinf(t, _state), "PolynomialCalcEqDist: T is infinite!", _state);
   31113             :     
   31114             :     /*
   31115             :      * Special case: T is NAN
   31116             :      */
   31117           0 :     if( ae_isnan(t, _state) )
   31118             :     {
   31119           0 :         result = _state->v_nan;
   31120           0 :         return result;
   31121             :     }
   31122             :     
   31123             :     /*
   31124             :      * Special case: N=1
   31125             :      */
   31126           0 :     if( n==1 )
   31127             :     {
   31128           0 :         result = f->ptr.p_double[0];
   31129           0 :         return result;
   31130             :     }
   31131             :     
   31132             :     /*
   31133             :      * Prepare information for the recurrence formula
   31134             :      * used to calculate sin(pi*i/n) and
   31135             :      * cos(pi*i/n):
   31136             :      *
   31137             :      * A0    = 0
   31138             :      * Delta = pi/n
   31139             :      * Alpha = 2 sin^2 (Delta/2)
   31140             :      * Beta  = sin(Delta)
   31141             :      *
   31142             :      * so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta).
   31143             :      * Then we use
   31144             :      *
   31145             :      * sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x))
   31146             :      * cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x))
   31147             :      *
   31148             :      * to repeatedly calculate sin(..) and cos(..).
   31149             :      */
   31150           0 :     threshold = ae_sqrt(ae_minrealnumber, _state);
   31151           0 :     t = (t-0.5*(a+b))/(0.5*(b-a));
   31152           0 :     a0 = 0.0;
   31153           0 :     delta = ae_pi/(n-1);
   31154           0 :     alpha = 2*ae_sqr(ae_sin(delta/2, _state), _state);
   31155           0 :     beta = ae_sin(delta, _state);
   31156             :     
   31157             :     /*
   31158             :      * First, decide: should we use "safe" formula (guarded
   31159             :      * against overflow) or fast one?
   31160             :      */
   31161           0 :     ca = ae_cos(a0, _state);
   31162           0 :     sa = ae_sin(a0, _state);
   31163           0 :     j = 0;
   31164           0 :     x = ca;
   31165           0 :     s = t-x;
   31166           0 :     for(i=1; i<=n-1; i++)
   31167             :     {
   31168             :         
   31169             :         /*
   31170             :          * Next X[i]
   31171             :          */
   31172           0 :         temps = sa-(alpha*sa-beta*ca);
   31173           0 :         tempc = ca-(alpha*ca+beta*sa);
   31174           0 :         sa = temps;
   31175           0 :         ca = tempc;
   31176           0 :         x = ca;
   31177             :         
   31178             :         /*
   31179             :          * Use X[i]
   31180             :          */
   31181           0 :         if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) )
   31182             :         {
   31183           0 :             s = t-x;
   31184           0 :             j = i;
   31185             :         }
   31186             :     }
   31187           0 :     if( ae_fp_eq(s,(double)(0)) )
   31188             :     {
   31189           0 :         result = f->ptr.p_double[j];
   31190           0 :         return result;
   31191             :     }
   31192           0 :     if( ae_fp_greater(ae_fabs(s, _state),threshold) )
   31193             :     {
   31194             :         
   31195             :         /*
   31196             :          * use fast formula
   31197             :          */
   31198           0 :         j = -1;
   31199           0 :         s = 1.0;
   31200             :     }
   31201             :     
   31202             :     /*
   31203             :      * Calculate using safe or fast barycentric formula
   31204             :      */
   31205           0 :     s1 = (double)(0);
   31206           0 :     s2 = (double)(0);
   31207           0 :     ca = ae_cos(a0, _state);
   31208           0 :     sa = ae_sin(a0, _state);
   31209           0 :     p1 = 1.0;
   31210           0 :     for(i=0; i<=n-1; i++)
   31211             :     {
   31212             :         
   31213             :         /*
   31214             :          * Calculate X[i], W[i]
   31215             :          */
   31216           0 :         x = ca;
   31217           0 :         if( i==0||i==n-1 )
   31218             :         {
   31219           0 :             w = 0.5*p1;
   31220             :         }
   31221             :         else
   31222             :         {
   31223           0 :             w = 1.0*p1;
   31224             :         }
   31225             :         
   31226             :         /*
   31227             :          * Proceed
   31228             :          */
   31229           0 :         if( i!=j )
   31230             :         {
   31231           0 :             v = s*w/(t-x);
   31232           0 :             s1 = s1+v*f->ptr.p_double[i];
   31233           0 :             s2 = s2+v;
   31234             :         }
   31235             :         else
   31236             :         {
   31237           0 :             v = w;
   31238           0 :             s1 = s1+v*f->ptr.p_double[i];
   31239           0 :             s2 = s2+v;
   31240             :         }
   31241             :         
   31242             :         /*
   31243             :          * Next CA, SA, P1
   31244             :          */
   31245           0 :         temps = sa-(alpha*sa-beta*ca);
   31246           0 :         tempc = ca-(alpha*ca+beta*sa);
   31247           0 :         sa = temps;
   31248           0 :         ca = tempc;
   31249           0 :         p1 = -p1;
   31250             :     }
   31251           0 :     result = s1/s2;
   31252           0 :     return result;
   31253             : }
   31254             : 
   31255             : 
   31256             : #endif
   31257             : #if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD)
   31258             : 
   31259             : 
   31260             : /*************************************************************************
   31261             : This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
   31262             : Peucker algorithm, which stops after generating specified number of linear
   31263             : sections.
   31264             : 
   31265             : IMPORTANT:
   31266             : * it does NOT perform least-squares fitting; it  builds  curve,  but  this
   31267             :   curve does not minimize some least squares metric.  See  description  of
   31268             :   RDP algorithm (say, in Wikipedia) for more details on WHAT is performed.
   31269             : * this function does NOT work with parametric curves  (i.e.  curves  which
   31270             :   can be represented as {X(t),Y(t)}. It works with curves   which  can  be
   31271             :   represented as Y(X). Thus,  it  is  impossible  to  model  figures  like
   31272             :   circles  with  this  functions.
   31273             :   If  you  want  to  work  with  parametric   curves,   you   should   use
   31274             :   ParametricRDPFixed() function provided  by  "Parametric"  subpackage  of
   31275             :   "Interpolation" package.
   31276             : 
   31277             : INPUT PARAMETERS:
   31278             :     X       -   array of X-coordinates:
   31279             :                 * at least N elements
   31280             :                 * can be unordered (points are automatically sorted)
   31281             :                 * this function may accept non-distinct X (see below for
   31282             :                   more information on handling of such inputs)
   31283             :     Y       -   array of Y-coordinates:
   31284             :                 * at least N elements
   31285             :     N       -   number of elements in X/Y
   31286             :     M       -   desired number of sections:
   31287             :                 * at most M sections are generated by this function
   31288             :                 * less than M sections can be generated if we have N<M
   31289             :                   (or some X are non-distinct).
   31290             : 
   31291             : OUTPUT PARAMETERS:
   31292             :     X2      -   X-values of corner points for piecewise approximation,
   31293             :                 has length NSections+1 or zero (for NSections=0).
   31294             :     Y2      -   Y-values of corner points,
   31295             :                 has length NSections+1 or zero (for NSections=0).
   31296             :     NSections-  number of sections found by algorithm, NSections<=M,
   31297             :                 NSections can be zero for degenerate datasets
   31298             :                 (N<=1 or all X[] are non-distinct).
   31299             : 
   31300             : NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is  a  first  point  of
   31301             :       curve, (X2[NSection-1],Y2[NSection-1]) is the last point.
   31302             : 
   31303             :   -- ALGLIB --
   31304             :      Copyright 02.10.2014 by Bochkanov Sergey
   31305             : *************************************************************************/
   31306           0 : void lstfitpiecewiselinearrdpfixed(/* Real    */ ae_vector* x,
   31307             :      /* Real    */ ae_vector* y,
   31308             :      ae_int_t n,
   31309             :      ae_int_t m,
   31310             :      /* Real    */ ae_vector* x2,
   31311             :      /* Real    */ ae_vector* y2,
   31312             :      ae_int_t* nsections,
   31313             :      ae_state *_state)
   31314             : {
   31315             :     ae_frame _frame_block;
   31316             :     ae_vector _x;
   31317             :     ae_vector _y;
   31318             :     ae_int_t i;
   31319             :     ae_int_t j;
   31320             :     ae_int_t k;
   31321             :     ae_int_t k0;
   31322             :     ae_int_t k1;
   31323             :     ae_int_t k2;
   31324             :     ae_vector buf0;
   31325             :     ae_vector buf1;
   31326             :     ae_matrix sections;
   31327             :     ae_vector points;
   31328             :     double v;
   31329             :     ae_int_t worstidx;
   31330             :     double worsterror;
   31331             :     ae_int_t idx0;
   31332             :     ae_int_t idx1;
   31333             :     double e0;
   31334             :     double e1;
   31335             :     ae_vector heaperrors;
   31336             :     ae_vector heaptags;
   31337             : 
   31338           0 :     ae_frame_make(_state, &_frame_block);
   31339           0 :     memset(&_x, 0, sizeof(_x));
   31340           0 :     memset(&_y, 0, sizeof(_y));
   31341           0 :     memset(&buf0, 0, sizeof(buf0));
   31342           0 :     memset(&buf1, 0, sizeof(buf1));
   31343           0 :     memset(&sections, 0, sizeof(sections));
   31344           0 :     memset(&points, 0, sizeof(points));
   31345           0 :     memset(&heaperrors, 0, sizeof(heaperrors));
   31346           0 :     memset(&heaptags, 0, sizeof(heaptags));
   31347           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   31348           0 :     x = &_x;
   31349           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   31350           0 :     y = &_y;
   31351           0 :     ae_vector_clear(x2);
   31352           0 :     ae_vector_clear(y2);
   31353           0 :     *nsections = 0;
   31354           0 :     ae_vector_init(&buf0, 0, DT_REAL, _state, ae_true);
   31355           0 :     ae_vector_init(&buf1, 0, DT_REAL, _state, ae_true);
   31356           0 :     ae_matrix_init(&sections, 0, 0, DT_REAL, _state, ae_true);
   31357           0 :     ae_vector_init(&points, 0, DT_REAL, _state, ae_true);
   31358           0 :     ae_vector_init(&heaperrors, 0, DT_REAL, _state, ae_true);
   31359           0 :     ae_vector_init(&heaptags, 0, DT_INT, _state, ae_true);
   31360             : 
   31361           0 :     ae_assert(n>=0, "LSTFitPiecewiseLinearRDPFixed: N<0", _state);
   31362           0 :     ae_assert(m>=1, "LSTFitPiecewiseLinearRDPFixed: M<1", _state);
   31363           0 :     ae_assert(x->cnt>=n, "LSTFitPiecewiseLinearRDPFixed: Length(X)<N", _state);
   31364           0 :     ae_assert(y->cnt>=n, "LSTFitPiecewiseLinearRDPFixed: Length(Y)<N", _state);
   31365           0 :     if( n<=1 )
   31366             :     {
   31367           0 :         *nsections = 0;
   31368           0 :         ae_frame_leave(_state);
   31369           0 :         return;
   31370             :     }
   31371             :     
   31372             :     /*
   31373             :      * Sort points.
   31374             :      * Handle possible ties (tied values are replaced by their mean)
   31375             :      */
   31376           0 :     tagsortfastr(x, y, &buf0, &buf1, n, _state);
   31377           0 :     i = 0;
   31378           0 :     while(i<=n-1)
   31379             :     {
   31380           0 :         j = i+1;
   31381           0 :         v = y->ptr.p_double[i];
   31382           0 :         while(j<=n-1&&ae_fp_eq(x->ptr.p_double[j],x->ptr.p_double[i]))
   31383             :         {
   31384           0 :             v = v+y->ptr.p_double[j];
   31385           0 :             j = j+1;
   31386             :         }
   31387           0 :         v = v/(j-i);
   31388           0 :         for(k=i; k<=j-1; k++)
   31389             :         {
   31390           0 :             y->ptr.p_double[k] = v;
   31391             :         }
   31392           0 :         i = j;
   31393             :     }
   31394             :     
   31395             :     /*
   31396             :      * Handle degenerate case x[0]=x[N-1]
   31397             :      */
   31398           0 :     if( ae_fp_eq(x->ptr.p_double[n-1],x->ptr.p_double[0]) )
   31399             :     {
   31400           0 :         *nsections = 0;
   31401           0 :         ae_frame_leave(_state);
   31402           0 :         return;
   31403             :     }
   31404             :     
   31405             :     /*
   31406             :      * Prepare first section
   31407             :      */
   31408           0 :     lsfit_rdpanalyzesection(x, y, 0, n-1, &worstidx, &worsterror, _state);
   31409           0 :     ae_matrix_set_length(&sections, m, 4, _state);
   31410           0 :     ae_vector_set_length(&heaperrors, m, _state);
   31411           0 :     ae_vector_set_length(&heaptags, m, _state);
   31412           0 :     *nsections = 1;
   31413           0 :     sections.ptr.pp_double[0][0] = (double)(0);
   31414           0 :     sections.ptr.pp_double[0][1] = (double)(n-1);
   31415           0 :     sections.ptr.pp_double[0][2] = (double)(worstidx);
   31416           0 :     sections.ptr.pp_double[0][3] = worsterror;
   31417           0 :     heaperrors.ptr.p_double[0] = worsterror;
   31418           0 :     heaptags.ptr.p_int[0] = 0;
   31419           0 :     ae_assert(ae_fp_eq(sections.ptr.pp_double[0][1],(double)(n-1)), "RDP algorithm: integrity check failed", _state);
   31420             :     
   31421             :     /*
   31422             :      * Main loop.
   31423             :      * Repeatedly find section with worst error and divide it.
   31424             :      * Terminate after M-th section, or because of other reasons (see loop internals).
   31425             :      */
   31426           0 :     while(*nsections<m)
   31427             :     {
   31428             :         
   31429             :         /*
   31430             :          * Break if worst section has zero error.
   31431             :          * Store index of worst section to K.
   31432             :          */
   31433           0 :         if( ae_fp_eq(heaperrors.ptr.p_double[0],(double)(0)) )
   31434             :         {
   31435           0 :             break;
   31436             :         }
   31437           0 :         k = heaptags.ptr.p_int[0];
   31438             :         
   31439             :         /*
   31440             :          * K-th section is divided in two:
   31441             :          * * first  one spans interval from X[Sections[K,0]] to X[Sections[K,2]]
   31442             :          * * second one spans interval from X[Sections[K,2]] to X[Sections[K,1]]
   31443             :          *
   31444             :          * First section is stored at K-th position, second one is appended to the table.
   31445             :          * Then we update heap which stores pairs of (error,section_index)
   31446             :          */
   31447           0 :         k0 = ae_round(sections.ptr.pp_double[k][0], _state);
   31448           0 :         k1 = ae_round(sections.ptr.pp_double[k][1], _state);
   31449           0 :         k2 = ae_round(sections.ptr.pp_double[k][2], _state);
   31450           0 :         lsfit_rdpanalyzesection(x, y, k0, k2, &idx0, &e0, _state);
   31451           0 :         lsfit_rdpanalyzesection(x, y, k2, k1, &idx1, &e1, _state);
   31452           0 :         sections.ptr.pp_double[k][0] = (double)(k0);
   31453           0 :         sections.ptr.pp_double[k][1] = (double)(k2);
   31454           0 :         sections.ptr.pp_double[k][2] = (double)(idx0);
   31455           0 :         sections.ptr.pp_double[k][3] = e0;
   31456           0 :         tagheapreplacetopi(&heaperrors, &heaptags, *nsections, e0, k, _state);
   31457           0 :         sections.ptr.pp_double[*nsections][0] = (double)(k2);
   31458           0 :         sections.ptr.pp_double[*nsections][1] = (double)(k1);
   31459           0 :         sections.ptr.pp_double[*nsections][2] = (double)(idx1);
   31460           0 :         sections.ptr.pp_double[*nsections][3] = e1;
   31461           0 :         tagheappushi(&heaperrors, &heaptags, nsections, e1, *nsections, _state);
   31462             :     }
   31463             :     
   31464             :     /*
   31465             :      * Convert from sections to points
   31466             :      */
   31467           0 :     ae_vector_set_length(&points, *nsections+1, _state);
   31468           0 :     k = ae_round(sections.ptr.pp_double[0][1], _state);
   31469           0 :     for(i=0; i<=*nsections-1; i++)
   31470             :     {
   31471           0 :         points.ptr.p_double[i] = (double)(ae_round(sections.ptr.pp_double[i][0], _state));
   31472           0 :         if( ae_fp_greater(x->ptr.p_double[ae_round(sections.ptr.pp_double[i][1], _state)],x->ptr.p_double[k]) )
   31473             :         {
   31474           0 :             k = ae_round(sections.ptr.pp_double[i][1], _state);
   31475             :         }
   31476             :     }
   31477           0 :     points.ptr.p_double[*nsections] = (double)(k);
   31478           0 :     tagsortfast(&points, &buf0, *nsections+1, _state);
   31479             :     
   31480             :     /*
   31481             :      * Output sections:
   31482             :      * * first NSection elements of X2/Y2 are filled by x/y at left boundaries of sections
   31483             :      * * last element of X2/Y2 is filled by right boundary of rightmost section
   31484             :      * * X2/Y2 is sorted by ascending of X2
   31485             :      */
   31486           0 :     ae_vector_set_length(x2, *nsections+1, _state);
   31487           0 :     ae_vector_set_length(y2, *nsections+1, _state);
   31488           0 :     for(i=0; i<=*nsections; i++)
   31489             :     {
   31490           0 :         x2->ptr.p_double[i] = x->ptr.p_double[ae_round(points.ptr.p_double[i], _state)];
   31491           0 :         y2->ptr.p_double[i] = y->ptr.p_double[ae_round(points.ptr.p_double[i], _state)];
   31492             :     }
   31493           0 :     ae_frame_leave(_state);
   31494             : }
   31495             : 
   31496             : 
   31497             : /*************************************************************************
   31498             : This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
   31499             : Peucker algorithm, which stops after achieving desired precision.
   31500             : 
   31501             : IMPORTANT:
   31502             : * it performs non-least-squares fitting; it builds curve, but  this  curve
   31503             :   does not minimize some least squares  metric.  See  description  of  RDP
   31504             :   algorithm (say, in Wikipedia) for more details on WHAT is performed.
   31505             : * this function does NOT work with parametric curves  (i.e.  curves  which
   31506             :   can be represented as {X(t),Y(t)}. It works with curves   which  can  be
   31507             :   represented as Y(X). Thus, it is impossible to model figures like circles
   31508             :   with this functions.
   31509             :   If  you  want  to  work  with  parametric   curves,   you   should   use
   31510             :   ParametricRDPFixed() function provided  by  "Parametric"  subpackage  of
   31511             :   "Interpolation" package.
   31512             : 
   31513             : INPUT PARAMETERS:
   31514             :     X       -   array of X-coordinates:
   31515             :                 * at least N elements
   31516             :                 * can be unordered (points are automatically sorted)
   31517             :                 * this function may accept non-distinct X (see below for
   31518             :                   more information on handling of such inputs)
   31519             :     Y       -   array of Y-coordinates:
   31520             :                 * at least N elements
   31521             :     N       -   number of elements in X/Y
   31522             :     Eps     -   positive number, desired precision.
   31523             :     
   31524             : 
   31525             : OUTPUT PARAMETERS:
   31526             :     X2      -   X-values of corner points for piecewise approximation,
   31527             :                 has length NSections+1 or zero (for NSections=0).
   31528             :     Y2      -   Y-values of corner points,
   31529             :                 has length NSections+1 or zero (for NSections=0).
   31530             :     NSections-  number of sections found by algorithm,
   31531             :                 NSections can be zero for degenerate datasets
   31532             :                 (N<=1 or all X[] are non-distinct).
   31533             : 
   31534             : NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is  a  first  point  of
   31535             :       curve, (X2[NSection-1],Y2[NSection-1]) is the last point.
   31536             : 
   31537             :   -- ALGLIB --
   31538             :      Copyright 02.10.2014 by Bochkanov Sergey
   31539             : *************************************************************************/
   31540           0 : void lstfitpiecewiselinearrdp(/* Real    */ ae_vector* x,
   31541             :      /* Real    */ ae_vector* y,
   31542             :      ae_int_t n,
   31543             :      double eps,
   31544             :      /* Real    */ ae_vector* x2,
   31545             :      /* Real    */ ae_vector* y2,
   31546             :      ae_int_t* nsections,
   31547             :      ae_state *_state)
   31548             : {
   31549             :     ae_frame _frame_block;
   31550             :     ae_vector _x;
   31551             :     ae_vector _y;
   31552             :     ae_int_t i;
   31553             :     ae_int_t j;
   31554             :     ae_int_t k;
   31555             :     ae_vector buf0;
   31556             :     ae_vector buf1;
   31557             :     ae_vector xtmp;
   31558             :     ae_vector ytmp;
   31559             :     double v;
   31560             :     ae_int_t npts;
   31561             : 
   31562           0 :     ae_frame_make(_state, &_frame_block);
   31563           0 :     memset(&_x, 0, sizeof(_x));
   31564           0 :     memset(&_y, 0, sizeof(_y));
   31565           0 :     memset(&buf0, 0, sizeof(buf0));
   31566           0 :     memset(&buf1, 0, sizeof(buf1));
   31567           0 :     memset(&xtmp, 0, sizeof(xtmp));
   31568           0 :     memset(&ytmp, 0, sizeof(ytmp));
   31569           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   31570           0 :     x = &_x;
   31571           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   31572           0 :     y = &_y;
   31573           0 :     ae_vector_clear(x2);
   31574           0 :     ae_vector_clear(y2);
   31575           0 :     *nsections = 0;
   31576           0 :     ae_vector_init(&buf0, 0, DT_REAL, _state, ae_true);
   31577           0 :     ae_vector_init(&buf1, 0, DT_REAL, _state, ae_true);
   31578           0 :     ae_vector_init(&xtmp, 0, DT_REAL, _state, ae_true);
   31579           0 :     ae_vector_init(&ytmp, 0, DT_REAL, _state, ae_true);
   31580             : 
   31581           0 :     ae_assert(n>=0, "LSTFitPiecewiseLinearRDP: N<0", _state);
   31582           0 :     ae_assert(ae_fp_greater(eps,(double)(0)), "LSTFitPiecewiseLinearRDP: Eps<=0", _state);
   31583           0 :     ae_assert(x->cnt>=n, "LSTFitPiecewiseLinearRDP: Length(X)<N", _state);
   31584           0 :     ae_assert(y->cnt>=n, "LSTFitPiecewiseLinearRDP: Length(Y)<N", _state);
   31585           0 :     if( n<=1 )
   31586             :     {
   31587           0 :         *nsections = 0;
   31588           0 :         ae_frame_leave(_state);
   31589           0 :         return;
   31590             :     }
   31591             :     
   31592             :     /*
   31593             :      * Sort points.
   31594             :      * Handle possible ties (tied values are replaced by their mean)
   31595             :      */
   31596           0 :     tagsortfastr(x, y, &buf0, &buf1, n, _state);
   31597           0 :     i = 0;
   31598           0 :     while(i<=n-1)
   31599             :     {
   31600           0 :         j = i+1;
   31601           0 :         v = y->ptr.p_double[i];
   31602           0 :         while(j<=n-1&&ae_fp_eq(x->ptr.p_double[j],x->ptr.p_double[i]))
   31603             :         {
   31604           0 :             v = v+y->ptr.p_double[j];
   31605           0 :             j = j+1;
   31606             :         }
   31607           0 :         v = v/(j-i);
   31608           0 :         for(k=i; k<=j-1; k++)
   31609             :         {
   31610           0 :             y->ptr.p_double[k] = v;
   31611             :         }
   31612           0 :         i = j;
   31613             :     }
   31614             :     
   31615             :     /*
   31616             :      * Handle degenerate case x[0]=x[N-1]
   31617             :      */
   31618           0 :     if( ae_fp_eq(x->ptr.p_double[n-1],x->ptr.p_double[0]) )
   31619             :     {
   31620           0 :         *nsections = 0;
   31621           0 :         ae_frame_leave(_state);
   31622           0 :         return;
   31623             :     }
   31624             :     
   31625             :     /*
   31626             :      * Prepare data for recursive algorithm
   31627             :      */
   31628           0 :     ae_vector_set_length(&xtmp, n, _state);
   31629           0 :     ae_vector_set_length(&ytmp, n, _state);
   31630           0 :     npts = 2;
   31631           0 :     xtmp.ptr.p_double[0] = x->ptr.p_double[0];
   31632           0 :     ytmp.ptr.p_double[0] = y->ptr.p_double[0];
   31633           0 :     xtmp.ptr.p_double[1] = x->ptr.p_double[n-1];
   31634           0 :     ytmp.ptr.p_double[1] = y->ptr.p_double[n-1];
   31635           0 :     lsfit_rdprecursive(x, y, 0, n-1, eps, &xtmp, &ytmp, &npts, _state);
   31636             :     
   31637             :     /*
   31638             :      * Output sections:
   31639             :      * * first NSection elements of X2/Y2 are filled by x/y at left boundaries of sections
   31640             :      * * last element of X2/Y2 is filled by right boundary of rightmost section
   31641             :      * * X2/Y2 is sorted by ascending of X2
   31642             :      */
   31643           0 :     *nsections = npts-1;
   31644           0 :     ae_vector_set_length(x2, npts, _state);
   31645           0 :     ae_vector_set_length(y2, npts, _state);
   31646           0 :     for(i=0; i<=*nsections; i++)
   31647             :     {
   31648           0 :         x2->ptr.p_double[i] = xtmp.ptr.p_double[i];
   31649           0 :         y2->ptr.p_double[i] = ytmp.ptr.p_double[i];
   31650             :     }
   31651           0 :     tagsortfastr(x2, y2, &buf0, &buf1, npts, _state);
   31652           0 :     ae_frame_leave(_state);
   31653             : }
   31654             : 
   31655             : 
   31656             : /*************************************************************************
   31657             : Fitting by polynomials in barycentric form. This function provides  simple
   31658             : unterface for unconstrained unweighted fitting. See  PolynomialFitWC()  if
   31659             : you need constrained fitting.
   31660             : 
   31661             : Task is linear, so linear least squares solver is used. Complexity of this
   31662             : computational scheme is O(N*M^2), mostly dominated by least squares solver
   31663             : 
   31664             : SEE ALSO:
   31665             :     PolynomialFitWC()
   31666             : 
   31667             : NOTES:
   31668             :     you can convert P from barycentric form  to  the  power  or  Chebyshev
   31669             :     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
   31670             :     POLINT subpackage.
   31671             :     
   31672             :   ! COMMERCIAL EDITION OF ALGLIB:
   31673             :   ! 
   31674             :   ! Commercial Edition of ALGLIB includes following important improvements
   31675             :   ! of this function:
   31676             :   ! * high-performance native backend with same C# interface (C# version)
   31677             :   ! * multithreading support (C++ and C# versions)
   31678             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   31679             :   !   (C++ and C# versions, x86/x64 platform)
   31680             :   ! 
   31681             :   ! We recommend you to read 'Working with commercial version' section  of
   31682             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   31683             :   ! related features provided by commercial edition of ALGLIB.
   31684             : 
   31685             : INPUT PARAMETERS:
   31686             :     X   -   points, array[0..N-1].
   31687             :     Y   -   function values, array[0..N-1].
   31688             :     N   -   number of points, N>0
   31689             :             * if given, only leading N elements of X/Y are used
   31690             :             * if not given, automatically determined from sizes of X/Y
   31691             :     M   -   number of basis functions (= polynomial_degree + 1), M>=1
   31692             : 
   31693             : OUTPUT PARAMETERS:
   31694             :     Info-   same format as in LSFitLinearW() subroutine:
   31695             :             * Info>0    task is solved
   31696             :             * Info<=0   an error occured:
   31697             :                         -4 means inconvergence of internal SVD
   31698             :     P   -   interpolant in barycentric form.
   31699             :     Rep -   report, same format as in LSFitLinearW() subroutine.
   31700             :             Following fields are set:
   31701             :             * RMSError      rms error on the (X,Y).
   31702             :             * AvgError      average error on the (X,Y).
   31703             :             * AvgRelError   average relative error on the non-zero Y
   31704             :             * MaxError      maximum error
   31705             :                             NON-WEIGHTED ERRORS ARE CALCULATED
   31706             : 
   31707             :   -- ALGLIB PROJECT --
   31708             :      Copyright 10.12.2009 by Bochkanov Sergey
   31709             : *************************************************************************/
   31710           0 : void polynomialfit(/* Real    */ ae_vector* x,
   31711             :      /* Real    */ ae_vector* y,
   31712             :      ae_int_t n,
   31713             :      ae_int_t m,
   31714             :      ae_int_t* info,
   31715             :      barycentricinterpolant* p,
   31716             :      polynomialfitreport* rep,
   31717             :      ae_state *_state)
   31718             : {
   31719             :     ae_frame _frame_block;
   31720             :     ae_int_t i;
   31721             :     ae_vector w;
   31722             :     ae_vector xc;
   31723             :     ae_vector yc;
   31724             :     ae_vector dc;
   31725             : 
   31726           0 :     ae_frame_make(_state, &_frame_block);
   31727           0 :     memset(&w, 0, sizeof(w));
   31728           0 :     memset(&xc, 0, sizeof(xc));
   31729           0 :     memset(&yc, 0, sizeof(yc));
   31730           0 :     memset(&dc, 0, sizeof(dc));
   31731           0 :     *info = 0;
   31732           0 :     _barycentricinterpolant_clear(p);
   31733           0 :     _polynomialfitreport_clear(rep);
   31734           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   31735           0 :     ae_vector_init(&xc, 0, DT_REAL, _state, ae_true);
   31736           0 :     ae_vector_init(&yc, 0, DT_REAL, _state, ae_true);
   31737           0 :     ae_vector_init(&dc, 0, DT_INT, _state, ae_true);
   31738             : 
   31739           0 :     ae_assert(n>0, "PolynomialFit: N<=0!", _state);
   31740           0 :     ae_assert(m>0, "PolynomialFit: M<=0!", _state);
   31741           0 :     ae_assert(x->cnt>=n, "PolynomialFit: Length(X)<N!", _state);
   31742           0 :     ae_assert(y->cnt>=n, "PolynomialFit: Length(Y)<N!", _state);
   31743           0 :     ae_assert(isfinitevector(x, n, _state), "PolynomialFit: X contains infinite or NaN values!", _state);
   31744           0 :     ae_assert(isfinitevector(y, n, _state), "PolynomialFit: Y contains infinite or NaN values!", _state);
   31745           0 :     ae_vector_set_length(&w, n, _state);
   31746           0 :     for(i=0; i<=n-1; i++)
   31747             :     {
   31748           0 :         w.ptr.p_double[i] = (double)(1);
   31749             :     }
   31750           0 :     polynomialfitwc(x, y, &w, n, &xc, &yc, &dc, 0, m, info, p, rep, _state);
   31751           0 :     ae_frame_leave(_state);
   31752           0 : }
   31753             : 
   31754             : 
   31755             : /*************************************************************************
   31756             : Weighted  fitting by polynomials in barycentric form, with constraints  on
   31757             : function values or first derivatives.
   31758             : 
   31759             : Small regularizing term is used when solving constrained tasks (to improve
   31760             : stability).
   31761             : 
   31762             : Task is linear, so linear least squares solver is used. Complexity of this
   31763             : computational scheme is O(N*M^2), mostly dominated by least squares solver
   31764             : 
   31765             : SEE ALSO:
   31766             :     PolynomialFit()
   31767             : 
   31768             : NOTES:
   31769             :     you can convert P from barycentric form  to  the  power  or  Chebyshev
   31770             :     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
   31771             :     POLINT subpackage.
   31772             :     
   31773             :   ! COMMERCIAL EDITION OF ALGLIB:
   31774             :   ! 
   31775             :   ! Commercial Edition of ALGLIB includes following important improvements
   31776             :   ! of this function:
   31777             :   ! * high-performance native backend with same C# interface (C# version)
   31778             :   ! * multithreading support (C++ and C# versions)
   31779             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   31780             :   !   (C++ and C# versions, x86/x64 platform)
   31781             :   ! 
   31782             :   ! We recommend you to read 'Working with commercial version' section  of
   31783             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   31784             :   ! related features provided by commercial edition of ALGLIB.
   31785             : 
   31786             : INPUT PARAMETERS:
   31787             :     X   -   points, array[0..N-1].
   31788             :     Y   -   function values, array[0..N-1].
   31789             :     W   -   weights, array[0..N-1]
   31790             :             Each summand in square  sum  of  approximation deviations from
   31791             :             given  values  is  multiplied  by  the square of corresponding
   31792             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
   31793             :             task.
   31794             :     N   -   number of points, N>0.
   31795             :             * if given, only leading N elements of X/Y/W are used
   31796             :             * if not given, automatically determined from sizes of X/Y/W
   31797             :     XC  -   points where polynomial values/derivatives are constrained,
   31798             :             array[0..K-1].
   31799             :     YC  -   values of constraints, array[0..K-1]
   31800             :     DC  -   array[0..K-1], types of constraints:
   31801             :             * DC[i]=0   means that P(XC[i])=YC[i]
   31802             :             * DC[i]=1   means that P'(XC[i])=YC[i]
   31803             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
   31804             :     K   -   number of constraints, 0<=K<M.
   31805             :             K=0 means no constraints (XC/YC/DC are not used in such cases)
   31806             :     M   -   number of basis functions (= polynomial_degree + 1), M>=1
   31807             : 
   31808             : OUTPUT PARAMETERS:
   31809             :     Info-   same format as in LSFitLinearW() subroutine:
   31810             :             * Info>0    task is solved
   31811             :             * Info<=0   an error occured:
   31812             :                         -4 means inconvergence of internal SVD
   31813             :                         -3 means inconsistent constraints
   31814             :     P   -   interpolant in barycentric form.
   31815             :     Rep -   report, same format as in LSFitLinearW() subroutine.
   31816             :             Following fields are set:
   31817             :             * RMSError      rms error on the (X,Y).
   31818             :             * AvgError      average error on the (X,Y).
   31819             :             * AvgRelError   average relative error on the non-zero Y
   31820             :             * MaxError      maximum error
   31821             :                             NON-WEIGHTED ERRORS ARE CALCULATED
   31822             : 
   31823             : IMPORTANT:
   31824             :     this subroitine doesn't calculate task's condition number for K<>0.
   31825             : 
   31826             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
   31827             : 
   31828             : Setting constraints can lead  to undesired  results,  like ill-conditioned
   31829             : behavior, or inconsistency being detected. From the other side,  it allows
   31830             : us to improve quality of the fit. Here we summarize  our  experience  with
   31831             : constrained regression splines:
   31832             : * even simple constraints can be inconsistent, see  Wikipedia  article  on
   31833             :   this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation
   31834             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
   31835             :   constraints will be consistent
   31836             : * in the general case, consistency of constraints is NOT GUARANTEED.
   31837             : * in the one special cases, however, we can  guarantee  consistency.  This
   31838             :   case  is:  M>1  and constraints on the function values (NOT DERIVATIVES)
   31839             : 
   31840             : Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
   31841             : can't solve your task without them. Anything beyond  special  cases  given
   31842             : above is not guaranteed and may result in inconsistency.
   31843             : 
   31844             :   -- ALGLIB PROJECT --
   31845             :      Copyright 10.12.2009 by Bochkanov Sergey
   31846             : *************************************************************************/
   31847           0 : void polynomialfitwc(/* Real    */ ae_vector* x,
   31848             :      /* Real    */ ae_vector* y,
   31849             :      /* Real    */ ae_vector* w,
   31850             :      ae_int_t n,
   31851             :      /* Real    */ ae_vector* xc,
   31852             :      /* Real    */ ae_vector* yc,
   31853             :      /* Integer */ ae_vector* dc,
   31854             :      ae_int_t k,
   31855             :      ae_int_t m,
   31856             :      ae_int_t* info,
   31857             :      barycentricinterpolant* p,
   31858             :      polynomialfitreport* rep,
   31859             :      ae_state *_state)
   31860             : {
   31861             :     ae_frame _frame_block;
   31862             :     ae_vector _x;
   31863             :     ae_vector _y;
   31864             :     ae_vector _w;
   31865             :     ae_vector _xc;
   31866             :     ae_vector _yc;
   31867             :     double xa;
   31868             :     double xb;
   31869             :     double sa;
   31870             :     double sb;
   31871             :     ae_vector xoriginal;
   31872             :     ae_vector yoriginal;
   31873             :     ae_vector y2;
   31874             :     ae_vector w2;
   31875             :     ae_vector tmp;
   31876             :     ae_vector tmp2;
   31877             :     ae_vector bx;
   31878             :     ae_vector by;
   31879             :     ae_vector bw;
   31880             :     ae_int_t i;
   31881             :     ae_int_t j;
   31882             :     double u;
   31883             :     double v;
   31884             :     double s;
   31885             :     ae_int_t relcnt;
   31886             :     lsfitreport lrep;
   31887             : 
   31888           0 :     ae_frame_make(_state, &_frame_block);
   31889           0 :     memset(&_x, 0, sizeof(_x));
   31890           0 :     memset(&_y, 0, sizeof(_y));
   31891           0 :     memset(&_w, 0, sizeof(_w));
   31892           0 :     memset(&_xc, 0, sizeof(_xc));
   31893           0 :     memset(&_yc, 0, sizeof(_yc));
   31894           0 :     memset(&xoriginal, 0, sizeof(xoriginal));
   31895           0 :     memset(&yoriginal, 0, sizeof(yoriginal));
   31896           0 :     memset(&y2, 0, sizeof(y2));
   31897           0 :     memset(&w2, 0, sizeof(w2));
   31898           0 :     memset(&tmp, 0, sizeof(tmp));
   31899           0 :     memset(&tmp2, 0, sizeof(tmp2));
   31900           0 :     memset(&bx, 0, sizeof(bx));
   31901           0 :     memset(&by, 0, sizeof(by));
   31902           0 :     memset(&bw, 0, sizeof(bw));
   31903           0 :     memset(&lrep, 0, sizeof(lrep));
   31904           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   31905           0 :     x = &_x;
   31906           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   31907           0 :     y = &_y;
   31908           0 :     ae_vector_init_copy(&_w, w, _state, ae_true);
   31909           0 :     w = &_w;
   31910           0 :     ae_vector_init_copy(&_xc, xc, _state, ae_true);
   31911           0 :     xc = &_xc;
   31912           0 :     ae_vector_init_copy(&_yc, yc, _state, ae_true);
   31913           0 :     yc = &_yc;
   31914           0 :     *info = 0;
   31915           0 :     _barycentricinterpolant_clear(p);
   31916           0 :     _polynomialfitreport_clear(rep);
   31917           0 :     ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true);
   31918           0 :     ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true);
   31919           0 :     ae_vector_init(&y2, 0, DT_REAL, _state, ae_true);
   31920           0 :     ae_vector_init(&w2, 0, DT_REAL, _state, ae_true);
   31921           0 :     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
   31922           0 :     ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true);
   31923           0 :     ae_vector_init(&bx, 0, DT_REAL, _state, ae_true);
   31924           0 :     ae_vector_init(&by, 0, DT_REAL, _state, ae_true);
   31925           0 :     ae_vector_init(&bw, 0, DT_REAL, _state, ae_true);
   31926           0 :     _lsfitreport_init(&lrep, _state, ae_true);
   31927             : 
   31928           0 :     ae_assert(n>0, "PolynomialFitWC: N<=0!", _state);
   31929           0 :     ae_assert(m>0, "PolynomialFitWC: M<=0!", _state);
   31930           0 :     ae_assert(k>=0, "PolynomialFitWC: K<0!", _state);
   31931           0 :     ae_assert(k<m, "PolynomialFitWC: K>=M!", _state);
   31932           0 :     ae_assert(x->cnt>=n, "PolynomialFitWC: Length(X)<N!", _state);
   31933           0 :     ae_assert(y->cnt>=n, "PolynomialFitWC: Length(Y)<N!", _state);
   31934           0 :     ae_assert(w->cnt>=n, "PolynomialFitWC: Length(W)<N!", _state);
   31935           0 :     ae_assert(xc->cnt>=k, "PolynomialFitWC: Length(XC)<K!", _state);
   31936           0 :     ae_assert(yc->cnt>=k, "PolynomialFitWC: Length(YC)<K!", _state);
   31937           0 :     ae_assert(dc->cnt>=k, "PolynomialFitWC: Length(DC)<K!", _state);
   31938           0 :     ae_assert(isfinitevector(x, n, _state), "PolynomialFitWC: X contains infinite or NaN values!", _state);
   31939           0 :     ae_assert(isfinitevector(y, n, _state), "PolynomialFitWC: Y contains infinite or NaN values!", _state);
   31940           0 :     ae_assert(isfinitevector(w, n, _state), "PolynomialFitWC: X contains infinite or NaN values!", _state);
   31941           0 :     ae_assert(isfinitevector(xc, k, _state), "PolynomialFitWC: XC contains infinite or NaN values!", _state);
   31942           0 :     ae_assert(isfinitevector(yc, k, _state), "PolynomialFitWC: YC contains infinite or NaN values!", _state);
   31943           0 :     for(i=0; i<=k-1; i++)
   31944             :     {
   31945           0 :         ae_assert(dc->ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "PolynomialFitWC: one of DC[] is not 0 or 1!", _state);
   31946             :     }
   31947             :     
   31948             :     /*
   31949             :      * Scale X, Y, XC, YC.
   31950             :      * Solve scaled problem using internal Chebyshev fitting function.
   31951             :      */
   31952           0 :     lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state);
   31953           0 :     lsfit_internalchebyshevfit(x, y, w, n, xc, yc, dc, k, m, info, &tmp, &lrep, _state);
   31954           0 :     if( *info<0 )
   31955             :     {
   31956           0 :         ae_frame_leave(_state);
   31957           0 :         return;
   31958             :     }
   31959             :     
   31960             :     /*
   31961             :      * Generate barycentric model and scale it
   31962             :      * * BX, BY store barycentric model nodes
   31963             :      * * FMatrix is reused (remember - it is at least MxM, what we need)
   31964             :      *
   31965             :      * Model intialization is done in O(M^2). In principle, it can be
   31966             :      * done in O(M*log(M)), but before it we solved task with O(N*M^2)
   31967             :      * complexity, so it is only a small amount of total time spent.
   31968             :      */
   31969           0 :     ae_vector_set_length(&bx, m, _state);
   31970           0 :     ae_vector_set_length(&by, m, _state);
   31971           0 :     ae_vector_set_length(&bw, m, _state);
   31972           0 :     ae_vector_set_length(&tmp2, m, _state);
   31973           0 :     s = (double)(1);
   31974           0 :     for(i=0; i<=m-1; i++)
   31975             :     {
   31976           0 :         if( m!=1 )
   31977             :         {
   31978           0 :             u = ae_cos(ae_pi*i/(m-1), _state);
   31979             :         }
   31980             :         else
   31981             :         {
   31982           0 :             u = (double)(0);
   31983             :         }
   31984           0 :         v = (double)(0);
   31985           0 :         for(j=0; j<=m-1; j++)
   31986             :         {
   31987           0 :             if( j==0 )
   31988             :             {
   31989           0 :                 tmp2.ptr.p_double[j] = (double)(1);
   31990             :             }
   31991             :             else
   31992             :             {
   31993           0 :                 if( j==1 )
   31994             :                 {
   31995           0 :                     tmp2.ptr.p_double[j] = u;
   31996             :                 }
   31997             :                 else
   31998             :                 {
   31999           0 :                     tmp2.ptr.p_double[j] = 2*u*tmp2.ptr.p_double[j-1]-tmp2.ptr.p_double[j-2];
   32000             :                 }
   32001             :             }
   32002           0 :             v = v+tmp.ptr.p_double[j]*tmp2.ptr.p_double[j];
   32003             :         }
   32004           0 :         bx.ptr.p_double[i] = u;
   32005           0 :         by.ptr.p_double[i] = v;
   32006           0 :         bw.ptr.p_double[i] = s;
   32007           0 :         if( i==0||i==m-1 )
   32008             :         {
   32009           0 :             bw.ptr.p_double[i] = 0.5*bw.ptr.p_double[i];
   32010             :         }
   32011           0 :         s = -s;
   32012             :     }
   32013           0 :     barycentricbuildxyw(&bx, &by, &bw, m, p, _state);
   32014           0 :     barycentriclintransx(p, 2/(xb-xa), -(xa+xb)/(xb-xa), _state);
   32015           0 :     barycentriclintransy(p, sb-sa, sa, _state);
   32016             :     
   32017             :     /*
   32018             :      * Scale absolute errors obtained from LSFitLinearW.
   32019             :      * Relative error should be calculated separately
   32020             :      * (because of shifting/scaling of the task)
   32021             :      */
   32022           0 :     rep->taskrcond = lrep.taskrcond;
   32023           0 :     rep->rmserror = lrep.rmserror*(sb-sa);
   32024           0 :     rep->avgerror = lrep.avgerror*(sb-sa);
   32025           0 :     rep->maxerror = lrep.maxerror*(sb-sa);
   32026           0 :     rep->avgrelerror = (double)(0);
   32027           0 :     relcnt = 0;
   32028           0 :     for(i=0; i<=n-1; i++)
   32029             :     {
   32030           0 :         if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) )
   32031             :         {
   32032           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);
   32033           0 :             relcnt = relcnt+1;
   32034             :         }
   32035             :     }
   32036           0 :     if( relcnt!=0 )
   32037             :     {
   32038           0 :         rep->avgrelerror = rep->avgrelerror/relcnt;
   32039             :     }
   32040           0 :     ae_frame_leave(_state);
   32041             : }
   32042             : 
   32043             : 
   32044             : /*************************************************************************
   32045             : This function calculates value of four-parameter logistic (4PL)  model  at
   32046             : specified point X. 4PL model has following form:
   32047             : 
   32048             :     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
   32049             : 
   32050             : INPUT PARAMETERS:
   32051             :     X       -   current point, X>=0:
   32052             :                 * zero X is correctly handled even for B<=0
   32053             :                 * negative X results in exception.
   32054             :     A, B, C, D- parameters of 4PL model:
   32055             :                 * A is unconstrained
   32056             :                 * B is unconstrained; zero or negative values are handled
   32057             :                   correctly.
   32058             :                 * C>0, non-positive value results in exception
   32059             :                 * D is unconstrained
   32060             :                 
   32061             : RESULT:
   32062             :     model value at X
   32063             : 
   32064             : NOTE: if B=0, denominator is assumed to be equal to 2.0 even  for  zero  X
   32065             :       (strictly speaking, 0^0 is undefined).
   32066             : 
   32067             : NOTE: this function also throws exception  if  all  input  parameters  are
   32068             :       correct, but overflow was detected during calculations.
   32069             :       
   32070             : NOTE: this function performs a lot of checks;  if  you  need  really  high
   32071             :       performance, consider evaluating model  yourself,  without  checking
   32072             :       for degenerate cases.
   32073             :       
   32074             :     
   32075             :   -- ALGLIB PROJECT --
   32076             :      Copyright 14.05.2014 by Bochkanov Sergey
   32077             : *************************************************************************/
   32078           0 : double logisticcalc4(double x,
   32079             :      double a,
   32080             :      double b,
   32081             :      double c,
   32082             :      double d,
   32083             :      ae_state *_state)
   32084             : {
   32085             :     double result;
   32086             : 
   32087             : 
   32088           0 :     ae_assert(ae_isfinite(x, _state), "LogisticCalc4: X is not finite", _state);
   32089           0 :     ae_assert(ae_isfinite(a, _state), "LogisticCalc4: A is not finite", _state);
   32090           0 :     ae_assert(ae_isfinite(b, _state), "LogisticCalc4: B is not finite", _state);
   32091           0 :     ae_assert(ae_isfinite(c, _state), "LogisticCalc4: C is not finite", _state);
   32092           0 :     ae_assert(ae_isfinite(d, _state), "LogisticCalc4: D is not finite", _state);
   32093           0 :     ae_assert(ae_fp_greater_eq(x,(double)(0)), "LogisticCalc4: X is negative", _state);
   32094           0 :     ae_assert(ae_fp_greater(c,(double)(0)), "LogisticCalc4: C is non-positive", _state);
   32095             :     
   32096             :     /*
   32097             :      * Check for degenerate cases
   32098             :      */
   32099           0 :     if( ae_fp_eq(b,(double)(0)) )
   32100             :     {
   32101           0 :         result = 0.5*(a+d);
   32102           0 :         return result;
   32103             :     }
   32104           0 :     if( ae_fp_eq(x,(double)(0)) )
   32105             :     {
   32106           0 :         if( ae_fp_greater(b,(double)(0)) )
   32107             :         {
   32108           0 :             result = a;
   32109             :         }
   32110             :         else
   32111             :         {
   32112           0 :             result = d;
   32113             :         }
   32114           0 :         return result;
   32115             :     }
   32116             :     
   32117             :     /*
   32118             :      * General case
   32119             :      */
   32120           0 :     result = d+(a-d)/(1.0+ae_pow(x/c, b, _state));
   32121           0 :     ae_assert(ae_isfinite(result, _state), "LogisticCalc4: overflow during calculations", _state);
   32122           0 :     return result;
   32123             : }
   32124             : 
   32125             : 
   32126             : /*************************************************************************
   32127             : This function calculates value of five-parameter logistic (5PL)  model  at
   32128             : specified point X. 5PL model has following form:
   32129             : 
   32130             :     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
   32131             : 
   32132             : INPUT PARAMETERS:
   32133             :     X       -   current point, X>=0:
   32134             :                 * zero X is correctly handled even for B<=0
   32135             :                 * negative X results in exception.
   32136             :     A, B, C, D, G- parameters of 5PL model:
   32137             :                 * A is unconstrained
   32138             :                 * B is unconstrained; zero or negative values are handled
   32139             :                   correctly.
   32140             :                 * C>0, non-positive value results in exception
   32141             :                 * D is unconstrained
   32142             :                 * G>0, non-positive value results in exception
   32143             :                 
   32144             : RESULT:
   32145             :     model value at X
   32146             : 
   32147             : NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even  for
   32148             :       zero X (strictly speaking, 0^0 is undefined).
   32149             : 
   32150             : NOTE: this function also throws exception  if  all  input  parameters  are
   32151             :       correct, but overflow was detected during calculations.
   32152             :       
   32153             : NOTE: this function performs a lot of checks;  if  you  need  really  high
   32154             :       performance, consider evaluating model  yourself,  without  checking
   32155             :       for degenerate cases.
   32156             :       
   32157             :     
   32158             :   -- ALGLIB PROJECT --
   32159             :      Copyright 14.05.2014 by Bochkanov Sergey
   32160             : *************************************************************************/
   32161           0 : double logisticcalc5(double x,
   32162             :      double a,
   32163             :      double b,
   32164             :      double c,
   32165             :      double d,
   32166             :      double g,
   32167             :      ae_state *_state)
   32168             : {
   32169             :     double result;
   32170             : 
   32171             : 
   32172           0 :     ae_assert(ae_isfinite(x, _state), "LogisticCalc5: X is not finite", _state);
   32173           0 :     ae_assert(ae_isfinite(a, _state), "LogisticCalc5: A is not finite", _state);
   32174           0 :     ae_assert(ae_isfinite(b, _state), "LogisticCalc5: B is not finite", _state);
   32175           0 :     ae_assert(ae_isfinite(c, _state), "LogisticCalc5: C is not finite", _state);
   32176           0 :     ae_assert(ae_isfinite(d, _state), "LogisticCalc5: D is not finite", _state);
   32177           0 :     ae_assert(ae_isfinite(g, _state), "LogisticCalc5: G is not finite", _state);
   32178           0 :     ae_assert(ae_fp_greater_eq(x,(double)(0)), "LogisticCalc5: X is negative", _state);
   32179           0 :     ae_assert(ae_fp_greater(c,(double)(0)), "LogisticCalc5: C is non-positive", _state);
   32180           0 :     ae_assert(ae_fp_greater(g,(double)(0)), "LogisticCalc5: G is non-positive", _state);
   32181             :     
   32182             :     /*
   32183             :      * Check for degenerate cases
   32184             :      */
   32185           0 :     if( ae_fp_eq(b,(double)(0)) )
   32186             :     {
   32187           0 :         result = d+(a-d)/ae_pow(2.0, g, _state);
   32188           0 :         return result;
   32189             :     }
   32190           0 :     if( ae_fp_eq(x,(double)(0)) )
   32191             :     {
   32192           0 :         if( ae_fp_greater(b,(double)(0)) )
   32193             :         {
   32194           0 :             result = a;
   32195             :         }
   32196             :         else
   32197             :         {
   32198           0 :             result = d;
   32199             :         }
   32200           0 :         return result;
   32201             :     }
   32202             :     
   32203             :     /*
   32204             :      * General case
   32205             :      */
   32206           0 :     result = d+(a-d)/ae_pow(1.0+ae_pow(x/c, b, _state), g, _state);
   32207           0 :     ae_assert(ae_isfinite(result, _state), "LogisticCalc5: overflow during calculations", _state);
   32208           0 :     return result;
   32209             : }
   32210             : 
   32211             : 
   32212             : /*************************************************************************
   32213             : This function fits four-parameter logistic (4PL) model  to  data  provided
   32214             : by user. 4PL model has following form:
   32215             : 
   32216             :     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
   32217             : 
   32218             : Here:
   32219             :     * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL)
   32220             :     * B>=0
   32221             :     * C>0
   32222             :     
   32223             : IMPORTANT: output of this function is constrained in  such  way that  B>0.
   32224             :            Because 4PL model is symmetric with respect to B, there  is  no
   32225             :            need to explore  B<0.  Constraining  B  makes  algorithm easier
   32226             :            to stabilize and debug.
   32227             :            Users  who  for  some  reason  prefer to work with negative B's
   32228             :            should transform output themselves (swap A and D, replace B  by
   32229             :            -B).
   32230             :            
   32231             : 4PL fitting is implemented as follows:
   32232             : * we perform small number of restarts from random locations which helps to
   32233             :   solve problem of bad local extrema. Locations are only partially  random
   32234             :   - we use input data to determine good  initial  guess,  but  we  include
   32235             :   controlled amount of randomness.
   32236             : * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
   32237             :   parameters B and C - it allows us to find good  initial  guess  for  the
   32238             :   second stage without risk of running into "flat spot".
   32239             : * second  Levenberg-Marquardt  round  is   performed   without   excessive
   32240             :   constraints. Results from the previous round are used as initial guess.
   32241             : * after fitting is done, we compare results with best values found so far,
   32242             :   rewrite "best solution" if needed, and move to next random location.
   32243             :   
   32244             : Overall algorithm is very stable and is not prone to  bad  local  extrema.
   32245             : Furthermore, it automatically scales when input data have  very  large  or
   32246             : very small range.
   32247             : 
   32248             : INPUT PARAMETERS:
   32249             :     X       -   array[N], stores X-values.
   32250             :                 MUST include only non-negative numbers  (but  may  include
   32251             :                 zero values). Can be unsorted.
   32252             :     Y       -   array[N], values to fit.
   32253             :     N       -   number of points. If N is less than  length  of  X/Y, only
   32254             :                 leading N elements are used.
   32255             :                 
   32256             : OUTPUT PARAMETERS:
   32257             :     A, B, C, D- parameters of 4PL model
   32258             :     Rep     -   fitting report. This structure has many fields,  but  ONLY
   32259             :                 ONES LISTED BELOW ARE SET:
   32260             :                 * Rep.IterationsCount - number of iterations performed
   32261             :                 * Rep.RMSError - root-mean-square error
   32262             :                 * Rep.AvgError - average absolute error
   32263             :                 * Rep.AvgRelError - average relative error (calculated for
   32264             :                   non-zero Y-values)
   32265             :                 * Rep.MaxError - maximum absolute error
   32266             :                 * Rep.R2 - coefficient of determination,  R-squared.  This
   32267             :                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
   32268             :                   of nonlinear  regression  there  are  multiple  ways  to
   32269             :                   define R2, each of them giving different results).
   32270             : 
   32271             : NOTE: for stability reasons the B parameter is restricted by [1/1000,1000]
   32272             :       range. It prevents  algorithm from making trial steps  deep into the
   32273             :       area of bad parameters.
   32274             : 
   32275             : NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
   32276             :       LogisticCalc4() function.
   32277             : 
   32278             : NOTE: if you need better control over fitting process than provided by this
   32279             :       function, you may use LogisticFit45X().
   32280             :                 
   32281             : NOTE: step is automatically scaled according to scale of parameters  being
   32282             :       fitted before we compare its length with EpsX. Thus,  this  function
   32283             :       can be used to fit data with very small or very large values without
   32284             :       changing EpsX.
   32285             :     
   32286             : 
   32287             :   -- ALGLIB PROJECT --
   32288             :      Copyright 14.02.2014 by Bochkanov Sergey
   32289             : *************************************************************************/
   32290           0 : void logisticfit4(/* Real    */ ae_vector* x,
   32291             :      /* Real    */ ae_vector* y,
   32292             :      ae_int_t n,
   32293             :      double* a,
   32294             :      double* b,
   32295             :      double* c,
   32296             :      double* d,
   32297             :      lsfitreport* rep,
   32298             :      ae_state *_state)
   32299             : {
   32300             :     ae_frame _frame_block;
   32301             :     ae_vector _x;
   32302             :     ae_vector _y;
   32303             :     double g;
   32304             : 
   32305           0 :     ae_frame_make(_state, &_frame_block);
   32306           0 :     memset(&_x, 0, sizeof(_x));
   32307           0 :     memset(&_y, 0, sizeof(_y));
   32308           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   32309           0 :     x = &_x;
   32310           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   32311           0 :     y = &_y;
   32312           0 :     *a = 0;
   32313           0 :     *b = 0;
   32314           0 :     *c = 0;
   32315           0 :     *d = 0;
   32316           0 :     _lsfitreport_clear(rep);
   32317             : 
   32318           0 :     logisticfit45x(x, y, n, _state->v_nan, _state->v_nan, ae_true, 0.0, 0.0, 0, a, b, c, d, &g, rep, _state);
   32319           0 :     ae_frame_leave(_state);
   32320           0 : }
   32321             : 
   32322             : 
   32323             : /*************************************************************************
   32324             : This function fits four-parameter logistic (4PL) model  to  data  provided
   32325             : by user, with optional constraints on parameters A and D.  4PL  model  has
   32326             : following form:
   32327             : 
   32328             :     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
   32329             : 
   32330             : Here:
   32331             :     * A, D - with optional equality constraints
   32332             :     * B>=0
   32333             :     * C>0
   32334             :     
   32335             : IMPORTANT: output of this function is constrained in  such  way that  B>0.
   32336             :            Because 4PL model is symmetric with respect to B, there  is  no
   32337             :            need to explore  B<0.  Constraining  B  makes  algorithm easier
   32338             :            to stabilize and debug.
   32339             :            Users  who  for  some  reason  prefer to work with negative B's
   32340             :            should transform output themselves (swap A and D, replace B  by
   32341             :            -B).
   32342             :            
   32343             : 4PL fitting is implemented as follows:
   32344             : * we perform small number of restarts from random locations which helps to
   32345             :   solve problem of bad local extrema. Locations are only partially  random
   32346             :   - we use input data to determine good  initial  guess,  but  we  include
   32347             :   controlled amount of randomness.
   32348             : * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
   32349             :   parameters B and C - it allows us to find good  initial  guess  for  the
   32350             :   second stage without risk of running into "flat spot".
   32351             : * second  Levenberg-Marquardt  round  is   performed   without   excessive
   32352             :   constraints. Results from the previous round are used as initial guess.
   32353             : * after fitting is done, we compare results with best values found so far,
   32354             :   rewrite "best solution" if needed, and move to next random location.
   32355             :   
   32356             : Overall algorithm is very stable and is not prone to  bad  local  extrema.
   32357             : Furthermore, it automatically scales when input data have  very  large  or
   32358             : very small range.
   32359             : 
   32360             : INPUT PARAMETERS:
   32361             :     X       -   array[N], stores X-values.
   32362             :                 MUST include only non-negative numbers  (but  may  include
   32363             :                 zero values). Can be unsorted.
   32364             :     Y       -   array[N], values to fit.
   32365             :     N       -   number of points. If N is less than  length  of  X/Y, only
   32366             :                 leading N elements are used.
   32367             :     CnstrLeft-  optional equality constraint for model value at the   left
   32368             :                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
   32369             :                 not need constraint on the model value at X=0 (in C++  you
   32370             :                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
   32371             :                 Double.NaN).
   32372             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
   32373             :                 information about constraints.
   32374             :     CnstrRight- optional equality constraint for model value at X=infinity.
   32375             :                 Specify NAN (Not-a-Number) if you do not  need  constraint
   32376             :                 on the model value (in C++  you can pass alglib::fp_nan as
   32377             :                 parameter, in  C# it will  be Double.NaN).
   32378             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
   32379             :                 information about constraints.
   32380             :                 
   32381             : OUTPUT PARAMETERS:
   32382             :     A, B, C, D- parameters of 4PL model
   32383             :     Rep     -   fitting report. This structure has many fields,  but  ONLY
   32384             :                 ONES LISTED BELOW ARE SET:
   32385             :                 * Rep.IterationsCount - number of iterations performed
   32386             :                 * Rep.RMSError - root-mean-square error
   32387             :                 * Rep.AvgError - average absolute error
   32388             :                 * Rep.AvgRelError - average relative error (calculated for
   32389             :                   non-zero Y-values)
   32390             :                 * Rep.MaxError - maximum absolute error
   32391             :                 * Rep.R2 - coefficient of determination,  R-squared.  This
   32392             :                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
   32393             :                   of nonlinear  regression  there  are  multiple  ways  to
   32394             :                   define R2, each of them giving different results).
   32395             : 
   32396             : NOTE: for stability reasons the B parameter is restricted by [1/1000,1000]
   32397             :       range. It prevents  algorithm from making trial steps  deep into the
   32398             :       area of bad parameters.
   32399             : 
   32400             : NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
   32401             :       LogisticCalc4() function.
   32402             : 
   32403             : NOTE: if you need better control over fitting process than provided by this
   32404             :       function, you may use LogisticFit45X().
   32405             :                 
   32406             : NOTE: step is automatically scaled according to scale of parameters  being
   32407             :       fitted before we compare its length with EpsX. Thus,  this  function
   32408             :       can be used to fit data with very small or very large values without
   32409             :       changing EpsX.
   32410             : 
   32411             : EQUALITY CONSTRAINTS ON PARAMETERS
   32412             : 
   32413             : 4PL/5PL solver supports equality constraints on model values at  the  left
   32414             : boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
   32415             : completely optional and you can specify both of them, only  one  -  or  no
   32416             : constraints at all.
   32417             : 
   32418             : Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
   32419             : fitting), and CnstrRight contains right  one.  For  4PL,  left  constraint
   32420             : ALWAYS corresponds to parameter A, and right one is ALWAYS  constraint  on
   32421             : D. That's because 4PL model is normalized in such way that B>=0.
   32422             :     
   32423             : 
   32424             :   -- ALGLIB PROJECT --
   32425             :      Copyright 14.02.2014 by Bochkanov Sergey
   32426             : *************************************************************************/
   32427           0 : void logisticfit4ec(/* Real    */ ae_vector* x,
   32428             :      /* Real    */ ae_vector* y,
   32429             :      ae_int_t n,
   32430             :      double cnstrleft,
   32431             :      double cnstrright,
   32432             :      double* a,
   32433             :      double* b,
   32434             :      double* c,
   32435             :      double* d,
   32436             :      lsfitreport* rep,
   32437             :      ae_state *_state)
   32438             : {
   32439             :     ae_frame _frame_block;
   32440             :     ae_vector _x;
   32441             :     ae_vector _y;
   32442             :     double g;
   32443             : 
   32444           0 :     ae_frame_make(_state, &_frame_block);
   32445           0 :     memset(&_x, 0, sizeof(_x));
   32446           0 :     memset(&_y, 0, sizeof(_y));
   32447           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   32448           0 :     x = &_x;
   32449           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   32450           0 :     y = &_y;
   32451           0 :     *a = 0;
   32452           0 :     *b = 0;
   32453           0 :     *c = 0;
   32454           0 :     *d = 0;
   32455           0 :     _lsfitreport_clear(rep);
   32456             : 
   32457           0 :     logisticfit45x(x, y, n, cnstrleft, cnstrright, ae_true, 0.0, 0.0, 0, a, b, c, d, &g, rep, _state);
   32458           0 :     ae_frame_leave(_state);
   32459           0 : }
   32460             : 
   32461             : 
   32462             : /*************************************************************************
   32463             : This function fits five-parameter logistic (5PL) model  to  data  provided
   32464             : by user. 5PL model has following form:
   32465             : 
   32466             :     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
   32467             : 
   32468             : Here:
   32469             :     * A, D - unconstrained
   32470             :     * B - unconstrained
   32471             :     * C>0
   32472             :     * G>0
   32473             :     
   32474             : IMPORTANT: unlike in  4PL  fitting,  output  of  this  function   is   NOT
   32475             :            constrained in  such  way that B is guaranteed to be  positive.
   32476             :            Furthermore,  unlike  4PL,  5PL  model  is  NOT  symmetric with
   32477             :            respect to B, so you can NOT transform model to equivalent one,
   32478             :            with B having desired sign (>0 or <0).
   32479             :     
   32480             : 5PL fitting is implemented as follows:
   32481             : * we perform small number of restarts from random locations which helps to
   32482             :   solve problem of bad local extrema. Locations are only partially  random
   32483             :   - we use input data to determine good  initial  guess,  but  we  include
   32484             :   controlled amount of randomness.
   32485             : * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
   32486             :   parameters B and C - it allows us to find good  initial  guess  for  the
   32487             :   second stage without risk of running into "flat spot".  Parameter  G  is
   32488             :   fixed at G=1.
   32489             : * second  Levenberg-Marquardt  round  is   performed   without   excessive
   32490             :   constraints on B and C, but with G still equal to 1.  Results  from  the
   32491             :   previous round are used as initial guess.
   32492             : * third Levenberg-Marquardt round relaxes constraints on G  and  tries  two
   32493             :   different models - one with B>0 and one with B<0.
   32494             : * after fitting is done, we compare results with best values found so far,
   32495             :   rewrite "best solution" if needed, and move to next random location.
   32496             :   
   32497             : Overall algorithm is very stable and is not prone to  bad  local  extrema.
   32498             : Furthermore, it automatically scales when input data have  very  large  or
   32499             : very small range.
   32500             : 
   32501             : INPUT PARAMETERS:
   32502             :     X       -   array[N], stores X-values.
   32503             :                 MUST include only non-negative numbers  (but  may  include
   32504             :                 zero values). Can be unsorted.
   32505             :     Y       -   array[N], values to fit.
   32506             :     N       -   number of points. If N is less than  length  of  X/Y, only
   32507             :                 leading N elements are used.
   32508             :                 
   32509             : OUTPUT PARAMETERS:
   32510             :     A,B,C,D,G-  parameters of 5PL model
   32511             :     Rep     -   fitting report. This structure has many fields,  but  ONLY
   32512             :                 ONES LISTED BELOW ARE SET:
   32513             :                 * Rep.IterationsCount - number of iterations performed
   32514             :                 * Rep.RMSError - root-mean-square error
   32515             :                 * Rep.AvgError - average absolute error
   32516             :                 * Rep.AvgRelError - average relative error (calculated for
   32517             :                   non-zero Y-values)
   32518             :                 * Rep.MaxError - maximum absolute error
   32519             :                 * Rep.R2 - coefficient of determination,  R-squared.  This
   32520             :                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
   32521             :                   of nonlinear  regression  there  are  multiple  ways  to
   32522             :                   define R2, each of them giving different results).
   32523             : 
   32524             : NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
   32525             :       range, and G is restricted by [1/10,10] range. It prevents algorithm
   32526             :       from making trial steps deep into the area of bad parameters.
   32527             : 
   32528             : NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
   32529             :       LogisticCalc5() function.
   32530             : 
   32531             : NOTE: if you need better control over fitting process than provided by this
   32532             :       function, you may use LogisticFit45X().
   32533             :                 
   32534             : NOTE: step is automatically scaled according to scale of parameters  being
   32535             :       fitted before we compare its length with EpsX. Thus,  this  function
   32536             :       can be used to fit data with very small or very large values without
   32537             :       changing EpsX.
   32538             :     
   32539             : 
   32540             :   -- ALGLIB PROJECT --
   32541             :      Copyright 14.02.2014 by Bochkanov Sergey
   32542             : *************************************************************************/
   32543           0 : void logisticfit5(/* Real    */ ae_vector* x,
   32544             :      /* Real    */ ae_vector* y,
   32545             :      ae_int_t n,
   32546             :      double* a,
   32547             :      double* b,
   32548             :      double* c,
   32549             :      double* d,
   32550             :      double* g,
   32551             :      lsfitreport* rep,
   32552             :      ae_state *_state)
   32553             : {
   32554             :     ae_frame _frame_block;
   32555             :     ae_vector _x;
   32556             :     ae_vector _y;
   32557             : 
   32558           0 :     ae_frame_make(_state, &_frame_block);
   32559           0 :     memset(&_x, 0, sizeof(_x));
   32560           0 :     memset(&_y, 0, sizeof(_y));
   32561           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   32562           0 :     x = &_x;
   32563           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   32564           0 :     y = &_y;
   32565           0 :     *a = 0;
   32566           0 :     *b = 0;
   32567           0 :     *c = 0;
   32568           0 :     *d = 0;
   32569           0 :     *g = 0;
   32570           0 :     _lsfitreport_clear(rep);
   32571             : 
   32572           0 :     logisticfit45x(x, y, n, _state->v_nan, _state->v_nan, ae_false, 0.0, 0.0, 0, a, b, c, d, g, rep, _state);
   32573           0 :     ae_frame_leave(_state);
   32574           0 : }
   32575             : 
   32576             : 
   32577             : /*************************************************************************
   32578             : This function fits five-parameter logistic (5PL) model  to  data  provided
   32579             : by user, subject to optional equality constraints on parameters A  and  D.
   32580             : 5PL model has following form:
   32581             : 
   32582             :     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
   32583             : 
   32584             : Here:
   32585             :     * A, D - with optional equality constraints
   32586             :     * B - unconstrained
   32587             :     * C>0
   32588             :     * G>0
   32589             :     
   32590             : IMPORTANT: unlike in  4PL  fitting,  output  of  this  function   is   NOT
   32591             :            constrained in  such  way that B is guaranteed to be  positive.
   32592             :            Furthermore,  unlike  4PL,  5PL  model  is  NOT  symmetric with
   32593             :            respect to B, so you can NOT transform model to equivalent one,
   32594             :            with B having desired sign (>0 or <0).
   32595             :     
   32596             : 5PL fitting is implemented as follows:
   32597             : * we perform small number of restarts from random locations which helps to
   32598             :   solve problem of bad local extrema. Locations are only partially  random
   32599             :   - we use input data to determine good  initial  guess,  but  we  include
   32600             :   controlled amount of randomness.
   32601             : * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
   32602             :   parameters B and C - it allows us to find good  initial  guess  for  the
   32603             :   second stage without risk of running into "flat spot".  Parameter  G  is
   32604             :   fixed at G=1.
   32605             : * second  Levenberg-Marquardt  round  is   performed   without   excessive
   32606             :   constraints on B and C, but with G still equal to 1.  Results  from  the
   32607             :   previous round are used as initial guess.
   32608             : * third Levenberg-Marquardt round relaxes constraints on G  and  tries  two
   32609             :   different models - one with B>0 and one with B<0.
   32610             : * after fitting is done, we compare results with best values found so far,
   32611             :   rewrite "best solution" if needed, and move to next random location.
   32612             :   
   32613             : Overall algorithm is very stable and is not prone to  bad  local  extrema.
   32614             : Furthermore, it automatically scales when input data have  very  large  or
   32615             : very small range.
   32616             : 
   32617             : INPUT PARAMETERS:
   32618             :     X       -   array[N], stores X-values.
   32619             :                 MUST include only non-negative numbers  (but  may  include
   32620             :                 zero values). Can be unsorted.
   32621             :     Y       -   array[N], values to fit.
   32622             :     N       -   number of points. If N is less than  length  of  X/Y, only
   32623             :                 leading N elements are used.
   32624             :     CnstrLeft-  optional equality constraint for model value at the   left
   32625             :                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
   32626             :                 not need constraint on the model value at X=0 (in C++  you
   32627             :                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
   32628             :                 Double.NaN).
   32629             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
   32630             :                 information about constraints.
   32631             :     CnstrRight- optional equality constraint for model value at X=infinity.
   32632             :                 Specify NAN (Not-a-Number) if you do not  need  constraint
   32633             :                 on the model value (in C++  you can pass alglib::fp_nan as
   32634             :                 parameter, in  C# it will  be Double.NaN).
   32635             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
   32636             :                 information about constraints.
   32637             :                 
   32638             : OUTPUT PARAMETERS:
   32639             :     A,B,C,D,G-  parameters of 5PL model
   32640             :     Rep     -   fitting report. This structure has many fields,  but  ONLY
   32641             :                 ONES LISTED BELOW ARE SET:
   32642             :                 * Rep.IterationsCount - number of iterations performed
   32643             :                 * Rep.RMSError - root-mean-square error
   32644             :                 * Rep.AvgError - average absolute error
   32645             :                 * Rep.AvgRelError - average relative error (calculated for
   32646             :                   non-zero Y-values)
   32647             :                 * Rep.MaxError - maximum absolute error
   32648             :                 * Rep.R2 - coefficient of determination,  R-squared.  This
   32649             :                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
   32650             :                   of nonlinear  regression  there  are  multiple  ways  to
   32651             :                   define R2, each of them giving different results).
   32652             : 
   32653             : NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
   32654             :       range, and G is restricted by [1/10,10] range. It prevents algorithm
   32655             :       from making trial steps deep into the area of bad parameters.
   32656             : 
   32657             : NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
   32658             :       LogisticCalc5() function.
   32659             : 
   32660             : NOTE: if you need better control over fitting process than provided by this
   32661             :       function, you may use LogisticFit45X().
   32662             :                 
   32663             : NOTE: step is automatically scaled according to scale of parameters  being
   32664             :       fitted before we compare its length with EpsX. Thus,  this  function
   32665             :       can be used to fit data with very small or very large values without
   32666             :       changing EpsX.
   32667             : 
   32668             : EQUALITY CONSTRAINTS ON PARAMETERS
   32669             : 
   32670             : 5PL solver supports equality constraints on model  values  at   the   left
   32671             : boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
   32672             : completely optional and you can specify both of them, only  one  -  or  no
   32673             : constraints at all.
   32674             : 
   32675             : Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
   32676             : fitting), and CnstrRight contains right  one.
   32677             : 
   32678             : Unlike 4PL one, 5PL model is NOT symmetric with respect to  change in sign
   32679             : of B. Thus, negative B's are possible, and left constraint  may  constrain
   32680             : parameter A (for positive B's)  -  or  parameter  D  (for  negative  B's).
   32681             : Similarly changes meaning of right constraint.
   32682             : 
   32683             : You do not have to decide what parameter to  constrain  -  algorithm  will
   32684             : automatically determine correct parameters as fitting progresses. However,
   32685             : question highlighted above is important when you interpret fitting results.
   32686             :     
   32687             : 
   32688             :   -- ALGLIB PROJECT --
   32689             :      Copyright 14.02.2014 by Bochkanov Sergey
   32690             : *************************************************************************/
   32691           0 : void logisticfit5ec(/* Real    */ ae_vector* x,
   32692             :      /* Real    */ ae_vector* y,
   32693             :      ae_int_t n,
   32694             :      double cnstrleft,
   32695             :      double cnstrright,
   32696             :      double* a,
   32697             :      double* b,
   32698             :      double* c,
   32699             :      double* d,
   32700             :      double* g,
   32701             :      lsfitreport* rep,
   32702             :      ae_state *_state)
   32703             : {
   32704             :     ae_frame _frame_block;
   32705             :     ae_vector _x;
   32706             :     ae_vector _y;
   32707             : 
   32708           0 :     ae_frame_make(_state, &_frame_block);
   32709           0 :     memset(&_x, 0, sizeof(_x));
   32710           0 :     memset(&_y, 0, sizeof(_y));
   32711           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   32712           0 :     x = &_x;
   32713           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   32714           0 :     y = &_y;
   32715           0 :     *a = 0;
   32716           0 :     *b = 0;
   32717           0 :     *c = 0;
   32718           0 :     *d = 0;
   32719           0 :     *g = 0;
   32720           0 :     _lsfitreport_clear(rep);
   32721             : 
   32722           0 :     logisticfit45x(x, y, n, cnstrleft, cnstrright, ae_false, 0.0, 0.0, 0, a, b, c, d, g, rep, _state);
   32723           0 :     ae_frame_leave(_state);
   32724           0 : }
   32725             : 
   32726             : 
   32727             : /*************************************************************************
   32728             : This is "expert" 4PL/5PL fitting function, which can be used if  you  need
   32729             : better control over fitting process than provided  by  LogisticFit4()  or
   32730             : LogisticFit5().
   32731             : 
   32732             : This function fits model of the form
   32733             : 
   32734             :     F(x|A,B,C,D)   = D+(A-D)/(1+Power(x/C,B))           (4PL model)
   32735             : 
   32736             : or
   32737             : 
   32738             :     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)    (5PL model)
   32739             :     
   32740             : Here:
   32741             :     * A, D - unconstrained
   32742             :     * B>=0 for 4PL, unconstrained for 5PL
   32743             :     * C>0
   32744             :     * G>0 (if present)
   32745             : 
   32746             : INPUT PARAMETERS:
   32747             :     X       -   array[N], stores X-values.
   32748             :                 MUST include only non-negative numbers  (but  may  include
   32749             :                 zero values). Can be unsorted.
   32750             :     Y       -   array[N], values to fit.
   32751             :     N       -   number of points. If N is less than  length  of  X/Y, only
   32752             :                 leading N elements are used.
   32753             :     CnstrLeft-  optional equality constraint for model value at the   left
   32754             :                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
   32755             :                 not need constraint on the model value at X=0 (in C++  you
   32756             :                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
   32757             :                 Double.NaN).
   32758             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
   32759             :                 information about constraints.
   32760             :     CnstrRight- optional equality constraint for model value at X=infinity.
   32761             :                 Specify NAN (Not-a-Number) if you do not  need  constraint
   32762             :                 on the model value (in C++  you can pass alglib::fp_nan as
   32763             :                 parameter, in  C# it will  be Double.NaN).
   32764             :                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
   32765             :                 information about constraints.
   32766             :     Is4PL   -   whether 4PL or 5PL models are fitted
   32767             :     LambdaV -   regularization coefficient, LambdaV>=0.
   32768             :                 Set it to zero unless you know what you are doing.
   32769             :     EpsX    -   stopping condition (step size), EpsX>=0.
   32770             :                 Zero value means that small step is automatically chosen.
   32771             :                 See notes below for more information.
   32772             :     RsCnt   -   number of repeated restarts from  random  points.  4PL/5PL
   32773             :                 models are prone to problem of bad local extrema. Utilizing
   32774             :                 multiple random restarts allows  us  to  improve algorithm
   32775             :                 convergence.
   32776             :                 RsCnt>=0.
   32777             :                 Zero value means that function automatically choose  small
   32778             :                 amount of restarts (recommended).
   32779             :                 
   32780             : OUTPUT PARAMETERS:
   32781             :     A, B, C, D- parameters of 4PL model
   32782             :     G       -   parameter of 5PL model; for Is4PL=True, G=1 is returned.
   32783             :     Rep     -   fitting report. This structure has many fields,  but  ONLY
   32784             :                 ONES LISTED BELOW ARE SET:
   32785             :                 * Rep.IterationsCount - number of iterations performed
   32786             :                 * Rep.RMSError - root-mean-square error
   32787             :                 * Rep.AvgError - average absolute error
   32788             :                 * Rep.AvgRelError - average relative error (calculated for
   32789             :                   non-zero Y-values)
   32790             :                 * Rep.MaxError - maximum absolute error
   32791             :                 * Rep.R2 - coefficient of determination,  R-squared.  This
   32792             :                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
   32793             :                   of nonlinear  regression  there  are  multiple  ways  to
   32794             :                   define R2, each of them giving different results).
   32795             :                 
   32796             : NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
   32797             :       range, and G is restricted by [1/10,10] range. It prevents algorithm
   32798             :       from making trial steps deep into the area of bad parameters.
   32799             : 
   32800             : NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
   32801             :       LogisticCalc5() function.
   32802             : 
   32803             : NOTE: step is automatically scaled according to scale of parameters  being
   32804             :       fitted before we compare its length with EpsX. Thus,  this  function
   32805             :       can be used to fit data with very small or very large values without
   32806             :       changing EpsX.
   32807             : 
   32808             : EQUALITY CONSTRAINTS ON PARAMETERS
   32809             : 
   32810             : 4PL/5PL solver supports equality constraints on model values at  the  left
   32811             : boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
   32812             : completely optional and you can specify both of them, only  one  -  or  no
   32813             : constraints at all.
   32814             : 
   32815             : Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
   32816             : fitting), and CnstrRight contains right  one.  For  4PL,  left  constraint
   32817             : ALWAYS corresponds to parameter A, and right one is ALWAYS  constraint  on
   32818             : D. That's because 4PL model is normalized in such way that B>=0.
   32819             : 
   32820             : For 5PL model things are different. Unlike  4PL  one,  5PL  model  is  NOT
   32821             : symmetric with respect to  change  in  sign  of  B. Thus, negative B's are
   32822             : possible, and left constraint may constrain parameter A (for positive B's)
   32823             : - or parameter D (for negative B's). Similarly changes  meaning  of  right
   32824             : constraint.
   32825             : 
   32826             : You do not have to decide what parameter to  constrain  -  algorithm  will
   32827             : automatically determine correct parameters as fitting progresses. However,
   32828             : question highlighted above is important when you interpret fitting results.
   32829             :     
   32830             : 
   32831             :   -- ALGLIB PROJECT --
   32832             :      Copyright 14.02.2014 by Bochkanov Sergey
   32833             : *************************************************************************/
   32834           0 : void logisticfit45x(/* Real    */ ae_vector* x,
   32835             :      /* Real    */ ae_vector* y,
   32836             :      ae_int_t n,
   32837             :      double cnstrleft,
   32838             :      double cnstrright,
   32839             :      ae_bool is4pl,
   32840             :      double lambdav,
   32841             :      double epsx,
   32842             :      ae_int_t rscnt,
   32843             :      double* a,
   32844             :      double* b,
   32845             :      double* c,
   32846             :      double* d,
   32847             :      double* g,
   32848             :      lsfitreport* rep,
   32849             :      ae_state *_state)
   32850             : {
   32851             :     ae_frame _frame_block;
   32852             :     ae_vector _x;
   32853             :     ae_vector _y;
   32854             :     ae_int_t i;
   32855             :     ae_int_t outerit;
   32856             :     ae_int_t nz;
   32857             :     double v;
   32858             :     ae_vector p0;
   32859             :     ae_vector p1;
   32860             :     ae_vector p2;
   32861             :     ae_vector bndl;
   32862             :     ae_vector bndu;
   32863             :     ae_vector s;
   32864             :     ae_vector bndl1;
   32865             :     ae_vector bndu1;
   32866             :     ae_vector bndl2;
   32867             :     ae_vector bndu2;
   32868             :     ae_matrix z;
   32869             :     hqrndstate rs;
   32870             :     minlmstate state;
   32871             :     minlmreport replm;
   32872             :     ae_int_t maxits;
   32873             :     double fbest;
   32874             :     double flast;
   32875             :     double scalex;
   32876             :     double scaley;
   32877             :     ae_vector bufx;
   32878             :     ae_vector bufy;
   32879             :     double fposb;
   32880             :     double fnegb;
   32881             : 
   32882           0 :     ae_frame_make(_state, &_frame_block);
   32883           0 :     memset(&_x, 0, sizeof(_x));
   32884           0 :     memset(&_y, 0, sizeof(_y));
   32885           0 :     memset(&p0, 0, sizeof(p0));
   32886           0 :     memset(&p1, 0, sizeof(p1));
   32887           0 :     memset(&p2, 0, sizeof(p2));
   32888           0 :     memset(&bndl, 0, sizeof(bndl));
   32889           0 :     memset(&bndu, 0, sizeof(bndu));
   32890           0 :     memset(&s, 0, sizeof(s));
   32891           0 :     memset(&bndl1, 0, sizeof(bndl1));
   32892           0 :     memset(&bndu1, 0, sizeof(bndu1));
   32893           0 :     memset(&bndl2, 0, sizeof(bndl2));
   32894           0 :     memset(&bndu2, 0, sizeof(bndu2));
   32895           0 :     memset(&z, 0, sizeof(z));
   32896           0 :     memset(&rs, 0, sizeof(rs));
   32897           0 :     memset(&state, 0, sizeof(state));
   32898           0 :     memset(&replm, 0, sizeof(replm));
   32899           0 :     memset(&bufx, 0, sizeof(bufx));
   32900           0 :     memset(&bufy, 0, sizeof(bufy));
   32901           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   32902           0 :     x = &_x;
   32903           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   32904           0 :     y = &_y;
   32905           0 :     *a = 0;
   32906           0 :     *b = 0;
   32907           0 :     *c = 0;
   32908           0 :     *d = 0;
   32909           0 :     *g = 0;
   32910           0 :     _lsfitreport_clear(rep);
   32911           0 :     ae_vector_init(&p0, 0, DT_REAL, _state, ae_true);
   32912           0 :     ae_vector_init(&p1, 0, DT_REAL, _state, ae_true);
   32913           0 :     ae_vector_init(&p2, 0, DT_REAL, _state, ae_true);
   32914           0 :     ae_vector_init(&bndl, 0, DT_REAL, _state, ae_true);
   32915           0 :     ae_vector_init(&bndu, 0, DT_REAL, _state, ae_true);
   32916           0 :     ae_vector_init(&s, 0, DT_REAL, _state, ae_true);
   32917           0 :     ae_vector_init(&bndl1, 0, DT_REAL, _state, ae_true);
   32918           0 :     ae_vector_init(&bndu1, 0, DT_REAL, _state, ae_true);
   32919           0 :     ae_vector_init(&bndl2, 0, DT_REAL, _state, ae_true);
   32920           0 :     ae_vector_init(&bndu2, 0, DT_REAL, _state, ae_true);
   32921           0 :     ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true);
   32922           0 :     _hqrndstate_init(&rs, _state, ae_true);
   32923           0 :     _minlmstate_init(&state, _state, ae_true);
   32924           0 :     _minlmreport_init(&replm, _state, ae_true);
   32925           0 :     ae_vector_init(&bufx, 0, DT_REAL, _state, ae_true);
   32926           0 :     ae_vector_init(&bufy, 0, DT_REAL, _state, ae_true);
   32927             : 
   32928           0 :     ae_assert(ae_isfinite(epsx, _state), "LogisticFitX: EpsX is infinite/NAN", _state);
   32929           0 :     ae_assert(ae_isfinite(lambdav, _state), "LogisticFitX: LambdaV is infinite/NAN", _state);
   32930           0 :     ae_assert(ae_isfinite(cnstrleft, _state)||ae_isnan(cnstrleft, _state), "LogisticFitX: CnstrLeft is NOT finite or NAN", _state);
   32931           0 :     ae_assert(ae_isfinite(cnstrright, _state)||ae_isnan(cnstrright, _state), "LogisticFitX: CnstrRight is NOT finite or NAN", _state);
   32932           0 :     ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "LogisticFitX: negative LambdaV", _state);
   32933           0 :     ae_assert(n>0, "LogisticFitX: N<=0", _state);
   32934           0 :     ae_assert(rscnt>=0, "LogisticFitX: RsCnt<0", _state);
   32935           0 :     ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "LogisticFitX: EpsX<0", _state);
   32936           0 :     ae_assert(x->cnt>=n, "LogisticFitX: Length(X)<N", _state);
   32937           0 :     ae_assert(y->cnt>=n, "LogisticFitX: Length(Y)<N", _state);
   32938           0 :     ae_assert(isfinitevector(x, n, _state), "LogisticFitX: X contains infinite/NAN values", _state);
   32939           0 :     ae_assert(isfinitevector(y, n, _state), "LogisticFitX: X contains infinite/NAN values", _state);
   32940           0 :     hqrndseed(2211, 1033044, &rs, _state);
   32941           0 :     lsfit_clearreport(rep, _state);
   32942           0 :     if( ae_fp_eq(epsx,(double)(0)) )
   32943             :     {
   32944           0 :         epsx = 1.0E-10;
   32945             :     }
   32946           0 :     if( rscnt==0 )
   32947             :     {
   32948           0 :         rscnt = 4;
   32949             :     }
   32950           0 :     maxits = 1000;
   32951             :     
   32952             :     /*
   32953             :      * Sort points by X.
   32954             :      * Determine number of zero and non-zero values.
   32955             :      */
   32956           0 :     tagsortfastr(x, y, &bufx, &bufy, n, _state);
   32957           0 :     ae_assert(ae_fp_greater_eq(x->ptr.p_double[0],(double)(0)), "LogisticFitX: some X[] are negative", _state);
   32958           0 :     nz = n;
   32959           0 :     for(i=0; i<=n-1; i++)
   32960             :     {
   32961           0 :         if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) )
   32962             :         {
   32963           0 :             nz = i;
   32964           0 :             break;
   32965             :         }
   32966             :     }
   32967             :     
   32968             :     /*
   32969             :      * For NZ=N (all X[] are zero) special code is used.
   32970             :      * For NZ<N we use general-purpose code.
   32971             :      */
   32972           0 :     rep->iterationscount = 0;
   32973           0 :     if( nz==n )
   32974             :     {
   32975             :         
   32976             :         /*
   32977             :          * NZ=N, degenerate problem.
   32978             :          * No need to run optimizer.
   32979             :          */
   32980           0 :         v = 0.0;
   32981           0 :         for(i=0; i<=n-1; i++)
   32982             :         {
   32983           0 :             v = v+y->ptr.p_double[i];
   32984             :         }
   32985           0 :         v = v/n;
   32986           0 :         if( ae_isfinite(cnstrleft, _state) )
   32987             :         {
   32988           0 :             *a = cnstrleft;
   32989             :         }
   32990             :         else
   32991             :         {
   32992           0 :             *a = v;
   32993             :         }
   32994           0 :         *b = (double)(1);
   32995           0 :         *c = (double)(1);
   32996           0 :         if( ae_isfinite(cnstrright, _state) )
   32997             :         {
   32998           0 :             *d = cnstrright;
   32999             :         }
   33000             :         else
   33001             :         {
   33002           0 :             *d = *a;
   33003             :         }
   33004           0 :         *g = (double)(1);
   33005           0 :         lsfit_logisticfit45errors(x, y, n, *a, *b, *c, *d, *g, rep, _state);
   33006           0 :         ae_frame_leave(_state);
   33007           0 :         return;
   33008             :     }
   33009             :     
   33010             :     /*
   33011             :      * Non-degenerate problem.
   33012             :      * Determine scale of data.
   33013             :      */
   33014           0 :     scalex = x->ptr.p_double[nz+(n-nz)/2];
   33015           0 :     ae_assert(ae_fp_greater(scalex,(double)(0)), "LogisticFitX: internal error", _state);
   33016           0 :     v = 0.0;
   33017           0 :     for(i=0; i<=n-1; i++)
   33018             :     {
   33019           0 :         v = v+y->ptr.p_double[i];
   33020             :     }
   33021           0 :     v = v/n;
   33022           0 :     scaley = 0.0;
   33023           0 :     for(i=0; i<=n-1; i++)
   33024             :     {
   33025           0 :         scaley = scaley+ae_sqr(y->ptr.p_double[i]-v, _state);
   33026             :     }
   33027           0 :     scaley = ae_sqrt(scaley/n, _state);
   33028           0 :     if( ae_fp_eq(scaley,(double)(0)) )
   33029             :     {
   33030           0 :         scaley = 1.0;
   33031             :     }
   33032           0 :     ae_vector_set_length(&s, 5, _state);
   33033           0 :     s.ptr.p_double[0] = scaley;
   33034           0 :     s.ptr.p_double[1] = 0.1;
   33035           0 :     s.ptr.p_double[2] = scalex;
   33036           0 :     s.ptr.p_double[3] = scaley;
   33037           0 :     s.ptr.p_double[4] = 0.1;
   33038           0 :     ae_vector_set_length(&p0, 5, _state);
   33039           0 :     p0.ptr.p_double[0] = (double)(0);
   33040           0 :     p0.ptr.p_double[1] = (double)(0);
   33041           0 :     p0.ptr.p_double[2] = (double)(0);
   33042           0 :     p0.ptr.p_double[3] = (double)(0);
   33043           0 :     p0.ptr.p_double[4] = (double)(0);
   33044           0 :     ae_vector_set_length(&bndl, 5, _state);
   33045           0 :     ae_vector_set_length(&bndu, 5, _state);
   33046           0 :     ae_vector_set_length(&bndl1, 5, _state);
   33047           0 :     ae_vector_set_length(&bndu1, 5, _state);
   33048           0 :     ae_vector_set_length(&bndl2, 5, _state);
   33049           0 :     ae_vector_set_length(&bndu2, 5, _state);
   33050           0 :     minlmcreatevj(5, n+5, &p0, &state, _state);
   33051           0 :     minlmsetscale(&state, &s, _state);
   33052           0 :     minlmsetcond(&state, epsx, maxits, _state);
   33053           0 :     minlmsetxrep(&state, ae_true, _state);
   33054           0 :     ae_vector_set_length(&p1, 5, _state);
   33055           0 :     ae_vector_set_length(&p2, 5, _state);
   33056             :     
   33057             :     /*
   33058             :      * Is it 4PL problem?
   33059             :      */
   33060           0 :     if( is4pl )
   33061             :     {
   33062             :         
   33063             :         /*
   33064             :          * Run outer iterations
   33065             :          */
   33066           0 :         *a = (double)(0);
   33067           0 :         *b = (double)(1);
   33068           0 :         *c = (double)(1);
   33069           0 :         *d = (double)(1);
   33070           0 :         *g = (double)(1);
   33071           0 :         fbest = ae_maxrealnumber;
   33072           0 :         for(outerit=0; outerit<=rscnt-1; outerit++)
   33073             :         {
   33074             :             
   33075             :             /*
   33076             :              * Prepare initial point; use B>0
   33077             :              */
   33078           0 :             if( ae_isfinite(cnstrleft, _state) )
   33079             :             {
   33080           0 :                 p1.ptr.p_double[0] = cnstrleft;
   33081             :             }
   33082             :             else
   33083             :             {
   33084           0 :                 p1.ptr.p_double[0] = y->ptr.p_double[0]+0.15*scaley*(hqrnduniformr(&rs, _state)-0.5);
   33085             :             }
   33086           0 :             p1.ptr.p_double[1] = 0.5+hqrnduniformr(&rs, _state);
   33087           0 :             p1.ptr.p_double[2] = x->ptr.p_double[nz+hqrnduniformi(&rs, n-nz, _state)];
   33088           0 :             if( ae_isfinite(cnstrright, _state) )
   33089             :             {
   33090           0 :                 p1.ptr.p_double[3] = cnstrright;
   33091             :             }
   33092             :             else
   33093             :             {
   33094           0 :                 p1.ptr.p_double[3] = y->ptr.p_double[n-1]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5);
   33095             :             }
   33096           0 :             p1.ptr.p_double[4] = 1.0;
   33097             :             
   33098             :             /*
   33099             :              * Run optimization with tight constraints and increased regularization
   33100             :              */
   33101           0 :             if( ae_isfinite(cnstrleft, _state) )
   33102             :             {
   33103           0 :                 bndl.ptr.p_double[0] = cnstrleft;
   33104           0 :                 bndu.ptr.p_double[0] = cnstrleft;
   33105             :             }
   33106             :             else
   33107             :             {
   33108           0 :                 bndl.ptr.p_double[0] = _state->v_neginf;
   33109           0 :                 bndu.ptr.p_double[0] = _state->v_posinf;
   33110             :             }
   33111           0 :             bndl.ptr.p_double[1] = 0.5;
   33112           0 :             bndu.ptr.p_double[1] = 2.0;
   33113           0 :             bndl.ptr.p_double[2] = 0.5*scalex;
   33114           0 :             bndu.ptr.p_double[2] = 2.0*scalex;
   33115           0 :             if( ae_isfinite(cnstrright, _state) )
   33116             :             {
   33117           0 :                 bndl.ptr.p_double[3] = cnstrright;
   33118           0 :                 bndu.ptr.p_double[3] = cnstrright;
   33119             :             }
   33120             :             else
   33121             :             {
   33122           0 :                 bndl.ptr.p_double[3] = _state->v_neginf;
   33123           0 :                 bndu.ptr.p_double[3] = _state->v_posinf;
   33124             :             }
   33125           0 :             bndl.ptr.p_double[4] = 1.0;
   33126           0 :             bndu.ptr.p_double[4] = 1.0;
   33127           0 :             minlmsetbc(&state, &bndl, &bndu, _state);
   33128           0 :             lsfit_logisticfitinternal(x, y, n, is4pl, 100*lambdav, &state, &replm, &p1, &flast, _state);
   33129           0 :             rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33130             :             
   33131             :             /*
   33132             :              * Relax constraints, run optimization one more time
   33133             :              */
   33134           0 :             bndl.ptr.p_double[1] = 0.1;
   33135           0 :             bndu.ptr.p_double[1] = 10.0;
   33136           0 :             bndl.ptr.p_double[2] = ae_machineepsilon*scalex;
   33137           0 :             bndu.ptr.p_double[2] = scalex/ae_machineepsilon;
   33138           0 :             minlmsetbc(&state, &bndl, &bndu, _state);
   33139           0 :             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
   33140           0 :             rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33141             :             
   33142             :             /*
   33143             :              * Relax constraints more, run optimization one more time
   33144             :              */
   33145           0 :             bndl.ptr.p_double[1] = 0.01;
   33146           0 :             bndu.ptr.p_double[1] = 100.0;
   33147           0 :             minlmsetbc(&state, &bndl, &bndu, _state);
   33148           0 :             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
   33149           0 :             rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33150             :             
   33151             :             /*
   33152             :              * Relax constraints ever more, run optimization one more time
   33153             :              */
   33154           0 :             bndl.ptr.p_double[1] = 0.001;
   33155           0 :             bndu.ptr.p_double[1] = 1000.0;
   33156           0 :             minlmsetbc(&state, &bndl, &bndu, _state);
   33157           0 :             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
   33158           0 :             rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33159             :             
   33160             :             /*
   33161             :              * Compare results with best value found so far.
   33162             :              */
   33163           0 :             if( ae_fp_less(flast,fbest) )
   33164             :             {
   33165           0 :                 *a = p1.ptr.p_double[0];
   33166           0 :                 *b = p1.ptr.p_double[1];
   33167           0 :                 *c = p1.ptr.p_double[2];
   33168           0 :                 *d = p1.ptr.p_double[3];
   33169           0 :                 *g = p1.ptr.p_double[4];
   33170           0 :                 fbest = flast;
   33171             :             }
   33172             :         }
   33173           0 :         lsfit_logisticfit45errors(x, y, n, *a, *b, *c, *d, *g, rep, _state);
   33174           0 :         ae_frame_leave(_state);
   33175           0 :         return;
   33176             :     }
   33177             :     
   33178             :     /*
   33179             :      * Well.... we have 5PL fit, and we have to test two separate branches:
   33180             :      * B>0 and B<0, because of asymmetry in the curve. First, we run optimization
   33181             :      * with tight constraints two times, in order to determine better sign for B.
   33182             :      *
   33183             :      * Run outer iterations
   33184             :      */
   33185           0 :     *a = (double)(0);
   33186           0 :     *b = (double)(1);
   33187           0 :     *c = (double)(1);
   33188           0 :     *d = (double)(1);
   33189           0 :     *g = (double)(1);
   33190           0 :     fbest = ae_maxrealnumber;
   33191           0 :     for(outerit=0; outerit<=rscnt-1; outerit++)
   33192             :     {
   33193             :         
   33194             :         /*
   33195             :          * First, we try positive B.
   33196             :          */
   33197           0 :         p1.ptr.p_double[0] = y->ptr.p_double[0]+0.15*scaley*(hqrnduniformr(&rs, _state)-0.5);
   33198           0 :         p1.ptr.p_double[1] = 0.5+hqrnduniformr(&rs, _state);
   33199           0 :         p1.ptr.p_double[2] = x->ptr.p_double[nz+hqrnduniformi(&rs, n-nz, _state)];
   33200           0 :         p1.ptr.p_double[3] = y->ptr.p_double[n-1]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5);
   33201           0 :         p1.ptr.p_double[4] = 1.0;
   33202           0 :         bndl1.ptr.p_double[0] = _state->v_neginf;
   33203           0 :         bndu1.ptr.p_double[0] = _state->v_posinf;
   33204           0 :         bndl1.ptr.p_double[1] = 0.5;
   33205           0 :         bndu1.ptr.p_double[1] = 2.0;
   33206           0 :         bndl1.ptr.p_double[2] = 0.5*scalex;
   33207           0 :         bndu1.ptr.p_double[2] = 2.0*scalex;
   33208           0 :         bndl1.ptr.p_double[3] = _state->v_neginf;
   33209           0 :         bndu1.ptr.p_double[3] = _state->v_posinf;
   33210           0 :         bndl1.ptr.p_double[4] = 0.5;
   33211           0 :         bndu1.ptr.p_double[4] = 2.0;
   33212           0 :         if( ae_isfinite(cnstrleft, _state) )
   33213             :         {
   33214           0 :             p1.ptr.p_double[0] = cnstrleft;
   33215           0 :             bndl1.ptr.p_double[0] = cnstrleft;
   33216           0 :             bndu1.ptr.p_double[0] = cnstrleft;
   33217             :         }
   33218           0 :         if( ae_isfinite(cnstrright, _state) )
   33219             :         {
   33220           0 :             p1.ptr.p_double[3] = cnstrright;
   33221           0 :             bndl1.ptr.p_double[3] = cnstrright;
   33222           0 :             bndu1.ptr.p_double[3] = cnstrright;
   33223             :         }
   33224           0 :         minlmsetbc(&state, &bndl1, &bndu1, _state);
   33225           0 :         lsfit_logisticfitinternal(x, y, n, is4pl, 100*lambdav, &state, &replm, &p1, &fposb, _state);
   33226           0 :         rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33227             :         
   33228             :         /*
   33229             :          * Second attempt - with negative B (constraints are still tight).
   33230             :          */
   33231           0 :         p2.ptr.p_double[0] = y->ptr.p_double[n-1]+0.15*scaley*(hqrnduniformr(&rs, _state)-0.5);
   33232           0 :         p2.ptr.p_double[1] = -(0.5+hqrnduniformr(&rs, _state));
   33233           0 :         p2.ptr.p_double[2] = x->ptr.p_double[nz+hqrnduniformi(&rs, n-nz, _state)];
   33234           0 :         p2.ptr.p_double[3] = y->ptr.p_double[0]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5);
   33235           0 :         p2.ptr.p_double[4] = 1.0;
   33236           0 :         bndl2.ptr.p_double[0] = _state->v_neginf;
   33237           0 :         bndu2.ptr.p_double[0] = _state->v_posinf;
   33238           0 :         bndl2.ptr.p_double[1] = -2.0;
   33239           0 :         bndu2.ptr.p_double[1] = -0.5;
   33240           0 :         bndl2.ptr.p_double[2] = 0.5*scalex;
   33241           0 :         bndu2.ptr.p_double[2] = 2.0*scalex;
   33242           0 :         bndl2.ptr.p_double[3] = _state->v_neginf;
   33243           0 :         bndu2.ptr.p_double[3] = _state->v_posinf;
   33244           0 :         bndl2.ptr.p_double[4] = 0.5;
   33245           0 :         bndu2.ptr.p_double[4] = 2.0;
   33246           0 :         if( ae_isfinite(cnstrleft, _state) )
   33247             :         {
   33248           0 :             p2.ptr.p_double[3] = cnstrleft;
   33249           0 :             bndl2.ptr.p_double[3] = cnstrleft;
   33250           0 :             bndu2.ptr.p_double[3] = cnstrleft;
   33251             :         }
   33252           0 :         if( ae_isfinite(cnstrright, _state) )
   33253             :         {
   33254           0 :             p2.ptr.p_double[0] = cnstrright;
   33255           0 :             bndl2.ptr.p_double[0] = cnstrright;
   33256           0 :             bndu2.ptr.p_double[0] = cnstrright;
   33257             :         }
   33258           0 :         minlmsetbc(&state, &bndl2, &bndu2, _state);
   33259           0 :         lsfit_logisticfitinternal(x, y, n, is4pl, 100*lambdav, &state, &replm, &p2, &fnegb, _state);
   33260           0 :         rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33261             :         
   33262             :         /*
   33263             :          * Select best version of B sign
   33264             :          */
   33265           0 :         if( ae_fp_less(fposb,fnegb) )
   33266             :         {
   33267             :             
   33268             :             /*
   33269             :              * Prepare relaxed constraints assuming that B is positive
   33270             :              */
   33271           0 :             bndl1.ptr.p_double[1] = 0.1;
   33272           0 :             bndu1.ptr.p_double[1] = 10.0;
   33273           0 :             bndl1.ptr.p_double[2] = ae_machineepsilon*scalex;
   33274           0 :             bndu1.ptr.p_double[2] = scalex/ae_machineepsilon;
   33275           0 :             bndl1.ptr.p_double[4] = 0.1;
   33276           0 :             bndu1.ptr.p_double[4] = 10.0;
   33277           0 :             minlmsetbc(&state, &bndl1, &bndu1, _state);
   33278           0 :             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
   33279           0 :             rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33280             :             
   33281             :             /*
   33282             :              * Prepare stronger relaxation of constraints
   33283             :              */
   33284           0 :             bndl1.ptr.p_double[1] = 0.01;
   33285           0 :             bndu1.ptr.p_double[1] = 100.0;
   33286           0 :             minlmsetbc(&state, &bndl1, &bndu1, _state);
   33287           0 :             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
   33288           0 :             rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33289             :             
   33290             :             /*
   33291             :              * Prepare stronger relaxation of constraints
   33292             :              */
   33293           0 :             bndl1.ptr.p_double[1] = 0.001;
   33294           0 :             bndu1.ptr.p_double[1] = 1000.0;
   33295           0 :             minlmsetbc(&state, &bndl1, &bndu1, _state);
   33296           0 :             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
   33297           0 :             rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33298             :             
   33299             :             /*
   33300             :              * Compare results with best value found so far.
   33301             :              */
   33302           0 :             if( ae_fp_less(flast,fbest) )
   33303             :             {
   33304           0 :                 *a = p1.ptr.p_double[0];
   33305           0 :                 *b = p1.ptr.p_double[1];
   33306           0 :                 *c = p1.ptr.p_double[2];
   33307           0 :                 *d = p1.ptr.p_double[3];
   33308           0 :                 *g = p1.ptr.p_double[4];
   33309           0 :                 fbest = flast;
   33310             :             }
   33311             :         }
   33312             :         else
   33313             :         {
   33314             :             
   33315             :             /*
   33316             :              * Prepare relaxed constraints assuming that B is negative
   33317             :              */
   33318           0 :             bndl2.ptr.p_double[1] = -10.0;
   33319           0 :             bndu2.ptr.p_double[1] = -0.1;
   33320           0 :             bndl2.ptr.p_double[2] = ae_machineepsilon*scalex;
   33321           0 :             bndu2.ptr.p_double[2] = scalex/ae_machineepsilon;
   33322           0 :             bndl2.ptr.p_double[4] = 0.1;
   33323           0 :             bndu2.ptr.p_double[4] = 10.0;
   33324           0 :             minlmsetbc(&state, &bndl2, &bndu2, _state);
   33325           0 :             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p2, &flast, _state);
   33326           0 :             rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33327             :             
   33328             :             /*
   33329             :              * Prepare stronger relaxation
   33330             :              */
   33331           0 :             bndl2.ptr.p_double[1] = -100.0;
   33332           0 :             bndu2.ptr.p_double[1] = -0.01;
   33333           0 :             minlmsetbc(&state, &bndl2, &bndu2, _state);
   33334           0 :             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p2, &flast, _state);
   33335           0 :             rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33336             :             
   33337             :             /*
   33338             :              * Prepare stronger relaxation
   33339             :              */
   33340           0 :             bndl2.ptr.p_double[1] = -1000.0;
   33341           0 :             bndu2.ptr.p_double[1] = -0.001;
   33342           0 :             minlmsetbc(&state, &bndl2, &bndu2, _state);
   33343           0 :             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p2, &flast, _state);
   33344           0 :             rep->iterationscount = rep->iterationscount+replm.iterationscount;
   33345             :             
   33346             :             /*
   33347             :              * Compare results with best value found so far.
   33348             :              */
   33349           0 :             if( ae_fp_less(flast,fbest) )
   33350             :             {
   33351           0 :                 *a = p2.ptr.p_double[0];
   33352           0 :                 *b = p2.ptr.p_double[1];
   33353           0 :                 *c = p2.ptr.p_double[2];
   33354           0 :                 *d = p2.ptr.p_double[3];
   33355           0 :                 *g = p2.ptr.p_double[4];
   33356           0 :                 fbest = flast;
   33357             :             }
   33358             :         }
   33359             :     }
   33360           0 :     lsfit_logisticfit45errors(x, y, n, *a, *b, *c, *d, *g, rep, _state);
   33361           0 :     ae_frame_leave(_state);
   33362             : }
   33363             : 
   33364             : 
   33365             : /*************************************************************************
   33366             : Weghted rational least  squares  fitting  using  Floater-Hormann  rational
   33367             : functions  with  optimal  D  chosen  from  [0,9],  with  constraints   and
   33368             : individual weights.
   33369             : 
   33370             : Equidistant  grid  with M node on [min(x),max(x)]  is  used to build basis
   33371             : functions. Different values of D are tried, optimal D (least WEIGHTED root
   33372             : mean square error) is chosen.  Task  is  linear,  so  linear least squares
   33373             : solver  is  used.  Complexity  of  this  computational  scheme is O(N*M^2)
   33374             : (mostly dominated by the least squares solver).
   33375             : 
   33376             : SEE ALSO
   33377             : * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual
   33378             :   weights and constraints.
   33379             :   
   33380             :   ! COMMERCIAL EDITION OF ALGLIB:
   33381             :   ! 
   33382             :   ! Commercial Edition of ALGLIB includes following important improvements
   33383             :   ! of this function:
   33384             :   ! * high-performance native backend with same C# interface (C# version)
   33385             :   ! * multithreading support (C++ and C# versions)
   33386             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   33387             :   !   (C++ and C# versions, x86/x64 platform)
   33388             :   ! 
   33389             :   ! We recommend you to read 'Working with commercial version' section  of
   33390             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   33391             :   ! related features provided by commercial edition of ALGLIB.
   33392             : 
   33393             : INPUT PARAMETERS:
   33394             :     X   -   points, array[0..N-1].
   33395             :     Y   -   function values, array[0..N-1].
   33396             :     W   -   weights, array[0..N-1]
   33397             :             Each summand in square  sum  of  approximation deviations from
   33398             :             given  values  is  multiplied  by  the square of corresponding
   33399             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
   33400             :             task.
   33401             :     N   -   number of points, N>0.
   33402             :     XC  -   points where function values/derivatives are constrained,
   33403             :             array[0..K-1].
   33404             :     YC  -   values of constraints, array[0..K-1]
   33405             :     DC  -   array[0..K-1], types of constraints:
   33406             :             * DC[i]=0   means that S(XC[i])=YC[i]
   33407             :             * DC[i]=1   means that S'(XC[i])=YC[i]
   33408             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
   33409             :     K   -   number of constraints, 0<=K<M.
   33410             :             K=0 means no constraints (XC/YC/DC are not used in such cases)
   33411             :     M   -   number of basis functions ( = number_of_nodes), M>=2.
   33412             : 
   33413             : OUTPUT PARAMETERS:
   33414             :     Info-   same format as in LSFitLinearWC() subroutine.
   33415             :             * Info>0    task is solved
   33416             :             * Info<=0   an error occured:
   33417             :                         -4 means inconvergence of internal SVD
   33418             :                         -3 means inconsistent constraints
   33419             :                         -1 means another errors in parameters passed
   33420             :                            (N<=0, for example)
   33421             :     B   -   barycentric interpolant.
   33422             :     Rep -   report, same format as in LSFitLinearWC() subroutine.
   33423             :             Following fields are set:
   33424             :             * DBest         best value of the D parameter
   33425             :             * RMSError      rms error on the (X,Y).
   33426             :             * AvgError      average error on the (X,Y).
   33427             :             * AvgRelError   average relative error on the non-zero Y
   33428             :             * MaxError      maximum error
   33429             :                             NON-WEIGHTED ERRORS ARE CALCULATED
   33430             : 
   33431             : IMPORTANT:
   33432             :     this subroutine doesn't calculate task's condition number for K<>0.
   33433             : 
   33434             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
   33435             : 
   33436             : Setting constraints can lead  to undesired  results,  like ill-conditioned
   33437             : behavior, or inconsistency being detected. From the other side,  it allows
   33438             : us to improve quality of the fit. Here we summarize  our  experience  with
   33439             : constrained barycentric interpolants:
   33440             : * excessive  constraints  can  be  inconsistent.   Floater-Hormann   basis
   33441             :   functions aren't as flexible as splines (although they are very smooth).
   33442             : * the more evenly constraints are spread across [min(x),max(x)],  the more
   33443             :   chances that they will be consistent
   33444             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
   33445             :   constraints will be consistent
   33446             : * in the general case, consistency of constraints IS NOT GUARANTEED.
   33447             : * in the several special cases, however, we CAN guarantee consistency.
   33448             : * one of this cases is constraints on the function  VALUES at the interval
   33449             :   boundaries. Note that consustency of the  constraints  on  the  function
   33450             :   DERIVATIVES is NOT guaranteed (you can use in such cases  cubic  splines
   33451             :   which are more flexible).
   33452             : * another  special  case  is ONE constraint on the function value (OR, but
   33453             :   not AND, derivative) anywhere in the interval
   33454             : 
   33455             : Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
   33456             : can't solve your task without them. Anything beyond  special  cases  given
   33457             : above is not guaranteed and may result in inconsistency.
   33458             : 
   33459             :   -- ALGLIB PROJECT --
   33460             :      Copyright 18.08.2009 by Bochkanov Sergey
   33461             : *************************************************************************/
   33462           0 : void barycentricfitfloaterhormannwc(/* Real    */ ae_vector* x,
   33463             :      /* Real    */ ae_vector* y,
   33464             :      /* Real    */ ae_vector* w,
   33465             :      ae_int_t n,
   33466             :      /* Real    */ ae_vector* xc,
   33467             :      /* Real    */ ae_vector* yc,
   33468             :      /* Integer */ ae_vector* dc,
   33469             :      ae_int_t k,
   33470             :      ae_int_t m,
   33471             :      ae_int_t* info,
   33472             :      barycentricinterpolant* b,
   33473             :      barycentricfitreport* rep,
   33474             :      ae_state *_state)
   33475             : {
   33476             :     ae_frame _frame_block;
   33477             :     ae_int_t d;
   33478             :     ae_int_t i;
   33479             :     double wrmscur;
   33480             :     double wrmsbest;
   33481             :     barycentricinterpolant locb;
   33482             :     barycentricfitreport locrep;
   33483             :     ae_int_t locinfo;
   33484             : 
   33485           0 :     ae_frame_make(_state, &_frame_block);
   33486           0 :     memset(&locb, 0, sizeof(locb));
   33487           0 :     memset(&locrep, 0, sizeof(locrep));
   33488           0 :     *info = 0;
   33489           0 :     _barycentricinterpolant_clear(b);
   33490           0 :     _barycentricfitreport_clear(rep);
   33491           0 :     _barycentricinterpolant_init(&locb, _state, ae_true);
   33492           0 :     _barycentricfitreport_init(&locrep, _state, ae_true);
   33493             : 
   33494           0 :     ae_assert(n>0, "BarycentricFitFloaterHormannWC: N<=0!", _state);
   33495           0 :     ae_assert(m>0, "BarycentricFitFloaterHormannWC: M<=0!", _state);
   33496           0 :     ae_assert(k>=0, "BarycentricFitFloaterHormannWC: K<0!", _state);
   33497           0 :     ae_assert(k<m, "BarycentricFitFloaterHormannWC: K>=M!", _state);
   33498           0 :     ae_assert(x->cnt>=n, "BarycentricFitFloaterHormannWC: Length(X)<N!", _state);
   33499           0 :     ae_assert(y->cnt>=n, "BarycentricFitFloaterHormannWC: Length(Y)<N!", _state);
   33500           0 :     ae_assert(w->cnt>=n, "BarycentricFitFloaterHormannWC: Length(W)<N!", _state);
   33501           0 :     ae_assert(xc->cnt>=k, "BarycentricFitFloaterHormannWC: Length(XC)<K!", _state);
   33502           0 :     ae_assert(yc->cnt>=k, "BarycentricFitFloaterHormannWC: Length(YC)<K!", _state);
   33503           0 :     ae_assert(dc->cnt>=k, "BarycentricFitFloaterHormannWC: Length(DC)<K!", _state);
   33504           0 :     ae_assert(isfinitevector(x, n, _state), "BarycentricFitFloaterHormannWC: X contains infinite or NaN values!", _state);
   33505           0 :     ae_assert(isfinitevector(y, n, _state), "BarycentricFitFloaterHormannWC: Y contains infinite or NaN values!", _state);
   33506           0 :     ae_assert(isfinitevector(w, n, _state), "BarycentricFitFloaterHormannWC: X contains infinite or NaN values!", _state);
   33507           0 :     ae_assert(isfinitevector(xc, k, _state), "BarycentricFitFloaterHormannWC: XC contains infinite or NaN values!", _state);
   33508           0 :     ae_assert(isfinitevector(yc, k, _state), "BarycentricFitFloaterHormannWC: YC contains infinite or NaN values!", _state);
   33509           0 :     for(i=0; i<=k-1; i++)
   33510             :     {
   33511           0 :         ae_assert(dc->ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "BarycentricFitFloaterHormannWC: one of DC[] is not 0 or 1!", _state);
   33512             :     }
   33513             :     
   33514             :     /*
   33515             :      * Find optimal D
   33516             :      *
   33517             :      * Info is -3 by default (degenerate constraints).
   33518             :      * If LocInfo will always be equal to -3, Info will remain equal to -3.
   33519             :      * If at least once LocInfo will be -4, Info will be -4.
   33520             :      */
   33521           0 :     wrmsbest = ae_maxrealnumber;
   33522           0 :     rep->dbest = -1;
   33523           0 :     *info = -3;
   33524           0 :     for(d=0; d<=ae_minint(9, n-1, _state); d++)
   33525             :     {
   33526           0 :         lsfit_barycentricfitwcfixedd(x, y, w, n, xc, yc, dc, k, m, d, &locinfo, &locb, &locrep, _state);
   33527           0 :         ae_assert((locinfo==-4||locinfo==-3)||locinfo>0, "BarycentricFitFloaterHormannWC: unexpected result from BarycentricFitWCFixedD!", _state);
   33528           0 :         if( locinfo>0 )
   33529             :         {
   33530             :             
   33531             :             /*
   33532             :              * Calculate weghted RMS
   33533             :              */
   33534           0 :             wrmscur = (double)(0);
   33535           0 :             for(i=0; i<=n-1; i++)
   33536             :             {
   33537           0 :                 wrmscur = wrmscur+ae_sqr(w->ptr.p_double[i]*(y->ptr.p_double[i]-barycentriccalc(&locb, x->ptr.p_double[i], _state)), _state);
   33538             :             }
   33539           0 :             wrmscur = ae_sqrt(wrmscur/n, _state);
   33540           0 :             if( ae_fp_less(wrmscur,wrmsbest)||rep->dbest<0 )
   33541             :             {
   33542           0 :                 barycentriccopy(&locb, b, _state);
   33543           0 :                 rep->dbest = d;
   33544           0 :                 *info = 1;
   33545           0 :                 rep->rmserror = locrep.rmserror;
   33546           0 :                 rep->avgerror = locrep.avgerror;
   33547           0 :                 rep->avgrelerror = locrep.avgrelerror;
   33548           0 :                 rep->maxerror = locrep.maxerror;
   33549           0 :                 rep->taskrcond = locrep.taskrcond;
   33550           0 :                 wrmsbest = wrmscur;
   33551             :             }
   33552             :         }
   33553             :         else
   33554             :         {
   33555           0 :             if( locinfo!=-3&&*info<0 )
   33556             :             {
   33557           0 :                 *info = locinfo;
   33558             :             }
   33559             :         }
   33560             :     }
   33561           0 :     ae_frame_leave(_state);
   33562           0 : }
   33563             : 
   33564             : 
   33565             : /*************************************************************************
   33566             : Rational least squares fitting using  Floater-Hormann  rational  functions
   33567             : with optimal D chosen from [0,9].
   33568             : 
   33569             : Equidistant  grid  with M node on [min(x),max(x)]  is  used to build basis
   33570             : functions. Different values of D are tried, optimal  D  (least  root  mean
   33571             : square error) is chosen.  Task  is  linear, so linear least squares solver
   33572             : is used. Complexity  of  this  computational  scheme is  O(N*M^2)  (mostly
   33573             : dominated by the least squares solver).
   33574             : 
   33575             :   ! COMMERCIAL EDITION OF ALGLIB:
   33576             :   ! 
   33577             :   ! Commercial Edition of ALGLIB includes following important improvements
   33578             :   ! of this function:
   33579             :   ! * high-performance native backend with same C# interface (C# version)
   33580             :   ! * multithreading support (C++ and C# versions)
   33581             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   33582             :   !   (C++ and C# versions, x86/x64 platform)
   33583             :   ! 
   33584             :   ! We recommend you to read 'Working with commercial version' section  of
   33585             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   33586             :   ! related features provided by commercial edition of ALGLIB.
   33587             : 
   33588             : INPUT PARAMETERS:
   33589             :     X   -   points, array[0..N-1].
   33590             :     Y   -   function values, array[0..N-1].
   33591             :     N   -   number of points, N>0.
   33592             :     M   -   number of basis functions ( = number_of_nodes), M>=2.
   33593             : 
   33594             : OUTPUT PARAMETERS:
   33595             :     Info-   same format as in LSFitLinearWC() subroutine.
   33596             :             * Info>0    task is solved
   33597             :             * Info<=0   an error occured:
   33598             :                         -4 means inconvergence of internal SVD
   33599             :                         -3 means inconsistent constraints
   33600             :     B   -   barycentric interpolant.
   33601             :     Rep -   report, same format as in LSFitLinearWC() subroutine.
   33602             :             Following fields are set:
   33603             :             * DBest         best value of the D parameter
   33604             :             * RMSError      rms error on the (X,Y).
   33605             :             * AvgError      average error on the (X,Y).
   33606             :             * AvgRelError   average relative error on the non-zero Y
   33607             :             * MaxError      maximum error
   33608             :                             NON-WEIGHTED ERRORS ARE CALCULATED
   33609             : 
   33610             :   -- ALGLIB PROJECT --
   33611             :      Copyright 18.08.2009 by Bochkanov Sergey
   33612             : *************************************************************************/
   33613           0 : void barycentricfitfloaterhormann(/* Real    */ ae_vector* x,
   33614             :      /* Real    */ ae_vector* y,
   33615             :      ae_int_t n,
   33616             :      ae_int_t m,
   33617             :      ae_int_t* info,
   33618             :      barycentricinterpolant* b,
   33619             :      barycentricfitreport* rep,
   33620             :      ae_state *_state)
   33621             : {
   33622             :     ae_frame _frame_block;
   33623             :     ae_vector w;
   33624             :     ae_vector xc;
   33625             :     ae_vector yc;
   33626             :     ae_vector dc;
   33627             :     ae_int_t i;
   33628             : 
   33629           0 :     ae_frame_make(_state, &_frame_block);
   33630           0 :     memset(&w, 0, sizeof(w));
   33631           0 :     memset(&xc, 0, sizeof(xc));
   33632           0 :     memset(&yc, 0, sizeof(yc));
   33633           0 :     memset(&dc, 0, sizeof(dc));
   33634           0 :     *info = 0;
   33635           0 :     _barycentricinterpolant_clear(b);
   33636           0 :     _barycentricfitreport_clear(rep);
   33637           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   33638           0 :     ae_vector_init(&xc, 0, DT_REAL, _state, ae_true);
   33639           0 :     ae_vector_init(&yc, 0, DT_REAL, _state, ae_true);
   33640           0 :     ae_vector_init(&dc, 0, DT_INT, _state, ae_true);
   33641             : 
   33642           0 :     ae_assert(n>0, "BarycentricFitFloaterHormann: N<=0!", _state);
   33643           0 :     ae_assert(m>0, "BarycentricFitFloaterHormann: M<=0!", _state);
   33644           0 :     ae_assert(x->cnt>=n, "BarycentricFitFloaterHormann: Length(X)<N!", _state);
   33645           0 :     ae_assert(y->cnt>=n, "BarycentricFitFloaterHormann: Length(Y)<N!", _state);
   33646           0 :     ae_assert(isfinitevector(x, n, _state), "BarycentricFitFloaterHormann: X contains infinite or NaN values!", _state);
   33647           0 :     ae_assert(isfinitevector(y, n, _state), "BarycentricFitFloaterHormann: Y contains infinite or NaN values!", _state);
   33648           0 :     ae_vector_set_length(&w, n, _state);
   33649           0 :     for(i=0; i<=n-1; i++)
   33650             :     {
   33651           0 :         w.ptr.p_double[i] = (double)(1);
   33652             :     }
   33653           0 :     barycentricfitfloaterhormannwc(x, y, &w, n, &xc, &yc, &dc, 0, m, info, b, rep, _state);
   33654           0 :     ae_frame_leave(_state);
   33655           0 : }
   33656             : 
   33657             : 
   33658             : /*************************************************************************
   33659             : Weighted fitting by cubic  spline,  with constraints on function values or
   33660             : derivatives.
   33661             : 
   33662             : Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is  used to build
   33663             : basis functions. Basis functions are cubic splines with continuous  second
   33664             : derivatives  and  non-fixed first  derivatives  at  interval  ends.  Small
   33665             : regularizing term is used  when  solving  constrained  tasks  (to  improve
   33666             : stability).
   33667             : 
   33668             : Task is linear, so linear least squares solver is used. Complexity of this
   33669             : computational scheme is O(N*M^2), mostly dominated by least squares solver
   33670             : 
   33671             : SEE ALSO
   33672             :     Spline1DFitHermiteWC()  -   fitting by Hermite splines (more flexible,
   33673             :                                 less smooth)
   33674             :     Spline1DFitCubic()      -   "lightweight" fitting  by  cubic  splines,
   33675             :                                 without invididual weights and constraints
   33676             : 
   33677             :   ! COMMERCIAL EDITION OF ALGLIB:
   33678             :   ! 
   33679             :   ! Commercial Edition of ALGLIB includes following important improvements
   33680             :   ! of this function:
   33681             :   ! * high-performance native backend with same C# interface (C# version)
   33682             :   ! * multithreading support (C++ and C# versions)
   33683             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   33684             :   !   (C++ and C# versions, x86/x64 platform)
   33685             :   ! 
   33686             :   ! We recommend you to read 'Working with commercial version' section  of
   33687             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   33688             :   ! related features provided by commercial edition of ALGLIB.
   33689             :                                 
   33690             : INPUT PARAMETERS:
   33691             :     X   -   points, array[0..N-1].
   33692             :     Y   -   function values, array[0..N-1].
   33693             :     W   -   weights, array[0..N-1]
   33694             :             Each summand in square  sum  of  approximation deviations from
   33695             :             given  values  is  multiplied  by  the square of corresponding
   33696             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
   33697             :             task.
   33698             :     N   -   number of points (optional):
   33699             :             * N>0
   33700             :             * if given, only first N elements of X/Y/W are processed
   33701             :             * if not given, automatically determined from X/Y/W sizes
   33702             :     XC  -   points where spline values/derivatives are constrained,
   33703             :             array[0..K-1].
   33704             :     YC  -   values of constraints, array[0..K-1]
   33705             :     DC  -   array[0..K-1], types of constraints:
   33706             :             * DC[i]=0   means that S(XC[i])=YC[i]
   33707             :             * DC[i]=1   means that S'(XC[i])=YC[i]
   33708             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
   33709             :     K   -   number of constraints (optional):
   33710             :             * 0<=K<M.
   33711             :             * K=0 means no constraints (XC/YC/DC are not used)
   33712             :             * if given, only first K elements of XC/YC/DC are used
   33713             :             * if not given, automatically determined from XC/YC/DC
   33714             :     M   -   number of basis functions ( = number_of_nodes+2), M>=4.
   33715             : 
   33716             : OUTPUT PARAMETERS:
   33717             :     Info-   same format as in LSFitLinearWC() subroutine.
   33718             :             * Info>0    task is solved
   33719             :             * Info<=0   an error occured:
   33720             :                         -4 means inconvergence of internal SVD
   33721             :                         -3 means inconsistent constraints
   33722             :     S   -   spline interpolant.
   33723             :     Rep -   report, same format as in LSFitLinearWC() subroutine.
   33724             :             Following fields are set:
   33725             :             * RMSError      rms error on the (X,Y).
   33726             :             * AvgError      average error on the (X,Y).
   33727             :             * AvgRelError   average relative error on the non-zero Y
   33728             :             * MaxError      maximum error
   33729             :                             NON-WEIGHTED ERRORS ARE CALCULATED
   33730             : 
   33731             : IMPORTANT:
   33732             :     this subroitine doesn't calculate task's condition number for K<>0.
   33733             : 
   33734             : 
   33735             : ORDER OF POINTS
   33736             : 
   33737             : Subroutine automatically sorts points, so caller may pass unsorted array.
   33738             : 
   33739             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
   33740             : 
   33741             : Setting constraints can lead  to undesired  results,  like ill-conditioned
   33742             : behavior, or inconsistency being detected. From the other side,  it allows
   33743             : us to improve quality of the fit. Here we summarize  our  experience  with
   33744             : constrained regression splines:
   33745             : * excessive constraints can be inconsistent. Splines are  piecewise  cubic
   33746             :   functions, and it is easy to create an example, where  large  number  of
   33747             :   constraints  concentrated  in  small  area will result in inconsistency.
   33748             :   Just because spline is not flexible enough to satisfy all of  them.  And
   33749             :   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
   33750             :   consistent.
   33751             : * the more evenly constraints are spread across [min(x),max(x)],  the more
   33752             :   chances that they will be consistent
   33753             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
   33754             :   constraints will be consistent
   33755             : * in the general case, consistency of constraints IS NOT GUARANTEED.
   33756             : * in the several special cases, however, we CAN guarantee consistency.
   33757             : * one of this cases is constraints  on  the  function  values  AND/OR  its
   33758             :   derivatives at the interval boundaries.
   33759             : * another  special  case  is ONE constraint on the function value (OR, but
   33760             :   not AND, derivative) anywhere in the interval
   33761             : 
   33762             : Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
   33763             : can't solve your task without them. Anything beyond  special  cases  given
   33764             : above is not guaranteed and may result in inconsistency.
   33765             : 
   33766             : 
   33767             :   -- ALGLIB PROJECT --
   33768             :      Copyright 18.08.2009 by Bochkanov Sergey
   33769             : *************************************************************************/
   33770           0 : void spline1dfitcubicwc(/* Real    */ ae_vector* x,
   33771             :      /* Real    */ ae_vector* y,
   33772             :      /* Real    */ ae_vector* w,
   33773             :      ae_int_t n,
   33774             :      /* Real    */ ae_vector* xc,
   33775             :      /* Real    */ ae_vector* yc,
   33776             :      /* Integer */ ae_vector* dc,
   33777             :      ae_int_t k,
   33778             :      ae_int_t m,
   33779             :      ae_int_t* info,
   33780             :      spline1dinterpolant* s,
   33781             :      spline1dfitreport* rep,
   33782             :      ae_state *_state)
   33783             : {
   33784             :     ae_int_t i;
   33785             : 
   33786           0 :     *info = 0;
   33787           0 :     _spline1dinterpolant_clear(s);
   33788           0 :     _spline1dfitreport_clear(rep);
   33789             : 
   33790           0 :     ae_assert(n>=1, "Spline1DFitCubicWC: N<1!", _state);
   33791           0 :     ae_assert(m>=4, "Spline1DFitCubicWC: M<4!", _state);
   33792           0 :     ae_assert(k>=0, "Spline1DFitCubicWC: K<0!", _state);
   33793           0 :     ae_assert(k<m, "Spline1DFitCubicWC: K>=M!", _state);
   33794           0 :     ae_assert(x->cnt>=n, "Spline1DFitCubicWC: Length(X)<N!", _state);
   33795           0 :     ae_assert(y->cnt>=n, "Spline1DFitCubicWC: Length(Y)<N!", _state);
   33796           0 :     ae_assert(w->cnt>=n, "Spline1DFitCubicWC: Length(W)<N!", _state);
   33797           0 :     ae_assert(xc->cnt>=k, "Spline1DFitCubicWC: Length(XC)<K!", _state);
   33798           0 :     ae_assert(yc->cnt>=k, "Spline1DFitCubicWC: Length(YC)<K!", _state);
   33799           0 :     ae_assert(dc->cnt>=k, "Spline1DFitCubicWC: Length(DC)<K!", _state);
   33800           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DFitCubicWC: X contains infinite or NAN values!", _state);
   33801           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DFitCubicWC: Y contains infinite or NAN values!", _state);
   33802           0 :     ae_assert(isfinitevector(w, n, _state), "Spline1DFitCubicWC: Y contains infinite or NAN values!", _state);
   33803           0 :     ae_assert(isfinitevector(xc, k, _state), "Spline1DFitCubicWC: X contains infinite or NAN values!", _state);
   33804           0 :     ae_assert(isfinitevector(yc, k, _state), "Spline1DFitCubicWC: Y contains infinite or NAN values!", _state);
   33805           0 :     for(i=0; i<=k-1; i++)
   33806             :     {
   33807           0 :         ae_assert(dc->ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "Spline1DFitCubicWC: DC[i] is neither 0 or 1!", _state);
   33808             :     }
   33809           0 :     lsfit_spline1dfitinternal(0, x, y, w, n, xc, yc, dc, k, m, info, s, rep, _state);
   33810           0 : }
   33811             : 
   33812             : 
   33813             : /*************************************************************************
   33814             : Weighted  fitting  by Hermite spline,  with constraints on function values
   33815             : or first derivatives.
   33816             : 
   33817             : Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is  used  to  build
   33818             : basis functions. Basis functions are Hermite splines.  Small  regularizing
   33819             : term is used when solving constrained tasks (to improve stability).
   33820             : 
   33821             : Task is linear, so linear least squares solver is used. Complexity of this
   33822             : computational scheme is O(N*M^2), mostly dominated by least squares solver
   33823             : 
   33824             : SEE ALSO
   33825             :     Spline1DFitCubicWC()    -   fitting by Cubic splines (less flexible,
   33826             :                                 more smooth)
   33827             :     Spline1DFitHermite()    -   "lightweight" Hermite fitting, without
   33828             :                                 invididual weights and constraints
   33829             : 
   33830             :   ! COMMERCIAL EDITION OF ALGLIB:
   33831             :   ! 
   33832             :   ! Commercial Edition of ALGLIB includes following important improvements
   33833             :   ! of this function:
   33834             :   ! * high-performance native backend with same C# interface (C# version)
   33835             :   ! * multithreading support (C++ and C# versions)
   33836             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   33837             :   !   (C++ and C# versions, x86/x64 platform)
   33838             :   ! 
   33839             :   ! We recommend you to read 'Working with commercial version' section  of
   33840             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   33841             :   ! related features provided by commercial edition of ALGLIB.
   33842             :                                 
   33843             : INPUT PARAMETERS:
   33844             :     X   -   points, array[0..N-1].
   33845             :     Y   -   function values, array[0..N-1].
   33846             :     W   -   weights, array[0..N-1]
   33847             :             Each summand in square  sum  of  approximation deviations from
   33848             :             given  values  is  multiplied  by  the square of corresponding
   33849             :             weight. Fill it by 1's if you don't  want  to  solve  weighted
   33850             :             task.
   33851             :     N   -   number of points (optional):
   33852             :             * N>0
   33853             :             * if given, only first N elements of X/Y/W are processed
   33854             :             * if not given, automatically determined from X/Y/W sizes
   33855             :     XC  -   points where spline values/derivatives are constrained,
   33856             :             array[0..K-1].
   33857             :     YC  -   values of constraints, array[0..K-1]
   33858             :     DC  -   array[0..K-1], types of constraints:
   33859             :             * DC[i]=0   means that S(XC[i])=YC[i]
   33860             :             * DC[i]=1   means that S'(XC[i])=YC[i]
   33861             :             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
   33862             :     K   -   number of constraints (optional):
   33863             :             * 0<=K<M.
   33864             :             * K=0 means no constraints (XC/YC/DC are not used)
   33865             :             * if given, only first K elements of XC/YC/DC are used
   33866             :             * if not given, automatically determined from XC/YC/DC
   33867             :     M   -   number of basis functions (= 2 * number of nodes),
   33868             :             M>=4,
   33869             :             M IS EVEN!
   33870             : 
   33871             : OUTPUT PARAMETERS:
   33872             :     Info-   same format as in LSFitLinearW() subroutine:
   33873             :             * Info>0    task is solved
   33874             :             * Info<=0   an error occured:
   33875             :                         -4 means inconvergence of internal SVD
   33876             :                         -3 means inconsistent constraints
   33877             :                         -2 means odd M was passed (which is not supported)
   33878             :                         -1 means another errors in parameters passed
   33879             :                            (N<=0, for example)
   33880             :     S   -   spline interpolant.
   33881             :     Rep -   report, same format as in LSFitLinearW() subroutine.
   33882             :             Following fields are set:
   33883             :             * RMSError      rms error on the (X,Y).
   33884             :             * AvgError      average error on the (X,Y).
   33885             :             * AvgRelError   average relative error on the non-zero Y
   33886             :             * MaxError      maximum error
   33887             :                             NON-WEIGHTED ERRORS ARE CALCULATED
   33888             : 
   33889             : IMPORTANT:
   33890             :     this subroitine doesn't calculate task's condition number for K<>0.
   33891             : 
   33892             : IMPORTANT:
   33893             :     this subroitine supports only even M's
   33894             : 
   33895             : 
   33896             : ORDER OF POINTS
   33897             : 
   33898             : Subroutine automatically sorts points, so caller may pass unsorted array.
   33899             : 
   33900             : SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
   33901             : 
   33902             : Setting constraints can lead  to undesired  results,  like ill-conditioned
   33903             : behavior, or inconsistency being detected. From the other side,  it allows
   33904             : us to improve quality of the fit. Here we summarize  our  experience  with
   33905             : constrained regression splines:
   33906             : * excessive constraints can be inconsistent. Splines are  piecewise  cubic
   33907             :   functions, and it is easy to create an example, where  large  number  of
   33908             :   constraints  concentrated  in  small  area will result in inconsistency.
   33909             :   Just because spline is not flexible enough to satisfy all of  them.  And
   33910             :   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
   33911             :   consistent.
   33912             : * the more evenly constraints are spread across [min(x),max(x)],  the more
   33913             :   chances that they will be consistent
   33914             : * the  greater  is  M (given  fixed  constraints),  the  more chances that
   33915             :   constraints will be consistent
   33916             : * in the general case, consistency of constraints is NOT GUARANTEED.
   33917             : * in the several special cases, however, we can guarantee consistency.
   33918             : * one of this cases is  M>=4  and   constraints  on   the  function  value
   33919             :   (AND/OR its derivative) at the interval boundaries.
   33920             : * another special case is M>=4  and  ONE  constraint on the function value
   33921             :   (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)]
   33922             : 
   33923             : Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
   33924             : can't solve your task without them. Anything beyond  special  cases  given
   33925             : above is not guaranteed and may result in inconsistency.
   33926             : 
   33927             :   -- ALGLIB PROJECT --
   33928             :      Copyright 18.08.2009 by Bochkanov Sergey
   33929             : *************************************************************************/
   33930           0 : void spline1dfithermitewc(/* Real    */ ae_vector* x,
   33931             :      /* Real    */ ae_vector* y,
   33932             :      /* Real    */ ae_vector* w,
   33933             :      ae_int_t n,
   33934             :      /* Real    */ ae_vector* xc,
   33935             :      /* Real    */ ae_vector* yc,
   33936             :      /* Integer */ ae_vector* dc,
   33937             :      ae_int_t k,
   33938             :      ae_int_t m,
   33939             :      ae_int_t* info,
   33940             :      spline1dinterpolant* s,
   33941             :      spline1dfitreport* rep,
   33942             :      ae_state *_state)
   33943             : {
   33944             :     ae_int_t i;
   33945             : 
   33946           0 :     *info = 0;
   33947           0 :     _spline1dinterpolant_clear(s);
   33948           0 :     _spline1dfitreport_clear(rep);
   33949             : 
   33950           0 :     ae_assert(n>=1, "Spline1DFitHermiteWC: N<1!", _state);
   33951           0 :     ae_assert(m>=4, "Spline1DFitHermiteWC: M<4!", _state);
   33952           0 :     ae_assert(m%2==0, "Spline1DFitHermiteWC: M is odd!", _state);
   33953           0 :     ae_assert(k>=0, "Spline1DFitHermiteWC: K<0!", _state);
   33954           0 :     ae_assert(k<m, "Spline1DFitHermiteWC: K>=M!", _state);
   33955           0 :     ae_assert(x->cnt>=n, "Spline1DFitHermiteWC: Length(X)<N!", _state);
   33956           0 :     ae_assert(y->cnt>=n, "Spline1DFitHermiteWC: Length(Y)<N!", _state);
   33957           0 :     ae_assert(w->cnt>=n, "Spline1DFitHermiteWC: Length(W)<N!", _state);
   33958           0 :     ae_assert(xc->cnt>=k, "Spline1DFitHermiteWC: Length(XC)<K!", _state);
   33959           0 :     ae_assert(yc->cnt>=k, "Spline1DFitHermiteWC: Length(YC)<K!", _state);
   33960           0 :     ae_assert(dc->cnt>=k, "Spline1DFitHermiteWC: Length(DC)<K!", _state);
   33961           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DFitHermiteWC: X contains infinite or NAN values!", _state);
   33962           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DFitHermiteWC: Y contains infinite or NAN values!", _state);
   33963           0 :     ae_assert(isfinitevector(w, n, _state), "Spline1DFitHermiteWC: Y contains infinite or NAN values!", _state);
   33964           0 :     ae_assert(isfinitevector(xc, k, _state), "Spline1DFitHermiteWC: X contains infinite or NAN values!", _state);
   33965           0 :     ae_assert(isfinitevector(yc, k, _state), "Spline1DFitHermiteWC: Y contains infinite or NAN values!", _state);
   33966           0 :     for(i=0; i<=k-1; i++)
   33967             :     {
   33968           0 :         ae_assert(dc->ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "Spline1DFitHermiteWC: DC[i] is neither 0 or 1!", _state);
   33969             :     }
   33970           0 :     lsfit_spline1dfitinternal(1, x, y, w, n, xc, yc, dc, k, m, info, s, rep, _state);
   33971           0 : }
   33972             : 
   33973             : 
   33974             : /*************************************************************************
   33975             : Least squares fitting by cubic spline.
   33976             : 
   33977             : This subroutine is "lightweight" alternative for more complex and feature-
   33978             : rich Spline1DFitCubicWC().  See  Spline1DFitCubicWC() for more information
   33979             : about subroutine parameters (we don't duplicate it here because of length)
   33980             : 
   33981             :   ! COMMERCIAL EDITION OF ALGLIB:
   33982             :   ! 
   33983             :   ! Commercial Edition of ALGLIB includes following important improvements
   33984             :   ! of this function:
   33985             :   ! * high-performance native backend with same C# interface (C# version)
   33986             :   ! * multithreading support (C++ and C# versions)
   33987             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   33988             :   !   (C++ and C# versions, x86/x64 platform)
   33989             :   ! 
   33990             :   ! We recommend you to read 'Working with commercial version' section  of
   33991             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   33992             :   ! related features provided by commercial edition of ALGLIB.
   33993             : 
   33994             :   -- ALGLIB PROJECT --
   33995             :      Copyright 18.08.2009 by Bochkanov Sergey
   33996             : *************************************************************************/
   33997           0 : void spline1dfitcubic(/* Real    */ ae_vector* x,
   33998             :      /* Real    */ ae_vector* y,
   33999             :      ae_int_t n,
   34000             :      ae_int_t m,
   34001             :      ae_int_t* info,
   34002             :      spline1dinterpolant* s,
   34003             :      spline1dfitreport* rep,
   34004             :      ae_state *_state)
   34005             : {
   34006             :     ae_frame _frame_block;
   34007             :     ae_int_t i;
   34008             :     ae_vector w;
   34009             :     ae_vector xc;
   34010             :     ae_vector yc;
   34011             :     ae_vector dc;
   34012             : 
   34013           0 :     ae_frame_make(_state, &_frame_block);
   34014           0 :     memset(&w, 0, sizeof(w));
   34015           0 :     memset(&xc, 0, sizeof(xc));
   34016           0 :     memset(&yc, 0, sizeof(yc));
   34017           0 :     memset(&dc, 0, sizeof(dc));
   34018           0 :     *info = 0;
   34019           0 :     _spline1dinterpolant_clear(s);
   34020           0 :     _spline1dfitreport_clear(rep);
   34021           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   34022           0 :     ae_vector_init(&xc, 0, DT_REAL, _state, ae_true);
   34023           0 :     ae_vector_init(&yc, 0, DT_REAL, _state, ae_true);
   34024           0 :     ae_vector_init(&dc, 0, DT_INT, _state, ae_true);
   34025             : 
   34026           0 :     ae_assert(n>=1, "Spline1DFitCubic: N<1!", _state);
   34027           0 :     ae_assert(m>=4, "Spline1DFitCubic: M<4!", _state);
   34028           0 :     ae_assert(x->cnt>=n, "Spline1DFitCubic: Length(X)<N!", _state);
   34029           0 :     ae_assert(y->cnt>=n, "Spline1DFitCubic: Length(Y)<N!", _state);
   34030           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DFitCubic: X contains infinite or NAN values!", _state);
   34031           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DFitCubic: Y contains infinite or NAN values!", _state);
   34032           0 :     ae_vector_set_length(&w, n, _state);
   34033           0 :     for(i=0; i<=n-1; i++)
   34034             :     {
   34035           0 :         w.ptr.p_double[i] = (double)(1);
   34036             :     }
   34037           0 :     spline1dfitcubicwc(x, y, &w, n, &xc, &yc, &dc, 0, m, info, s, rep, _state);
   34038           0 :     ae_frame_leave(_state);
   34039           0 : }
   34040             : 
   34041             : 
   34042             : /*************************************************************************
   34043             : Least squares fitting by Hermite spline.
   34044             : 
   34045             : This subroutine is "lightweight" alternative for more complex and feature-
   34046             : rich Spline1DFitHermiteWC().  See Spline1DFitHermiteWC()  description  for
   34047             : more information about subroutine parameters (we don't duplicate  it  here
   34048             : because of length).
   34049             : 
   34050             :   ! COMMERCIAL EDITION OF ALGLIB:
   34051             :   ! 
   34052             :   ! Commercial Edition of ALGLIB includes following important improvements
   34053             :   ! of this function:
   34054             :   ! * high-performance native backend with same C# interface (C# version)
   34055             :   ! * multithreading support (C++ and C# versions)
   34056             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   34057             :   !   (C++ and C# versions, x86/x64 platform)
   34058             :   ! 
   34059             :   ! We recommend you to read 'Working with commercial version' section  of
   34060             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   34061             :   ! related features provided by commercial edition of ALGLIB.
   34062             : 
   34063             :   -- ALGLIB PROJECT --
   34064             :      Copyright 18.08.2009 by Bochkanov Sergey
   34065             : *************************************************************************/
   34066           0 : void spline1dfithermite(/* Real    */ ae_vector* x,
   34067             :      /* Real    */ ae_vector* y,
   34068             :      ae_int_t n,
   34069             :      ae_int_t m,
   34070             :      ae_int_t* info,
   34071             :      spline1dinterpolant* s,
   34072             :      spline1dfitreport* rep,
   34073             :      ae_state *_state)
   34074             : {
   34075             :     ae_frame _frame_block;
   34076             :     ae_int_t i;
   34077             :     ae_vector w;
   34078             :     ae_vector xc;
   34079             :     ae_vector yc;
   34080             :     ae_vector dc;
   34081             : 
   34082           0 :     ae_frame_make(_state, &_frame_block);
   34083           0 :     memset(&w, 0, sizeof(w));
   34084           0 :     memset(&xc, 0, sizeof(xc));
   34085           0 :     memset(&yc, 0, sizeof(yc));
   34086           0 :     memset(&dc, 0, sizeof(dc));
   34087           0 :     *info = 0;
   34088           0 :     _spline1dinterpolant_clear(s);
   34089           0 :     _spline1dfitreport_clear(rep);
   34090           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   34091           0 :     ae_vector_init(&xc, 0, DT_REAL, _state, ae_true);
   34092           0 :     ae_vector_init(&yc, 0, DT_REAL, _state, ae_true);
   34093           0 :     ae_vector_init(&dc, 0, DT_INT, _state, ae_true);
   34094             : 
   34095           0 :     ae_assert(n>=1, "Spline1DFitHermite: N<1!", _state);
   34096           0 :     ae_assert(m>=4, "Spline1DFitHermite: M<4!", _state);
   34097           0 :     ae_assert(m%2==0, "Spline1DFitHermite: M is odd!", _state);
   34098           0 :     ae_assert(x->cnt>=n, "Spline1DFitHermite: Length(X)<N!", _state);
   34099           0 :     ae_assert(y->cnt>=n, "Spline1DFitHermite: Length(Y)<N!", _state);
   34100           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DFitHermite: X contains infinite or NAN values!", _state);
   34101           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DFitHermite: Y contains infinite or NAN values!", _state);
   34102           0 :     ae_vector_set_length(&w, n, _state);
   34103           0 :     for(i=0; i<=n-1; i++)
   34104             :     {
   34105           0 :         w.ptr.p_double[i] = (double)(1);
   34106             :     }
   34107           0 :     spline1dfithermitewc(x, y, &w, n, &xc, &yc, &dc, 0, m, info, s, rep, _state);
   34108           0 :     ae_frame_leave(_state);
   34109           0 : }
   34110             : 
   34111             : 
   34112             : /*************************************************************************
   34113             : Weighted linear least squares fitting.
   34114             : 
   34115             : QR decomposition is used to reduce task to MxM, then triangular solver  or
   34116             : SVD-based solver is used depending on condition number of the  system.  It
   34117             : allows to maximize speed and retain decent accuracy.
   34118             : 
   34119             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
   34120             :            convenient to use PolynomialFit() function. This function gives
   34121             :            best  results  on  polynomial  problems  and  solves  numerical
   34122             :            stability  issues  which  arise  when   you   fit   high-degree
   34123             :            polynomials to your data.
   34124             :            
   34125             :   ! COMMERCIAL EDITION OF ALGLIB:
   34126             :   ! 
   34127             :   ! Commercial Edition of ALGLIB includes following important improvements
   34128             :   ! of this function:
   34129             :   ! * high-performance native backend with same C# interface (C# version)
   34130             :   ! * multithreading support (C++ and C# versions)
   34131             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   34132             :   !   (C++ and C# versions, x86/x64 platform)
   34133             :   ! 
   34134             :   ! We recommend you to read 'Working with commercial version' section  of
   34135             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   34136             :   ! related features provided by commercial edition of ALGLIB.
   34137             : 
   34138             : INPUT PARAMETERS:
   34139             :     Y       -   array[0..N-1] Function values in  N  points.
   34140             :     W       -   array[0..N-1]  Weights  corresponding to function  values.
   34141             :                 Each summand in square  sum  of  approximation  deviations
   34142             :                 from  given  values  is  multiplied  by  the   square   of
   34143             :                 corresponding weight.
   34144             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
   34145             :                 FMatrix[I, J] - value of J-th basis function in I-th point.
   34146             :     N       -   number of points used. N>=1.
   34147             :     M       -   number of basis functions, M>=1.
   34148             : 
   34149             : OUTPUT PARAMETERS:
   34150             :     Info    -   error code:
   34151             :                 * -4    internal SVD decomposition subroutine failed (very
   34152             :                         rare and for degenerate systems only)
   34153             :                 * -1    incorrect N/M were specified
   34154             :                 *  1    task is solved
   34155             :     C       -   decomposition coefficients, array[0..M-1]
   34156             :     Rep     -   fitting report. Following fields are set:
   34157             :                 * Rep.TaskRCond     reciprocal of condition number
   34158             :                 * R2                non-adjusted coefficient of determination
   34159             :                                     (non-weighted)
   34160             :                 * RMSError          rms error on the (X,Y).
   34161             :                 * AvgError          average error on the (X,Y).
   34162             :                 * AvgRelError       average relative error on the non-zero Y
   34163             :                 * MaxError          maximum error
   34164             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   34165             :                 
   34166             : ERRORS IN PARAMETERS                
   34167             :                 
   34168             : This  solver  also  calculates different kinds of errors in parameters and
   34169             : fills corresponding fields of report:
   34170             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   34171             : * Rep.ErrPar        errors in parameters, array[K],
   34172             :                     errpar = sqrt(diag(CovPar))
   34173             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   34174             :                     best-fit curve from "ideal" best-fit curve built  with
   34175             :                     infinite number of samples, array[N].
   34176             :                     errcurve = sqrt(diag(F*CovPar*F')),
   34177             :                     where F is functions matrix.
   34178             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   34179             :             
   34180             : NOTE:       noise in the data is estimated as follows:
   34181             :             * for fitting without user-supplied  weights  all  points  are
   34182             :               assumed to have same level of noise, which is estimated from
   34183             :               the data
   34184             :             * for fitting with user-supplied weights we assume that  noise
   34185             :               level in I-th point is inversely proportional to Ith weight.
   34186             :               Coefficient of proportionality is estimated from the data.
   34187             :             
   34188             : NOTE:       we apply small amount of regularization when we invert squared
   34189             :             Jacobian and calculate covariance matrix. It  guarantees  that
   34190             :             algorithm won't divide by zero  during  inversion,  but  skews
   34191             :             error estimates a bit (fractional error is about 10^-9).
   34192             :             
   34193             :             However, we believe that this difference is insignificant  for
   34194             :             all practical purposes except for the situation when you  want
   34195             :             to compare ALGLIB results with "reference"  implementation  up
   34196             :             to the last significant digit.
   34197             :             
   34198             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   34199             :             of freedom (covariances are divided by N-M instead of dividing
   34200             :             by N).
   34201             :                                     
   34202             :   -- ALGLIB --
   34203             :      Copyright 17.08.2009 by Bochkanov Sergey
   34204             : *************************************************************************/
   34205           0 : void lsfitlinearw(/* Real    */ ae_vector* y,
   34206             :      /* Real    */ ae_vector* w,
   34207             :      /* Real    */ ae_matrix* fmatrix,
   34208             :      ae_int_t n,
   34209             :      ae_int_t m,
   34210             :      ae_int_t* info,
   34211             :      /* Real    */ ae_vector* c,
   34212             :      lsfitreport* rep,
   34213             :      ae_state *_state)
   34214             : {
   34215             : 
   34216           0 :     *info = 0;
   34217           0 :     ae_vector_clear(c);
   34218           0 :     _lsfitreport_clear(rep);
   34219             : 
   34220           0 :     ae_assert(n>=1, "LSFitLinearW: N<1!", _state);
   34221           0 :     ae_assert(m>=1, "LSFitLinearW: M<1!", _state);
   34222           0 :     ae_assert(y->cnt>=n, "LSFitLinearW: length(Y)<N!", _state);
   34223           0 :     ae_assert(isfinitevector(y, n, _state), "LSFitLinearW: Y contains infinite or NaN values!", _state);
   34224           0 :     ae_assert(w->cnt>=n, "LSFitLinearW: length(W)<N!", _state);
   34225           0 :     ae_assert(isfinitevector(w, n, _state), "LSFitLinearW: W contains infinite or NaN values!", _state);
   34226           0 :     ae_assert(fmatrix->rows>=n, "LSFitLinearW: rows(FMatrix)<N!", _state);
   34227           0 :     ae_assert(fmatrix->cols>=m, "LSFitLinearW: cols(FMatrix)<M!", _state);
   34228           0 :     ae_assert(apservisfinitematrix(fmatrix, n, m, _state), "LSFitLinearW: FMatrix contains infinite or NaN values!", _state);
   34229           0 :     lsfit_lsfitlinearinternal(y, w, fmatrix, n, m, info, c, rep, _state);
   34230           0 : }
   34231             : 
   34232             : 
   34233             : /*************************************************************************
   34234             : Weighted constained linear least squares fitting.
   34235             : 
   34236             : This  is  variation  of LSFitLinearW(), which searchs for min|A*x=b| given
   34237             : that  K  additional  constaints  C*x=bc are satisfied. It reduces original
   34238             : task to modified one: min|B*y-d| WITHOUT constraints,  then LSFitLinearW()
   34239             : is called.
   34240             : 
   34241             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
   34242             :            convenient to use PolynomialFit() function. This function gives
   34243             :            best  results  on  polynomial  problems  and  solves  numerical
   34244             :            stability  issues  which  arise  when   you   fit   high-degree
   34245             :            polynomials to your data.
   34246             :            
   34247             :   ! COMMERCIAL EDITION OF ALGLIB:
   34248             :   ! 
   34249             :   ! Commercial Edition of ALGLIB includes following important improvements
   34250             :   ! of this function:
   34251             :   ! * high-performance native backend with same C# interface (C# version)
   34252             :   ! * multithreading support (C++ and C# versions)
   34253             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   34254             :   !   (C++ and C# versions, x86/x64 platform)
   34255             :   ! 
   34256             :   ! We recommend you to read 'Working with commercial version' section  of
   34257             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   34258             :   ! related features provided by commercial edition of ALGLIB.
   34259             : 
   34260             : INPUT PARAMETERS:
   34261             :     Y       -   array[0..N-1] Function values in  N  points.
   34262             :     W       -   array[0..N-1]  Weights  corresponding to function  values.
   34263             :                 Each summand in square  sum  of  approximation  deviations
   34264             :                 from  given  values  is  multiplied  by  the   square   of
   34265             :                 corresponding weight.
   34266             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
   34267             :                 FMatrix[I,J] - value of J-th basis function in I-th point.
   34268             :     CMatrix -   a table of constaints, array[0..K-1,0..M].
   34269             :                 I-th row of CMatrix corresponds to I-th linear constraint:
   34270             :                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
   34271             :     N       -   number of points used. N>=1.
   34272             :     M       -   number of basis functions, M>=1.
   34273             :     K       -   number of constraints, 0 <= K < M
   34274             :                 K=0 corresponds to absence of constraints.
   34275             : 
   34276             : OUTPUT PARAMETERS:
   34277             :     Info    -   error code:
   34278             :                 * -4    internal SVD decomposition subroutine failed (very
   34279             :                         rare and for degenerate systems only)
   34280             :                 * -3    either   too   many  constraints  (M   or   more),
   34281             :                         degenerate  constraints   (some   constraints  are
   34282             :                         repetead twice) or inconsistent  constraints  were
   34283             :                         specified.
   34284             :                 *  1    task is solved
   34285             :     C       -   decomposition coefficients, array[0..M-1]
   34286             :     Rep     -   fitting report. Following fields are set:
   34287             :                 * R2                non-adjusted coefficient of determination
   34288             :                                     (non-weighted)
   34289             :                 * RMSError          rms error on the (X,Y).
   34290             :                 * AvgError          average error on the (X,Y).
   34291             :                 * AvgRelError       average relative error on the non-zero Y
   34292             :                 * MaxError          maximum error
   34293             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   34294             : 
   34295             : IMPORTANT:
   34296             :     this subroitine doesn't calculate task's condition number for K<>0.
   34297             :                 
   34298             : ERRORS IN PARAMETERS                
   34299             :                 
   34300             : This  solver  also  calculates different kinds of errors in parameters and
   34301             : fills corresponding fields of report:
   34302             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   34303             : * Rep.ErrPar        errors in parameters, array[K],
   34304             :                     errpar = sqrt(diag(CovPar))
   34305             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   34306             :                     best-fit curve from "ideal" best-fit curve built  with
   34307             :                     infinite number of samples, array[N].
   34308             :                     errcurve = sqrt(diag(F*CovPar*F')),
   34309             :                     where F is functions matrix.
   34310             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   34311             : 
   34312             : IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
   34313             :             account boundary/linear constraints! Presence  of  constraints
   34314             :             changes distribution of errors, but there is no  easy  way  to
   34315             :             account for constraints when you calculate covariance matrix.
   34316             :             
   34317             : NOTE:       noise in the data is estimated as follows:
   34318             :             * for fitting without user-supplied  weights  all  points  are
   34319             :               assumed to have same level of noise, which is estimated from
   34320             :               the data
   34321             :             * for fitting with user-supplied weights we assume that  noise
   34322             :               level in I-th point is inversely proportional to Ith weight.
   34323             :               Coefficient of proportionality is estimated from the data.
   34324             :             
   34325             : NOTE:       we apply small amount of regularization when we invert squared
   34326             :             Jacobian and calculate covariance matrix. It  guarantees  that
   34327             :             algorithm won't divide by zero  during  inversion,  but  skews
   34328             :             error estimates a bit (fractional error is about 10^-9).
   34329             :             
   34330             :             However, we believe that this difference is insignificant  for
   34331             :             all practical purposes except for the situation when you  want
   34332             :             to compare ALGLIB results with "reference"  implementation  up
   34333             :             to the last significant digit.
   34334             :             
   34335             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   34336             :             of freedom (covariances are divided by N-M instead of dividing
   34337             :             by N).
   34338             : 
   34339             :   -- ALGLIB --
   34340             :      Copyright 07.09.2009 by Bochkanov Sergey
   34341             : *************************************************************************/
   34342           0 : void lsfitlinearwc(/* Real    */ ae_vector* y,
   34343             :      /* Real    */ ae_vector* w,
   34344             :      /* Real    */ ae_matrix* fmatrix,
   34345             :      /* Real    */ ae_matrix* cmatrix,
   34346             :      ae_int_t n,
   34347             :      ae_int_t m,
   34348             :      ae_int_t k,
   34349             :      ae_int_t* info,
   34350             :      /* Real    */ ae_vector* c,
   34351             :      lsfitreport* rep,
   34352             :      ae_state *_state)
   34353             : {
   34354             :     ae_frame _frame_block;
   34355             :     ae_vector _y;
   34356             :     ae_matrix _cmatrix;
   34357             :     ae_int_t i;
   34358             :     ae_int_t j;
   34359             :     ae_vector tau;
   34360             :     ae_matrix q;
   34361             :     ae_matrix f2;
   34362             :     ae_vector tmp;
   34363             :     ae_vector c0;
   34364             :     double v;
   34365             : 
   34366           0 :     ae_frame_make(_state, &_frame_block);
   34367           0 :     memset(&_y, 0, sizeof(_y));
   34368           0 :     memset(&_cmatrix, 0, sizeof(_cmatrix));
   34369           0 :     memset(&tau, 0, sizeof(tau));
   34370           0 :     memset(&q, 0, sizeof(q));
   34371           0 :     memset(&f2, 0, sizeof(f2));
   34372           0 :     memset(&tmp, 0, sizeof(tmp));
   34373           0 :     memset(&c0, 0, sizeof(c0));
   34374           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   34375           0 :     y = &_y;
   34376           0 :     ae_matrix_init_copy(&_cmatrix, cmatrix, _state, ae_true);
   34377           0 :     cmatrix = &_cmatrix;
   34378           0 :     *info = 0;
   34379           0 :     ae_vector_clear(c);
   34380           0 :     _lsfitreport_clear(rep);
   34381           0 :     ae_vector_init(&tau, 0, DT_REAL, _state, ae_true);
   34382           0 :     ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true);
   34383           0 :     ae_matrix_init(&f2, 0, 0, DT_REAL, _state, ae_true);
   34384           0 :     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
   34385           0 :     ae_vector_init(&c0, 0, DT_REAL, _state, ae_true);
   34386             : 
   34387           0 :     ae_assert(n>=1, "LSFitLinearWC: N<1!", _state);
   34388           0 :     ae_assert(m>=1, "LSFitLinearWC: M<1!", _state);
   34389           0 :     ae_assert(k>=0, "LSFitLinearWC: K<0!", _state);
   34390           0 :     ae_assert(y->cnt>=n, "LSFitLinearWC: length(Y)<N!", _state);
   34391           0 :     ae_assert(isfinitevector(y, n, _state), "LSFitLinearWC: Y contains infinite or NaN values!", _state);
   34392           0 :     ae_assert(w->cnt>=n, "LSFitLinearWC: length(W)<N!", _state);
   34393           0 :     ae_assert(isfinitevector(w, n, _state), "LSFitLinearWC: W contains infinite or NaN values!", _state);
   34394           0 :     ae_assert(fmatrix->rows>=n, "LSFitLinearWC: rows(FMatrix)<N!", _state);
   34395           0 :     ae_assert(fmatrix->cols>=m, "LSFitLinearWC: cols(FMatrix)<M!", _state);
   34396           0 :     ae_assert(apservisfinitematrix(fmatrix, n, m, _state), "LSFitLinearWC: FMatrix contains infinite or NaN values!", _state);
   34397           0 :     ae_assert(cmatrix->rows>=k, "LSFitLinearWC: rows(CMatrix)<K!", _state);
   34398           0 :     ae_assert(cmatrix->cols>=m+1||k==0, "LSFitLinearWC: cols(CMatrix)<M+1!", _state);
   34399           0 :     ae_assert(apservisfinitematrix(cmatrix, k, m+1, _state), "LSFitLinearWC: CMatrix contains infinite or NaN values!", _state);
   34400           0 :     if( k>=m )
   34401             :     {
   34402           0 :         *info = -3;
   34403           0 :         ae_frame_leave(_state);
   34404           0 :         return;
   34405             :     }
   34406             :     
   34407             :     /*
   34408             :      * Solve
   34409             :      */
   34410           0 :     if( k==0 )
   34411             :     {
   34412             :         
   34413             :         /*
   34414             :          * no constraints
   34415             :          */
   34416           0 :         lsfit_lsfitlinearinternal(y, w, fmatrix, n, m, info, c, rep, _state);
   34417             :     }
   34418             :     else
   34419             :     {
   34420             :         
   34421             :         /*
   34422             :          * First, find general form solution of constraints system:
   34423             :          * * factorize C = L*Q
   34424             :          * * unpack Q
   34425             :          * * fill upper part of C with zeros (for RCond)
   34426             :          *
   34427             :          * We got C=C0+Q2'*y where Q2 is lower M-K rows of Q.
   34428             :          */
   34429           0 :         rmatrixlq(cmatrix, k, m, &tau, _state);
   34430           0 :         rmatrixlqunpackq(cmatrix, k, m, &tau, m, &q, _state);
   34431           0 :         for(i=0; i<=k-1; i++)
   34432             :         {
   34433           0 :             for(j=i+1; j<=m-1; j++)
   34434             :             {
   34435           0 :                 cmatrix->ptr.pp_double[i][j] = 0.0;
   34436             :             }
   34437             :         }
   34438           0 :         if( ae_fp_less(rmatrixlurcondinf(cmatrix, k, _state),1000*ae_machineepsilon) )
   34439             :         {
   34440           0 :             *info = -3;
   34441           0 :             ae_frame_leave(_state);
   34442           0 :             return;
   34443             :         }
   34444           0 :         ae_vector_set_length(&tmp, k, _state);
   34445           0 :         for(i=0; i<=k-1; i++)
   34446             :         {
   34447           0 :             if( i>0 )
   34448             :             {
   34449           0 :                 v = ae_v_dotproduct(&cmatrix->ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,i-1));
   34450             :             }
   34451             :             else
   34452             :             {
   34453           0 :                 v = (double)(0);
   34454             :             }
   34455           0 :             tmp.ptr.p_double[i] = (cmatrix->ptr.pp_double[i][m]-v)/cmatrix->ptr.pp_double[i][i];
   34456             :         }
   34457           0 :         ae_vector_set_length(&c0, m, _state);
   34458           0 :         for(i=0; i<=m-1; i++)
   34459             :         {
   34460           0 :             c0.ptr.p_double[i] = (double)(0);
   34461             :         }
   34462           0 :         for(i=0; i<=k-1; i++)
   34463             :         {
   34464           0 :             v = tmp.ptr.p_double[i];
   34465           0 :             ae_v_addd(&c0.ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
   34466             :         }
   34467             :         
   34468             :         /*
   34469             :          * Second, prepare modified matrix F2 = F*Q2' and solve modified task
   34470             :          */
   34471           0 :         ae_vector_set_length(&tmp, ae_maxint(n, m, _state)+1, _state);
   34472           0 :         ae_matrix_set_length(&f2, n, m-k, _state);
   34473           0 :         matrixvectormultiply(fmatrix, 0, n-1, 0, m-1, ae_false, &c0, 0, m-1, -1.0, y, 0, n-1, 1.0, _state);
   34474           0 :         rmatrixgemm(n, m-k, m, 1.0, fmatrix, 0, 0, 0, &q, k, 0, 1, 0.0, &f2, 0, 0, _state);
   34475           0 :         lsfit_lsfitlinearinternal(y, w, &f2, n, m-k, info, &tmp, rep, _state);
   34476           0 :         rep->taskrcond = (double)(-1);
   34477           0 :         if( *info<=0 )
   34478             :         {
   34479           0 :             ae_frame_leave(_state);
   34480           0 :             return;
   34481             :         }
   34482             :         
   34483             :         /*
   34484             :          * then, convert back to original answer: C = C0 + Q2'*Y0
   34485             :          */
   34486           0 :         ae_vector_set_length(c, m, _state);
   34487           0 :         ae_v_move(&c->ptr.p_double[0], 1, &c0.ptr.p_double[0], 1, ae_v_len(0,m-1));
   34488           0 :         matrixvectormultiply(&q, k, m-1, 0, m-1, ae_true, &tmp, 0, m-k-1, 1.0, c, 0, m-1, 1.0, _state);
   34489             :     }
   34490           0 :     ae_frame_leave(_state);
   34491             : }
   34492             : 
   34493             : 
   34494             : /*************************************************************************
   34495             : Linear least squares fitting.
   34496             : 
   34497             : QR decomposition is used to reduce task to MxM, then triangular solver  or
   34498             : SVD-based solver is used depending on condition number of the  system.  It
   34499             : allows to maximize speed and retain decent accuracy.
   34500             : 
   34501             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
   34502             :            convenient to use PolynomialFit() function. This function gives
   34503             :            best  results  on  polynomial  problems  and  solves  numerical
   34504             :            stability  issues  which  arise  when   you   fit   high-degree
   34505             :            polynomials to your data.
   34506             :            
   34507             :   ! COMMERCIAL EDITION OF ALGLIB:
   34508             :   ! 
   34509             :   ! Commercial Edition of ALGLIB includes following important improvements
   34510             :   ! of this function:
   34511             :   ! * high-performance native backend with same C# interface (C# version)
   34512             :   ! * multithreading support (C++ and C# versions)
   34513             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   34514             :   !   (C++ and C# versions, x86/x64 platform)
   34515             :   ! 
   34516             :   ! We recommend you to read 'Working with commercial version' section  of
   34517             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   34518             :   ! related features provided by commercial edition of ALGLIB.
   34519             : 
   34520             : INPUT PARAMETERS:
   34521             :     Y       -   array[0..N-1] Function values in  N  points.
   34522             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
   34523             :                 FMatrix[I, J] - value of J-th basis function in I-th point.
   34524             :     N       -   number of points used. N>=1.
   34525             :     M       -   number of basis functions, M>=1.
   34526             : 
   34527             : OUTPUT PARAMETERS:
   34528             :     Info    -   error code:
   34529             :                 * -4    internal SVD decomposition subroutine failed (very
   34530             :                         rare and for degenerate systems only)
   34531             :                 *  1    task is solved
   34532             :     C       -   decomposition coefficients, array[0..M-1]
   34533             :     Rep     -   fitting report. Following fields are set:
   34534             :                 * Rep.TaskRCond     reciprocal of condition number
   34535             :                 * R2                non-adjusted coefficient of determination
   34536             :                                     (non-weighted)
   34537             :                 * RMSError          rms error on the (X,Y).
   34538             :                 * AvgError          average error on the (X,Y).
   34539             :                 * AvgRelError       average relative error on the non-zero Y
   34540             :                 * MaxError          maximum error
   34541             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   34542             :                 
   34543             : ERRORS IN PARAMETERS                
   34544             :                 
   34545             : This  solver  also  calculates different kinds of errors in parameters and
   34546             : fills corresponding fields of report:
   34547             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   34548             : * Rep.ErrPar        errors in parameters, array[K],
   34549             :                     errpar = sqrt(diag(CovPar))
   34550             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   34551             :                     best-fit curve from "ideal" best-fit curve built  with
   34552             :                     infinite number of samples, array[N].
   34553             :                     errcurve = sqrt(diag(F*CovPar*F')),
   34554             :                     where F is functions matrix.
   34555             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   34556             :             
   34557             : NOTE:       noise in the data is estimated as follows:
   34558             :             * for fitting without user-supplied  weights  all  points  are
   34559             :               assumed to have same level of noise, which is estimated from
   34560             :               the data
   34561             :             * for fitting with user-supplied weights we assume that  noise
   34562             :               level in I-th point is inversely proportional to Ith weight.
   34563             :               Coefficient of proportionality is estimated from the data.
   34564             :             
   34565             : NOTE:       we apply small amount of regularization when we invert squared
   34566             :             Jacobian and calculate covariance matrix. It  guarantees  that
   34567             :             algorithm won't divide by zero  during  inversion,  but  skews
   34568             :             error estimates a bit (fractional error is about 10^-9).
   34569             :             
   34570             :             However, we believe that this difference is insignificant  for
   34571             :             all practical purposes except for the situation when you  want
   34572             :             to compare ALGLIB results with "reference"  implementation  up
   34573             :             to the last significant digit.
   34574             :             
   34575             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   34576             :             of freedom (covariances are divided by N-M instead of dividing
   34577             :             by N).
   34578             : 
   34579             :   -- ALGLIB --
   34580             :      Copyright 17.08.2009 by Bochkanov Sergey
   34581             : *************************************************************************/
   34582           0 : void lsfitlinear(/* Real    */ ae_vector* y,
   34583             :      /* Real    */ ae_matrix* fmatrix,
   34584             :      ae_int_t n,
   34585             :      ae_int_t m,
   34586             :      ae_int_t* info,
   34587             :      /* Real    */ ae_vector* c,
   34588             :      lsfitreport* rep,
   34589             :      ae_state *_state)
   34590             : {
   34591             :     ae_frame _frame_block;
   34592             :     ae_vector w;
   34593             :     ae_int_t i;
   34594             : 
   34595           0 :     ae_frame_make(_state, &_frame_block);
   34596           0 :     memset(&w, 0, sizeof(w));
   34597           0 :     *info = 0;
   34598           0 :     ae_vector_clear(c);
   34599           0 :     _lsfitreport_clear(rep);
   34600           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   34601             : 
   34602           0 :     ae_assert(n>=1, "LSFitLinear: N<1!", _state);
   34603           0 :     ae_assert(m>=1, "LSFitLinear: M<1!", _state);
   34604           0 :     ae_assert(y->cnt>=n, "LSFitLinear: length(Y)<N!", _state);
   34605           0 :     ae_assert(isfinitevector(y, n, _state), "LSFitLinear: Y contains infinite or NaN values!", _state);
   34606           0 :     ae_assert(fmatrix->rows>=n, "LSFitLinear: rows(FMatrix)<N!", _state);
   34607           0 :     ae_assert(fmatrix->cols>=m, "LSFitLinear: cols(FMatrix)<M!", _state);
   34608           0 :     ae_assert(apservisfinitematrix(fmatrix, n, m, _state), "LSFitLinear: FMatrix contains infinite or NaN values!", _state);
   34609           0 :     ae_vector_set_length(&w, n, _state);
   34610           0 :     for(i=0; i<=n-1; i++)
   34611             :     {
   34612           0 :         w.ptr.p_double[i] = (double)(1);
   34613             :     }
   34614           0 :     lsfit_lsfitlinearinternal(y, &w, fmatrix, n, m, info, c, rep, _state);
   34615           0 :     ae_frame_leave(_state);
   34616           0 : }
   34617             : 
   34618             : 
   34619             : /*************************************************************************
   34620             : Constained linear least squares fitting.
   34621             : 
   34622             : This  is  variation  of LSFitLinear(),  which searchs for min|A*x=b| given
   34623             : that  K  additional  constaints  C*x=bc are satisfied. It reduces original
   34624             : task to modified one: min|B*y-d| WITHOUT constraints,  then  LSFitLinear()
   34625             : is called.
   34626             : 
   34627             : IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
   34628             :            convenient to use PolynomialFit() function. This function gives
   34629             :            best  results  on  polynomial  problems  and  solves  numerical
   34630             :            stability  issues  which  arise  when   you   fit   high-degree
   34631             :            polynomials to your data.
   34632             :            
   34633             :   ! COMMERCIAL EDITION OF ALGLIB:
   34634             :   ! 
   34635             :   ! Commercial Edition of ALGLIB includes following important improvements
   34636             :   ! of this function:
   34637             :   ! * high-performance native backend with same C# interface (C# version)
   34638             :   ! * multithreading support (C++ and C# versions)
   34639             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   34640             :   !   (C++ and C# versions, x86/x64 platform)
   34641             :   ! 
   34642             :   ! We recommend you to read 'Working with commercial version' section  of
   34643             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   34644             :   ! related features provided by commercial edition of ALGLIB.
   34645             : 
   34646             : INPUT PARAMETERS:
   34647             :     Y       -   array[0..N-1] Function values in  N  points.
   34648             :     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
   34649             :                 FMatrix[I,J] - value of J-th basis function in I-th point.
   34650             :     CMatrix -   a table of constaints, array[0..K-1,0..M].
   34651             :                 I-th row of CMatrix corresponds to I-th linear constraint:
   34652             :                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
   34653             :     N       -   number of points used. N>=1.
   34654             :     M       -   number of basis functions, M>=1.
   34655             :     K       -   number of constraints, 0 <= K < M
   34656             :                 K=0 corresponds to absence of constraints.
   34657             : 
   34658             : OUTPUT PARAMETERS:
   34659             :     Info    -   error code:
   34660             :                 * -4    internal SVD decomposition subroutine failed (very
   34661             :                         rare and for degenerate systems only)
   34662             :                 * -3    either   too   many  constraints  (M   or   more),
   34663             :                         degenerate  constraints   (some   constraints  are
   34664             :                         repetead twice) or inconsistent  constraints  were
   34665             :                         specified.
   34666             :                 *  1    task is solved
   34667             :     C       -   decomposition coefficients, array[0..M-1]
   34668             :     Rep     -   fitting report. Following fields are set:
   34669             :                 * R2                non-adjusted coefficient of determination
   34670             :                                     (non-weighted)
   34671             :                 * RMSError          rms error on the (X,Y).
   34672             :                 * AvgError          average error on the (X,Y).
   34673             :                 * AvgRelError       average relative error on the non-zero Y
   34674             :                 * MaxError          maximum error
   34675             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   34676             : 
   34677             : IMPORTANT:
   34678             :     this subroitine doesn't calculate task's condition number for K<>0.
   34679             :                 
   34680             : ERRORS IN PARAMETERS                
   34681             :                 
   34682             : This  solver  also  calculates different kinds of errors in parameters and
   34683             : fills corresponding fields of report:
   34684             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   34685             : * Rep.ErrPar        errors in parameters, array[K],
   34686             :                     errpar = sqrt(diag(CovPar))
   34687             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   34688             :                     best-fit curve from "ideal" best-fit curve built  with
   34689             :                     infinite number of samples, array[N].
   34690             :                     errcurve = sqrt(diag(F*CovPar*F')),
   34691             :                     where F is functions matrix.
   34692             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   34693             : 
   34694             : IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
   34695             :             account boundary/linear constraints! Presence  of  constraints
   34696             :             changes distribution of errors, but there is no  easy  way  to
   34697             :             account for constraints when you calculate covariance matrix.
   34698             :             
   34699             : NOTE:       noise in the data is estimated as follows:
   34700             :             * for fitting without user-supplied  weights  all  points  are
   34701             :               assumed to have same level of noise, which is estimated from
   34702             :               the data
   34703             :             * for fitting with user-supplied weights we assume that  noise
   34704             :               level in I-th point is inversely proportional to Ith weight.
   34705             :               Coefficient of proportionality is estimated from the data.
   34706             :             
   34707             : NOTE:       we apply small amount of regularization when we invert squared
   34708             :             Jacobian and calculate covariance matrix. It  guarantees  that
   34709             :             algorithm won't divide by zero  during  inversion,  but  skews
   34710             :             error estimates a bit (fractional error is about 10^-9).
   34711             :             
   34712             :             However, we believe that this difference is insignificant  for
   34713             :             all practical purposes except for the situation when you  want
   34714             :             to compare ALGLIB results with "reference"  implementation  up
   34715             :             to the last significant digit.
   34716             :             
   34717             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   34718             :             of freedom (covariances are divided by N-M instead of dividing
   34719             :             by N).
   34720             : 
   34721             :   -- ALGLIB --
   34722             :      Copyright 07.09.2009 by Bochkanov Sergey
   34723             : *************************************************************************/
   34724           0 : void lsfitlinearc(/* Real    */ ae_vector* y,
   34725             :      /* Real    */ ae_matrix* fmatrix,
   34726             :      /* Real    */ ae_matrix* cmatrix,
   34727             :      ae_int_t n,
   34728             :      ae_int_t m,
   34729             :      ae_int_t k,
   34730             :      ae_int_t* info,
   34731             :      /* Real    */ ae_vector* c,
   34732             :      lsfitreport* rep,
   34733             :      ae_state *_state)
   34734             : {
   34735             :     ae_frame _frame_block;
   34736             :     ae_vector _y;
   34737             :     ae_vector w;
   34738             :     ae_int_t i;
   34739             : 
   34740           0 :     ae_frame_make(_state, &_frame_block);
   34741           0 :     memset(&_y, 0, sizeof(_y));
   34742           0 :     memset(&w, 0, sizeof(w));
   34743           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   34744           0 :     y = &_y;
   34745           0 :     *info = 0;
   34746           0 :     ae_vector_clear(c);
   34747           0 :     _lsfitreport_clear(rep);
   34748           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   34749             : 
   34750           0 :     ae_assert(n>=1, "LSFitLinearC: N<1!", _state);
   34751           0 :     ae_assert(m>=1, "LSFitLinearC: M<1!", _state);
   34752           0 :     ae_assert(k>=0, "LSFitLinearC: K<0!", _state);
   34753           0 :     ae_assert(y->cnt>=n, "LSFitLinearC: length(Y)<N!", _state);
   34754           0 :     ae_assert(isfinitevector(y, n, _state), "LSFitLinearC: Y contains infinite or NaN values!", _state);
   34755           0 :     ae_assert(fmatrix->rows>=n, "LSFitLinearC: rows(FMatrix)<N!", _state);
   34756           0 :     ae_assert(fmatrix->cols>=m, "LSFitLinearC: cols(FMatrix)<M!", _state);
   34757           0 :     ae_assert(apservisfinitematrix(fmatrix, n, m, _state), "LSFitLinearC: FMatrix contains infinite or NaN values!", _state);
   34758           0 :     ae_assert(cmatrix->rows>=k, "LSFitLinearC: rows(CMatrix)<K!", _state);
   34759           0 :     ae_assert(cmatrix->cols>=m+1||k==0, "LSFitLinearC: cols(CMatrix)<M+1!", _state);
   34760           0 :     ae_assert(apservisfinitematrix(cmatrix, k, m+1, _state), "LSFitLinearC: CMatrix contains infinite or NaN values!", _state);
   34761           0 :     ae_vector_set_length(&w, n, _state);
   34762           0 :     for(i=0; i<=n-1; i++)
   34763             :     {
   34764           0 :         w.ptr.p_double[i] = (double)(1);
   34765             :     }
   34766           0 :     lsfitlinearwc(y, &w, fmatrix, cmatrix, n, m, k, info, c, rep, _state);
   34767           0 :     ae_frame_leave(_state);
   34768           0 : }
   34769             : 
   34770             : 
   34771             : /*************************************************************************
   34772             : Weighted nonlinear least squares fitting using function values only.
   34773             : 
   34774             : Combination of numerical differentiation and secant updates is used to
   34775             : obtain function Jacobian.
   34776             : 
   34777             : Nonlinear task min(F(c)) is solved, where
   34778             : 
   34779             :     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
   34780             : 
   34781             :     * N is a number of points,
   34782             :     * M is a dimension of a space points belong to,
   34783             :     * K is a dimension of a space of parameters being fitted,
   34784             :     * w is an N-dimensional vector of weight coefficients,
   34785             :     * x is a set of N points, each of them is an M-dimensional vector,
   34786             :     * c is a K-dimensional vector of parameters being fitted
   34787             : 
   34788             : This subroutine uses only f(c,x[i]).
   34789             : 
   34790             : INPUT PARAMETERS:
   34791             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   34792             :     Y       -   array[0..N-1], function values.
   34793             :     W       -   weights, array[0..N-1]
   34794             :     C       -   array[0..K-1], initial approximation to the solution,
   34795             :     N       -   number of points, N>1
   34796             :     M       -   dimension of space
   34797             :     K       -   number of parameters being fitted
   34798             :     DiffStep-   numerical differentiation step;
   34799             :                 should not be very small or large;
   34800             :                 large = loss of accuracy
   34801             :                 small = growth of round-off errors
   34802             : 
   34803             : OUTPUT PARAMETERS:
   34804             :     State   -   structure which stores algorithm state
   34805             : 
   34806             :   -- ALGLIB --
   34807             :      Copyright 18.10.2008 by Bochkanov Sergey
   34808             : *************************************************************************/
   34809           0 : void lsfitcreatewf(/* Real    */ ae_matrix* x,
   34810             :      /* Real    */ ae_vector* y,
   34811             :      /* Real    */ ae_vector* w,
   34812             :      /* Real    */ ae_vector* c,
   34813             :      ae_int_t n,
   34814             :      ae_int_t m,
   34815             :      ae_int_t k,
   34816             :      double diffstep,
   34817             :      lsfitstate* state,
   34818             :      ae_state *_state)
   34819             : {
   34820             :     ae_int_t i;
   34821             : 
   34822           0 :     _lsfitstate_clear(state);
   34823             : 
   34824           0 :     ae_assert(n>=1, "LSFitCreateWF: N<1!", _state);
   34825           0 :     ae_assert(m>=1, "LSFitCreateWF: M<1!", _state);
   34826           0 :     ae_assert(k>=1, "LSFitCreateWF: K<1!", _state);
   34827           0 :     ae_assert(c->cnt>=k, "LSFitCreateWF: length(C)<K!", _state);
   34828           0 :     ae_assert(isfinitevector(c, k, _state), "LSFitCreateWF: C contains infinite or NaN values!", _state);
   34829           0 :     ae_assert(y->cnt>=n, "LSFitCreateWF: length(Y)<N!", _state);
   34830           0 :     ae_assert(isfinitevector(y, n, _state), "LSFitCreateWF: Y contains infinite or NaN values!", _state);
   34831           0 :     ae_assert(w->cnt>=n, "LSFitCreateWF: length(W)<N!", _state);
   34832           0 :     ae_assert(isfinitevector(w, n, _state), "LSFitCreateWF: W contains infinite or NaN values!", _state);
   34833           0 :     ae_assert(x->rows>=n, "LSFitCreateWF: rows(X)<N!", _state);
   34834           0 :     ae_assert(x->cols>=m, "LSFitCreateWF: cols(X)<M!", _state);
   34835           0 :     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateWF: X contains infinite or NaN values!", _state);
   34836           0 :     ae_assert(ae_isfinite(diffstep, _state), "LSFitCreateWF: DiffStep is not finite!", _state);
   34837           0 :     ae_assert(ae_fp_greater(diffstep,(double)(0)), "LSFitCreateWF: DiffStep<=0!", _state);
   34838           0 :     state->teststep = (double)(0);
   34839           0 :     state->diffstep = diffstep;
   34840           0 :     state->npoints = n;
   34841           0 :     state->nweights = n;
   34842           0 :     state->wkind = 1;
   34843           0 :     state->m = m;
   34844           0 :     state->k = k;
   34845           0 :     lsfitsetcond(state, 0.0, 0, _state);
   34846           0 :     lsfitsetstpmax(state, 0.0, _state);
   34847           0 :     lsfitsetxrep(state, ae_false, _state);
   34848           0 :     ae_matrix_set_length(&state->taskx, n, m, _state);
   34849           0 :     ae_vector_set_length(&state->tasky, n, _state);
   34850           0 :     ae_vector_set_length(&state->taskw, n, _state);
   34851           0 :     ae_vector_set_length(&state->c, k, _state);
   34852           0 :     ae_vector_set_length(&state->c0, k, _state);
   34853           0 :     ae_vector_set_length(&state->c1, k, _state);
   34854           0 :     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   34855           0 :     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   34856           0 :     ae_vector_set_length(&state->x, m, _state);
   34857           0 :     ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
   34858           0 :     for(i=0; i<=n-1; i++)
   34859             :     {
   34860           0 :         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   34861           0 :         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
   34862             :     }
   34863           0 :     ae_vector_set_length(&state->s, k, _state);
   34864           0 :     ae_vector_set_length(&state->bndl, k, _state);
   34865           0 :     ae_vector_set_length(&state->bndu, k, _state);
   34866           0 :     for(i=0; i<=k-1; i++)
   34867             :     {
   34868           0 :         state->s.ptr.p_double[i] = 1.0;
   34869           0 :         state->bndl.ptr.p_double[i] = _state->v_neginf;
   34870           0 :         state->bndu.ptr.p_double[i] = _state->v_posinf;
   34871             :     }
   34872           0 :     state->optalgo = 0;
   34873           0 :     state->prevnpt = -1;
   34874           0 :     state->prevalgo = -1;
   34875           0 :     state->nec = 0;
   34876           0 :     state->nic = 0;
   34877           0 :     minlmcreatev(k, n, &state->c0, diffstep, &state->optstate, _state);
   34878           0 :     lsfit_lsfitclearrequestfields(state, _state);
   34879           0 :     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
   34880           0 :     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
   34881           0 :     state->rstate.stage = -1;
   34882           0 : }
   34883             : 
   34884             : 
   34885             : /*************************************************************************
   34886             : Nonlinear least squares fitting using function values only.
   34887             : 
   34888             : Combination of numerical differentiation and secant updates is used to
   34889             : obtain function Jacobian.
   34890             : 
   34891             : Nonlinear task min(F(c)) is solved, where
   34892             : 
   34893             :     F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2,
   34894             : 
   34895             :     * N is a number of points,
   34896             :     * M is a dimension of a space points belong to,
   34897             :     * K is a dimension of a space of parameters being fitted,
   34898             :     * w is an N-dimensional vector of weight coefficients,
   34899             :     * x is a set of N points, each of them is an M-dimensional vector,
   34900             :     * c is a K-dimensional vector of parameters being fitted
   34901             : 
   34902             : This subroutine uses only f(c,x[i]).
   34903             : 
   34904             : INPUT PARAMETERS:
   34905             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   34906             :     Y       -   array[0..N-1], function values.
   34907             :     C       -   array[0..K-1], initial approximation to the solution,
   34908             :     N       -   number of points, N>1
   34909             :     M       -   dimension of space
   34910             :     K       -   number of parameters being fitted
   34911             :     DiffStep-   numerical differentiation step;
   34912             :                 should not be very small or large;
   34913             :                 large = loss of accuracy
   34914             :                 small = growth of round-off errors
   34915             : 
   34916             : OUTPUT PARAMETERS:
   34917             :     State   -   structure which stores algorithm state
   34918             : 
   34919             :   -- ALGLIB --
   34920             :      Copyright 18.10.2008 by Bochkanov Sergey
   34921             : *************************************************************************/
   34922           0 : void lsfitcreatef(/* Real    */ ae_matrix* x,
   34923             :      /* Real    */ ae_vector* y,
   34924             :      /* Real    */ ae_vector* c,
   34925             :      ae_int_t n,
   34926             :      ae_int_t m,
   34927             :      ae_int_t k,
   34928             :      double diffstep,
   34929             :      lsfitstate* state,
   34930             :      ae_state *_state)
   34931             : {
   34932             :     ae_int_t i;
   34933             : 
   34934           0 :     _lsfitstate_clear(state);
   34935             : 
   34936           0 :     ae_assert(n>=1, "LSFitCreateF: N<1!", _state);
   34937           0 :     ae_assert(m>=1, "LSFitCreateF: M<1!", _state);
   34938           0 :     ae_assert(k>=1, "LSFitCreateF: K<1!", _state);
   34939           0 :     ae_assert(c->cnt>=k, "LSFitCreateF: length(C)<K!", _state);
   34940           0 :     ae_assert(isfinitevector(c, k, _state), "LSFitCreateF: C contains infinite or NaN values!", _state);
   34941           0 :     ae_assert(y->cnt>=n, "LSFitCreateF: length(Y)<N!", _state);
   34942           0 :     ae_assert(isfinitevector(y, n, _state), "LSFitCreateF: Y contains infinite or NaN values!", _state);
   34943           0 :     ae_assert(x->rows>=n, "LSFitCreateF: rows(X)<N!", _state);
   34944           0 :     ae_assert(x->cols>=m, "LSFitCreateF: cols(X)<M!", _state);
   34945           0 :     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateF: X contains infinite or NaN values!", _state);
   34946           0 :     ae_assert(x->rows>=n, "LSFitCreateF: rows(X)<N!", _state);
   34947           0 :     ae_assert(x->cols>=m, "LSFitCreateF: cols(X)<M!", _state);
   34948           0 :     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateF: X contains infinite or NaN values!", _state);
   34949           0 :     ae_assert(ae_isfinite(diffstep, _state), "LSFitCreateF: DiffStep is not finite!", _state);
   34950           0 :     ae_assert(ae_fp_greater(diffstep,(double)(0)), "LSFitCreateF: DiffStep<=0!", _state);
   34951           0 :     state->teststep = (double)(0);
   34952           0 :     state->diffstep = diffstep;
   34953           0 :     state->npoints = n;
   34954           0 :     state->wkind = 0;
   34955           0 :     state->m = m;
   34956           0 :     state->k = k;
   34957           0 :     lsfitsetcond(state, 0.0, 0, _state);
   34958           0 :     lsfitsetstpmax(state, 0.0, _state);
   34959           0 :     lsfitsetxrep(state, ae_false, _state);
   34960           0 :     ae_matrix_set_length(&state->taskx, n, m, _state);
   34961           0 :     ae_vector_set_length(&state->tasky, n, _state);
   34962           0 :     ae_vector_set_length(&state->c, k, _state);
   34963           0 :     ae_vector_set_length(&state->c0, k, _state);
   34964           0 :     ae_vector_set_length(&state->c1, k, _state);
   34965           0 :     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   34966           0 :     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   34967           0 :     ae_vector_set_length(&state->x, m, _state);
   34968           0 :     for(i=0; i<=n-1; i++)
   34969             :     {
   34970           0 :         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   34971           0 :         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
   34972             :     }
   34973           0 :     ae_vector_set_length(&state->s, k, _state);
   34974           0 :     ae_vector_set_length(&state->bndl, k, _state);
   34975           0 :     ae_vector_set_length(&state->bndu, k, _state);
   34976           0 :     for(i=0; i<=k-1; i++)
   34977             :     {
   34978           0 :         state->s.ptr.p_double[i] = 1.0;
   34979           0 :         state->bndl.ptr.p_double[i] = _state->v_neginf;
   34980           0 :         state->bndu.ptr.p_double[i] = _state->v_posinf;
   34981             :     }
   34982           0 :     state->optalgo = 0;
   34983           0 :     state->prevnpt = -1;
   34984           0 :     state->prevalgo = -1;
   34985           0 :     state->nec = 0;
   34986           0 :     state->nic = 0;
   34987           0 :     minlmcreatev(k, n, &state->c0, diffstep, &state->optstate, _state);
   34988           0 :     lsfit_lsfitclearrequestfields(state, _state);
   34989           0 :     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
   34990           0 :     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
   34991           0 :     state->rstate.stage = -1;
   34992           0 : }
   34993             : 
   34994             : 
   34995             : /*************************************************************************
   34996             : Weighted nonlinear least squares fitting using gradient only.
   34997             : 
   34998             : Nonlinear task min(F(c)) is solved, where
   34999             : 
   35000             :     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
   35001             :     
   35002             :     * N is a number of points,
   35003             :     * M is a dimension of a space points belong to,
   35004             :     * K is a dimension of a space of parameters being fitted,
   35005             :     * w is an N-dimensional vector of weight coefficients,
   35006             :     * x is a set of N points, each of them is an M-dimensional vector,
   35007             :     * c is a K-dimensional vector of parameters being fitted
   35008             :     
   35009             : This subroutine uses only f(c,x[i]) and its gradient.
   35010             :     
   35011             : INPUT PARAMETERS:
   35012             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   35013             :     Y       -   array[0..N-1], function values.
   35014             :     W       -   weights, array[0..N-1]
   35015             :     C       -   array[0..K-1], initial approximation to the solution,
   35016             :     N       -   number of points, N>1
   35017             :     M       -   dimension of space
   35018             :     K       -   number of parameters being fitted
   35019             :     CheapFG -   boolean flag, which is:
   35020             :                 * True  if both function and gradient calculation complexity
   35021             :                         are less than O(M^2).  An improved  algorithm  can
   35022             :                         be  used  which corresponds  to  FGJ  scheme  from
   35023             :                         MINLM unit.
   35024             :                 * False otherwise.
   35025             :                         Standard Jacibian-bases  Levenberg-Marquardt  algo
   35026             :                         will be used (FJ scheme).
   35027             : 
   35028             : OUTPUT PARAMETERS:
   35029             :     State   -   structure which stores algorithm state
   35030             : 
   35031             : See also:
   35032             :     LSFitResults
   35033             :     LSFitCreateFG (fitting without weights)
   35034             :     LSFitCreateWFGH (fitting using Hessian)
   35035             :     LSFitCreateFGH (fitting using Hessian, without weights)
   35036             : 
   35037             :   -- ALGLIB --
   35038             :      Copyright 17.08.2009 by Bochkanov Sergey
   35039             : *************************************************************************/
   35040           0 : void lsfitcreatewfg(/* Real    */ ae_matrix* x,
   35041             :      /* Real    */ ae_vector* y,
   35042             :      /* Real    */ ae_vector* w,
   35043             :      /* Real    */ ae_vector* c,
   35044             :      ae_int_t n,
   35045             :      ae_int_t m,
   35046             :      ae_int_t k,
   35047             :      ae_bool cheapfg,
   35048             :      lsfitstate* state,
   35049             :      ae_state *_state)
   35050             : {
   35051             :     ae_int_t i;
   35052             : 
   35053           0 :     _lsfitstate_clear(state);
   35054             : 
   35055           0 :     ae_assert(n>=1, "LSFitCreateWFG: N<1!", _state);
   35056           0 :     ae_assert(m>=1, "LSFitCreateWFG: M<1!", _state);
   35057           0 :     ae_assert(k>=1, "LSFitCreateWFG: K<1!", _state);
   35058           0 :     ae_assert(c->cnt>=k, "LSFitCreateWFG: length(C)<K!", _state);
   35059           0 :     ae_assert(isfinitevector(c, k, _state), "LSFitCreateWFG: C contains infinite or NaN values!", _state);
   35060           0 :     ae_assert(y->cnt>=n, "LSFitCreateWFG: length(Y)<N!", _state);
   35061           0 :     ae_assert(isfinitevector(y, n, _state), "LSFitCreateWFG: Y contains infinite or NaN values!", _state);
   35062           0 :     ae_assert(w->cnt>=n, "LSFitCreateWFG: length(W)<N!", _state);
   35063           0 :     ae_assert(isfinitevector(w, n, _state), "LSFitCreateWFG: W contains infinite or NaN values!", _state);
   35064           0 :     ae_assert(x->rows>=n, "LSFitCreateWFG: rows(X)<N!", _state);
   35065           0 :     ae_assert(x->cols>=m, "LSFitCreateWFG: cols(X)<M!", _state);
   35066           0 :     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateWFG: X contains infinite or NaN values!", _state);
   35067           0 :     state->teststep = (double)(0);
   35068           0 :     state->diffstep = (double)(0);
   35069           0 :     state->npoints = n;
   35070           0 :     state->nweights = n;
   35071           0 :     state->wkind = 1;
   35072           0 :     state->m = m;
   35073           0 :     state->k = k;
   35074           0 :     lsfitsetcond(state, 0.0, 0, _state);
   35075           0 :     lsfitsetstpmax(state, 0.0, _state);
   35076           0 :     lsfitsetxrep(state, ae_false, _state);
   35077           0 :     ae_matrix_set_length(&state->taskx, n, m, _state);
   35078           0 :     ae_vector_set_length(&state->tasky, n, _state);
   35079           0 :     ae_vector_set_length(&state->taskw, n, _state);
   35080           0 :     ae_vector_set_length(&state->c, k, _state);
   35081           0 :     ae_vector_set_length(&state->c0, k, _state);
   35082           0 :     ae_vector_set_length(&state->c1, k, _state);
   35083           0 :     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   35084           0 :     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   35085           0 :     ae_vector_set_length(&state->x, m, _state);
   35086           0 :     ae_vector_set_length(&state->g, k, _state);
   35087           0 :     ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
   35088           0 :     for(i=0; i<=n-1; i++)
   35089             :     {
   35090           0 :         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   35091           0 :         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
   35092             :     }
   35093           0 :     ae_vector_set_length(&state->s, k, _state);
   35094           0 :     ae_vector_set_length(&state->bndl, k, _state);
   35095           0 :     ae_vector_set_length(&state->bndu, k, _state);
   35096           0 :     for(i=0; i<=k-1; i++)
   35097             :     {
   35098           0 :         state->s.ptr.p_double[i] = 1.0;
   35099           0 :         state->bndl.ptr.p_double[i] = _state->v_neginf;
   35100           0 :         state->bndu.ptr.p_double[i] = _state->v_posinf;
   35101             :     }
   35102           0 :     state->optalgo = 1;
   35103           0 :     state->prevnpt = -1;
   35104           0 :     state->prevalgo = -1;
   35105           0 :     state->nec = 0;
   35106           0 :     state->nic = 0;
   35107           0 :     if( cheapfg )
   35108             :     {
   35109           0 :         minlmcreatevgj(k, n, &state->c0, &state->optstate, _state);
   35110             :     }
   35111             :     else
   35112             :     {
   35113           0 :         minlmcreatevj(k, n, &state->c0, &state->optstate, _state);
   35114             :     }
   35115           0 :     lsfit_lsfitclearrequestfields(state, _state);
   35116           0 :     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
   35117           0 :     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
   35118           0 :     state->rstate.stage = -1;
   35119           0 : }
   35120             : 
   35121             : 
   35122             : /*************************************************************************
   35123             : Nonlinear least squares fitting using gradient only, without individual
   35124             : weights.
   35125             : 
   35126             : Nonlinear task min(F(c)) is solved, where
   35127             : 
   35128             :     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
   35129             : 
   35130             :     * N is a number of points,
   35131             :     * M is a dimension of a space points belong to,
   35132             :     * K is a dimension of a space of parameters being fitted,
   35133             :     * x is a set of N points, each of them is an M-dimensional vector,
   35134             :     * c is a K-dimensional vector of parameters being fitted
   35135             : 
   35136             : This subroutine uses only f(c,x[i]) and its gradient.
   35137             : 
   35138             : INPUT PARAMETERS:
   35139             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   35140             :     Y       -   array[0..N-1], function values.
   35141             :     C       -   array[0..K-1], initial approximation to the solution,
   35142             :     N       -   number of points, N>1
   35143             :     M       -   dimension of space
   35144             :     K       -   number of parameters being fitted
   35145             :     CheapFG -   boolean flag, which is:
   35146             :                 * True  if both function and gradient calculation complexity
   35147             :                         are less than O(M^2).  An improved  algorithm  can
   35148             :                         be  used  which corresponds  to  FGJ  scheme  from
   35149             :                         MINLM unit.
   35150             :                 * False otherwise.
   35151             :                         Standard Jacibian-bases  Levenberg-Marquardt  algo
   35152             :                         will be used (FJ scheme).
   35153             : 
   35154             : OUTPUT PARAMETERS:
   35155             :     State   -   structure which stores algorithm state
   35156             : 
   35157             :   -- ALGLIB --
   35158             :      Copyright 17.08.2009 by Bochkanov Sergey
   35159             : *************************************************************************/
   35160           0 : void lsfitcreatefg(/* Real    */ ae_matrix* x,
   35161             :      /* Real    */ ae_vector* y,
   35162             :      /* Real    */ ae_vector* c,
   35163             :      ae_int_t n,
   35164             :      ae_int_t m,
   35165             :      ae_int_t k,
   35166             :      ae_bool cheapfg,
   35167             :      lsfitstate* state,
   35168             :      ae_state *_state)
   35169             : {
   35170             :     ae_int_t i;
   35171             : 
   35172           0 :     _lsfitstate_clear(state);
   35173             : 
   35174           0 :     ae_assert(n>=1, "LSFitCreateFG: N<1!", _state);
   35175           0 :     ae_assert(m>=1, "LSFitCreateFG: M<1!", _state);
   35176           0 :     ae_assert(k>=1, "LSFitCreateFG: K<1!", _state);
   35177           0 :     ae_assert(c->cnt>=k, "LSFitCreateFG: length(C)<K!", _state);
   35178           0 :     ae_assert(isfinitevector(c, k, _state), "LSFitCreateFG: C contains infinite or NaN values!", _state);
   35179           0 :     ae_assert(y->cnt>=n, "LSFitCreateFG: length(Y)<N!", _state);
   35180           0 :     ae_assert(isfinitevector(y, n, _state), "LSFitCreateFG: Y contains infinite or NaN values!", _state);
   35181           0 :     ae_assert(x->rows>=n, "LSFitCreateFG: rows(X)<N!", _state);
   35182           0 :     ae_assert(x->cols>=m, "LSFitCreateFG: cols(X)<M!", _state);
   35183           0 :     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateFG: X contains infinite or NaN values!", _state);
   35184           0 :     ae_assert(x->rows>=n, "LSFitCreateFG: rows(X)<N!", _state);
   35185           0 :     ae_assert(x->cols>=m, "LSFitCreateFG: cols(X)<M!", _state);
   35186           0 :     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateFG: X contains infinite or NaN values!", _state);
   35187           0 :     state->teststep = (double)(0);
   35188           0 :     state->diffstep = (double)(0);
   35189           0 :     state->npoints = n;
   35190           0 :     state->wkind = 0;
   35191           0 :     state->m = m;
   35192           0 :     state->k = k;
   35193           0 :     lsfitsetcond(state, 0.0, 0, _state);
   35194           0 :     lsfitsetstpmax(state, 0.0, _state);
   35195           0 :     lsfitsetxrep(state, ae_false, _state);
   35196           0 :     ae_matrix_set_length(&state->taskx, n, m, _state);
   35197           0 :     ae_vector_set_length(&state->tasky, n, _state);
   35198           0 :     ae_vector_set_length(&state->c, k, _state);
   35199           0 :     ae_vector_set_length(&state->c0, k, _state);
   35200           0 :     ae_vector_set_length(&state->c1, k, _state);
   35201           0 :     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   35202           0 :     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   35203           0 :     ae_vector_set_length(&state->x, m, _state);
   35204           0 :     ae_vector_set_length(&state->g, k, _state);
   35205           0 :     for(i=0; i<=n-1; i++)
   35206             :     {
   35207           0 :         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   35208           0 :         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
   35209             :     }
   35210           0 :     ae_vector_set_length(&state->s, k, _state);
   35211           0 :     ae_vector_set_length(&state->bndl, k, _state);
   35212           0 :     ae_vector_set_length(&state->bndu, k, _state);
   35213           0 :     for(i=0; i<=k-1; i++)
   35214             :     {
   35215           0 :         state->s.ptr.p_double[i] = 1.0;
   35216           0 :         state->bndl.ptr.p_double[i] = _state->v_neginf;
   35217           0 :         state->bndu.ptr.p_double[i] = _state->v_posinf;
   35218             :     }
   35219           0 :     state->optalgo = 1;
   35220           0 :     state->prevnpt = -1;
   35221           0 :     state->prevalgo = -1;
   35222           0 :     state->nec = 0;
   35223           0 :     state->nic = 0;
   35224           0 :     if( cheapfg )
   35225             :     {
   35226           0 :         minlmcreatevgj(k, n, &state->c0, &state->optstate, _state);
   35227             :     }
   35228             :     else
   35229             :     {
   35230           0 :         minlmcreatevj(k, n, &state->c0, &state->optstate, _state);
   35231             :     }
   35232           0 :     lsfit_lsfitclearrequestfields(state, _state);
   35233           0 :     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
   35234           0 :     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
   35235           0 :     state->rstate.stage = -1;
   35236           0 : }
   35237             : 
   35238             : 
   35239             : /*************************************************************************
   35240             : Weighted nonlinear least squares fitting using gradient/Hessian.
   35241             : 
   35242             : Nonlinear task min(F(c)) is solved, where
   35243             : 
   35244             :     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
   35245             : 
   35246             :     * N is a number of points,
   35247             :     * M is a dimension of a space points belong to,
   35248             :     * K is a dimension of a space of parameters being fitted,
   35249             :     * w is an N-dimensional vector of weight coefficients,
   35250             :     * x is a set of N points, each of them is an M-dimensional vector,
   35251             :     * c is a K-dimensional vector of parameters being fitted
   35252             : 
   35253             : This subroutine uses f(c,x[i]), its gradient and its Hessian.
   35254             : 
   35255             : INPUT PARAMETERS:
   35256             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   35257             :     Y       -   array[0..N-1], function values.
   35258             :     W       -   weights, array[0..N-1]
   35259             :     C       -   array[0..K-1], initial approximation to the solution,
   35260             :     N       -   number of points, N>1
   35261             :     M       -   dimension of space
   35262             :     K       -   number of parameters being fitted
   35263             : 
   35264             : OUTPUT PARAMETERS:
   35265             :     State   -   structure which stores algorithm state
   35266             : 
   35267             :   -- ALGLIB --
   35268             :      Copyright 17.08.2009 by Bochkanov Sergey
   35269             : *************************************************************************/
   35270           0 : void lsfitcreatewfgh(/* Real    */ ae_matrix* x,
   35271             :      /* Real    */ ae_vector* y,
   35272             :      /* Real    */ ae_vector* w,
   35273             :      /* Real    */ ae_vector* c,
   35274             :      ae_int_t n,
   35275             :      ae_int_t m,
   35276             :      ae_int_t k,
   35277             :      lsfitstate* state,
   35278             :      ae_state *_state)
   35279             : {
   35280             :     ae_int_t i;
   35281             : 
   35282           0 :     _lsfitstate_clear(state);
   35283             : 
   35284           0 :     ae_assert(n>=1, "LSFitCreateWFGH: N<1!", _state);
   35285           0 :     ae_assert(m>=1, "LSFitCreateWFGH: M<1!", _state);
   35286           0 :     ae_assert(k>=1, "LSFitCreateWFGH: K<1!", _state);
   35287           0 :     ae_assert(c->cnt>=k, "LSFitCreateWFGH: length(C)<K!", _state);
   35288           0 :     ae_assert(isfinitevector(c, k, _state), "LSFitCreateWFGH: C contains infinite or NaN values!", _state);
   35289           0 :     ae_assert(y->cnt>=n, "LSFitCreateWFGH: length(Y)<N!", _state);
   35290           0 :     ae_assert(isfinitevector(y, n, _state), "LSFitCreateWFGH: Y contains infinite or NaN values!", _state);
   35291           0 :     ae_assert(w->cnt>=n, "LSFitCreateWFGH: length(W)<N!", _state);
   35292           0 :     ae_assert(isfinitevector(w, n, _state), "LSFitCreateWFGH: W contains infinite or NaN values!", _state);
   35293           0 :     ae_assert(x->rows>=n, "LSFitCreateWFGH: rows(X)<N!", _state);
   35294           0 :     ae_assert(x->cols>=m, "LSFitCreateWFGH: cols(X)<M!", _state);
   35295           0 :     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateWFGH: X contains infinite or NaN values!", _state);
   35296           0 :     state->teststep = (double)(0);
   35297           0 :     state->diffstep = (double)(0);
   35298           0 :     state->npoints = n;
   35299           0 :     state->nweights = n;
   35300           0 :     state->wkind = 1;
   35301           0 :     state->m = m;
   35302           0 :     state->k = k;
   35303           0 :     lsfitsetcond(state, 0.0, 0, _state);
   35304           0 :     lsfitsetstpmax(state, 0.0, _state);
   35305           0 :     lsfitsetxrep(state, ae_false, _state);
   35306           0 :     ae_matrix_set_length(&state->taskx, n, m, _state);
   35307           0 :     ae_vector_set_length(&state->tasky, n, _state);
   35308           0 :     ae_vector_set_length(&state->taskw, n, _state);
   35309           0 :     ae_vector_set_length(&state->c, k, _state);
   35310           0 :     ae_vector_set_length(&state->c0, k, _state);
   35311           0 :     ae_vector_set_length(&state->c1, k, _state);
   35312           0 :     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   35313           0 :     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   35314           0 :     ae_matrix_set_length(&state->h, k, k, _state);
   35315           0 :     ae_vector_set_length(&state->x, m, _state);
   35316           0 :     ae_vector_set_length(&state->g, k, _state);
   35317           0 :     ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
   35318           0 :     for(i=0; i<=n-1; i++)
   35319             :     {
   35320           0 :         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   35321           0 :         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
   35322             :     }
   35323           0 :     ae_vector_set_length(&state->s, k, _state);
   35324           0 :     ae_vector_set_length(&state->bndl, k, _state);
   35325           0 :     ae_vector_set_length(&state->bndu, k, _state);
   35326           0 :     for(i=0; i<=k-1; i++)
   35327             :     {
   35328           0 :         state->s.ptr.p_double[i] = 1.0;
   35329           0 :         state->bndl.ptr.p_double[i] = _state->v_neginf;
   35330           0 :         state->bndu.ptr.p_double[i] = _state->v_posinf;
   35331             :     }
   35332           0 :     state->optalgo = 2;
   35333           0 :     state->prevnpt = -1;
   35334           0 :     state->prevalgo = -1;
   35335           0 :     state->nec = 0;
   35336           0 :     state->nic = 0;
   35337           0 :     minlmcreatefgh(k, &state->c0, &state->optstate, _state);
   35338           0 :     lsfit_lsfitclearrequestfields(state, _state);
   35339           0 :     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
   35340           0 :     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
   35341           0 :     state->rstate.stage = -1;
   35342           0 : }
   35343             : 
   35344             : 
   35345             : /*************************************************************************
   35346             : Nonlinear least squares fitting using gradient/Hessian, without individial
   35347             : weights.
   35348             : 
   35349             : Nonlinear task min(F(c)) is solved, where
   35350             : 
   35351             :     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
   35352             : 
   35353             :     * N is a number of points,
   35354             :     * M is a dimension of a space points belong to,
   35355             :     * K is a dimension of a space of parameters being fitted,
   35356             :     * x is a set of N points, each of them is an M-dimensional vector,
   35357             :     * c is a K-dimensional vector of parameters being fitted
   35358             : 
   35359             : This subroutine uses f(c,x[i]), its gradient and its Hessian.
   35360             : 
   35361             : INPUT PARAMETERS:
   35362             :     X       -   array[0..N-1,0..M-1], points (one row = one point)
   35363             :     Y       -   array[0..N-1], function values.
   35364             :     C       -   array[0..K-1], initial approximation to the solution,
   35365             :     N       -   number of points, N>1
   35366             :     M       -   dimension of space
   35367             :     K       -   number of parameters being fitted
   35368             : 
   35369             : OUTPUT PARAMETERS:
   35370             :     State   -   structure which stores algorithm state
   35371             : 
   35372             : 
   35373             :   -- ALGLIB --
   35374             :      Copyright 17.08.2009 by Bochkanov Sergey
   35375             : *************************************************************************/
   35376           0 : void lsfitcreatefgh(/* Real    */ ae_matrix* x,
   35377             :      /* Real    */ ae_vector* y,
   35378             :      /* Real    */ ae_vector* c,
   35379             :      ae_int_t n,
   35380             :      ae_int_t m,
   35381             :      ae_int_t k,
   35382             :      lsfitstate* state,
   35383             :      ae_state *_state)
   35384             : {
   35385             :     ae_int_t i;
   35386             : 
   35387           0 :     _lsfitstate_clear(state);
   35388             : 
   35389           0 :     ae_assert(n>=1, "LSFitCreateFGH: N<1!", _state);
   35390           0 :     ae_assert(m>=1, "LSFitCreateFGH: M<1!", _state);
   35391           0 :     ae_assert(k>=1, "LSFitCreateFGH: K<1!", _state);
   35392           0 :     ae_assert(c->cnt>=k, "LSFitCreateFGH: length(C)<K!", _state);
   35393           0 :     ae_assert(isfinitevector(c, k, _state), "LSFitCreateFGH: C contains infinite or NaN values!", _state);
   35394           0 :     ae_assert(y->cnt>=n, "LSFitCreateFGH: length(Y)<N!", _state);
   35395           0 :     ae_assert(isfinitevector(y, n, _state), "LSFitCreateFGH: Y contains infinite or NaN values!", _state);
   35396           0 :     ae_assert(x->rows>=n, "LSFitCreateFGH: rows(X)<N!", _state);
   35397           0 :     ae_assert(x->cols>=m, "LSFitCreateFGH: cols(X)<M!", _state);
   35398           0 :     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateFGH: X contains infinite or NaN values!", _state);
   35399           0 :     state->teststep = (double)(0);
   35400           0 :     state->diffstep = (double)(0);
   35401           0 :     state->npoints = n;
   35402           0 :     state->wkind = 0;
   35403           0 :     state->m = m;
   35404           0 :     state->k = k;
   35405           0 :     lsfitsetcond(state, 0.0, 0, _state);
   35406           0 :     lsfitsetstpmax(state, 0.0, _state);
   35407           0 :     lsfitsetxrep(state, ae_false, _state);
   35408           0 :     ae_matrix_set_length(&state->taskx, n, m, _state);
   35409           0 :     ae_vector_set_length(&state->tasky, n, _state);
   35410           0 :     ae_vector_set_length(&state->c, k, _state);
   35411           0 :     ae_vector_set_length(&state->c0, k, _state);
   35412           0 :     ae_vector_set_length(&state->c1, k, _state);
   35413           0 :     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   35414           0 :     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
   35415           0 :     ae_matrix_set_length(&state->h, k, k, _state);
   35416           0 :     ae_vector_set_length(&state->x, m, _state);
   35417           0 :     ae_vector_set_length(&state->g, k, _state);
   35418           0 :     for(i=0; i<=n-1; i++)
   35419             :     {
   35420           0 :         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   35421           0 :         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
   35422             :     }
   35423           0 :     ae_vector_set_length(&state->s, k, _state);
   35424           0 :     ae_vector_set_length(&state->bndl, k, _state);
   35425           0 :     ae_vector_set_length(&state->bndu, k, _state);
   35426           0 :     for(i=0; i<=k-1; i++)
   35427             :     {
   35428           0 :         state->s.ptr.p_double[i] = 1.0;
   35429           0 :         state->bndl.ptr.p_double[i] = _state->v_neginf;
   35430           0 :         state->bndu.ptr.p_double[i] = _state->v_posinf;
   35431             :     }
   35432           0 :     state->optalgo = 2;
   35433           0 :     state->prevnpt = -1;
   35434           0 :     state->prevalgo = -1;
   35435           0 :     state->nec = 0;
   35436           0 :     state->nic = 0;
   35437           0 :     minlmcreatefgh(k, &state->c0, &state->optstate, _state);
   35438           0 :     lsfit_lsfitclearrequestfields(state, _state);
   35439           0 :     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
   35440           0 :     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
   35441           0 :     state->rstate.stage = -1;
   35442           0 : }
   35443             : 
   35444             : 
   35445             : /*************************************************************************
   35446             : Stopping conditions for nonlinear least squares fitting.
   35447             : 
   35448             : INPUT PARAMETERS:
   35449             :     State   -   structure which stores algorithm state
   35450             :     EpsX    -   >=0
   35451             :                 The subroutine finishes its work if  on  k+1-th  iteration
   35452             :                 the condition |v|<=EpsX is fulfilled, where:
   35453             :                 * |.| means Euclidian norm
   35454             :                 * v - scaled step vector, v[i]=dx[i]/s[i]
   35455             :                 * dx - ste pvector, dx=X(k+1)-X(k)
   35456             :                 * s - scaling coefficients set by LSFitSetScale()
   35457             :     MaxIts  -   maximum number of iterations. If MaxIts=0, the  number  of
   35458             :                 iterations   is    unlimited.   Only   Levenberg-Marquardt
   35459             :                 iterations  are  counted  (L-BFGS/CG  iterations  are  NOT
   35460             :                 counted because their cost is very low compared to that of
   35461             :                 LM).
   35462             : 
   35463             : NOTE
   35464             : 
   35465             : Passing EpsX=0  and  MaxIts=0  (simultaneously)  will  lead  to  automatic
   35466             : stopping criterion selection (according to the scheme used by MINLM unit).
   35467             : 
   35468             : 
   35469             :   -- ALGLIB --
   35470             :      Copyright 17.08.2009 by Bochkanov Sergey
   35471             : *************************************************************************/
   35472           0 : void lsfitsetcond(lsfitstate* state,
   35473             :      double epsx,
   35474             :      ae_int_t maxits,
   35475             :      ae_state *_state)
   35476             : {
   35477             : 
   35478             : 
   35479           0 :     ae_assert(ae_isfinite(epsx, _state), "LSFitSetCond: EpsX is not finite!", _state);
   35480           0 :     ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "LSFitSetCond: negative EpsX!", _state);
   35481           0 :     ae_assert(maxits>=0, "LSFitSetCond: negative MaxIts!", _state);
   35482           0 :     state->epsx = epsx;
   35483           0 :     state->maxits = maxits;
   35484           0 : }
   35485             : 
   35486             : 
   35487             : /*************************************************************************
   35488             : This function sets maximum step length
   35489             : 
   35490             : INPUT PARAMETERS:
   35491             :     State   -   structure which stores algorithm state
   35492             :     StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
   35493             :                 want to limit step length.
   35494             : 
   35495             : Use this subroutine when you optimize target function which contains exp()
   35496             : or  other  fast  growing  functions,  and optimization algorithm makes too
   35497             : large  steps  which  leads  to overflow. This function allows us to reject
   35498             : steps  that  are  too  large  (and  therefore  expose  us  to the possible
   35499             : overflow) without actually calculating function value at the x+stp*d.
   35500             : 
   35501             : NOTE: non-zero StpMax leads to moderate  performance  degradation  because
   35502             : intermediate  step  of  preconditioned L-BFGS optimization is incompatible
   35503             : with limits on step size.
   35504             : 
   35505             :   -- ALGLIB --
   35506             :      Copyright 02.04.2010 by Bochkanov Sergey
   35507             : *************************************************************************/
   35508           0 : void lsfitsetstpmax(lsfitstate* state, double stpmax, ae_state *_state)
   35509             : {
   35510             : 
   35511             : 
   35512           0 :     ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "LSFitSetStpMax: StpMax<0!", _state);
   35513           0 :     state->stpmax = stpmax;
   35514           0 : }
   35515             : 
   35516             : 
   35517             : /*************************************************************************
   35518             : This function turns on/off reporting.
   35519             : 
   35520             : INPUT PARAMETERS:
   35521             :     State   -   structure which stores algorithm state
   35522             :     NeedXRep-   whether iteration reports are needed or not
   35523             :     
   35524             : When reports are needed, State.C (current parameters) and State.F (current
   35525             : value of fitting function) are reported.
   35526             : 
   35527             : 
   35528             :   -- ALGLIB --
   35529             :      Copyright 15.08.2010 by Bochkanov Sergey
   35530             : *************************************************************************/
   35531           0 : void lsfitsetxrep(lsfitstate* state, ae_bool needxrep, ae_state *_state)
   35532             : {
   35533             : 
   35534             : 
   35535           0 :     state->xrep = needxrep;
   35536           0 : }
   35537             : 
   35538             : 
   35539             : /*************************************************************************
   35540             : This function sets scaling coefficients for underlying optimizer.
   35541             : 
   35542             : ALGLIB optimizers use scaling matrices to test stopping  conditions  (step
   35543             : size and gradient are scaled before comparison with tolerances).  Scale of
   35544             : the I-th variable is a translation invariant measure of:
   35545             : a) "how large" the variable is
   35546             : b) how large the step should be to make significant changes in the function
   35547             : 
   35548             : Generally, scale is NOT considered to be a form of preconditioner.  But LM
   35549             : optimizer is unique in that it uses scaling matrix both  in  the  stopping
   35550             : condition tests and as Marquardt damping factor.
   35551             : 
   35552             : Proper scaling is very important for the algorithm performance. It is less
   35553             : important for the quality of results, but still has some influence (it  is
   35554             : easier  to  converge  when  variables  are  properly  scaled, so premature
   35555             : stopping is possible when very badly scalled variables are  combined  with
   35556             : relaxed stopping conditions).
   35557             : 
   35558             : INPUT PARAMETERS:
   35559             :     State   -   structure stores algorithm state
   35560             :     S       -   array[N], non-zero scaling coefficients
   35561             :                 S[i] may be negative, sign doesn't matter.
   35562             : 
   35563             :   -- ALGLIB --
   35564             :      Copyright 14.01.2011 by Bochkanov Sergey
   35565             : *************************************************************************/
   35566           0 : void lsfitsetscale(lsfitstate* state,
   35567             :      /* Real    */ ae_vector* s,
   35568             :      ae_state *_state)
   35569             : {
   35570             :     ae_int_t i;
   35571             : 
   35572             : 
   35573           0 :     ae_assert(s->cnt>=state->k, "LSFitSetScale: Length(S)<K", _state);
   35574           0 :     for(i=0; i<=state->k-1; i++)
   35575             :     {
   35576           0 :         ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "LSFitSetScale: S contains infinite or NAN elements", _state);
   35577           0 :         ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "LSFitSetScale: S contains infinite or NAN elements", _state);
   35578           0 :         state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state);
   35579             :     }
   35580           0 : }
   35581             : 
   35582             : 
   35583             : /*************************************************************************
   35584             : This function sets boundary constraints for underlying optimizer
   35585             : 
   35586             : Boundary constraints are inactive by default (after initial creation).
   35587             : They are preserved until explicitly turned off with another SetBC() call.
   35588             : 
   35589             : INPUT PARAMETERS:
   35590             :     State   -   structure stores algorithm state
   35591             :     BndL    -   lower bounds, array[K].
   35592             :                 If some (all) variables are unbounded, you may specify
   35593             :                 very small number or -INF (latter is recommended because
   35594             :                 it will allow solver to use better algorithm).
   35595             :     BndU    -   upper bounds, array[K].
   35596             :                 If some (all) variables are unbounded, you may specify
   35597             :                 very large number or +INF (latter is recommended because
   35598             :                 it will allow solver to use better algorithm).
   35599             : 
   35600             : NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th
   35601             : variable will be "frozen" at X[i]=BndL[i]=BndU[i].
   35602             : 
   35603             : NOTE 2: unlike other constrained optimization algorithms, this solver  has
   35604             : following useful properties:
   35605             : * bound constraints are always satisfied exactly
   35606             : * function is evaluated only INSIDE area specified by bound constraints
   35607             : 
   35608             :   -- ALGLIB --
   35609             :      Copyright 14.01.2011 by Bochkanov Sergey
   35610             : *************************************************************************/
   35611           0 : void lsfitsetbc(lsfitstate* state,
   35612             :      /* Real    */ ae_vector* bndl,
   35613             :      /* Real    */ ae_vector* bndu,
   35614             :      ae_state *_state)
   35615             : {
   35616             :     ae_int_t i;
   35617             :     ae_int_t k;
   35618             : 
   35619             : 
   35620           0 :     k = state->k;
   35621           0 :     ae_assert(bndl->cnt>=k, "LSFitSetBC: Length(BndL)<K", _state);
   35622           0 :     ae_assert(bndu->cnt>=k, "LSFitSetBC: Length(BndU)<K", _state);
   35623           0 :     for(i=0; i<=k-1; i++)
   35624             :     {
   35625           0 :         ae_assert(ae_isfinite(bndl->ptr.p_double[i], _state)||ae_isneginf(bndl->ptr.p_double[i], _state), "LSFitSetBC: BndL contains NAN or +INF", _state);
   35626           0 :         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);
   35627           0 :         if( ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state) )
   35628             :         {
   35629           0 :             ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "LSFitSetBC: BndL[i]>BndU[i]", _state);
   35630             :         }
   35631           0 :         state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i];
   35632           0 :         state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i];
   35633             :     }
   35634           0 : }
   35635             : 
   35636             : 
   35637             : /*************************************************************************
   35638             : This function sets linear constraints for underlying optimizer
   35639             : 
   35640             : Linear constraints are inactive by default (after initial creation).
   35641             : They are preserved until explicitly turned off with another SetLC() call.
   35642             : 
   35643             : INPUT PARAMETERS:
   35644             :     State   -   structure stores algorithm state
   35645             :     C       -   linear constraints, array[K,N+1].
   35646             :                 Each row of C represents one constraint, either equality
   35647             :                 or inequality (see below):
   35648             :                 * first N elements correspond to coefficients,
   35649             :                 * last element corresponds to the right part.
   35650             :                 All elements of C (including right part) must be finite.
   35651             :     CT      -   type of constraints, array[K]:
   35652             :                 * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1]
   35653             :                 * if CT[i]=0, then I-th constraint is C[i,*]*x  = C[i,n+1]
   35654             :                 * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1]
   35655             :     K       -   number of equality/inequality constraints, K>=0:
   35656             :                 * if given, only leading K elements of C/CT are used
   35657             :                 * if not given, automatically determined from sizes of C/CT
   35658             : 
   35659             : IMPORTANT: if you have linear constraints, it is strongly  recommended  to
   35660             :            set scale of variables with lsfitsetscale(). QP solver which is
   35661             :            used to calculate linearly constrained steps heavily relies  on
   35662             :            good scaling of input problems.
   35663             :            
   35664             : NOTE: linear  (non-box)  constraints  are  satisfied only approximately  -
   35665             :       there  always  exists some violation due  to  numerical  errors  and
   35666             :       algorithmic limitations.
   35667             : 
   35668             : NOTE: general linear constraints  add  significant  overhead  to  solution
   35669             :       process. Although solver performs roughly same amount of  iterations
   35670             :       (when compared  with  similar  box-only  constrained  problem), each
   35671             :       iteration   now    involves  solution  of  linearly  constrained  QP
   35672             :       subproblem, which requires ~3-5 times more Cholesky  decompositions.
   35673             :       Thus, if you can reformulate your problem in such way  this  it  has
   35674             :       only box constraints, it may be beneficial to do so.
   35675             : 
   35676             :   -- ALGLIB --
   35677             :      Copyright 29.04.2017 by Bochkanov Sergey
   35678             : *************************************************************************/
   35679           0 : void lsfitsetlc(lsfitstate* state,
   35680             :      /* Real    */ ae_matrix* c,
   35681             :      /* Integer */ ae_vector* ct,
   35682             :      ae_int_t k,
   35683             :      ae_state *_state)
   35684             : {
   35685             :     ae_int_t i;
   35686             :     ae_int_t n;
   35687             : 
   35688             : 
   35689           0 :     n = state->k;
   35690             :     
   35691             :     /*
   35692             :      * First, check for errors in the inputs
   35693             :      */
   35694           0 :     ae_assert(k>=0, "LSFitSetLC: K<0", _state);
   35695           0 :     ae_assert(c->cols>=n+1||k==0, "LSFitSetLC: Cols(C)<N+1", _state);
   35696           0 :     ae_assert(c->rows>=k, "LSFitSetLC: Rows(C)<K", _state);
   35697           0 :     ae_assert(ct->cnt>=k, "LSFitSetLC: Length(CT)<K", _state);
   35698           0 :     ae_assert(apservisfinitematrix(c, k, n+1, _state), "LSFitSetLC: C contains infinite or NaN values!", _state);
   35699             :     
   35700             :     /*
   35701             :      * Handle zero K
   35702             :      */
   35703           0 :     if( k==0 )
   35704             :     {
   35705           0 :         state->nec = 0;
   35706           0 :         state->nic = 0;
   35707           0 :         return;
   35708             :     }
   35709             :     
   35710             :     /*
   35711             :      * Equality constraints are stored first, in the upper
   35712             :      * NEC rows of State.CLEIC matrix. Inequality constraints
   35713             :      * are stored in the next NIC rows.
   35714             :      *
   35715             :      * NOTE: we convert inequality constraints to the form
   35716             :      * A*x<=b before copying them.
   35717             :      */
   35718           0 :     rmatrixsetlengthatleast(&state->cleic, k, n+1, _state);
   35719           0 :     state->nec = 0;
   35720           0 :     state->nic = 0;
   35721           0 :     for(i=0; i<=k-1; i++)
   35722             :     {
   35723           0 :         if( ct->ptr.p_int[i]==0 )
   35724             :         {
   35725           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));
   35726           0 :             state->nec = state->nec+1;
   35727             :         }
   35728             :     }
   35729           0 :     for(i=0; i<=k-1; i++)
   35730             :     {
   35731           0 :         if( ct->ptr.p_int[i]!=0 )
   35732             :         {
   35733           0 :             if( ct->ptr.p_int[i]>0 )
   35734             :             {
   35735           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));
   35736             :             }
   35737             :             else
   35738             :             {
   35739           0 :                 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));
   35740             :             }
   35741           0 :             state->nic = state->nic+1;
   35742             :         }
   35743             :     }
   35744             : }
   35745             : 
   35746             : 
   35747             : /*************************************************************************
   35748             : NOTES:
   35749             : 
   35750             : 1. this algorithm is somewhat unusual because it works with  parameterized
   35751             :    function f(C,X), where X is a function argument (we  have  many  points
   35752             :    which are characterized by different  argument  values),  and  C  is  a
   35753             :    parameter to fit.
   35754             : 
   35755             :    For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1,  then
   35756             :    x will be argument, and {c0,c1} will be parameters.
   35757             :    
   35758             :    It is important to understand that this algorithm finds minimum in  the
   35759             :    space of function PARAMETERS (not arguments), so it  needs  derivatives
   35760             :    of f() with respect to C, not X.
   35761             :    
   35762             :    In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1}
   35763             :    instead of {df/dx} = {c0}.
   35764             : 
   35765             : 2. Callback functions accept C as the first parameter, and X as the second
   35766             : 
   35767             : 3. If  state  was  created  with  LSFitCreateFG(),  algorithm  needs  just
   35768             :    function   and   its   gradient,   but   if   state   was  created with
   35769             :    LSFitCreateFGH(), algorithm will need function, gradient and Hessian.
   35770             :    
   35771             :    According  to  the  said  above,  there  ase  several  versions of this
   35772             :    function, which accept different sets of callbacks.
   35773             :    
   35774             :    This flexibility opens way to subtle errors - you may create state with
   35775             :    LSFitCreateFGH() (optimization using Hessian), but call function  which
   35776             :    does not accept Hessian. So when algorithm will request Hessian,  there
   35777             :    will be no callback to call. In this case exception will be thrown.
   35778             :    
   35779             :    Be careful to avoid such errors because there is no way to find them at
   35780             :    compile time - you can see them at runtime only.
   35781             : 
   35782             :   -- ALGLIB --
   35783             :      Copyright 17.08.2009 by Bochkanov Sergey
   35784             : *************************************************************************/
   35785           0 : ae_bool lsfititeration(lsfitstate* state, ae_state *_state)
   35786             : {
   35787             :     double lx;
   35788             :     double lf;
   35789             :     double ld;
   35790             :     double rx;
   35791             :     double rf;
   35792             :     double rd;
   35793             :     ae_int_t n;
   35794             :     ae_int_t m;
   35795             :     ae_int_t k;
   35796             :     double v;
   35797             :     double vv;
   35798             :     double relcnt;
   35799             :     ae_int_t i;
   35800             :     ae_int_t j;
   35801             :     ae_int_t j1;
   35802             :     ae_int_t info;
   35803             :     ae_bool result;
   35804             : 
   35805             : 
   35806             :     
   35807             :     /*
   35808             :      * Reverse communication preparations
   35809             :      * I know it looks ugly, but it works the same way
   35810             :      * anywhere from C++ to Python.
   35811             :      *
   35812             :      * This code initializes locals by:
   35813             :      * * random values determined during code
   35814             :      *   generation - on first subroutine call
   35815             :      * * values from previous call - on subsequent calls
   35816             :      */
   35817           0 :     if( state->rstate.stage>=0 )
   35818             :     {
   35819           0 :         n = state->rstate.ia.ptr.p_int[0];
   35820           0 :         m = state->rstate.ia.ptr.p_int[1];
   35821           0 :         k = state->rstate.ia.ptr.p_int[2];
   35822           0 :         i = state->rstate.ia.ptr.p_int[3];
   35823           0 :         j = state->rstate.ia.ptr.p_int[4];
   35824           0 :         j1 = state->rstate.ia.ptr.p_int[5];
   35825           0 :         info = state->rstate.ia.ptr.p_int[6];
   35826           0 :         lx = state->rstate.ra.ptr.p_double[0];
   35827           0 :         lf = state->rstate.ra.ptr.p_double[1];
   35828           0 :         ld = state->rstate.ra.ptr.p_double[2];
   35829           0 :         rx = state->rstate.ra.ptr.p_double[3];
   35830           0 :         rf = state->rstate.ra.ptr.p_double[4];
   35831           0 :         rd = state->rstate.ra.ptr.p_double[5];
   35832           0 :         v = state->rstate.ra.ptr.p_double[6];
   35833           0 :         vv = state->rstate.ra.ptr.p_double[7];
   35834           0 :         relcnt = state->rstate.ra.ptr.p_double[8];
   35835             :     }
   35836             :     else
   35837             :     {
   35838           0 :         n = 359;
   35839           0 :         m = -58;
   35840           0 :         k = -919;
   35841           0 :         i = -909;
   35842           0 :         j = 81;
   35843           0 :         j1 = 255;
   35844           0 :         info = 74;
   35845           0 :         lx = -788;
   35846           0 :         lf = 809;
   35847           0 :         ld = 205;
   35848           0 :         rx = -838;
   35849           0 :         rf = 939;
   35850           0 :         rd = -526;
   35851           0 :         v = 763;
   35852           0 :         vv = -541;
   35853           0 :         relcnt = -698;
   35854             :     }
   35855           0 :     if( state->rstate.stage==0 )
   35856             :     {
   35857           0 :         goto lbl_0;
   35858             :     }
   35859           0 :     if( state->rstate.stage==1 )
   35860             :     {
   35861           0 :         goto lbl_1;
   35862             :     }
   35863           0 :     if( state->rstate.stage==2 )
   35864             :     {
   35865           0 :         goto lbl_2;
   35866             :     }
   35867           0 :     if( state->rstate.stage==3 )
   35868             :     {
   35869           0 :         goto lbl_3;
   35870             :     }
   35871           0 :     if( state->rstate.stage==4 )
   35872             :     {
   35873           0 :         goto lbl_4;
   35874             :     }
   35875           0 :     if( state->rstate.stage==5 )
   35876             :     {
   35877           0 :         goto lbl_5;
   35878             :     }
   35879           0 :     if( state->rstate.stage==6 )
   35880             :     {
   35881           0 :         goto lbl_6;
   35882             :     }
   35883           0 :     if( state->rstate.stage==7 )
   35884             :     {
   35885           0 :         goto lbl_7;
   35886             :     }
   35887           0 :     if( state->rstate.stage==8 )
   35888             :     {
   35889           0 :         goto lbl_8;
   35890             :     }
   35891           0 :     if( state->rstate.stage==9 )
   35892             :     {
   35893           0 :         goto lbl_9;
   35894             :     }
   35895           0 :     if( state->rstate.stage==10 )
   35896             :     {
   35897           0 :         goto lbl_10;
   35898             :     }
   35899           0 :     if( state->rstate.stage==11 )
   35900             :     {
   35901           0 :         goto lbl_11;
   35902             :     }
   35903           0 :     if( state->rstate.stage==12 )
   35904             :     {
   35905           0 :         goto lbl_12;
   35906             :     }
   35907           0 :     if( state->rstate.stage==13 )
   35908             :     {
   35909           0 :         goto lbl_13;
   35910             :     }
   35911             :     
   35912             :     /*
   35913             :      * Routine body
   35914             :      */
   35915             :     
   35916             :     /*
   35917             :      * Init
   35918             :      */
   35919           0 :     if( state->wkind==1 )
   35920             :     {
   35921           0 :         ae_assert(state->npoints==state->nweights, "LSFitFit: number of points is not equal to the number of weights", _state);
   35922             :     }
   35923           0 :     state->repvaridx = -1;
   35924           0 :     n = state->npoints;
   35925           0 :     m = state->m;
   35926           0 :     k = state->k;
   35927           0 :     ivectorsetlengthatleast(&state->tmpct, state->nec+state->nic, _state);
   35928           0 :     for(i=0; i<=state->nec-1; i++)
   35929             :     {
   35930           0 :         state->tmpct.ptr.p_int[i] = 0;
   35931             :     }
   35932           0 :     for(i=0; i<=state->nic-1; i++)
   35933             :     {
   35934           0 :         state->tmpct.ptr.p_int[state->nec+i] = -1;
   35935             :     }
   35936           0 :     minlmsetcond(&state->optstate, state->epsx, state->maxits, _state);
   35937           0 :     minlmsetstpmax(&state->optstate, state->stpmax, _state);
   35938           0 :     minlmsetxrep(&state->optstate, state->xrep, _state);
   35939           0 :     minlmsetscale(&state->optstate, &state->s, _state);
   35940           0 :     minlmsetbc(&state->optstate, &state->bndl, &state->bndu, _state);
   35941           0 :     minlmsetlc(&state->optstate, &state->cleic, &state->tmpct, state->nec+state->nic, _state);
   35942             :     
   35943             :     /*
   35944             :      *  Check that user-supplied gradient is correct
   35945             :      */
   35946           0 :     lsfit_lsfitclearrequestfields(state, _state);
   35947           0 :     if( !(ae_fp_greater(state->teststep,(double)(0))&&state->optalgo==1) )
   35948             :     {
   35949           0 :         goto lbl_14;
   35950             :     }
   35951           0 :     for(i=0; i<=k-1; i++)
   35952             :     {
   35953           0 :         state->c.ptr.p_double[i] = state->c0.ptr.p_double[i];
   35954           0 :         if( ae_isfinite(state->bndl.ptr.p_double[i], _state) )
   35955             :         {
   35956           0 :             state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state);
   35957             :         }
   35958           0 :         if( ae_isfinite(state->bndu.ptr.p_double[i], _state) )
   35959             :         {
   35960           0 :             state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
   35961             :         }
   35962             :     }
   35963           0 :     state->needfg = ae_true;
   35964           0 :     i = 0;
   35965           0 : lbl_16:
   35966           0 :     if( i>k-1 )
   35967             :     {
   35968           0 :         goto lbl_18;
   35969             :     }
   35970           0 :     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);
   35971           0 :     v = state->c.ptr.p_double[i];
   35972           0 :     j = 0;
   35973           0 : lbl_19:
   35974           0 :     if( j>n-1 )
   35975             :     {
   35976           0 :         goto lbl_21;
   35977             :     }
   35978           0 :     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[j][0], 1, ae_v_len(0,m-1));
   35979           0 :     state->c.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i];
   35980           0 :     if( ae_isfinite(state->bndl.ptr.p_double[i], _state) )
   35981             :     {
   35982           0 :         state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state);
   35983             :     }
   35984           0 :     lx = state->c.ptr.p_double[i];
   35985           0 :     state->rstate.stage = 0;
   35986           0 :     goto lbl_rcomm;
   35987           0 : lbl_0:
   35988           0 :     lf = state->f;
   35989           0 :     ld = state->g.ptr.p_double[i];
   35990           0 :     state->c.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i];
   35991           0 :     if( ae_isfinite(state->bndu.ptr.p_double[i], _state) )
   35992             :     {
   35993           0 :         state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
   35994             :     }
   35995           0 :     rx = state->c.ptr.p_double[i];
   35996           0 :     state->rstate.stage = 1;
   35997           0 :     goto lbl_rcomm;
   35998           0 : lbl_1:
   35999           0 :     rf = state->f;
   36000           0 :     rd = state->g.ptr.p_double[i];
   36001           0 :     state->c.ptr.p_double[i] = (lx+rx)/2;
   36002           0 :     if( ae_isfinite(state->bndl.ptr.p_double[i], _state) )
   36003             :     {
   36004           0 :         state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state);
   36005             :     }
   36006           0 :     if( ae_isfinite(state->bndu.ptr.p_double[i], _state) )
   36007             :     {
   36008           0 :         state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
   36009             :     }
   36010           0 :     state->rstate.stage = 2;
   36011           0 :     goto lbl_rcomm;
   36012           0 : lbl_2:
   36013           0 :     state->c.ptr.p_double[i] = v;
   36014           0 :     if( !derivativecheck(lf, ld, rf, rd, state->f, state->g.ptr.p_double[i], rx-lx, _state) )
   36015             :     {
   36016           0 :         state->repvaridx = i;
   36017           0 :         state->repterminationtype = -7;
   36018           0 :         result = ae_false;
   36019           0 :         return result;
   36020             :     }
   36021           0 :     j = j+1;
   36022           0 :     goto lbl_19;
   36023           0 : lbl_21:
   36024           0 :     i = i+1;
   36025           0 :     goto lbl_16;
   36026           0 : lbl_18:
   36027           0 :     state->needfg = ae_false;
   36028           0 : lbl_14:
   36029             :     
   36030             :     /*
   36031             :      * Fill WCur by weights:
   36032             :      * * for WKind=0 unit weights are chosen
   36033             :      * * for WKind=1 we use user-supplied weights stored in State.TaskW
   36034             :      */
   36035           0 :     rvectorsetlengthatleast(&state->wcur, n, _state);
   36036           0 :     for(i=0; i<=n-1; i++)
   36037             :     {
   36038           0 :         state->wcur.ptr.p_double[i] = 1.0;
   36039           0 :         if( state->wkind==1 )
   36040             :         {
   36041           0 :             state->wcur.ptr.p_double[i] = state->taskw.ptr.p_double[i];
   36042             :         }
   36043             :     }
   36044             :     
   36045             :     /*
   36046             :      * Optimize
   36047             :      */
   36048           0 : lbl_22:
   36049           0 :     if( !minlmiteration(&state->optstate, _state) )
   36050             :     {
   36051           0 :         goto lbl_23;
   36052             :     }
   36053           0 :     if( !state->optstate.needfi )
   36054             :     {
   36055           0 :         goto lbl_24;
   36056             :     }
   36057             :     
   36058             :     /*
   36059             :      * calculate f[] = wi*(f(xi,c)-yi)
   36060             :      */
   36061           0 :     i = 0;
   36062           0 : lbl_26:
   36063           0 :     if( i>n-1 )
   36064             :     {
   36065           0 :         goto lbl_28;
   36066             :     }
   36067           0 :     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
   36068           0 :     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   36069           0 :     state->pointindex = i;
   36070           0 :     lsfit_lsfitclearrequestfields(state, _state);
   36071           0 :     state->needf = ae_true;
   36072           0 :     state->rstate.stage = 3;
   36073           0 :     goto lbl_rcomm;
   36074           0 : lbl_3:
   36075           0 :     state->needf = ae_false;
   36076           0 :     vv = state->wcur.ptr.p_double[i];
   36077           0 :     state->optstate.fi.ptr.p_double[i] = vv*(state->f-state->tasky.ptr.p_double[i]);
   36078           0 :     i = i+1;
   36079           0 :     goto lbl_26;
   36080           0 : lbl_28:
   36081           0 :     goto lbl_22;
   36082           0 : lbl_24:
   36083           0 :     if( !state->optstate.needf )
   36084             :     {
   36085           0 :         goto lbl_29;
   36086             :     }
   36087             :     
   36088             :     /*
   36089             :      * calculate F = sum (wi*(f(xi,c)-yi))^2
   36090             :      */
   36091           0 :     state->optstate.f = (double)(0);
   36092           0 :     i = 0;
   36093           0 : lbl_31:
   36094           0 :     if( i>n-1 )
   36095             :     {
   36096           0 :         goto lbl_33;
   36097             :     }
   36098           0 :     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
   36099           0 :     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   36100           0 :     state->pointindex = i;
   36101           0 :     lsfit_lsfitclearrequestfields(state, _state);
   36102           0 :     state->needf = ae_true;
   36103           0 :     state->rstate.stage = 4;
   36104           0 :     goto lbl_rcomm;
   36105           0 : lbl_4:
   36106           0 :     state->needf = ae_false;
   36107           0 :     vv = state->wcur.ptr.p_double[i];
   36108           0 :     state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state);
   36109           0 :     i = i+1;
   36110           0 :     goto lbl_31;
   36111           0 : lbl_33:
   36112           0 :     goto lbl_22;
   36113           0 : lbl_29:
   36114           0 :     if( !state->optstate.needfg )
   36115             :     {
   36116           0 :         goto lbl_34;
   36117             :     }
   36118             :     
   36119             :     /*
   36120             :      * calculate F/gradF
   36121             :      */
   36122           0 :     state->optstate.f = (double)(0);
   36123           0 :     for(i=0; i<=k-1; i++)
   36124             :     {
   36125           0 :         state->optstate.g.ptr.p_double[i] = (double)(0);
   36126             :     }
   36127           0 :     i = 0;
   36128           0 : lbl_36:
   36129           0 :     if( i>n-1 )
   36130             :     {
   36131           0 :         goto lbl_38;
   36132             :     }
   36133           0 :     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
   36134           0 :     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   36135           0 :     state->pointindex = i;
   36136           0 :     lsfit_lsfitclearrequestfields(state, _state);
   36137           0 :     state->needfg = ae_true;
   36138           0 :     state->rstate.stage = 5;
   36139           0 :     goto lbl_rcomm;
   36140           0 : lbl_5:
   36141           0 :     state->needfg = ae_false;
   36142           0 :     vv = state->wcur.ptr.p_double[i];
   36143           0 :     state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state);
   36144           0 :     v = ae_sqr(vv, _state)*2*(state->f-state->tasky.ptr.p_double[i]);
   36145           0 :     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);
   36146           0 :     i = i+1;
   36147           0 :     goto lbl_36;
   36148           0 : lbl_38:
   36149           0 :     goto lbl_22;
   36150           0 : lbl_34:
   36151           0 :     if( !state->optstate.needfij )
   36152             :     {
   36153           0 :         goto lbl_39;
   36154             :     }
   36155             :     
   36156             :     /*
   36157             :      * calculate Fi/jac(Fi)
   36158             :      */
   36159           0 :     i = 0;
   36160           0 : lbl_41:
   36161           0 :     if( i>n-1 )
   36162             :     {
   36163           0 :         goto lbl_43;
   36164             :     }
   36165           0 :     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
   36166           0 :     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   36167           0 :     state->pointindex = i;
   36168           0 :     lsfit_lsfitclearrequestfields(state, _state);
   36169           0 :     state->needfg = ae_true;
   36170           0 :     state->rstate.stage = 6;
   36171           0 :     goto lbl_rcomm;
   36172           0 : lbl_6:
   36173           0 :     state->needfg = ae_false;
   36174           0 :     vv = state->wcur.ptr.p_double[i];
   36175           0 :     state->optstate.fi.ptr.p_double[i] = vv*(state->f-state->tasky.ptr.p_double[i]);
   36176           0 :     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);
   36177           0 :     i = i+1;
   36178           0 :     goto lbl_41;
   36179           0 : lbl_43:
   36180           0 :     goto lbl_22;
   36181           0 : lbl_39:
   36182           0 :     if( !state->optstate.needfgh )
   36183             :     {
   36184           0 :         goto lbl_44;
   36185             :     }
   36186             :     
   36187             :     /*
   36188             :      * calculate F/grad(F)/hess(F)
   36189             :      */
   36190           0 :     state->optstate.f = (double)(0);
   36191           0 :     for(i=0; i<=k-1; i++)
   36192             :     {
   36193           0 :         state->optstate.g.ptr.p_double[i] = (double)(0);
   36194             :     }
   36195           0 :     for(i=0; i<=k-1; i++)
   36196             :     {
   36197           0 :         for(j=0; j<=k-1; j++)
   36198             :         {
   36199           0 :             state->optstate.h.ptr.pp_double[i][j] = (double)(0);
   36200             :         }
   36201             :     }
   36202           0 :     i = 0;
   36203           0 : lbl_46:
   36204           0 :     if( i>n-1 )
   36205             :     {
   36206           0 :         goto lbl_48;
   36207             :     }
   36208           0 :     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
   36209           0 :     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   36210           0 :     state->pointindex = i;
   36211           0 :     lsfit_lsfitclearrequestfields(state, _state);
   36212           0 :     state->needfgh = ae_true;
   36213           0 :     state->rstate.stage = 7;
   36214           0 :     goto lbl_rcomm;
   36215           0 : lbl_7:
   36216           0 :     state->needfgh = ae_false;
   36217           0 :     vv = state->wcur.ptr.p_double[i];
   36218           0 :     state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state);
   36219           0 :     v = ae_sqr(vv, _state)*2*(state->f-state->tasky.ptr.p_double[i]);
   36220           0 :     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);
   36221           0 :     for(j=0; j<=k-1; j++)
   36222             :     {
   36223           0 :         v = 2*ae_sqr(vv, _state)*state->g.ptr.p_double[j];
   36224           0 :         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);
   36225           0 :         v = 2*ae_sqr(vv, _state)*(state->f-state->tasky.ptr.p_double[i]);
   36226           0 :         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);
   36227             :     }
   36228           0 :     i = i+1;
   36229           0 :     goto lbl_46;
   36230           0 : lbl_48:
   36231           0 :     goto lbl_22;
   36232           0 : lbl_44:
   36233           0 :     if( !state->optstate.xupdated )
   36234             :     {
   36235           0 :         goto lbl_49;
   36236             :     }
   36237             :     
   36238             :     /*
   36239             :      * Report new iteration
   36240             :      */
   36241           0 :     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
   36242           0 :     state->f = state->optstate.f;
   36243           0 :     lsfit_lsfitclearrequestfields(state, _state);
   36244           0 :     state->xupdated = ae_true;
   36245           0 :     state->rstate.stage = 8;
   36246           0 :     goto lbl_rcomm;
   36247           0 : lbl_8:
   36248           0 :     state->xupdated = ae_false;
   36249           0 :     goto lbl_22;
   36250           0 : lbl_49:
   36251           0 :     goto lbl_22;
   36252           0 : lbl_23:
   36253             :     
   36254             :     /*
   36255             :      * Extract results
   36256             :      *
   36257             :      * NOTE: reverse communication protocol used by this unit does NOT
   36258             :      *       allow us to reallocate State.C[] array. Thus, we extract
   36259             :      *       results to the temporary variable in order to avoid possible
   36260             :      *       reallocation.
   36261             :      */
   36262           0 :     minlmresults(&state->optstate, &state->c1, &state->optrep, _state);
   36263           0 :     state->repterminationtype = state->optrep.terminationtype;
   36264           0 :     state->repiterationscount = state->optrep.iterationscount;
   36265             :     
   36266             :     /*
   36267             :      * calculate errors
   36268             :      */
   36269           0 :     if( state->repterminationtype<=0 )
   36270             :     {
   36271           0 :         goto lbl_51;
   36272             :     }
   36273             :     
   36274             :     /*
   36275             :      * Calculate RMS/Avg/Max/... errors
   36276             :      */
   36277           0 :     state->reprmserror = (double)(0);
   36278           0 :     state->repwrmserror = (double)(0);
   36279           0 :     state->repavgerror = (double)(0);
   36280           0 :     state->repavgrelerror = (double)(0);
   36281           0 :     state->repmaxerror = (double)(0);
   36282           0 :     relcnt = (double)(0);
   36283           0 :     i = 0;
   36284           0 : lbl_53:
   36285           0 :     if( i>n-1 )
   36286             :     {
   36287           0 :         goto lbl_55;
   36288             :     }
   36289           0 :     ae_v_move(&state->c.ptr.p_double[0], 1, &state->c1.ptr.p_double[0], 1, ae_v_len(0,k-1));
   36290           0 :     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   36291           0 :     state->pointindex = i;
   36292           0 :     lsfit_lsfitclearrequestfields(state, _state);
   36293           0 :     state->needf = ae_true;
   36294           0 :     state->rstate.stage = 9;
   36295           0 :     goto lbl_rcomm;
   36296           0 : lbl_9:
   36297           0 :     state->needf = ae_false;
   36298           0 :     v = state->f;
   36299           0 :     vv = state->wcur.ptr.p_double[i];
   36300           0 :     state->reprmserror = state->reprmserror+ae_sqr(v-state->tasky.ptr.p_double[i], _state);
   36301           0 :     state->repwrmserror = state->repwrmserror+ae_sqr(vv*(v-state->tasky.ptr.p_double[i]), _state);
   36302           0 :     state->repavgerror = state->repavgerror+ae_fabs(v-state->tasky.ptr.p_double[i], _state);
   36303           0 :     if( ae_fp_neq(state->tasky.ptr.p_double[i],(double)(0)) )
   36304             :     {
   36305           0 :         state->repavgrelerror = state->repavgrelerror+ae_fabs(v-state->tasky.ptr.p_double[i], _state)/ae_fabs(state->tasky.ptr.p_double[i], _state);
   36306           0 :         relcnt = relcnt+1;
   36307             :     }
   36308           0 :     state->repmaxerror = ae_maxreal(state->repmaxerror, ae_fabs(v-state->tasky.ptr.p_double[i], _state), _state);
   36309           0 :     i = i+1;
   36310           0 :     goto lbl_53;
   36311           0 : lbl_55:
   36312           0 :     state->reprmserror = ae_sqrt(state->reprmserror/n, _state);
   36313           0 :     state->repwrmserror = ae_sqrt(state->repwrmserror/n, _state);
   36314           0 :     state->repavgerror = state->repavgerror/n;
   36315           0 :     if( ae_fp_neq(relcnt,(double)(0)) )
   36316             :     {
   36317           0 :         state->repavgrelerror = state->repavgrelerror/relcnt;
   36318             :     }
   36319             :     
   36320             :     /*
   36321             :      * Calculate covariance matrix
   36322             :      */
   36323           0 :     rmatrixsetlengthatleast(&state->tmpjac, n, k, _state);
   36324           0 :     rvectorsetlengthatleast(&state->tmpf, n, _state);
   36325           0 :     rvectorsetlengthatleast(&state->tmp, k, _state);
   36326           0 :     if( ae_fp_less_eq(state->diffstep,(double)(0)) )
   36327             :     {
   36328           0 :         goto lbl_56;
   36329             :     }
   36330             :     
   36331             :     /*
   36332             :      * Compute Jacobian by means of numerical differentiation
   36333             :      */
   36334           0 :     lsfit_lsfitclearrequestfields(state, _state);
   36335           0 :     state->needf = ae_true;
   36336           0 :     i = 0;
   36337           0 : lbl_58:
   36338           0 :     if( i>n-1 )
   36339             :     {
   36340           0 :         goto lbl_60;
   36341             :     }
   36342           0 :     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   36343           0 :     state->pointindex = i;
   36344           0 :     state->rstate.stage = 10;
   36345           0 :     goto lbl_rcomm;
   36346           0 : lbl_10:
   36347           0 :     state->tmpf.ptr.p_double[i] = state->f;
   36348           0 :     j = 0;
   36349           0 : lbl_61:
   36350           0 :     if( j>k-1 )
   36351             :     {
   36352           0 :         goto lbl_63;
   36353             :     }
   36354           0 :     v = state->c.ptr.p_double[j];
   36355           0 :     lx = v-state->diffstep*state->s.ptr.p_double[j];
   36356           0 :     state->c.ptr.p_double[j] = lx;
   36357           0 :     if( ae_isfinite(state->bndl.ptr.p_double[j], _state) )
   36358             :     {
   36359           0 :         state->c.ptr.p_double[j] = ae_maxreal(state->c.ptr.p_double[j], state->bndl.ptr.p_double[j], _state);
   36360             :     }
   36361           0 :     state->rstate.stage = 11;
   36362           0 :     goto lbl_rcomm;
   36363           0 : lbl_11:
   36364           0 :     lf = state->f;
   36365           0 :     rx = v+state->diffstep*state->s.ptr.p_double[j];
   36366           0 :     state->c.ptr.p_double[j] = rx;
   36367           0 :     if( ae_isfinite(state->bndu.ptr.p_double[j], _state) )
   36368             :     {
   36369           0 :         state->c.ptr.p_double[j] = ae_minreal(state->c.ptr.p_double[j], state->bndu.ptr.p_double[j], _state);
   36370             :     }
   36371           0 :     state->rstate.stage = 12;
   36372           0 :     goto lbl_rcomm;
   36373           0 : lbl_12:
   36374           0 :     rf = state->f;
   36375           0 :     state->c.ptr.p_double[j] = v;
   36376           0 :     if( ae_fp_neq(rx,lx) )
   36377             :     {
   36378           0 :         state->tmpjac.ptr.pp_double[i][j] = (rf-lf)/(rx-lx);
   36379             :     }
   36380             :     else
   36381             :     {
   36382           0 :         state->tmpjac.ptr.pp_double[i][j] = (double)(0);
   36383             :     }
   36384           0 :     j = j+1;
   36385           0 :     goto lbl_61;
   36386           0 : lbl_63:
   36387           0 :     i = i+1;
   36388           0 :     goto lbl_58;
   36389           0 : lbl_60:
   36390           0 :     state->needf = ae_false;
   36391           0 :     goto lbl_57;
   36392           0 : lbl_56:
   36393             :     
   36394             :     /*
   36395             :      * Jacobian is calculated with user-provided analytic gradient
   36396             :      */
   36397           0 :     lsfit_lsfitclearrequestfields(state, _state);
   36398           0 :     state->needfg = ae_true;
   36399           0 :     i = 0;
   36400           0 : lbl_64:
   36401           0 :     if( i>n-1 )
   36402             :     {
   36403           0 :         goto lbl_66;
   36404             :     }
   36405           0 :     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
   36406           0 :     state->pointindex = i;
   36407           0 :     state->rstate.stage = 13;
   36408           0 :     goto lbl_rcomm;
   36409           0 : lbl_13:
   36410           0 :     state->tmpf.ptr.p_double[i] = state->f;
   36411           0 :     for(j=0; j<=k-1; j++)
   36412             :     {
   36413           0 :         state->tmpjac.ptr.pp_double[i][j] = state->g.ptr.p_double[j];
   36414             :     }
   36415           0 :     i = i+1;
   36416           0 :     goto lbl_64;
   36417           0 : lbl_66:
   36418           0 :     state->needfg = ae_false;
   36419           0 : lbl_57:
   36420           0 :     for(i=0; i<=k-1; i++)
   36421             :     {
   36422           0 :         state->tmp.ptr.p_double[i] = 0.0;
   36423             :     }
   36424           0 :     lsfit_estimateerrors(&state->tmpjac, &state->tmpf, &state->tasky, &state->wcur, &state->tmp, &state->s, n, k, &state->rep, &state->tmpjacw, 0, _state);
   36425           0 : lbl_51:
   36426           0 :     result = ae_false;
   36427           0 :     return result;
   36428             :     
   36429             :     /*
   36430             :      * Saving state
   36431             :      */
   36432           0 : lbl_rcomm:
   36433           0 :     result = ae_true;
   36434           0 :     state->rstate.ia.ptr.p_int[0] = n;
   36435           0 :     state->rstate.ia.ptr.p_int[1] = m;
   36436           0 :     state->rstate.ia.ptr.p_int[2] = k;
   36437           0 :     state->rstate.ia.ptr.p_int[3] = i;
   36438           0 :     state->rstate.ia.ptr.p_int[4] = j;
   36439           0 :     state->rstate.ia.ptr.p_int[5] = j1;
   36440           0 :     state->rstate.ia.ptr.p_int[6] = info;
   36441           0 :     state->rstate.ra.ptr.p_double[0] = lx;
   36442           0 :     state->rstate.ra.ptr.p_double[1] = lf;
   36443           0 :     state->rstate.ra.ptr.p_double[2] = ld;
   36444           0 :     state->rstate.ra.ptr.p_double[3] = rx;
   36445           0 :     state->rstate.ra.ptr.p_double[4] = rf;
   36446           0 :     state->rstate.ra.ptr.p_double[5] = rd;
   36447           0 :     state->rstate.ra.ptr.p_double[6] = v;
   36448           0 :     state->rstate.ra.ptr.p_double[7] = vv;
   36449           0 :     state->rstate.ra.ptr.p_double[8] = relcnt;
   36450           0 :     return result;
   36451             : }
   36452             : 
   36453             : 
   36454             : /*************************************************************************
   36455             : Nonlinear least squares fitting results.
   36456             : 
   36457             : Called after return from LSFitFit().
   36458             : 
   36459             : INPUT PARAMETERS:
   36460             :     State   -   algorithm state
   36461             : 
   36462             : OUTPUT PARAMETERS:
   36463             :     Info    -   completion code:
   36464             :                     * -8    optimizer   detected  NAN/INF  in  the  target
   36465             :                             function and/or gradient
   36466             :                     * -7    gradient verification failed.
   36467             :                             See LSFitSetGradientCheck() for more information.
   36468             :                     * -3    inconsistent constraints
   36469             :                     *  2    relative step is no more than EpsX.
   36470             :                     *  5    MaxIts steps was taken
   36471             :                     *  7    stopping conditions are too stringent,
   36472             :                             further improvement is impossible
   36473             :     C       -   array[0..K-1], solution
   36474             :     Rep     -   optimization report. On success following fields are set:
   36475             :                 * R2                non-adjusted coefficient of determination
   36476             :                                     (non-weighted)
   36477             :                 * RMSError          rms error on the (X,Y).
   36478             :                 * AvgError          average error on the (X,Y).
   36479             :                 * AvgRelError       average relative error on the non-zero Y
   36480             :                 * MaxError          maximum error
   36481             :                                     NON-WEIGHTED ERRORS ARE CALCULATED
   36482             :                 * WRMSError         weighted rms error on the (X,Y).
   36483             :                 
   36484             : ERRORS IN PARAMETERS                
   36485             :                 
   36486             : This  solver  also  calculates different kinds of errors in parameters and
   36487             : fills corresponding fields of report:
   36488             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   36489             : * Rep.ErrPar        errors in parameters, array[K],
   36490             :                     errpar = sqrt(diag(CovPar))
   36491             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   36492             :                     best-fit curve from "ideal" best-fit curve built  with
   36493             :                     infinite number of samples, array[N].
   36494             :                     errcurve = sqrt(diag(J*CovPar*J')),
   36495             :                     where J is Jacobian matrix.
   36496             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   36497             : 
   36498             : IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
   36499             :             account boundary/linear constraints! Presence  of  constraints
   36500             :             changes distribution of errors, but there is no  easy  way  to
   36501             :             account for constraints when you calculate covariance matrix.
   36502             :             
   36503             : NOTE:       noise in the data is estimated as follows:
   36504             :             * for fitting without user-supplied  weights  all  points  are
   36505             :               assumed to have same level of noise, which is estimated from
   36506             :               the data
   36507             :             * for fitting with user-supplied weights we assume that  noise
   36508             :               level in I-th point is inversely proportional to Ith weight.
   36509             :               Coefficient of proportionality is estimated from the data.
   36510             :             
   36511             : NOTE:       we apply small amount of regularization when we invert squared
   36512             :             Jacobian and calculate covariance matrix. It  guarantees  that
   36513             :             algorithm won't divide by zero  during  inversion,  but  skews
   36514             :             error estimates a bit (fractional error is about 10^-9).
   36515             :             
   36516             :             However, we believe that this difference is insignificant  for
   36517             :             all practical purposes except for the situation when you  want
   36518             :             to compare ALGLIB results with "reference"  implementation  up
   36519             :             to the last significant digit.
   36520             :             
   36521             : NOTE:       covariance matrix is estimated using  correction  for  degrees
   36522             :             of freedom (covariances are divided by N-M instead of dividing
   36523             :             by N).
   36524             : 
   36525             :   -- ALGLIB --
   36526             :      Copyright 17.08.2009 by Bochkanov Sergey
   36527             : *************************************************************************/
   36528           0 : void lsfitresults(lsfitstate* state,
   36529             :      ae_int_t* info,
   36530             :      /* Real    */ ae_vector* c,
   36531             :      lsfitreport* rep,
   36532             :      ae_state *_state)
   36533             : {
   36534             :     ae_int_t i;
   36535             :     ae_int_t j;
   36536             : 
   36537           0 :     *info = 0;
   36538           0 :     ae_vector_clear(c);
   36539           0 :     _lsfitreport_clear(rep);
   36540             : 
   36541           0 :     lsfit_clearreport(rep, _state);
   36542           0 :     *info = state->repterminationtype;
   36543           0 :     rep->varidx = state->repvaridx;
   36544           0 :     if( *info>0 )
   36545             :     {
   36546           0 :         ae_vector_set_length(c, state->k, _state);
   36547           0 :         ae_v_move(&c->ptr.p_double[0], 1, &state->c1.ptr.p_double[0], 1, ae_v_len(0,state->k-1));
   36548           0 :         rep->rmserror = state->reprmserror;
   36549           0 :         rep->wrmserror = state->repwrmserror;
   36550           0 :         rep->avgerror = state->repavgerror;
   36551           0 :         rep->avgrelerror = state->repavgrelerror;
   36552           0 :         rep->maxerror = state->repmaxerror;
   36553           0 :         rep->iterationscount = state->repiterationscount;
   36554           0 :         ae_matrix_set_length(&rep->covpar, state->k, state->k, _state);
   36555           0 :         ae_vector_set_length(&rep->errpar, state->k, _state);
   36556           0 :         ae_vector_set_length(&rep->errcurve, state->npoints, _state);
   36557           0 :         ae_vector_set_length(&rep->noise, state->npoints, _state);
   36558           0 :         rep->r2 = state->rep.r2;
   36559           0 :         for(i=0; i<=state->k-1; i++)
   36560             :         {
   36561           0 :             for(j=0; j<=state->k-1; j++)
   36562             :             {
   36563           0 :                 rep->covpar.ptr.pp_double[i][j] = state->rep.covpar.ptr.pp_double[i][j];
   36564             :             }
   36565           0 :             rep->errpar.ptr.p_double[i] = state->rep.errpar.ptr.p_double[i];
   36566             :         }
   36567           0 :         for(i=0; i<=state->npoints-1; i++)
   36568             :         {
   36569           0 :             rep->errcurve.ptr.p_double[i] = state->rep.errcurve.ptr.p_double[i];
   36570           0 :             rep->noise.ptr.p_double[i] = state->rep.noise.ptr.p_double[i];
   36571             :         }
   36572             :     }
   36573           0 : }
   36574             : 
   36575             : 
   36576             : /*************************************************************************
   36577             : This  subroutine  turns  on  verification  of  the  user-supplied analytic
   36578             : gradient:
   36579             : * user calls this subroutine before fitting begins
   36580             : * LSFitFit() is called
   36581             : * prior to actual fitting, for  each  point  in  data  set  X_i  and  each
   36582             :   component  of  parameters  being  fited C_j algorithm performs following
   36583             :   steps:
   36584             :   * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j],
   36585             :     where C_j is j-th parameter and S[j] is a scale of j-th parameter
   36586             :   * if needed, steps are bounded with respect to constraints on C[]
   36587             :   * F(X_i|C) is evaluated at these trial points
   36588             :   * we perform one more evaluation in the middle point of the interval
   36589             :   * we  build  cubic  model using function values and derivatives at trial
   36590             :     points and we compare its prediction with actual value in  the  middle
   36591             :     point
   36592             :   * in case difference between prediction and actual value is higher  than
   36593             :     some predetermined threshold, algorithm stops with completion code -7;
   36594             :     Rep.VarIdx is set to index of the parameter with incorrect derivative.
   36595             : * after verification is over, algorithm proceeds to the actual optimization.
   36596             : 
   36597             : NOTE 1: verification needs N*K (points count * parameters count)  gradient
   36598             :         evaluations. It is very costly and you should use it only for  low
   36599             :         dimensional  problems,  when  you  want  to  be  sure  that you've
   36600             :         correctly calculated analytic derivatives. You should not  use  it
   36601             :         in the production code  (unless  you  want  to  check  derivatives
   36602             :         provided by some third party).
   36603             : 
   36604             : NOTE 2: you  should  carefully  choose  TestStep. Value which is too large
   36605             :         (so large that function behaviour is significantly non-cubic) will
   36606             :         lead to false alarms. You may use  different  step  for  different
   36607             :         parameters by means of setting scale with LSFitSetScale().
   36608             : 
   36609             : NOTE 3: this function may lead to false positives. In case it reports that
   36610             :         I-th  derivative was calculated incorrectly, you may decrease test
   36611             :         step  and  try  one  more  time  - maybe your function changes too
   36612             :         sharply  and  your  step  is  too  large for such rapidly chanding
   36613             :         function.
   36614             : 
   36615             : NOTE 4: this function works only for optimizers created with LSFitCreateWFG()
   36616             :         or LSFitCreateFG() constructors.
   36617             :         
   36618             : INPUT PARAMETERS:
   36619             :     State       -   structure used to store algorithm state
   36620             :     TestStep    -   verification step:
   36621             :                     * TestStep=0 turns verification off
   36622             :                     * TestStep>0 activates verification
   36623             : 
   36624             :   -- ALGLIB --
   36625             :      Copyright 15.06.2012 by Bochkanov Sergey
   36626             : *************************************************************************/
   36627           0 : void lsfitsetgradientcheck(lsfitstate* state,
   36628             :      double teststep,
   36629             :      ae_state *_state)
   36630             : {
   36631             : 
   36632             : 
   36633           0 :     ae_assert(ae_isfinite(teststep, _state), "LSFitSetGradientCheck: TestStep contains NaN or Infinite", _state);
   36634           0 :     ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "LSFitSetGradientCheck: invalid argument TestStep(TestStep<0)", _state);
   36635           0 :     state->teststep = teststep;
   36636           0 : }
   36637             : 
   36638             : 
   36639             : /*************************************************************************
   36640             : This function analyzes section of curve for processing by RDP algorithm:
   36641             : given set of points X,Y with indexes [I0,I1] it returns point with
   36642             : worst deviation from linear model (non-parametric version which sees curve
   36643             : as Y(x)).
   36644             : 
   36645             : Input parameters:
   36646             :     X, Y        -   SORTED arrays.
   36647             :     I0,I1       -   interval (boundaries included) to process
   36648             :     Eps         -   desired precision
   36649             :     
   36650             : OUTPUT PARAMETERS:
   36651             :     WorstIdx    -   index of worst point
   36652             :     WorstError  -   error at worst point
   36653             :     
   36654             : NOTE: this function guarantees that it returns exactly zero for a section
   36655             :       with less than 3 points.
   36656             : 
   36657             :   -- ALGLIB PROJECT --
   36658             :      Copyright 02.10.2014 by Bochkanov Sergey
   36659             : *************************************************************************/
   36660           0 : static void lsfit_rdpanalyzesection(/* Real    */ ae_vector* x,
   36661             :      /* Real    */ ae_vector* y,
   36662             :      ae_int_t i0,
   36663             :      ae_int_t i1,
   36664             :      ae_int_t* worstidx,
   36665             :      double* worsterror,
   36666             :      ae_state *_state)
   36667             : {
   36668             :     ae_int_t i;
   36669             :     double xleft;
   36670             :     double xright;
   36671             :     double vx;
   36672             :     double ve;
   36673             :     double a;
   36674             :     double b;
   36675             : 
   36676           0 :     *worstidx = 0;
   36677           0 :     *worsterror = 0;
   36678             : 
   36679           0 :     xleft = x->ptr.p_double[i0];
   36680           0 :     xright = x->ptr.p_double[i1];
   36681           0 :     if( i1-i0+1<3||ae_fp_eq(xright,xleft) )
   36682             :     {
   36683           0 :         *worstidx = i0;
   36684           0 :         *worsterror = 0.0;
   36685           0 :         return;
   36686             :     }
   36687           0 :     a = (y->ptr.p_double[i1]-y->ptr.p_double[i0])/(xright-xleft);
   36688           0 :     b = (y->ptr.p_double[i0]*xright-y->ptr.p_double[i1]*xleft)/(xright-xleft);
   36689           0 :     *worstidx = -1;
   36690           0 :     *worsterror = (double)(0);
   36691           0 :     for(i=i0+1; i<=i1-1; i++)
   36692             :     {
   36693           0 :         vx = x->ptr.p_double[i];
   36694           0 :         ve = ae_fabs(a*vx+b-y->ptr.p_double[i], _state);
   36695           0 :         if( (ae_fp_greater(vx,xleft)&&ae_fp_less(vx,xright))&&ae_fp_greater(ve,*worsterror) )
   36696             :         {
   36697           0 :             *worsterror = ve;
   36698           0 :             *worstidx = i;
   36699             :         }
   36700             :     }
   36701             : }
   36702             : 
   36703             : 
   36704             : /*************************************************************************
   36705             : Recursive splitting of interval [I0,I1] (right boundary included) with RDP
   36706             : algorithm (non-parametric version which sees curve as Y(x)).
   36707             : 
   36708             : Input parameters:
   36709             :     X, Y        -   SORTED arrays.
   36710             :     I0,I1       -   interval (boundaries included) to process
   36711             :     Eps         -   desired precision
   36712             :     XOut,YOut   -   preallocated output arrays large enough to store result;
   36713             :                     XOut[0..1], YOut[0..1] contain first and last points of
   36714             :                     curve
   36715             :     NOut        -   must contain 2 on input
   36716             :     
   36717             : OUTPUT PARAMETERS:
   36718             :     XOut, YOut  -   curve generated by RDP algorithm, UNSORTED
   36719             :     NOut        -   number of points in curve
   36720             : 
   36721             :   -- ALGLIB PROJECT --
   36722             :      Copyright 02.10.2014 by Bochkanov Sergey
   36723             : *************************************************************************/
   36724           0 : static void lsfit_rdprecursive(/* Real    */ ae_vector* x,
   36725             :      /* Real    */ ae_vector* y,
   36726             :      ae_int_t i0,
   36727             :      ae_int_t i1,
   36728             :      double eps,
   36729             :      /* Real    */ ae_vector* xout,
   36730             :      /* Real    */ ae_vector* yout,
   36731             :      ae_int_t* nout,
   36732             :      ae_state *_state)
   36733             : {
   36734             :     ae_int_t worstidx;
   36735             :     double worsterror;
   36736             : 
   36737             : 
   36738           0 :     ae_assert(ae_fp_greater(eps,(double)(0)), "RDPRecursive: internal error, Eps<0", _state);
   36739           0 :     lsfit_rdpanalyzesection(x, y, i0, i1, &worstidx, &worsterror, _state);
   36740           0 :     if( ae_fp_less_eq(worsterror,eps) )
   36741             :     {
   36742           0 :         return;
   36743             :     }
   36744           0 :     xout->ptr.p_double[*nout] = x->ptr.p_double[worstidx];
   36745           0 :     yout->ptr.p_double[*nout] = y->ptr.p_double[worstidx];
   36746           0 :     *nout = *nout+1;
   36747           0 :     if( worstidx-i0<i1-worstidx )
   36748             :     {
   36749           0 :         lsfit_rdprecursive(x, y, i0, worstidx, eps, xout, yout, nout, _state);
   36750           0 :         lsfit_rdprecursive(x, y, worstidx, i1, eps, xout, yout, nout, _state);
   36751             :     }
   36752             :     else
   36753             :     {
   36754           0 :         lsfit_rdprecursive(x, y, worstidx, i1, eps, xout, yout, nout, _state);
   36755           0 :         lsfit_rdprecursive(x, y, i0, worstidx, eps, xout, yout, nout, _state);
   36756             :     }
   36757             : }
   36758             : 
   36759             : 
   36760             : /*************************************************************************
   36761             : Internal 4PL/5PL fitting function.
   36762             : 
   36763             : Accepts X, Y and already initialized and prepared MinLMState structure.
   36764             : On input P1 contains initial guess, on output it contains solution.  FLast
   36765             : stores function value at P1.
   36766             : *************************************************************************/
   36767           0 : static void lsfit_logisticfitinternal(/* Real    */ ae_vector* x,
   36768             :      /* Real    */ ae_vector* y,
   36769             :      ae_int_t n,
   36770             :      ae_bool is4pl,
   36771             :      double lambdav,
   36772             :      minlmstate* state,
   36773             :      minlmreport* replm,
   36774             :      /* Real    */ ae_vector* p1,
   36775             :      double* flast,
   36776             :      ae_state *_state)
   36777             : {
   36778             :     ae_int_t i;
   36779             :     ae_int_t j;
   36780             :     double ta;
   36781             :     double tb;
   36782             :     double tc;
   36783             :     double td;
   36784             :     double tg;
   36785             :     double vp0;
   36786             :     double vp1;
   36787             : 
   36788           0 :     *flast = 0;
   36789             : 
   36790           0 :     minlmrestartfrom(state, p1, _state);
   36791           0 :     while(minlmiteration(state, _state))
   36792             :     {
   36793           0 :         ta = state->x.ptr.p_double[0];
   36794           0 :         tb = state->x.ptr.p_double[1];
   36795           0 :         tc = state->x.ptr.p_double[2];
   36796           0 :         td = state->x.ptr.p_double[3];
   36797           0 :         tg = state->x.ptr.p_double[4];
   36798           0 :         if( state->xupdated )
   36799             :         {
   36800             :             
   36801             :             /*
   36802             :              * Save best function value obtained so far.
   36803             :              */
   36804           0 :             *flast = state->f;
   36805           0 :             continue;
   36806             :         }
   36807           0 :         if( state->needfi||state->needfij )
   36808             :         {
   36809             :             
   36810             :             /*
   36811             :              * Function vector and Jacobian
   36812             :              */
   36813           0 :             for(i=0; i<=n-1; i++)
   36814             :             {
   36815           0 :                 ae_assert(ae_fp_greater_eq(x->ptr.p_double[i],(double)(0)), "LogisticFitInternal: integrity error", _state);
   36816             :                 
   36817             :                 /*
   36818             :                  * Handle zero X
   36819             :                  */
   36820           0 :                 if( ae_fp_eq(x->ptr.p_double[i],(double)(0)) )
   36821             :                 {
   36822           0 :                     if( ae_fp_greater_eq(tb,(double)(0)) )
   36823             :                     {
   36824             :                         
   36825             :                         /*
   36826             :                          * Positive or zero TB, limit X^TB subject to X->+0 is equal to zero.
   36827             :                          */
   36828           0 :                         state->fi.ptr.p_double[i] = ta-y->ptr.p_double[i];
   36829           0 :                         if( state->needfij )
   36830             :                         {
   36831           0 :                             state->j.ptr.pp_double[i][0] = (double)(1);
   36832           0 :                             state->j.ptr.pp_double[i][1] = (double)(0);
   36833           0 :                             state->j.ptr.pp_double[i][2] = (double)(0);
   36834           0 :                             state->j.ptr.pp_double[i][3] = (double)(0);
   36835           0 :                             state->j.ptr.pp_double[i][4] = (double)(0);
   36836             :                         }
   36837             :                     }
   36838             :                     else
   36839             :                     {
   36840             :                         
   36841             :                         /*
   36842             :                          * Negative TB, limit X^TB subject to X->+0 is equal to +INF.
   36843             :                          */
   36844           0 :                         state->fi.ptr.p_double[i] = td-y->ptr.p_double[i];
   36845           0 :                         if( state->needfij )
   36846             :                         {
   36847           0 :                             state->j.ptr.pp_double[i][0] = (double)(0);
   36848           0 :                             state->j.ptr.pp_double[i][1] = (double)(0);
   36849           0 :                             state->j.ptr.pp_double[i][2] = (double)(0);
   36850           0 :                             state->j.ptr.pp_double[i][3] = (double)(1);
   36851           0 :                             state->j.ptr.pp_double[i][4] = (double)(0);
   36852             :                         }
   36853             :                     }
   36854           0 :                     continue;
   36855             :                 }
   36856             :                 
   36857             :                 /*
   36858             :                  * Positive X.
   36859             :                  * Prepare VP0/VP1, it may become infinite or nearly overflow in some rare cases,
   36860             :                  * handle these cases
   36861             :                  */
   36862           0 :                 vp0 = ae_pow(x->ptr.p_double[i]/tc, tb, _state);
   36863           0 :                 if( is4pl )
   36864             :                 {
   36865           0 :                     vp1 = 1+vp0;
   36866             :                 }
   36867             :                 else
   36868             :                 {
   36869           0 :                     vp1 = ae_pow(1+vp0, tg, _state);
   36870             :                 }
   36871           0 :                 if( (!ae_isfinite(vp1, _state)||ae_fp_greater(vp0,1.0E50))||ae_fp_greater(vp1,1.0E50) )
   36872             :                 {
   36873             :                     
   36874             :                     /*
   36875             :                      * VP0/VP1 are not finite, assume that it is +INF or -INF
   36876             :                      */
   36877           0 :                     state->fi.ptr.p_double[i] = td-y->ptr.p_double[i];
   36878           0 :                     if( state->needfij )
   36879             :                     {
   36880           0 :                         state->j.ptr.pp_double[i][0] = (double)(0);
   36881           0 :                         state->j.ptr.pp_double[i][1] = (double)(0);
   36882           0 :                         state->j.ptr.pp_double[i][2] = (double)(0);
   36883           0 :                         state->j.ptr.pp_double[i][3] = (double)(1);
   36884           0 :                         state->j.ptr.pp_double[i][4] = (double)(0);
   36885             :                     }
   36886           0 :                     continue;
   36887             :                 }
   36888             :                 
   36889             :                 /*
   36890             :                  * VP0/VP1 are finite, normal processing
   36891             :                  */
   36892           0 :                 if( is4pl )
   36893             :                 {
   36894           0 :                     state->fi.ptr.p_double[i] = td+(ta-td)/vp1-y->ptr.p_double[i];
   36895           0 :                     if( state->needfij )
   36896             :                     {
   36897           0 :                         state->j.ptr.pp_double[i][0] = 1/vp1;
   36898           0 :                         state->j.ptr.pp_double[i][1] = -(ta-td)*vp0*ae_log(x->ptr.p_double[i]/tc, _state)/ae_sqr(vp1, _state);
   36899           0 :                         state->j.ptr.pp_double[i][2] = (ta-td)*(tb/tc)*vp0/ae_sqr(vp1, _state);
   36900           0 :                         state->j.ptr.pp_double[i][3] = 1-1/vp1;
   36901           0 :                         state->j.ptr.pp_double[i][4] = (double)(0);
   36902             :                     }
   36903             :                 }
   36904             :                 else
   36905             :                 {
   36906           0 :                     state->fi.ptr.p_double[i] = td+(ta-td)/vp1-y->ptr.p_double[i];
   36907           0 :                     if( state->needfij )
   36908             :                     {
   36909           0 :                         state->j.ptr.pp_double[i][0] = 1/vp1;
   36910           0 :                         state->j.ptr.pp_double[i][1] = (ta-td)*(-tg)*ae_pow(1+vp0, -tg-1, _state)*vp0*ae_log(x->ptr.p_double[i]/tc, _state);
   36911           0 :                         state->j.ptr.pp_double[i][2] = (ta-td)*(-tg)*ae_pow(1+vp0, -tg-1, _state)*vp0*(-tb/tc);
   36912           0 :                         state->j.ptr.pp_double[i][3] = 1-1/vp1;
   36913           0 :                         state->j.ptr.pp_double[i][4] = -(ta-td)/vp1*ae_log(1+vp0, _state);
   36914             :                     }
   36915             :                 }
   36916             :             }
   36917             :             
   36918             :             /*
   36919             :              * Add regularizer
   36920             :              */
   36921           0 :             for(i=0; i<=4; i++)
   36922             :             {
   36923           0 :                 state->fi.ptr.p_double[n+i] = lambdav*state->x.ptr.p_double[i];
   36924           0 :                 if( state->needfij )
   36925             :                 {
   36926           0 :                     for(j=0; j<=4; j++)
   36927             :                     {
   36928           0 :                         state->j.ptr.pp_double[n+i][j] = 0.0;
   36929             :                     }
   36930           0 :                     state->j.ptr.pp_double[n+i][i] = lambdav;
   36931             :                 }
   36932             :             }
   36933             :             
   36934             :             /*
   36935             :              * Done
   36936             :              */
   36937           0 :             continue;
   36938             :         }
   36939           0 :         ae_assert(ae_false, "LogisticFitX: internal error", _state);
   36940             :     }
   36941           0 :     minlmresultsbuf(state, p1, replm, _state);
   36942           0 :     ae_assert(replm->terminationtype>0, "LogisticFitX: internal error", _state);
   36943           0 : }
   36944             : 
   36945             : 
   36946             : /*************************************************************************
   36947             : Calculate errors for 4PL/5PL fit.
   36948             : Leaves other fields of Rep unchanged, so caller should properly initialize
   36949             : it with ClearRep() call.
   36950             : 
   36951             :   -- ALGLIB PROJECT --
   36952             :      Copyright 28.04.2017 by Bochkanov Sergey
   36953             : *************************************************************************/
   36954           0 : static void lsfit_logisticfit45errors(/* Real    */ ae_vector* x,
   36955             :      /* Real    */ ae_vector* y,
   36956             :      ae_int_t n,
   36957             :      double a,
   36958             :      double b,
   36959             :      double c,
   36960             :      double d,
   36961             :      double g,
   36962             :      lsfitreport* rep,
   36963             :      ae_state *_state)
   36964             : {
   36965             :     ae_int_t i;
   36966             :     ae_int_t k;
   36967             :     double v;
   36968             :     double rss;
   36969             :     double tss;
   36970             :     double meany;
   36971             : 
   36972             : 
   36973             :     
   36974             :     /*
   36975             :      * Calculate errors
   36976             :      */
   36977           0 :     rep->rmserror = (double)(0);
   36978           0 :     rep->avgerror = (double)(0);
   36979           0 :     rep->avgrelerror = (double)(0);
   36980           0 :     rep->maxerror = (double)(0);
   36981           0 :     k = 0;
   36982           0 :     rss = 0.0;
   36983           0 :     tss = 0.0;
   36984           0 :     meany = 0.0;
   36985           0 :     for(i=0; i<=n-1; i++)
   36986             :     {
   36987           0 :         meany = meany+y->ptr.p_double[i];
   36988             :     }
   36989           0 :     meany = meany/n;
   36990           0 :     for(i=0; i<=n-1; i++)
   36991             :     {
   36992             :         
   36993             :         /*
   36994             :          * Calculate residual from regression
   36995             :          */
   36996           0 :         if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) )
   36997             :         {
   36998           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];
   36999             :         }
   37000             :         else
   37001             :         {
   37002           0 :             if( ae_fp_greater_eq(b,(double)(0)) )
   37003             :             {
   37004           0 :                 v = a-y->ptr.p_double[i];
   37005             :             }
   37006             :             else
   37007             :             {
   37008           0 :                 v = d-y->ptr.p_double[i];
   37009             :             }
   37010             :         }
   37011             :         
   37012             :         /*
   37013             :          * Update RSS (residual sum of squares) and TSS (total sum of squares)
   37014             :          * which are used to calculate coefficient of determination.
   37015             :          *
   37016             :          * NOTE: we use formula R2 = 1-RSS/TSS because it has nice property of
   37017             :          *       being equal to 0.0 if and only if model perfectly fits data.
   37018             :          *
   37019             :          *       When we fit nonlinear models, there are exist multiple ways of
   37020             :          *       determining R2, each of them giving different results. Formula
   37021             :          *       above is the most intuitive one.
   37022             :          */
   37023           0 :         rss = rss+v*v;
   37024           0 :         tss = tss+ae_sqr(y->ptr.p_double[i]-meany, _state);
   37025             :         
   37026             :         /*
   37027             :          * Update errors
   37028             :          */
   37029           0 :         rep->rmserror = rep->rmserror+ae_sqr(v, _state);
   37030           0 :         rep->avgerror = rep->avgerror+ae_fabs(v, _state);
   37031           0 :         if( ae_fp_neq(y->ptr.p_double[i],(double)(0)) )
   37032             :         {
   37033           0 :             rep->avgrelerror = rep->avgrelerror+ae_fabs(v/y->ptr.p_double[i], _state);
   37034           0 :             k = k+1;
   37035             :         }
   37036           0 :         rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
   37037             :     }
   37038           0 :     rep->rmserror = ae_sqrt(rep->rmserror/n, _state);
   37039           0 :     rep->avgerror = rep->avgerror/n;
   37040           0 :     if( k>0 )
   37041             :     {
   37042           0 :         rep->avgrelerror = rep->avgrelerror/k;
   37043             :     }
   37044           0 :     rep->r2 = 1.0-rss/tss;
   37045           0 : }
   37046             : 
   37047             : 
   37048             : /*************************************************************************
   37049             : Internal spline fitting subroutine
   37050             : 
   37051             :   -- ALGLIB PROJECT --
   37052             :      Copyright 08.09.2009 by Bochkanov Sergey
   37053             : *************************************************************************/
   37054           0 : static void lsfit_spline1dfitinternal(ae_int_t st,
   37055             :      /* Real    */ ae_vector* x,
   37056             :      /* Real    */ ae_vector* y,
   37057             :      /* Real    */ ae_vector* w,
   37058             :      ae_int_t n,
   37059             :      /* Real    */ ae_vector* xc,
   37060             :      /* Real    */ ae_vector* yc,
   37061             :      /* Integer */ ae_vector* dc,
   37062             :      ae_int_t k,
   37063             :      ae_int_t m,
   37064             :      ae_int_t* info,
   37065             :      spline1dinterpolant* s,
   37066             :      spline1dfitreport* rep,
   37067             :      ae_state *_state)
   37068             : {
   37069             :     ae_frame _frame_block;
   37070             :     ae_vector _x;
   37071             :     ae_vector _y;
   37072             :     ae_vector _w;
   37073             :     ae_vector _xc;
   37074             :     ae_vector _yc;
   37075             :     ae_matrix fmatrix;
   37076             :     ae_matrix cmatrix;
   37077             :     ae_vector y2;
   37078             :     ae_vector w2;
   37079             :     ae_vector sx;
   37080             :     ae_vector sy;
   37081             :     ae_vector sd;
   37082             :     ae_vector tmp;
   37083             :     ae_vector xoriginal;
   37084             :     ae_vector yoriginal;
   37085             :     lsfitreport lrep;
   37086             :     double v0;
   37087             :     double v1;
   37088             :     double v2;
   37089             :     double mx;
   37090             :     spline1dinterpolant s2;
   37091             :     ae_int_t i;
   37092             :     ae_int_t j;
   37093             :     ae_int_t relcnt;
   37094             :     double xa;
   37095             :     double xb;
   37096             :     double sa;
   37097             :     double sb;
   37098             :     double bl;
   37099             :     double br;
   37100             :     double decay;
   37101             : 
   37102           0 :     ae_frame_make(_state, &_frame_block);
   37103           0 :     memset(&_x, 0, sizeof(_x));
   37104           0 :     memset(&_y, 0, sizeof(_y));
   37105           0 :     memset(&_w, 0, sizeof(_w));
   37106           0 :     memset(&_xc, 0, sizeof(_xc));
   37107           0 :     memset(&_yc, 0, sizeof(_yc));
   37108           0 :     memset(&fmatrix, 0, sizeof(fmatrix));
   37109           0 :     memset(&cmatrix, 0, sizeof(cmatrix));
   37110           0 :     memset(&y2, 0, sizeof(y2));
   37111           0 :     memset(&w2, 0, sizeof(w2));
   37112           0 :     memset(&sx, 0, sizeof(sx));
   37113           0 :     memset(&sy, 0, sizeof(sy));
   37114           0 :     memset(&sd, 0, sizeof(sd));
   37115           0 :     memset(&tmp, 0, sizeof(tmp));
   37116           0 :     memset(&xoriginal, 0, sizeof(xoriginal));
   37117           0 :     memset(&yoriginal, 0, sizeof(yoriginal));
   37118           0 :     memset(&lrep, 0, sizeof(lrep));
   37119           0 :     memset(&s2, 0, sizeof(s2));
   37120           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   37121           0 :     x = &_x;
   37122           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   37123           0 :     y = &_y;
   37124           0 :     ae_vector_init_copy(&_w, w, _state, ae_true);
   37125           0 :     w = &_w;
   37126           0 :     ae_vector_init_copy(&_xc, xc, _state, ae_true);
   37127           0 :     xc = &_xc;
   37128           0 :     ae_vector_init_copy(&_yc, yc, _state, ae_true);
   37129           0 :     yc = &_yc;
   37130           0 :     *info = 0;
   37131           0 :     _spline1dinterpolant_clear(s);
   37132           0 :     _spline1dfitreport_clear(rep);
   37133           0 :     ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true);
   37134           0 :     ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true);
   37135           0 :     ae_vector_init(&y2, 0, DT_REAL, _state, ae_true);
   37136           0 :     ae_vector_init(&w2, 0, DT_REAL, _state, ae_true);
   37137           0 :     ae_vector_init(&sx, 0, DT_REAL, _state, ae_true);
   37138           0 :     ae_vector_init(&sy, 0, DT_REAL, _state, ae_true);
   37139           0 :     ae_vector_init(&sd, 0, DT_REAL, _state, ae_true);
   37140           0 :     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
   37141           0 :     ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true);
   37142           0 :     ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true);
   37143           0 :     _lsfitreport_init(&lrep, _state, ae_true);
   37144           0 :     _spline1dinterpolant_init(&s2, _state, ae_true);
   37145             : 
   37146           0 :     ae_assert(st==0||st==1, "Spline1DFit: internal error!", _state);
   37147           0 :     if( st==0&&m<4 )
   37148             :     {
   37149           0 :         *info = -1;
   37150           0 :         ae_frame_leave(_state);
   37151           0 :         return;
   37152             :     }
   37153           0 :     if( st==1&&m<4 )
   37154             :     {
   37155           0 :         *info = -1;
   37156           0 :         ae_frame_leave(_state);
   37157           0 :         return;
   37158             :     }
   37159           0 :     if( (n<1||k<0)||k>=m )
   37160             :     {
   37161           0 :         *info = -1;
   37162           0 :         ae_frame_leave(_state);
   37163           0 :         return;
   37164             :     }
   37165           0 :     for(i=0; i<=k-1; i++)
   37166             :     {
   37167           0 :         *info = 0;
   37168           0 :         if( dc->ptr.p_int[i]<0 )
   37169             :         {
   37170           0 :             *info = -1;
   37171             :         }
   37172           0 :         if( dc->ptr.p_int[i]>1 )
   37173             :         {
   37174           0 :             *info = -1;
   37175             :         }
   37176           0 :         if( *info<0 )
   37177             :         {
   37178           0 :             ae_frame_leave(_state);
   37179           0 :             return;
   37180             :         }
   37181             :     }
   37182           0 :     if( st==1&&m%2!=0 )
   37183             :     {
   37184             :         
   37185             :         /*
   37186             :          * Hermite fitter must have even number of basis functions
   37187             :          */
   37188           0 :         *info = -2;
   37189           0 :         ae_frame_leave(_state);
   37190           0 :         return;
   37191             :     }
   37192             :     
   37193             :     /*
   37194             :      * weight decay for correct handling of task which becomes
   37195             :      * degenerate after constraints are applied
   37196             :      */
   37197           0 :     decay = 10000*ae_machineepsilon;
   37198             :     
   37199             :     /*
   37200             :      * Scale X, Y, XC, YC
   37201             :      */
   37202           0 :     lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state);
   37203             :     
   37204             :     /*
   37205             :      * allocate space, initialize:
   37206             :      * * SX     -   grid for basis functions
   37207             :      * * SY     -   values of basis functions at grid points
   37208             :      * * FMatrix-   values of basis functions at X[]
   37209             :      * * CMatrix-   values (derivatives) of basis functions at XC[]
   37210             :      */
   37211           0 :     ae_vector_set_length(&y2, n+m, _state);
   37212           0 :     ae_vector_set_length(&w2, n+m, _state);
   37213           0 :     ae_matrix_set_length(&fmatrix, n+m, m, _state);
   37214           0 :     if( k>0 )
   37215             :     {
   37216           0 :         ae_matrix_set_length(&cmatrix, k, m+1, _state);
   37217             :     }
   37218           0 :     if( st==0 )
   37219             :     {
   37220             :         
   37221             :         /*
   37222             :          * allocate space for cubic spline
   37223             :          */
   37224           0 :         ae_vector_set_length(&sx, m-2, _state);
   37225           0 :         ae_vector_set_length(&sy, m-2, _state);
   37226           0 :         for(j=0; j<=m-2-1; j++)
   37227             :         {
   37228           0 :             sx.ptr.p_double[j] = (double)(2*j)/(double)(m-2-1)-1;
   37229             :         }
   37230             :     }
   37231           0 :     if( st==1 )
   37232             :     {
   37233             :         
   37234             :         /*
   37235             :          * allocate space for Hermite spline
   37236             :          */
   37237           0 :         ae_vector_set_length(&sx, m/2, _state);
   37238           0 :         ae_vector_set_length(&sy, m/2, _state);
   37239           0 :         ae_vector_set_length(&sd, m/2, _state);
   37240           0 :         for(j=0; j<=m/2-1; j++)
   37241             :         {
   37242           0 :             sx.ptr.p_double[j] = (double)(2*j)/(double)(m/2-1)-1;
   37243             :         }
   37244             :     }
   37245             :     
   37246             :     /*
   37247             :      * Prepare design and constraints matrices:
   37248             :      * * fill constraints matrix
   37249             :      * * fill first N rows of design matrix with values
   37250             :      * * fill next M rows of design matrix with regularizing term
   37251             :      * * append M zeros to Y
   37252             :      * * append M elements, mean(abs(W)) each, to W
   37253             :      */
   37254           0 :     for(j=0; j<=m-1; j++)
   37255             :     {
   37256             :         
   37257             :         /*
   37258             :          * prepare Jth basis function
   37259             :          */
   37260           0 :         if( st==0 )
   37261             :         {
   37262             :             
   37263             :             /*
   37264             :              * cubic spline basis
   37265             :              */
   37266           0 :             for(i=0; i<=m-2-1; i++)
   37267             :             {
   37268           0 :                 sy.ptr.p_double[i] = (double)(0);
   37269             :             }
   37270           0 :             bl = (double)(0);
   37271           0 :             br = (double)(0);
   37272           0 :             if( j<m-2 )
   37273             :             {
   37274           0 :                 sy.ptr.p_double[j] = (double)(1);
   37275             :             }
   37276           0 :             if( j==m-2 )
   37277             :             {
   37278           0 :                 bl = (double)(1);
   37279             :             }
   37280           0 :             if( j==m-1 )
   37281             :             {
   37282           0 :                 br = (double)(1);
   37283             :             }
   37284           0 :             spline1dbuildcubic(&sx, &sy, m-2, 1, bl, 1, br, &s2, _state);
   37285             :         }
   37286           0 :         if( st==1 )
   37287             :         {
   37288             :             
   37289             :             /*
   37290             :              * Hermite basis
   37291             :              */
   37292           0 :             for(i=0; i<=m/2-1; i++)
   37293             :             {
   37294           0 :                 sy.ptr.p_double[i] = (double)(0);
   37295           0 :                 sd.ptr.p_double[i] = (double)(0);
   37296             :             }
   37297           0 :             if( j%2==0 )
   37298             :             {
   37299           0 :                 sy.ptr.p_double[j/2] = (double)(1);
   37300             :             }
   37301             :             else
   37302             :             {
   37303           0 :                 sd.ptr.p_double[j/2] = (double)(1);
   37304             :             }
   37305           0 :             spline1dbuildhermite(&sx, &sy, &sd, m/2, &s2, _state);
   37306             :         }
   37307             :         
   37308             :         /*
   37309             :          * values at X[], XC[]
   37310             :          */
   37311           0 :         for(i=0; i<=n-1; i++)
   37312             :         {
   37313           0 :             fmatrix.ptr.pp_double[i][j] = spline1dcalc(&s2, x->ptr.p_double[i], _state);
   37314             :         }
   37315           0 :         for(i=0; i<=k-1; i++)
   37316             :         {
   37317           0 :             ae_assert(dc->ptr.p_int[i]>=0&&dc->ptr.p_int[i]<=2, "Spline1DFit: internal error!", _state);
   37318           0 :             spline1ddiff(&s2, xc->ptr.p_double[i], &v0, &v1, &v2, _state);
   37319           0 :             if( dc->ptr.p_int[i]==0 )
   37320             :             {
   37321           0 :                 cmatrix.ptr.pp_double[i][j] = v0;
   37322             :             }
   37323           0 :             if( dc->ptr.p_int[i]==1 )
   37324             :             {
   37325           0 :                 cmatrix.ptr.pp_double[i][j] = v1;
   37326             :             }
   37327           0 :             if( dc->ptr.p_int[i]==2 )
   37328             :             {
   37329           0 :                 cmatrix.ptr.pp_double[i][j] = v2;
   37330             :             }
   37331             :         }
   37332             :     }
   37333           0 :     for(i=0; i<=k-1; i++)
   37334             :     {
   37335           0 :         cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i];
   37336             :     }
   37337           0 :     for(i=0; i<=m-1; i++)
   37338             :     {
   37339           0 :         for(j=0; j<=m-1; j++)
   37340             :         {
   37341           0 :             if( i==j )
   37342             :             {
   37343           0 :                 fmatrix.ptr.pp_double[n+i][j] = decay;
   37344             :             }
   37345             :             else
   37346             :             {
   37347           0 :                 fmatrix.ptr.pp_double[n+i][j] = (double)(0);
   37348             :             }
   37349             :         }
   37350             :     }
   37351           0 :     ae_vector_set_length(&y2, n+m, _state);
   37352           0 :     ae_vector_set_length(&w2, n+m, _state);
   37353           0 :     ae_v_move(&y2.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
   37354           0 :     ae_v_move(&w2.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
   37355           0 :     mx = (double)(0);
   37356           0 :     for(i=0; i<=n-1; i++)
   37357             :     {
   37358           0 :         mx = mx+ae_fabs(w->ptr.p_double[i], _state);
   37359             :     }
   37360           0 :     mx = mx/n;
   37361           0 :     for(i=0; i<=m-1; i++)
   37362             :     {
   37363           0 :         y2.ptr.p_double[n+i] = (double)(0);
   37364           0 :         w2.ptr.p_double[n+i] = mx;
   37365             :     }
   37366             :     
   37367             :     /*
   37368             :      * Solve constrained task
   37369             :      */
   37370           0 :     if( k>0 )
   37371             :     {
   37372             :         
   37373             :         /*
   37374             :          * solve using regularization
   37375             :          */
   37376           0 :         lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, &tmp, &lrep, _state);
   37377             :     }
   37378             :     else
   37379             :     {
   37380             :         
   37381             :         /*
   37382             :          * no constraints, no regularization needed
   37383             :          */
   37384           0 :         lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, k, info, &tmp, &lrep, _state);
   37385             :     }
   37386           0 :     if( *info<0 )
   37387             :     {
   37388           0 :         ae_frame_leave(_state);
   37389           0 :         return;
   37390             :     }
   37391             :     
   37392             :     /*
   37393             :      * Generate spline and scale it
   37394             :      */
   37395           0 :     if( st==0 )
   37396             :     {
   37397             :         
   37398             :         /*
   37399             :          * cubic spline basis
   37400             :          */
   37401           0 :         ae_v_move(&sy.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-2-1));
   37402           0 :         spline1dbuildcubic(&sx, &sy, m-2, 1, tmp.ptr.p_double[m-2], 1, tmp.ptr.p_double[m-1], s, _state);
   37403             :     }
   37404           0 :     if( st==1 )
   37405             :     {
   37406             :         
   37407             :         /*
   37408             :          * Hermite basis
   37409             :          */
   37410           0 :         for(i=0; i<=m/2-1; i++)
   37411             :         {
   37412           0 :             sy.ptr.p_double[i] = tmp.ptr.p_double[2*i];
   37413           0 :             sd.ptr.p_double[i] = tmp.ptr.p_double[2*i+1];
   37414             :         }
   37415           0 :         spline1dbuildhermite(&sx, &sy, &sd, m/2, s, _state);
   37416             :     }
   37417           0 :     spline1dlintransx(s, 2/(xb-xa), -(xa+xb)/(xb-xa), _state);
   37418           0 :     spline1dlintransy(s, sb-sa, sa, _state);
   37419             :     
   37420             :     /*
   37421             :      * Scale absolute errors obtained from LSFitLinearW.
   37422             :      * Relative error should be calculated separately
   37423             :      * (because of shifting/scaling of the task)
   37424             :      */
   37425           0 :     rep->taskrcond = lrep.taskrcond;
   37426           0 :     rep->rmserror = lrep.rmserror*(sb-sa);
   37427           0 :     rep->avgerror = lrep.avgerror*(sb-sa);
   37428           0 :     rep->maxerror = lrep.maxerror*(sb-sa);
   37429           0 :     rep->avgrelerror = (double)(0);
   37430           0 :     relcnt = 0;
   37431           0 :     for(i=0; i<=n-1; i++)
   37432             :     {
   37433           0 :         if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) )
   37434             :         {
   37435           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);
   37436           0 :             relcnt = relcnt+1;
   37437             :         }
   37438             :     }
   37439           0 :     if( relcnt!=0 )
   37440             :     {
   37441           0 :         rep->avgrelerror = rep->avgrelerror/relcnt;
   37442             :     }
   37443           0 :     ae_frame_leave(_state);
   37444             : }
   37445             : 
   37446             : 
   37447             : /*************************************************************************
   37448             : Internal fitting subroutine
   37449             : *************************************************************************/
   37450           0 : static void lsfit_lsfitlinearinternal(/* Real    */ ae_vector* y,
   37451             :      /* Real    */ ae_vector* w,
   37452             :      /* Real    */ ae_matrix* fmatrix,
   37453             :      ae_int_t n,
   37454             :      ae_int_t m,
   37455             :      ae_int_t* info,
   37456             :      /* Real    */ ae_vector* c,
   37457             :      lsfitreport* rep,
   37458             :      ae_state *_state)
   37459             : {
   37460             :     ae_frame _frame_block;
   37461             :     double threshold;
   37462             :     ae_matrix ft;
   37463             :     ae_matrix q;
   37464             :     ae_matrix l;
   37465             :     ae_matrix r;
   37466             :     ae_vector b;
   37467             :     ae_vector wmod;
   37468             :     ae_vector tau;
   37469             :     ae_vector nzeros;
   37470             :     ae_vector s;
   37471             :     ae_int_t i;
   37472             :     ae_int_t j;
   37473             :     double v;
   37474             :     ae_vector sv;
   37475             :     ae_matrix u;
   37476             :     ae_matrix vt;
   37477             :     ae_vector tmp;
   37478             :     ae_vector utb;
   37479             :     ae_vector sutb;
   37480             :     ae_int_t relcnt;
   37481             : 
   37482           0 :     ae_frame_make(_state, &_frame_block);
   37483           0 :     memset(&ft, 0, sizeof(ft));
   37484           0 :     memset(&q, 0, sizeof(q));
   37485           0 :     memset(&l, 0, sizeof(l));
   37486           0 :     memset(&r, 0, sizeof(r));
   37487           0 :     memset(&b, 0, sizeof(b));
   37488           0 :     memset(&wmod, 0, sizeof(wmod));
   37489           0 :     memset(&tau, 0, sizeof(tau));
   37490           0 :     memset(&nzeros, 0, sizeof(nzeros));
   37491           0 :     memset(&s, 0, sizeof(s));
   37492           0 :     memset(&sv, 0, sizeof(sv));
   37493           0 :     memset(&u, 0, sizeof(u));
   37494           0 :     memset(&vt, 0, sizeof(vt));
   37495           0 :     memset(&tmp, 0, sizeof(tmp));
   37496           0 :     memset(&utb, 0, sizeof(utb));
   37497           0 :     memset(&sutb, 0, sizeof(sutb));
   37498           0 :     *info = 0;
   37499           0 :     ae_vector_clear(c);
   37500           0 :     _lsfitreport_clear(rep);
   37501           0 :     ae_matrix_init(&ft, 0, 0, DT_REAL, _state, ae_true);
   37502           0 :     ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true);
   37503           0 :     ae_matrix_init(&l, 0, 0, DT_REAL, _state, ae_true);
   37504           0 :     ae_matrix_init(&r, 0, 0, DT_REAL, _state, ae_true);
   37505           0 :     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
   37506           0 :     ae_vector_init(&wmod, 0, DT_REAL, _state, ae_true);
   37507           0 :     ae_vector_init(&tau, 0, DT_REAL, _state, ae_true);
   37508           0 :     ae_vector_init(&nzeros, 0, DT_REAL, _state, ae_true);
   37509           0 :     ae_vector_init(&s, 0, DT_REAL, _state, ae_true);
   37510           0 :     ae_vector_init(&sv, 0, DT_REAL, _state, ae_true);
   37511           0 :     ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true);
   37512           0 :     ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true);
   37513           0 :     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
   37514           0 :     ae_vector_init(&utb, 0, DT_REAL, _state, ae_true);
   37515           0 :     ae_vector_init(&sutb, 0, DT_REAL, _state, ae_true);
   37516             : 
   37517           0 :     lsfit_clearreport(rep, _state);
   37518           0 :     if( n<1||m<1 )
   37519             :     {
   37520           0 :         *info = -1;
   37521           0 :         ae_frame_leave(_state);
   37522           0 :         return;
   37523             :     }
   37524           0 :     *info = 1;
   37525           0 :     threshold = ae_sqrt(ae_machineepsilon, _state);
   37526             :     
   37527             :     /*
   37528             :      * Degenerate case, needs special handling
   37529             :      */
   37530           0 :     if( n<m )
   37531             :     {
   37532             :         
   37533             :         /*
   37534             :          * Create design matrix.
   37535             :          */
   37536           0 :         ae_matrix_set_length(&ft, n, m, _state);
   37537           0 :         ae_vector_set_length(&b, n, _state);
   37538           0 :         ae_vector_set_length(&wmod, n, _state);
   37539           0 :         for(j=0; j<=n-1; j++)
   37540             :         {
   37541           0 :             v = w->ptr.p_double[j];
   37542           0 :             ae_v_moved(&ft.ptr.pp_double[j][0], 1, &fmatrix->ptr.pp_double[j][0], 1, ae_v_len(0,m-1), v);
   37543           0 :             b.ptr.p_double[j] = w->ptr.p_double[j]*y->ptr.p_double[j];
   37544           0 :             wmod.ptr.p_double[j] = (double)(1);
   37545             :         }
   37546             :         
   37547             :         /*
   37548             :          * LQ decomposition and reduction to M=N
   37549             :          */
   37550           0 :         ae_vector_set_length(c, m, _state);
   37551           0 :         for(i=0; i<=m-1; i++)
   37552             :         {
   37553           0 :             c->ptr.p_double[i] = (double)(0);
   37554             :         }
   37555           0 :         rep->taskrcond = (double)(0);
   37556           0 :         rmatrixlq(&ft, n, m, &tau, _state);
   37557           0 :         rmatrixlqunpackq(&ft, n, m, &tau, n, &q, _state);
   37558           0 :         rmatrixlqunpackl(&ft, n, m, &l, _state);
   37559           0 :         lsfit_lsfitlinearinternal(&b, &wmod, &l, n, n, info, &tmp, rep, _state);
   37560           0 :         if( *info<=0 )
   37561             :         {
   37562           0 :             ae_frame_leave(_state);
   37563           0 :             return;
   37564             :         }
   37565           0 :         for(i=0; i<=n-1; i++)
   37566             :         {
   37567           0 :             v = tmp.ptr.p_double[i];
   37568           0 :             ae_v_addd(&c->ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
   37569             :         }
   37570           0 :         ae_frame_leave(_state);
   37571           0 :         return;
   37572             :     }
   37573             :     
   37574             :     /*
   37575             :      * N>=M. Generate design matrix and reduce to N=M using
   37576             :      * QR decomposition.
   37577             :      */
   37578           0 :     ae_matrix_set_length(&ft, n, m, _state);
   37579           0 :     ae_vector_set_length(&b, n, _state);
   37580           0 :     for(j=0; j<=n-1; j++)
   37581             :     {
   37582           0 :         v = w->ptr.p_double[j];
   37583           0 :         ae_v_moved(&ft.ptr.pp_double[j][0], 1, &fmatrix->ptr.pp_double[j][0], 1, ae_v_len(0,m-1), v);
   37584           0 :         b.ptr.p_double[j] = w->ptr.p_double[j]*y->ptr.p_double[j];
   37585             :     }
   37586           0 :     rmatrixqr(&ft, n, m, &tau, _state);
   37587           0 :     rmatrixqrunpackq(&ft, n, m, &tau, m, &q, _state);
   37588           0 :     rmatrixqrunpackr(&ft, n, m, &r, _state);
   37589           0 :     ae_vector_set_length(&tmp, m, _state);
   37590           0 :     for(i=0; i<=m-1; i++)
   37591             :     {
   37592           0 :         tmp.ptr.p_double[i] = (double)(0);
   37593             :     }
   37594           0 :     for(i=0; i<=n-1; i++)
   37595             :     {
   37596           0 :         v = b.ptr.p_double[i];
   37597           0 :         ae_v_addd(&tmp.ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
   37598             :     }
   37599           0 :     ae_vector_set_length(&b, m, _state);
   37600           0 :     ae_v_move(&b.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1));
   37601             :     
   37602             :     /*
   37603             :      * R contains reduced MxM design upper triangular matrix,
   37604             :      * B contains reduced Mx1 right part.
   37605             :      *
   37606             :      * Determine system condition number and decide
   37607             :      * should we use triangular solver (faster) or
   37608             :      * SVD-based solver (more stable).
   37609             :      *
   37610             :      * We can use LU-based RCond estimator for this task.
   37611             :      */
   37612           0 :     rep->taskrcond = rmatrixlurcondinf(&r, m, _state);
   37613           0 :     if( ae_fp_greater(rep->taskrcond,threshold) )
   37614             :     {
   37615             :         
   37616             :         /*
   37617             :          * use QR-based solver
   37618             :          */
   37619           0 :         ae_vector_set_length(c, m, _state);
   37620           0 :         c->ptr.p_double[m-1] = b.ptr.p_double[m-1]/r.ptr.pp_double[m-1][m-1];
   37621           0 :         for(i=m-2; i>=0; i--)
   37622             :         {
   37623           0 :             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));
   37624           0 :             c->ptr.p_double[i] = (b.ptr.p_double[i]-v)/r.ptr.pp_double[i][i];
   37625             :         }
   37626             :     }
   37627             :     else
   37628             :     {
   37629             :         
   37630             :         /*
   37631             :          * use SVD-based solver
   37632             :          */
   37633           0 :         if( !rmatrixsvd(&r, m, m, 1, 1, 2, &sv, &u, &vt, _state) )
   37634             :         {
   37635           0 :             *info = -4;
   37636           0 :             ae_frame_leave(_state);
   37637           0 :             return;
   37638             :         }
   37639           0 :         ae_vector_set_length(&utb, m, _state);
   37640           0 :         ae_vector_set_length(&sutb, m, _state);
   37641           0 :         for(i=0; i<=m-1; i++)
   37642             :         {
   37643           0 :             utb.ptr.p_double[i] = (double)(0);
   37644             :         }
   37645           0 :         for(i=0; i<=m-1; i++)
   37646             :         {
   37647           0 :             v = b.ptr.p_double[i];
   37648           0 :             ae_v_addd(&utb.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
   37649             :         }
   37650           0 :         if( ae_fp_greater(sv.ptr.p_double[0],(double)(0)) )
   37651             :         {
   37652           0 :             rep->taskrcond = sv.ptr.p_double[m-1]/sv.ptr.p_double[0];
   37653           0 :             for(i=0; i<=m-1; i++)
   37654             :             {
   37655           0 :                 if( ae_fp_greater(sv.ptr.p_double[i],threshold*sv.ptr.p_double[0]) )
   37656             :                 {
   37657           0 :                     sutb.ptr.p_double[i] = utb.ptr.p_double[i]/sv.ptr.p_double[i];
   37658             :                 }
   37659             :                 else
   37660             :                 {
   37661           0 :                     sutb.ptr.p_double[i] = (double)(0);
   37662             :                 }
   37663             :             }
   37664             :         }
   37665             :         else
   37666             :         {
   37667           0 :             rep->taskrcond = (double)(0);
   37668           0 :             for(i=0; i<=m-1; i++)
   37669             :             {
   37670           0 :                 sutb.ptr.p_double[i] = (double)(0);
   37671             :             }
   37672             :         }
   37673           0 :         ae_vector_set_length(c, m, _state);
   37674           0 :         for(i=0; i<=m-1; i++)
   37675             :         {
   37676           0 :             c->ptr.p_double[i] = (double)(0);
   37677             :         }
   37678           0 :         for(i=0; i<=m-1; i++)
   37679             :         {
   37680           0 :             v = sutb.ptr.p_double[i];
   37681           0 :             ae_v_addd(&c->ptr.p_double[0], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
   37682             :         }
   37683             :     }
   37684             :     
   37685             :     /*
   37686             :      * calculate errors
   37687             :      */
   37688           0 :     rep->rmserror = (double)(0);
   37689           0 :     rep->avgerror = (double)(0);
   37690           0 :     rep->avgrelerror = (double)(0);
   37691           0 :     rep->maxerror = (double)(0);
   37692           0 :     relcnt = 0;
   37693           0 :     for(i=0; i<=n-1; i++)
   37694             :     {
   37695           0 :         v = ae_v_dotproduct(&fmatrix->ptr.pp_double[i][0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,m-1));
   37696           0 :         rep->rmserror = rep->rmserror+ae_sqr(v-y->ptr.p_double[i], _state);
   37697           0 :         rep->avgerror = rep->avgerror+ae_fabs(v-y->ptr.p_double[i], _state);
   37698           0 :         if( ae_fp_neq(y->ptr.p_double[i],(double)(0)) )
   37699             :         {
   37700           0 :             rep->avgrelerror = rep->avgrelerror+ae_fabs(v-y->ptr.p_double[i], _state)/ae_fabs(y->ptr.p_double[i], _state);
   37701           0 :             relcnt = relcnt+1;
   37702             :         }
   37703           0 :         rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-y->ptr.p_double[i], _state), _state);
   37704             :     }
   37705           0 :     rep->rmserror = ae_sqrt(rep->rmserror/n, _state);
   37706           0 :     rep->avgerror = rep->avgerror/n;
   37707           0 :     if( relcnt!=0 )
   37708             :     {
   37709           0 :         rep->avgrelerror = rep->avgrelerror/relcnt;
   37710             :     }
   37711           0 :     ae_vector_set_length(&nzeros, n, _state);
   37712           0 :     ae_vector_set_length(&s, m, _state);
   37713           0 :     for(i=0; i<=m-1; i++)
   37714             :     {
   37715           0 :         s.ptr.p_double[i] = (double)(0);
   37716             :     }
   37717           0 :     for(i=0; i<=n-1; i++)
   37718             :     {
   37719           0 :         for(j=0; j<=m-1; j++)
   37720             :         {
   37721           0 :             s.ptr.p_double[j] = s.ptr.p_double[j]+ae_sqr(fmatrix->ptr.pp_double[i][j], _state);
   37722             :         }
   37723           0 :         nzeros.ptr.p_double[i] = (double)(0);
   37724             :     }
   37725           0 :     for(i=0; i<=m-1; i++)
   37726             :     {
   37727           0 :         if( ae_fp_neq(s.ptr.p_double[i],(double)(0)) )
   37728             :         {
   37729           0 :             s.ptr.p_double[i] = ae_sqrt(1/s.ptr.p_double[i], _state);
   37730             :         }
   37731             :         else
   37732             :         {
   37733           0 :             s.ptr.p_double[i] = (double)(1);
   37734             :         }
   37735             :     }
   37736           0 :     lsfit_estimateerrors(fmatrix, &nzeros, y, w, c, &s, n, m, rep, &r, 1, _state);
   37737           0 :     ae_frame_leave(_state);
   37738             : }
   37739             : 
   37740             : 
   37741             : /*************************************************************************
   37742             : Internal subroutine
   37743             : *************************************************************************/
   37744           0 : static void lsfit_lsfitclearrequestfields(lsfitstate* state,
   37745             :      ae_state *_state)
   37746             : {
   37747             : 
   37748             : 
   37749           0 :     state->needf = ae_false;
   37750           0 :     state->needfg = ae_false;
   37751           0 :     state->needfgh = ae_false;
   37752           0 :     state->xupdated = ae_false;
   37753           0 : }
   37754             : 
   37755             : 
   37756             : /*************************************************************************
   37757             : Internal subroutine, calculates barycentric basis functions.
   37758             : Used for efficient simultaneous calculation of N basis functions.
   37759             : 
   37760             :   -- ALGLIB --
   37761             :      Copyright 17.08.2009 by Bochkanov Sergey
   37762             : *************************************************************************/
   37763           0 : static void lsfit_barycentriccalcbasis(barycentricinterpolant* b,
   37764             :      double t,
   37765             :      /* Real    */ ae_vector* y,
   37766             :      ae_state *_state)
   37767             : {
   37768             :     double s2;
   37769             :     double s;
   37770             :     double v;
   37771             :     ae_int_t i;
   37772             :     ae_int_t j;
   37773             : 
   37774             : 
   37775             :     
   37776             :     /*
   37777             :      * special case: N=1
   37778             :      */
   37779           0 :     if( b->n==1 )
   37780             :     {
   37781           0 :         y->ptr.p_double[0] = (double)(1);
   37782           0 :         return;
   37783             :     }
   37784             :     
   37785             :     /*
   37786             :      * Here we assume that task is normalized, i.e.:
   37787             :      * 1. abs(Y[i])<=1
   37788             :      * 2. abs(W[i])<=1
   37789             :      * 3. X[] is ordered
   37790             :      *
   37791             :      * First, we decide: should we use "safe" formula (guarded
   37792             :      * against overflow) or fast one?
   37793             :      */
   37794           0 :     s = ae_fabs(t-b->x.ptr.p_double[0], _state);
   37795           0 :     for(i=0; i<=b->n-1; i++)
   37796             :     {
   37797           0 :         v = b->x.ptr.p_double[i];
   37798           0 :         if( ae_fp_eq(v,t) )
   37799             :         {
   37800           0 :             for(j=0; j<=b->n-1; j++)
   37801             :             {
   37802           0 :                 y->ptr.p_double[j] = (double)(0);
   37803             :             }
   37804           0 :             y->ptr.p_double[i] = (double)(1);
   37805           0 :             return;
   37806             :         }
   37807           0 :         v = ae_fabs(t-v, _state);
   37808           0 :         if( ae_fp_less(v,s) )
   37809             :         {
   37810           0 :             s = v;
   37811             :         }
   37812             :     }
   37813           0 :     s2 = (double)(0);
   37814           0 :     for(i=0; i<=b->n-1; i++)
   37815             :     {
   37816           0 :         v = s/(t-b->x.ptr.p_double[i]);
   37817           0 :         v = v*b->w.ptr.p_double[i];
   37818           0 :         y->ptr.p_double[i] = v;
   37819           0 :         s2 = s2+v;
   37820             :     }
   37821           0 :     v = 1/s2;
   37822           0 :     ae_v_muld(&y->ptr.p_double[0], 1, ae_v_len(0,b->n-1), v);
   37823             : }
   37824             : 
   37825             : 
   37826             : /*************************************************************************
   37827             : This is internal function for Chebyshev fitting.
   37828             : 
   37829             : It assumes that input data are normalized:
   37830             : * X/XC belong to [-1,+1],
   37831             : * mean(Y)=0, stddev(Y)=1.
   37832             : 
   37833             : It does not checks inputs for errors.
   37834             : 
   37835             : This function is used to fit general (shifted) Chebyshev models, power
   37836             : basis models or barycentric models.
   37837             : 
   37838             : INPUT PARAMETERS:
   37839             :     X   -   points, array[0..N-1].
   37840             :     Y   -   function values, array[0..N-1].
   37841             :     W   -   weights, array[0..N-1]
   37842             :     N   -   number of points, N>0.
   37843             :     XC  -   points where polynomial values/derivatives are constrained,
   37844             :             array[0..K-1].
   37845             :     YC  -   values of constraints, array[0..K-1]
   37846             :     DC  -   array[0..K-1], types of constraints:
   37847             :             * DC[i]=0   means that P(XC[i])=YC[i]
   37848             :             * DC[i]=1   means that P'(XC[i])=YC[i]
   37849             :     K   -   number of constraints, 0<=K<M.
   37850             :             K=0 means no constraints (XC/YC/DC are not used in such cases)
   37851             :     M   -   number of basis functions (= polynomial_degree + 1), M>=1
   37852             : 
   37853             : OUTPUT PARAMETERS:
   37854             :     Info-   same format as in LSFitLinearW() subroutine:
   37855             :             * Info>0    task is solved
   37856             :             * Info<=0   an error occured:
   37857             :                         -4 means inconvergence of internal SVD
   37858             :                         -3 means inconsistent constraints
   37859             :     C   -   interpolant in Chebyshev form; [-1,+1] is used as base interval
   37860             :     Rep -   report, same format as in LSFitLinearW() subroutine.
   37861             :             Following fields are set:
   37862             :             * RMSError      rms error on the (X,Y).
   37863             :             * AvgError      average error on the (X,Y).
   37864             :             * AvgRelError   average relative error on the non-zero Y
   37865             :             * MaxError      maximum error
   37866             :                             NON-WEIGHTED ERRORS ARE CALCULATED
   37867             : 
   37868             : IMPORTANT:
   37869             :     this subroitine doesn't calculate task's condition number for K<>0.
   37870             : 
   37871             :   -- ALGLIB PROJECT --
   37872             :      Copyright 10.12.2009 by Bochkanov Sergey
   37873             : *************************************************************************/
   37874           0 : static void lsfit_internalchebyshevfit(/* Real    */ ae_vector* x,
   37875             :      /* Real    */ ae_vector* y,
   37876             :      /* Real    */ ae_vector* w,
   37877             :      ae_int_t n,
   37878             :      /* Real    */ ae_vector* xc,
   37879             :      /* Real    */ ae_vector* yc,
   37880             :      /* Integer */ ae_vector* dc,
   37881             :      ae_int_t k,
   37882             :      ae_int_t m,
   37883             :      ae_int_t* info,
   37884             :      /* Real    */ ae_vector* c,
   37885             :      lsfitreport* rep,
   37886             :      ae_state *_state)
   37887             : {
   37888             :     ae_frame _frame_block;
   37889             :     ae_vector _xc;
   37890             :     ae_vector _yc;
   37891             :     ae_vector y2;
   37892             :     ae_vector w2;
   37893             :     ae_vector tmp;
   37894             :     ae_vector tmp2;
   37895             :     ae_vector tmpdiff;
   37896             :     ae_vector bx;
   37897             :     ae_vector by;
   37898             :     ae_vector bw;
   37899             :     ae_matrix fmatrix;
   37900             :     ae_matrix cmatrix;
   37901             :     ae_int_t i;
   37902             :     ae_int_t j;
   37903             :     double mx;
   37904             :     double decay;
   37905             : 
   37906           0 :     ae_frame_make(_state, &_frame_block);
   37907           0 :     memset(&_xc, 0, sizeof(_xc));
   37908           0 :     memset(&_yc, 0, sizeof(_yc));
   37909           0 :     memset(&y2, 0, sizeof(y2));
   37910           0 :     memset(&w2, 0, sizeof(w2));
   37911           0 :     memset(&tmp, 0, sizeof(tmp));
   37912           0 :     memset(&tmp2, 0, sizeof(tmp2));
   37913           0 :     memset(&tmpdiff, 0, sizeof(tmpdiff));
   37914           0 :     memset(&bx, 0, sizeof(bx));
   37915           0 :     memset(&by, 0, sizeof(by));
   37916           0 :     memset(&bw, 0, sizeof(bw));
   37917           0 :     memset(&fmatrix, 0, sizeof(fmatrix));
   37918           0 :     memset(&cmatrix, 0, sizeof(cmatrix));
   37919           0 :     ae_vector_init_copy(&_xc, xc, _state, ae_true);
   37920           0 :     xc = &_xc;
   37921           0 :     ae_vector_init_copy(&_yc, yc, _state, ae_true);
   37922           0 :     yc = &_yc;
   37923           0 :     *info = 0;
   37924           0 :     ae_vector_clear(c);
   37925           0 :     _lsfitreport_clear(rep);
   37926           0 :     ae_vector_init(&y2, 0, DT_REAL, _state, ae_true);
   37927           0 :     ae_vector_init(&w2, 0, DT_REAL, _state, ae_true);
   37928           0 :     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
   37929           0 :     ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true);
   37930           0 :     ae_vector_init(&tmpdiff, 0, DT_REAL, _state, ae_true);
   37931           0 :     ae_vector_init(&bx, 0, DT_REAL, _state, ae_true);
   37932           0 :     ae_vector_init(&by, 0, DT_REAL, _state, ae_true);
   37933           0 :     ae_vector_init(&bw, 0, DT_REAL, _state, ae_true);
   37934           0 :     ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true);
   37935           0 :     ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true);
   37936             : 
   37937           0 :     lsfit_clearreport(rep, _state);
   37938             :     
   37939             :     /*
   37940             :      * weight decay for correct handling of task which becomes
   37941             :      * degenerate after constraints are applied
   37942             :      */
   37943           0 :     decay = 10000*ae_machineepsilon;
   37944             :     
   37945             :     /*
   37946             :      * allocate space, initialize/fill:
   37947             :      * * FMatrix-   values of basis functions at X[]
   37948             :      * * CMatrix-   values (derivatives) of basis functions at XC[]
   37949             :      * * fill constraints matrix
   37950             :      * * fill first N rows of design matrix with values
   37951             :      * * fill next M rows of design matrix with regularizing term
   37952             :      * * append M zeros to Y
   37953             :      * * append M elements, mean(abs(W)) each, to W
   37954             :      */
   37955           0 :     ae_vector_set_length(&y2, n+m, _state);
   37956           0 :     ae_vector_set_length(&w2, n+m, _state);
   37957           0 :     ae_vector_set_length(&tmp, m, _state);
   37958           0 :     ae_vector_set_length(&tmpdiff, m, _state);
   37959           0 :     ae_matrix_set_length(&fmatrix, n+m, m, _state);
   37960           0 :     if( k>0 )
   37961             :     {
   37962           0 :         ae_matrix_set_length(&cmatrix, k, m+1, _state);
   37963             :     }
   37964             :     
   37965             :     /*
   37966             :      * Fill design matrix, Y2, W2:
   37967             :      * * first N rows with basis functions for original points
   37968             :      * * next M rows with decay terms
   37969             :      */
   37970           0 :     for(i=0; i<=n-1; i++)
   37971             :     {
   37972             :         
   37973             :         /*
   37974             :          * prepare Ith row
   37975             :          * use Tmp for calculations to avoid multidimensional arrays overhead
   37976             :          */
   37977           0 :         for(j=0; j<=m-1; j++)
   37978             :         {
   37979           0 :             if( j==0 )
   37980             :             {
   37981           0 :                 tmp.ptr.p_double[j] = (double)(1);
   37982             :             }
   37983             :             else
   37984             :             {
   37985           0 :                 if( j==1 )
   37986             :                 {
   37987           0 :                     tmp.ptr.p_double[j] = x->ptr.p_double[i];
   37988             :                 }
   37989             :                 else
   37990             :                 {
   37991           0 :                     tmp.ptr.p_double[j] = 2*x->ptr.p_double[i]*tmp.ptr.p_double[j-1]-tmp.ptr.p_double[j-2];
   37992             :                 }
   37993             :             }
   37994             :         }
   37995           0 :         ae_v_move(&fmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1));
   37996             :     }
   37997           0 :     for(i=0; i<=m-1; i++)
   37998             :     {
   37999           0 :         for(j=0; j<=m-1; j++)
   38000             :         {
   38001           0 :             if( i==j )
   38002             :             {
   38003           0 :                 fmatrix.ptr.pp_double[n+i][j] = decay;
   38004             :             }
   38005             :             else
   38006             :             {
   38007           0 :                 fmatrix.ptr.pp_double[n+i][j] = (double)(0);
   38008             :             }
   38009             :         }
   38010             :     }
   38011           0 :     ae_v_move(&y2.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
   38012           0 :     ae_v_move(&w2.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
   38013           0 :     mx = (double)(0);
   38014           0 :     for(i=0; i<=n-1; i++)
   38015             :     {
   38016           0 :         mx = mx+ae_fabs(w->ptr.p_double[i], _state);
   38017             :     }
   38018           0 :     mx = mx/n;
   38019           0 :     for(i=0; i<=m-1; i++)
   38020             :     {
   38021           0 :         y2.ptr.p_double[n+i] = (double)(0);
   38022           0 :         w2.ptr.p_double[n+i] = mx;
   38023             :     }
   38024             :     
   38025             :     /*
   38026             :      * fill constraints matrix
   38027             :      */
   38028           0 :     for(i=0; i<=k-1; i++)
   38029             :     {
   38030             :         
   38031             :         /*
   38032             :          * prepare Ith row
   38033             :          * use Tmp for basis function values,
   38034             :          * TmpDiff for basos function derivatives
   38035             :          */
   38036           0 :         for(j=0; j<=m-1; j++)
   38037             :         {
   38038           0 :             if( j==0 )
   38039             :             {
   38040           0 :                 tmp.ptr.p_double[j] = (double)(1);
   38041           0 :                 tmpdiff.ptr.p_double[j] = (double)(0);
   38042             :             }
   38043             :             else
   38044             :             {
   38045           0 :                 if( j==1 )
   38046             :                 {
   38047           0 :                     tmp.ptr.p_double[j] = xc->ptr.p_double[i];
   38048           0 :                     tmpdiff.ptr.p_double[j] = (double)(1);
   38049             :                 }
   38050             :                 else
   38051             :                 {
   38052           0 :                     tmp.ptr.p_double[j] = 2*xc->ptr.p_double[i]*tmp.ptr.p_double[j-1]-tmp.ptr.p_double[j-2];
   38053           0 :                     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];
   38054             :                 }
   38055             :             }
   38056             :         }
   38057           0 :         if( dc->ptr.p_int[i]==0 )
   38058             :         {
   38059           0 :             ae_v_move(&cmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1));
   38060             :         }
   38061           0 :         if( dc->ptr.p_int[i]==1 )
   38062             :         {
   38063           0 :             ae_v_move(&cmatrix.ptr.pp_double[i][0], 1, &tmpdiff.ptr.p_double[0], 1, ae_v_len(0,m-1));
   38064             :         }
   38065           0 :         cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i];
   38066             :     }
   38067             :     
   38068             :     /*
   38069             :      * Solve constrained task
   38070             :      */
   38071           0 :     if( k>0 )
   38072             :     {
   38073             :         
   38074             :         /*
   38075             :          * solve using regularization
   38076             :          */
   38077           0 :         lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, c, rep, _state);
   38078             :     }
   38079             :     else
   38080             :     {
   38081             :         
   38082             :         /*
   38083             :          * no constraints, no regularization needed
   38084             :          */
   38085           0 :         lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, 0, info, c, rep, _state);
   38086             :     }
   38087           0 :     if( *info<0 )
   38088             :     {
   38089           0 :         ae_frame_leave(_state);
   38090           0 :         return;
   38091             :     }
   38092           0 :     ae_frame_leave(_state);
   38093             : }
   38094             : 
   38095             : 
   38096             : /*************************************************************************
   38097             : Internal Floater-Hormann fitting subroutine for fixed D
   38098             : *************************************************************************/
   38099           0 : static void lsfit_barycentricfitwcfixedd(/* Real    */ ae_vector* x,
   38100             :      /* Real    */ ae_vector* y,
   38101             :      /* Real    */ ae_vector* w,
   38102             :      ae_int_t n,
   38103             :      /* Real    */ ae_vector* xc,
   38104             :      /* Real    */ ae_vector* yc,
   38105             :      /* Integer */ ae_vector* dc,
   38106             :      ae_int_t k,
   38107             :      ae_int_t m,
   38108             :      ae_int_t d,
   38109             :      ae_int_t* info,
   38110             :      barycentricinterpolant* b,
   38111             :      barycentricfitreport* rep,
   38112             :      ae_state *_state)
   38113             : {
   38114             :     ae_frame _frame_block;
   38115             :     ae_vector _x;
   38116             :     ae_vector _y;
   38117             :     ae_vector _w;
   38118             :     ae_vector _xc;
   38119             :     ae_vector _yc;
   38120             :     ae_matrix fmatrix;
   38121             :     ae_matrix cmatrix;
   38122             :     ae_vector y2;
   38123             :     ae_vector w2;
   38124             :     ae_vector sx;
   38125             :     ae_vector sy;
   38126             :     ae_vector sbf;
   38127             :     ae_vector xoriginal;
   38128             :     ae_vector yoriginal;
   38129             :     ae_vector tmp;
   38130             :     lsfitreport lrep;
   38131             :     double v0;
   38132             :     double v1;
   38133             :     double mx;
   38134             :     barycentricinterpolant b2;
   38135             :     ae_int_t i;
   38136             :     ae_int_t j;
   38137             :     ae_int_t relcnt;
   38138             :     double xa;
   38139             :     double xb;
   38140             :     double sa;
   38141             :     double sb;
   38142             :     double decay;
   38143             : 
   38144           0 :     ae_frame_make(_state, &_frame_block);
   38145           0 :     memset(&_x, 0, sizeof(_x));
   38146           0 :     memset(&_y, 0, sizeof(_y));
   38147           0 :     memset(&_w, 0, sizeof(_w));
   38148           0 :     memset(&_xc, 0, sizeof(_xc));
   38149           0 :     memset(&_yc, 0, sizeof(_yc));
   38150           0 :     memset(&fmatrix, 0, sizeof(fmatrix));
   38151           0 :     memset(&cmatrix, 0, sizeof(cmatrix));
   38152           0 :     memset(&y2, 0, sizeof(y2));
   38153           0 :     memset(&w2, 0, sizeof(w2));
   38154           0 :     memset(&sx, 0, sizeof(sx));
   38155           0 :     memset(&sy, 0, sizeof(sy));
   38156           0 :     memset(&sbf, 0, sizeof(sbf));
   38157           0 :     memset(&xoriginal, 0, sizeof(xoriginal));
   38158           0 :     memset(&yoriginal, 0, sizeof(yoriginal));
   38159           0 :     memset(&tmp, 0, sizeof(tmp));
   38160           0 :     memset(&lrep, 0, sizeof(lrep));
   38161           0 :     memset(&b2, 0, sizeof(b2));
   38162           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   38163           0 :     x = &_x;
   38164           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   38165           0 :     y = &_y;
   38166           0 :     ae_vector_init_copy(&_w, w, _state, ae_true);
   38167           0 :     w = &_w;
   38168           0 :     ae_vector_init_copy(&_xc, xc, _state, ae_true);
   38169           0 :     xc = &_xc;
   38170           0 :     ae_vector_init_copy(&_yc, yc, _state, ae_true);
   38171           0 :     yc = &_yc;
   38172           0 :     *info = 0;
   38173           0 :     _barycentricinterpolant_clear(b);
   38174           0 :     _barycentricfitreport_clear(rep);
   38175           0 :     ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true);
   38176           0 :     ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true);
   38177           0 :     ae_vector_init(&y2, 0, DT_REAL, _state, ae_true);
   38178           0 :     ae_vector_init(&w2, 0, DT_REAL, _state, ae_true);
   38179           0 :     ae_vector_init(&sx, 0, DT_REAL, _state, ae_true);
   38180           0 :     ae_vector_init(&sy, 0, DT_REAL, _state, ae_true);
   38181           0 :     ae_vector_init(&sbf, 0, DT_REAL, _state, ae_true);
   38182           0 :     ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true);
   38183           0 :     ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true);
   38184           0 :     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
   38185           0 :     _lsfitreport_init(&lrep, _state, ae_true);
   38186           0 :     _barycentricinterpolant_init(&b2, _state, ae_true);
   38187             : 
   38188           0 :     if( ((n<1||m<2)||k<0)||k>=m )
   38189             :     {
   38190           0 :         *info = -1;
   38191           0 :         ae_frame_leave(_state);
   38192           0 :         return;
   38193             :     }
   38194           0 :     for(i=0; i<=k-1; i++)
   38195             :     {
   38196           0 :         *info = 0;
   38197           0 :         if( dc->ptr.p_int[i]<0 )
   38198             :         {
   38199           0 :             *info = -1;
   38200             :         }
   38201           0 :         if( dc->ptr.p_int[i]>1 )
   38202             :         {
   38203           0 :             *info = -1;
   38204             :         }
   38205           0 :         if( *info<0 )
   38206             :         {
   38207           0 :             ae_frame_leave(_state);
   38208           0 :             return;
   38209             :         }
   38210             :     }
   38211             :     
   38212             :     /*
   38213             :      * weight decay for correct handling of task which becomes
   38214             :      * degenerate after constraints are applied
   38215             :      */
   38216           0 :     decay = 10000*ae_machineepsilon;
   38217             :     
   38218             :     /*
   38219             :      * Scale X, Y, XC, YC
   38220             :      */
   38221           0 :     lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state);
   38222             :     
   38223             :     /*
   38224             :      * allocate space, initialize:
   38225             :      * * FMatrix-   values of basis functions at X[]
   38226             :      * * CMatrix-   values (derivatives) of basis functions at XC[]
   38227             :      */
   38228           0 :     ae_vector_set_length(&y2, n+m, _state);
   38229           0 :     ae_vector_set_length(&w2, n+m, _state);
   38230           0 :     ae_matrix_set_length(&fmatrix, n+m, m, _state);
   38231           0 :     if( k>0 )
   38232             :     {
   38233           0 :         ae_matrix_set_length(&cmatrix, k, m+1, _state);
   38234             :     }
   38235           0 :     ae_vector_set_length(&y2, n+m, _state);
   38236           0 :     ae_vector_set_length(&w2, n+m, _state);
   38237             :     
   38238             :     /*
   38239             :      * Prepare design and constraints matrices:
   38240             :      * * fill constraints matrix
   38241             :      * * fill first N rows of design matrix with values
   38242             :      * * fill next M rows of design matrix with regularizing term
   38243             :      * * append M zeros to Y
   38244             :      * * append M elements, mean(abs(W)) each, to W
   38245             :      */
   38246           0 :     ae_vector_set_length(&sx, m, _state);
   38247           0 :     ae_vector_set_length(&sy, m, _state);
   38248           0 :     ae_vector_set_length(&sbf, m, _state);
   38249           0 :     for(j=0; j<=m-1; j++)
   38250             :     {
   38251           0 :         sx.ptr.p_double[j] = (double)(2*j)/(double)(m-1)-1;
   38252             :     }
   38253           0 :     for(i=0; i<=m-1; i++)
   38254             :     {
   38255           0 :         sy.ptr.p_double[i] = (double)(1);
   38256             :     }
   38257           0 :     barycentricbuildfloaterhormann(&sx, &sy, m, d, &b2, _state);
   38258           0 :     mx = (double)(0);
   38259           0 :     for(i=0; i<=n-1; i++)
   38260             :     {
   38261           0 :         lsfit_barycentriccalcbasis(&b2, x->ptr.p_double[i], &sbf, _state);
   38262           0 :         ae_v_move(&fmatrix.ptr.pp_double[i][0], 1, &sbf.ptr.p_double[0], 1, ae_v_len(0,m-1));
   38263           0 :         y2.ptr.p_double[i] = y->ptr.p_double[i];
   38264           0 :         w2.ptr.p_double[i] = w->ptr.p_double[i];
   38265           0 :         mx = mx+ae_fabs(w->ptr.p_double[i], _state)/n;
   38266             :     }
   38267           0 :     for(i=0; i<=m-1; i++)
   38268             :     {
   38269           0 :         for(j=0; j<=m-1; j++)
   38270             :         {
   38271           0 :             if( i==j )
   38272             :             {
   38273           0 :                 fmatrix.ptr.pp_double[n+i][j] = decay;
   38274             :             }
   38275             :             else
   38276             :             {
   38277           0 :                 fmatrix.ptr.pp_double[n+i][j] = (double)(0);
   38278             :             }
   38279             :         }
   38280           0 :         y2.ptr.p_double[n+i] = (double)(0);
   38281           0 :         w2.ptr.p_double[n+i] = mx;
   38282             :     }
   38283           0 :     if( k>0 )
   38284             :     {
   38285           0 :         for(j=0; j<=m-1; j++)
   38286             :         {
   38287           0 :             for(i=0; i<=m-1; i++)
   38288             :             {
   38289           0 :                 sy.ptr.p_double[i] = (double)(0);
   38290             :             }
   38291           0 :             sy.ptr.p_double[j] = (double)(1);
   38292           0 :             barycentricbuildfloaterhormann(&sx, &sy, m, d, &b2, _state);
   38293           0 :             for(i=0; i<=k-1; i++)
   38294             :             {
   38295           0 :                 ae_assert(dc->ptr.p_int[i]>=0&&dc->ptr.p_int[i]<=1, "BarycentricFit: internal error!", _state);
   38296           0 :                 barycentricdiff1(&b2, xc->ptr.p_double[i], &v0, &v1, _state);
   38297           0 :                 if( dc->ptr.p_int[i]==0 )
   38298             :                 {
   38299           0 :                     cmatrix.ptr.pp_double[i][j] = v0;
   38300             :                 }
   38301           0 :                 if( dc->ptr.p_int[i]==1 )
   38302             :                 {
   38303           0 :                     cmatrix.ptr.pp_double[i][j] = v1;
   38304             :                 }
   38305             :             }
   38306             :         }
   38307           0 :         for(i=0; i<=k-1; i++)
   38308             :         {
   38309           0 :             cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i];
   38310             :         }
   38311             :     }
   38312             :     
   38313             :     /*
   38314             :      * Solve constrained task
   38315             :      */
   38316           0 :     if( k>0 )
   38317             :     {
   38318             :         
   38319             :         /*
   38320             :          * solve using regularization
   38321             :          */
   38322           0 :         lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, &tmp, &lrep, _state);
   38323             :     }
   38324             :     else
   38325             :     {
   38326             :         
   38327             :         /*
   38328             :          * no constraints, no regularization needed
   38329             :          */
   38330           0 :         lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, k, info, &tmp, &lrep, _state);
   38331             :     }
   38332           0 :     if( *info<0 )
   38333             :     {
   38334           0 :         ae_frame_leave(_state);
   38335           0 :         return;
   38336             :     }
   38337             :     
   38338             :     /*
   38339             :      * Generate interpolant and scale it
   38340             :      */
   38341           0 :     ae_v_move(&sy.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1));
   38342           0 :     barycentricbuildfloaterhormann(&sx, &sy, m, d, b, _state);
   38343           0 :     barycentriclintransx(b, 2/(xb-xa), -(xa+xb)/(xb-xa), _state);
   38344           0 :     barycentriclintransy(b, sb-sa, sa, _state);
   38345             :     
   38346             :     /*
   38347             :      * Scale absolute errors obtained from LSFitLinearW.
   38348             :      * Relative error should be calculated separately
   38349             :      * (because of shifting/scaling of the task)
   38350             :      */
   38351           0 :     rep->taskrcond = lrep.taskrcond;
   38352           0 :     rep->rmserror = lrep.rmserror*(sb-sa);
   38353           0 :     rep->avgerror = lrep.avgerror*(sb-sa);
   38354           0 :     rep->maxerror = lrep.maxerror*(sb-sa);
   38355           0 :     rep->avgrelerror = (double)(0);
   38356           0 :     relcnt = 0;
   38357           0 :     for(i=0; i<=n-1; i++)
   38358             :     {
   38359           0 :         if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) )
   38360             :         {
   38361           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);
   38362           0 :             relcnt = relcnt+1;
   38363             :         }
   38364             :     }
   38365           0 :     if( relcnt!=0 )
   38366             :     {
   38367           0 :         rep->avgrelerror = rep->avgrelerror/relcnt;
   38368             :     }
   38369           0 :     ae_frame_leave(_state);
   38370             : }
   38371             : 
   38372             : 
   38373           0 : static void lsfit_clearreport(lsfitreport* rep, ae_state *_state)
   38374             : {
   38375             : 
   38376             : 
   38377           0 :     rep->taskrcond = (double)(0);
   38378           0 :     rep->iterationscount = 0;
   38379           0 :     rep->varidx = -1;
   38380           0 :     rep->rmserror = (double)(0);
   38381           0 :     rep->avgerror = (double)(0);
   38382           0 :     rep->avgrelerror = (double)(0);
   38383           0 :     rep->maxerror = (double)(0);
   38384           0 :     rep->wrmserror = (double)(0);
   38385           0 :     rep->r2 = (double)(0);
   38386           0 :     ae_matrix_set_length(&rep->covpar, 0, 0, _state);
   38387           0 :     ae_vector_set_length(&rep->errpar, 0, _state);
   38388           0 :     ae_vector_set_length(&rep->errcurve, 0, _state);
   38389           0 :     ae_vector_set_length(&rep->noise, 0, _state);
   38390           0 : }
   38391             : 
   38392             : 
   38393             : /*************************************************************************
   38394             : This internal function estimates covariance matrix and other error-related
   38395             : information for linear/nonlinear least squares model.
   38396             : 
   38397             : It has a bit awkward interface, but it can be used  for  both  linear  and
   38398             : nonlinear problems.
   38399             : 
   38400             : INPUT PARAMETERS:
   38401             :     F1  -   array[0..N-1,0..K-1]:
   38402             :             * for linear problems - matrix of function values
   38403             :             * for nonlinear problems - Jacobian matrix
   38404             :     F0  -   array[0..N-1]:
   38405             :             * for linear problems - must be filled with zeros
   38406             :             * for nonlinear problems - must store values of function being
   38407             :               fitted
   38408             :     Y   -   array[0..N-1]:
   38409             :             * for linear and nonlinear problems - must store target values
   38410             :     W   -   weights, array[0..N-1]:
   38411             :             * for linear and nonlinear problems - weights
   38412             :     X   -   array[0..K-1]:
   38413             :             * for linear and nonlinear problems - current solution
   38414             :     S   -   array[0..K-1]:
   38415             :             * its components should be strictly positive
   38416             :             * squared inverse of this diagonal matrix is used as damping
   38417             :               factor for covariance matrix (linear and nonlinear problems)
   38418             :             * for nonlinear problems, when scale of the variables is usually
   38419             :               explicitly given by user, you may use scale vector for this
   38420             :               parameter
   38421             :             * for linear problems you may set this parameter to
   38422             :               S=sqrt(1/diag(F'*F))
   38423             :             * this parameter is automatically rescaled by this function,
   38424             :               only relative magnitudes of its components (with respect to
   38425             :               each other) matter.
   38426             :     N   -   number of points, N>0.
   38427             :     K   -   number of dimensions
   38428             :     Rep -   structure which is used to store results
   38429             :     Z   -   additional matrix which, depending on ZKind, may contain some
   38430             :             information used to accelerate calculations - or just can be
   38431             :             temporary buffer:
   38432             :             * for ZKind=0       Z contains no information, just temporary
   38433             :                                 buffer which can be resized and used as needed
   38434             :             * for ZKind=1       Z contains triangular matrix from QR
   38435             :                                 decomposition of W*F1. This matrix can be used
   38436             :                                 to speedup calculation of covariance matrix.
   38437             :                                 It should not be changed by algorithm.
   38438             :     ZKind-  contents of Z
   38439             : 
   38440             : OUTPUT PARAMETERS:
   38441             : 
   38442             : * Rep.CovPar        covariance matrix for parameters, array[K,K].
   38443             : * Rep.ErrPar        errors in parameters, array[K],
   38444             :                     errpar = sqrt(diag(CovPar))
   38445             : * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
   38446             :                     best-fit curve from "ideal" best-fit curve built  with
   38447             :                     infinite number of samples, array[N].
   38448             :                     errcurve = sqrt(diag(J*CovPar*J')),
   38449             :                     where J is Jacobian matrix.
   38450             : * Rep.Noise         vector of per-point estimates of noise, array[N]
   38451             : * Rep.R2            coefficient of determination (non-weighted)
   38452             : 
   38453             : Other fields of Rep are not changed.
   38454             : 
   38455             : IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
   38456             :             account boundary/linear constraints! Presence  of  constraints
   38457             :             changes distribution of errors, but there is no  easy  way  to
   38458             :             account for constraints when you calculate covariance matrix.
   38459             :             
   38460             : NOTE:       noise in the data is estimated as follows:
   38461             :             * for fitting without user-supplied  weights  all  points  are
   38462             :               assumed to have same level of noise, which is estimated from
   38463             :               the data
   38464             :             * for fitting with user-supplied weights we assume that  noise
   38465             :               level in I-th point is inversely proportional to Ith weight.
   38466             :               Coefficient of proportionality is estimated from the data.
   38467             :             
   38468             : NOTE:       we apply small amount of regularization when we invert squared
   38469             :             Jacobian and calculate covariance matrix. It  guarantees  that
   38470             :             algorithm won't divide by zero  during  inversion,  but  skews
   38471             :             error estimates a bit (fractional error is about 10^-9).
   38472             :             
   38473             :             However, we believe that this difference is insignificant  for
   38474             :             all practical purposes except for the situation when you  want
   38475             :             to compare ALGLIB results with "reference"  implementation  up
   38476             :             to the last significant digit.
   38477             : 
   38478             :   -- ALGLIB PROJECT --
   38479             :      Copyright 10.12.2009 by Bochkanov Sergey
   38480             : *************************************************************************/
   38481           0 : static void lsfit_estimateerrors(/* Real    */ ae_matrix* f1,
   38482             :      /* Real    */ ae_vector* f0,
   38483             :      /* Real    */ ae_vector* y,
   38484             :      /* Real    */ ae_vector* w,
   38485             :      /* Real    */ ae_vector* x,
   38486             :      /* Real    */ ae_vector* s,
   38487             :      ae_int_t n,
   38488             :      ae_int_t k,
   38489             :      lsfitreport* rep,
   38490             :      /* Real    */ ae_matrix* z,
   38491             :      ae_int_t zkind,
   38492             :      ae_state *_state)
   38493             : {
   38494             :     ae_frame _frame_block;
   38495             :     ae_vector _s;
   38496             :     ae_int_t i;
   38497             :     ae_int_t j;
   38498             :     ae_int_t j1;
   38499             :     double v;
   38500             :     double noisec;
   38501             :     ae_int_t info;
   38502             :     matinvreport invrep;
   38503             :     ae_int_t nzcnt;
   38504             :     double avg;
   38505             :     double rss;
   38506             :     double tss;
   38507             :     double sz;
   38508             :     double ss;
   38509             : 
   38510           0 :     ae_frame_make(_state, &_frame_block);
   38511           0 :     memset(&_s, 0, sizeof(_s));
   38512           0 :     memset(&invrep, 0, sizeof(invrep));
   38513           0 :     ae_vector_init_copy(&_s, s, _state, ae_true);
   38514           0 :     s = &_s;
   38515           0 :     _matinvreport_init(&invrep, _state, ae_true);
   38516             : 
   38517             :     
   38518             :     /*
   38519             :      * Compute NZCnt - count of non-zero weights
   38520             :      */
   38521           0 :     nzcnt = 0;
   38522           0 :     for(i=0; i<=n-1; i++)
   38523             :     {
   38524           0 :         if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) )
   38525             :         {
   38526           0 :             nzcnt = nzcnt+1;
   38527             :         }
   38528             :     }
   38529             :     
   38530             :     /*
   38531             :      * Compute R2
   38532             :      */
   38533           0 :     if( nzcnt>0 )
   38534             :     {
   38535           0 :         avg = 0.0;
   38536           0 :         for(i=0; i<=n-1; i++)
   38537             :         {
   38538           0 :             if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) )
   38539             :             {
   38540           0 :                 avg = avg+y->ptr.p_double[i];
   38541             :             }
   38542             :         }
   38543           0 :         avg = avg/nzcnt;
   38544           0 :         rss = 0.0;
   38545           0 :         tss = 0.0;
   38546           0 :         for(i=0; i<=n-1; i++)
   38547             :         {
   38548           0 :             if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) )
   38549             :             {
   38550           0 :                 v = ae_v_dotproduct(&f1->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,k-1));
   38551           0 :                 v = v+f0->ptr.p_double[i];
   38552           0 :                 rss = rss+ae_sqr(v-y->ptr.p_double[i], _state);
   38553           0 :                 tss = tss+ae_sqr(y->ptr.p_double[i]-avg, _state);
   38554             :             }
   38555             :         }
   38556           0 :         if( ae_fp_neq(tss,(double)(0)) )
   38557             :         {
   38558           0 :             rep->r2 = ae_maxreal(1.0-rss/tss, 0.0, _state);
   38559             :         }
   38560             :         else
   38561             :         {
   38562           0 :             rep->r2 = 1.0;
   38563             :         }
   38564             :     }
   38565             :     else
   38566             :     {
   38567           0 :         rep->r2 = (double)(0);
   38568             :     }
   38569             :     
   38570             :     /*
   38571             :      * Compute estimate of proportionality between noise in the data and weights:
   38572             :      *     NoiseC = mean(per-point-noise*per-point-weight)
   38573             :      * Noise level (standard deviation) at each point is equal to NoiseC/W[I].
   38574             :      */
   38575           0 :     if( nzcnt>k )
   38576             :     {
   38577           0 :         noisec = 0.0;
   38578           0 :         for(i=0; i<=n-1; i++)
   38579             :         {
   38580           0 :             if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) )
   38581             :             {
   38582           0 :                 v = ae_v_dotproduct(&f1->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,k-1));
   38583           0 :                 v = v+f0->ptr.p_double[i];
   38584           0 :                 noisec = noisec+ae_sqr((v-y->ptr.p_double[i])*w->ptr.p_double[i], _state);
   38585             :             }
   38586             :         }
   38587           0 :         noisec = ae_sqrt(noisec/(nzcnt-k), _state);
   38588             :     }
   38589             :     else
   38590             :     {
   38591           0 :         noisec = 0.0;
   38592             :     }
   38593             :     
   38594             :     /*
   38595             :      * Two branches on noise level:
   38596             :      * * NoiseC>0   normal situation
   38597             :      * * NoiseC=0   degenerate case CovPar is filled by zeros
   38598             :      */
   38599           0 :     rmatrixsetlengthatleast(&rep->covpar, k, k, _state);
   38600           0 :     if( ae_fp_greater(noisec,(double)(0)) )
   38601             :     {
   38602             :         
   38603             :         /*
   38604             :          * Normal situation: non-zero noise level
   38605             :          */
   38606           0 :         ae_assert(zkind==0||zkind==1, "LSFit: internal error in EstimateErrors() function", _state);
   38607           0 :         if( zkind==0 )
   38608             :         {
   38609             :             
   38610             :             /*
   38611             :              * Z contains no additional information which can be used to speed up
   38612             :              * calculations. We have to calculate covariance matrix on our own:
   38613             :              * * Compute scaled Jacobian N*J, where N[i,i]=WCur[I]/NoiseC, store in Z
   38614             :              * * Compute Z'*Z, store in CovPar
   38615             :              * * Apply moderate regularization to CovPar and compute matrix inverse.
   38616             :              *   In case inverse failed, increase regularization parameter and try
   38617             :              *   again.
   38618             :              */
   38619           0 :             rmatrixsetlengthatleast(z, n, k, _state);
   38620           0 :             for(i=0; i<=n-1; i++)
   38621             :             {
   38622           0 :                 v = w->ptr.p_double[i]/noisec;
   38623           0 :                 ae_v_moved(&z->ptr.pp_double[i][0], 1, &f1->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v);
   38624             :             }
   38625             :             
   38626             :             /*
   38627             :              * Convert S to automatically scaled damped matrix:
   38628             :              * * calculate SZ - sum of diagonal elements of Z'*Z
   38629             :              * * calculate SS - sum of diagonal elements of S^(-2)
   38630             :              * * overwrite S by (SZ/SS)*S^(-2)
   38631             :              * * now S has approximately same magnitude as giagonal of Z'*Z
   38632             :              */
   38633           0 :             sz = (double)(0);
   38634           0 :             for(i=0; i<=n-1; i++)
   38635             :             {
   38636           0 :                 for(j=0; j<=k-1; j++)
   38637             :                 {
   38638           0 :                     sz = sz+z->ptr.pp_double[i][j]*z->ptr.pp_double[i][j];
   38639             :                 }
   38640             :             }
   38641           0 :             if( ae_fp_eq(sz,(double)(0)) )
   38642             :             {
   38643           0 :                 sz = (double)(1);
   38644             :             }
   38645           0 :             ss = (double)(0);
   38646           0 :             for(j=0; j<=k-1; j++)
   38647             :             {
   38648           0 :                 ss = ss+1/ae_sqr(s->ptr.p_double[j], _state);
   38649             :             }
   38650           0 :             for(j=0; j<=k-1; j++)
   38651             :             {
   38652           0 :                 s->ptr.p_double[j] = sz/ss/ae_sqr(s->ptr.p_double[j], _state);
   38653             :             }
   38654             :             
   38655             :             /*
   38656             :              * Calculate damped inverse inv(Z'*Z+S).
   38657             :              * We increase damping factor V until Z'*Z become well-conditioned.
   38658             :              */
   38659           0 :             v = 1.0E3*ae_machineepsilon;
   38660           0 :             do
   38661             :             {
   38662           0 :                 rmatrixsyrk(k, n, 1.0, z, 0, 0, 2, 0.0, &rep->covpar, 0, 0, ae_true, _state);
   38663           0 :                 for(i=0; i<=k-1; i++)
   38664             :                 {
   38665           0 :                     rep->covpar.ptr.pp_double[i][i] = rep->covpar.ptr.pp_double[i][i]+v*s->ptr.p_double[i];
   38666             :                 }
   38667           0 :                 spdmatrixinverse(&rep->covpar, k, ae_true, &info, &invrep, _state);
   38668           0 :                 v = 10*v;
   38669             :             }
   38670           0 :             while(info<=0);
   38671           0 :             for(i=0; i<=k-1; i++)
   38672             :             {
   38673           0 :                 for(j=i+1; j<=k-1; j++)
   38674             :                 {
   38675           0 :                     rep->covpar.ptr.pp_double[j][i] = rep->covpar.ptr.pp_double[i][j];
   38676             :                 }
   38677             :             }
   38678             :         }
   38679           0 :         if( zkind==1 )
   38680             :         {
   38681             :             
   38682             :             /*
   38683             :              * We can reuse additional information:
   38684             :              * * Z contains R matrix from QR decomposition of W*F1 
   38685             :              * * After multiplication by 1/NoiseC we get Z_mod = N*F1, where diag(N)=w[i]/NoiseC
   38686             :              * * Such triangular Z_mod is a Cholesky factor from decomposition of J'*N'*N*J.
   38687             :              *   Thus, we can calculate covariance matrix as inverse of the matrix given by
   38688             :              *   its Cholesky decomposition. It allow us to avoid time-consuming calculation
   38689             :              *   of J'*N'*N*J in CovPar - complexity is reduced from O(N*K^2) to O(K^3), which
   38690             :              *   is quite good because K is usually orders of magnitude smaller than N.
   38691             :              *
   38692             :              * First, convert S to automatically scaled damped matrix:
   38693             :              * * calculate SZ - sum of magnitudes of diagonal elements of Z/NoiseC
   38694             :              * * calculate SS - sum of diagonal elements of S^(-1)
   38695             :              * * overwrite S by (SZ/SS)*S^(-1)
   38696             :              * * now S has approximately same magnitude as giagonal of Z'*Z
   38697             :              */
   38698           0 :             sz = (double)(0);
   38699           0 :             for(j=0; j<=k-1; j++)
   38700             :             {
   38701           0 :                 sz = sz+ae_fabs(z->ptr.pp_double[j][j]/noisec, _state);
   38702             :             }
   38703           0 :             if( ae_fp_eq(sz,(double)(0)) )
   38704             :             {
   38705           0 :                 sz = (double)(1);
   38706             :             }
   38707           0 :             ss = (double)(0);
   38708           0 :             for(j=0; j<=k-1; j++)
   38709             :             {
   38710           0 :                 ss = ss+1/s->ptr.p_double[j];
   38711             :             }
   38712           0 :             for(j=0; j<=k-1; j++)
   38713             :             {
   38714           0 :                 s->ptr.p_double[j] = sz/ss/s->ptr.p_double[j];
   38715             :             }
   38716             :             
   38717             :             /*
   38718             :              * Calculate damped inverse of inv((Z+v*S)'*(Z+v*S))
   38719             :              * We increase damping factor V until matrix become well-conditioned.
   38720             :              */
   38721           0 :             v = 1.0E3*ae_machineepsilon;
   38722           0 :             do
   38723             :             {
   38724           0 :                 for(i=0; i<=k-1; i++)
   38725             :                 {
   38726           0 :                     for(j=i; j<=k-1; j++)
   38727             :                     {
   38728           0 :                         rep->covpar.ptr.pp_double[i][j] = z->ptr.pp_double[i][j]/noisec;
   38729             :                     }
   38730           0 :                     rep->covpar.ptr.pp_double[i][i] = rep->covpar.ptr.pp_double[i][i]+v*s->ptr.p_double[i];
   38731             :                 }
   38732           0 :                 spdmatrixcholeskyinverse(&rep->covpar, k, ae_true, &info, &invrep, _state);
   38733           0 :                 v = 10*v;
   38734             :             }
   38735           0 :             while(info<=0);
   38736           0 :             for(i=0; i<=k-1; i++)
   38737             :             {
   38738           0 :                 for(j=i+1; j<=k-1; j++)
   38739             :                 {
   38740           0 :                     rep->covpar.ptr.pp_double[j][i] = rep->covpar.ptr.pp_double[i][j];
   38741             :                 }
   38742             :             }
   38743             :         }
   38744             :     }
   38745             :     else
   38746             :     {
   38747             :         
   38748             :         /*
   38749             :          * Degenerate situation: zero noise level, covariance matrix is zero.
   38750             :          */
   38751           0 :         for(i=0; i<=k-1; i++)
   38752             :         {
   38753           0 :             for(j=0; j<=k-1; j++)
   38754             :             {
   38755           0 :                 rep->covpar.ptr.pp_double[j][i] = (double)(0);
   38756             :             }
   38757             :         }
   38758             :     }
   38759             :     
   38760             :     /*
   38761             :      * Estimate erorrs in parameters, curve and per-point noise
   38762             :      */
   38763           0 :     rvectorsetlengthatleast(&rep->errpar, k, _state);
   38764           0 :     rvectorsetlengthatleast(&rep->errcurve, n, _state);
   38765           0 :     rvectorsetlengthatleast(&rep->noise, n, _state);
   38766           0 :     for(i=0; i<=k-1; i++)
   38767             :     {
   38768           0 :         rep->errpar.ptr.p_double[i] = ae_sqrt(rep->covpar.ptr.pp_double[i][i], _state);
   38769             :     }
   38770           0 :     for(i=0; i<=n-1; i++)
   38771             :     {
   38772             :         
   38773             :         /*
   38774             :          * ErrCurve[I] is sqrt(P[i,i]) where P=J*CovPar*J'
   38775             :          */
   38776           0 :         v = 0.0;
   38777           0 :         for(j=0; j<=k-1; j++)
   38778             :         {
   38779           0 :             for(j1=0; j1<=k-1; j1++)
   38780             :             {
   38781           0 :                 v = v+f1->ptr.pp_double[i][j]*rep->covpar.ptr.pp_double[j][j1]*f1->ptr.pp_double[i][j1];
   38782             :             }
   38783             :         }
   38784           0 :         rep->errcurve.ptr.p_double[i] = ae_sqrt(v, _state);
   38785             :         
   38786             :         /*
   38787             :          * Noise[i] is filled using weights and current estimate of noise level
   38788             :          */
   38789           0 :         if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) )
   38790             :         {
   38791           0 :             rep->noise.ptr.p_double[i] = noisec/w->ptr.p_double[i];
   38792             :         }
   38793             :         else
   38794             :         {
   38795           0 :             rep->noise.ptr.p_double[i] = (double)(0);
   38796             :         }
   38797             :     }
   38798           0 :     ae_frame_leave(_state);
   38799           0 : }
   38800             : 
   38801             : 
   38802           0 : void _polynomialfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
   38803             : {
   38804           0 :     polynomialfitreport *p = (polynomialfitreport*)_p;
   38805           0 :     ae_touch_ptr((void*)p);
   38806           0 : }
   38807             : 
   38808             : 
   38809           0 : void _polynomialfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   38810             : {
   38811           0 :     polynomialfitreport *dst = (polynomialfitreport*)_dst;
   38812           0 :     polynomialfitreport *src = (polynomialfitreport*)_src;
   38813           0 :     dst->taskrcond = src->taskrcond;
   38814           0 :     dst->rmserror = src->rmserror;
   38815           0 :     dst->avgerror = src->avgerror;
   38816           0 :     dst->avgrelerror = src->avgrelerror;
   38817           0 :     dst->maxerror = src->maxerror;
   38818           0 : }
   38819             : 
   38820             : 
   38821           0 : void _polynomialfitreport_clear(void* _p)
   38822             : {
   38823           0 :     polynomialfitreport *p = (polynomialfitreport*)_p;
   38824           0 :     ae_touch_ptr((void*)p);
   38825           0 : }
   38826             : 
   38827             : 
   38828           0 : void _polynomialfitreport_destroy(void* _p)
   38829             : {
   38830           0 :     polynomialfitreport *p = (polynomialfitreport*)_p;
   38831           0 :     ae_touch_ptr((void*)p);
   38832           0 : }
   38833             : 
   38834             : 
   38835           0 : void _barycentricfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
   38836             : {
   38837           0 :     barycentricfitreport *p = (barycentricfitreport*)_p;
   38838           0 :     ae_touch_ptr((void*)p);
   38839           0 : }
   38840             : 
   38841             : 
   38842           0 : void _barycentricfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   38843             : {
   38844           0 :     barycentricfitreport *dst = (barycentricfitreport*)_dst;
   38845           0 :     barycentricfitreport *src = (barycentricfitreport*)_src;
   38846           0 :     dst->taskrcond = src->taskrcond;
   38847           0 :     dst->dbest = src->dbest;
   38848           0 :     dst->rmserror = src->rmserror;
   38849           0 :     dst->avgerror = src->avgerror;
   38850           0 :     dst->avgrelerror = src->avgrelerror;
   38851           0 :     dst->maxerror = src->maxerror;
   38852           0 : }
   38853             : 
   38854             : 
   38855           0 : void _barycentricfitreport_clear(void* _p)
   38856             : {
   38857           0 :     barycentricfitreport *p = (barycentricfitreport*)_p;
   38858           0 :     ae_touch_ptr((void*)p);
   38859           0 : }
   38860             : 
   38861             : 
   38862           0 : void _barycentricfitreport_destroy(void* _p)
   38863             : {
   38864           0 :     barycentricfitreport *p = (barycentricfitreport*)_p;
   38865           0 :     ae_touch_ptr((void*)p);
   38866           0 : }
   38867             : 
   38868             : 
   38869           0 : void _lsfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
   38870             : {
   38871           0 :     lsfitreport *p = (lsfitreport*)_p;
   38872           0 :     ae_touch_ptr((void*)p);
   38873           0 :     ae_matrix_init(&p->covpar, 0, 0, DT_REAL, _state, make_automatic);
   38874           0 :     ae_vector_init(&p->errpar, 0, DT_REAL, _state, make_automatic);
   38875           0 :     ae_vector_init(&p->errcurve, 0, DT_REAL, _state, make_automatic);
   38876           0 :     ae_vector_init(&p->noise, 0, DT_REAL, _state, make_automatic);
   38877           0 : }
   38878             : 
   38879             : 
   38880           0 : void _lsfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   38881             : {
   38882           0 :     lsfitreport *dst = (lsfitreport*)_dst;
   38883           0 :     lsfitreport *src = (lsfitreport*)_src;
   38884           0 :     dst->taskrcond = src->taskrcond;
   38885           0 :     dst->iterationscount = src->iterationscount;
   38886           0 :     dst->varidx = src->varidx;
   38887           0 :     dst->rmserror = src->rmserror;
   38888           0 :     dst->avgerror = src->avgerror;
   38889           0 :     dst->avgrelerror = src->avgrelerror;
   38890           0 :     dst->maxerror = src->maxerror;
   38891           0 :     dst->wrmserror = src->wrmserror;
   38892           0 :     ae_matrix_init_copy(&dst->covpar, &src->covpar, _state, make_automatic);
   38893           0 :     ae_vector_init_copy(&dst->errpar, &src->errpar, _state, make_automatic);
   38894           0 :     ae_vector_init_copy(&dst->errcurve, &src->errcurve, _state, make_automatic);
   38895           0 :     ae_vector_init_copy(&dst->noise, &src->noise, _state, make_automatic);
   38896           0 :     dst->r2 = src->r2;
   38897           0 : }
   38898             : 
   38899             : 
   38900           0 : void _lsfitreport_clear(void* _p)
   38901             : {
   38902           0 :     lsfitreport *p = (lsfitreport*)_p;
   38903           0 :     ae_touch_ptr((void*)p);
   38904           0 :     ae_matrix_clear(&p->covpar);
   38905           0 :     ae_vector_clear(&p->errpar);
   38906           0 :     ae_vector_clear(&p->errcurve);
   38907           0 :     ae_vector_clear(&p->noise);
   38908           0 : }
   38909             : 
   38910             : 
   38911           0 : void _lsfitreport_destroy(void* _p)
   38912             : {
   38913           0 :     lsfitreport *p = (lsfitreport*)_p;
   38914           0 :     ae_touch_ptr((void*)p);
   38915           0 :     ae_matrix_destroy(&p->covpar);
   38916           0 :     ae_vector_destroy(&p->errpar);
   38917           0 :     ae_vector_destroy(&p->errcurve);
   38918           0 :     ae_vector_destroy(&p->noise);
   38919           0 : }
   38920             : 
   38921             : 
   38922           0 : void _lsfitstate_init(void* _p, ae_state *_state, ae_bool make_automatic)
   38923             : {
   38924           0 :     lsfitstate *p = (lsfitstate*)_p;
   38925           0 :     ae_touch_ptr((void*)p);
   38926           0 :     ae_vector_init(&p->c0, 0, DT_REAL, _state, make_automatic);
   38927           0 :     ae_vector_init(&p->c1, 0, DT_REAL, _state, make_automatic);
   38928           0 :     ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic);
   38929           0 :     ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic);
   38930           0 :     ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic);
   38931           0 :     ae_matrix_init(&p->taskx, 0, 0, DT_REAL, _state, make_automatic);
   38932           0 :     ae_vector_init(&p->tasky, 0, DT_REAL, _state, make_automatic);
   38933           0 :     ae_vector_init(&p->taskw, 0, DT_REAL, _state, make_automatic);
   38934           0 :     ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic);
   38935           0 :     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
   38936           0 :     ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic);
   38937           0 :     ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic);
   38938           0 :     ae_matrix_init(&p->h, 0, 0, DT_REAL, _state, make_automatic);
   38939           0 :     ae_vector_init(&p->wcur, 0, DT_REAL, _state, make_automatic);
   38940           0 :     ae_vector_init(&p->tmpct, 0, DT_INT, _state, make_automatic);
   38941           0 :     ae_vector_init(&p->tmp, 0, DT_REAL, _state, make_automatic);
   38942           0 :     ae_vector_init(&p->tmpf, 0, DT_REAL, _state, make_automatic);
   38943           0 :     ae_matrix_init(&p->tmpjac, 0, 0, DT_REAL, _state, make_automatic);
   38944           0 :     ae_matrix_init(&p->tmpjacw, 0, 0, DT_REAL, _state, make_automatic);
   38945           0 :     _matinvreport_init(&p->invrep, _state, make_automatic);
   38946           0 :     _lsfitreport_init(&p->rep, _state, make_automatic);
   38947           0 :     _minlmstate_init(&p->optstate, _state, make_automatic);
   38948           0 :     _minlmreport_init(&p->optrep, _state, make_automatic);
   38949           0 :     _rcommstate_init(&p->rstate, _state, make_automatic);
   38950           0 : }
   38951             : 
   38952             : 
   38953           0 : void _lsfitstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   38954             : {
   38955           0 :     lsfitstate *dst = (lsfitstate*)_dst;
   38956           0 :     lsfitstate *src = (lsfitstate*)_src;
   38957           0 :     dst->optalgo = src->optalgo;
   38958           0 :     dst->m = src->m;
   38959           0 :     dst->k = src->k;
   38960           0 :     dst->epsx = src->epsx;
   38961           0 :     dst->maxits = src->maxits;
   38962           0 :     dst->stpmax = src->stpmax;
   38963           0 :     dst->xrep = src->xrep;
   38964           0 :     ae_vector_init_copy(&dst->c0, &src->c0, _state, make_automatic);
   38965           0 :     ae_vector_init_copy(&dst->c1, &src->c1, _state, make_automatic);
   38966           0 :     ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic);
   38967           0 :     ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic);
   38968           0 :     ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic);
   38969           0 :     ae_matrix_init_copy(&dst->taskx, &src->taskx, _state, make_automatic);
   38970           0 :     ae_vector_init_copy(&dst->tasky, &src->tasky, _state, make_automatic);
   38971           0 :     dst->npoints = src->npoints;
   38972           0 :     ae_vector_init_copy(&dst->taskw, &src->taskw, _state, make_automatic);
   38973           0 :     dst->nweights = src->nweights;
   38974           0 :     dst->wkind = src->wkind;
   38975           0 :     dst->wits = src->wits;
   38976           0 :     dst->diffstep = src->diffstep;
   38977           0 :     dst->teststep = src->teststep;
   38978           0 :     ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic);
   38979           0 :     dst->nec = src->nec;
   38980           0 :     dst->nic = src->nic;
   38981           0 :     dst->xupdated = src->xupdated;
   38982           0 :     dst->needf = src->needf;
   38983           0 :     dst->needfg = src->needfg;
   38984           0 :     dst->needfgh = src->needfgh;
   38985           0 :     dst->pointindex = src->pointindex;
   38986           0 :     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
   38987           0 :     ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic);
   38988           0 :     dst->f = src->f;
   38989           0 :     ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic);
   38990           0 :     ae_matrix_init_copy(&dst->h, &src->h, _state, make_automatic);
   38991           0 :     ae_vector_init_copy(&dst->wcur, &src->wcur, _state, make_automatic);
   38992           0 :     ae_vector_init_copy(&dst->tmpct, &src->tmpct, _state, make_automatic);
   38993           0 :     ae_vector_init_copy(&dst->tmp, &src->tmp, _state, make_automatic);
   38994           0 :     ae_vector_init_copy(&dst->tmpf, &src->tmpf, _state, make_automatic);
   38995           0 :     ae_matrix_init_copy(&dst->tmpjac, &src->tmpjac, _state, make_automatic);
   38996           0 :     ae_matrix_init_copy(&dst->tmpjacw, &src->tmpjacw, _state, make_automatic);
   38997           0 :     dst->tmpnoise = src->tmpnoise;
   38998           0 :     _matinvreport_init_copy(&dst->invrep, &src->invrep, _state, make_automatic);
   38999           0 :     dst->repiterationscount = src->repiterationscount;
   39000           0 :     dst->repterminationtype = src->repterminationtype;
   39001           0 :     dst->repvaridx = src->repvaridx;
   39002           0 :     dst->reprmserror = src->reprmserror;
   39003           0 :     dst->repavgerror = src->repavgerror;
   39004           0 :     dst->repavgrelerror = src->repavgrelerror;
   39005           0 :     dst->repmaxerror = src->repmaxerror;
   39006           0 :     dst->repwrmserror = src->repwrmserror;
   39007           0 :     _lsfitreport_init_copy(&dst->rep, &src->rep, _state, make_automatic);
   39008           0 :     _minlmstate_init_copy(&dst->optstate, &src->optstate, _state, make_automatic);
   39009           0 :     _minlmreport_init_copy(&dst->optrep, &src->optrep, _state, make_automatic);
   39010           0 :     dst->prevnpt = src->prevnpt;
   39011           0 :     dst->prevalgo = src->prevalgo;
   39012           0 :     _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic);
   39013           0 : }
   39014             : 
   39015             : 
   39016           0 : void _lsfitstate_clear(void* _p)
   39017             : {
   39018           0 :     lsfitstate *p = (lsfitstate*)_p;
   39019           0 :     ae_touch_ptr((void*)p);
   39020           0 :     ae_vector_clear(&p->c0);
   39021           0 :     ae_vector_clear(&p->c1);
   39022           0 :     ae_vector_clear(&p->s);
   39023           0 :     ae_vector_clear(&p->bndl);
   39024           0 :     ae_vector_clear(&p->bndu);
   39025           0 :     ae_matrix_clear(&p->taskx);
   39026           0 :     ae_vector_clear(&p->tasky);
   39027           0 :     ae_vector_clear(&p->taskw);
   39028           0 :     ae_matrix_clear(&p->cleic);
   39029           0 :     ae_vector_clear(&p->x);
   39030           0 :     ae_vector_clear(&p->c);
   39031           0 :     ae_vector_clear(&p->g);
   39032           0 :     ae_matrix_clear(&p->h);
   39033           0 :     ae_vector_clear(&p->wcur);
   39034           0 :     ae_vector_clear(&p->tmpct);
   39035           0 :     ae_vector_clear(&p->tmp);
   39036           0 :     ae_vector_clear(&p->tmpf);
   39037           0 :     ae_matrix_clear(&p->tmpjac);
   39038           0 :     ae_matrix_clear(&p->tmpjacw);
   39039           0 :     _matinvreport_clear(&p->invrep);
   39040           0 :     _lsfitreport_clear(&p->rep);
   39041           0 :     _minlmstate_clear(&p->optstate);
   39042           0 :     _minlmreport_clear(&p->optrep);
   39043           0 :     _rcommstate_clear(&p->rstate);
   39044           0 : }
   39045             : 
   39046             : 
   39047           0 : void _lsfitstate_destroy(void* _p)
   39048             : {
   39049           0 :     lsfitstate *p = (lsfitstate*)_p;
   39050           0 :     ae_touch_ptr((void*)p);
   39051           0 :     ae_vector_destroy(&p->c0);
   39052           0 :     ae_vector_destroy(&p->c1);
   39053           0 :     ae_vector_destroy(&p->s);
   39054           0 :     ae_vector_destroy(&p->bndl);
   39055           0 :     ae_vector_destroy(&p->bndu);
   39056           0 :     ae_matrix_destroy(&p->taskx);
   39057           0 :     ae_vector_destroy(&p->tasky);
   39058           0 :     ae_vector_destroy(&p->taskw);
   39059           0 :     ae_matrix_destroy(&p->cleic);
   39060           0 :     ae_vector_destroy(&p->x);
   39061           0 :     ae_vector_destroy(&p->c);
   39062           0 :     ae_vector_destroy(&p->g);
   39063           0 :     ae_matrix_destroy(&p->h);
   39064           0 :     ae_vector_destroy(&p->wcur);
   39065           0 :     ae_vector_destroy(&p->tmpct);
   39066           0 :     ae_vector_destroy(&p->tmp);
   39067           0 :     ae_vector_destroy(&p->tmpf);
   39068           0 :     ae_matrix_destroy(&p->tmpjac);
   39069           0 :     ae_matrix_destroy(&p->tmpjacw);
   39070           0 :     _matinvreport_destroy(&p->invrep);
   39071           0 :     _lsfitreport_destroy(&p->rep);
   39072           0 :     _minlmstate_destroy(&p->optstate);
   39073           0 :     _minlmreport_destroy(&p->optrep);
   39074           0 :     _rcommstate_destroy(&p->rstate);
   39075           0 : }
   39076             : 
   39077             : 
   39078             : #endif
   39079             : #if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD)
   39080             : 
   39081             : 
   39082             : /*************************************************************************
   39083             : This function creates RBF  model  for  a  scalar (NY=1)  or  vector (NY>1)
   39084             : function in a NX-dimensional space (NX=2 or NX=3).
   39085             : 
   39086             : INPUT PARAMETERS:
   39087             :     NX      -   dimension of the space, NX=2 or NX=3
   39088             :     NY      -   function dimension, NY>=1
   39089             : 
   39090             : OUTPUT PARAMETERS:
   39091             :     S       -   RBF model (initially equals to zero)
   39092             : 
   39093             :   -- ALGLIB --
   39094             :      Copyright 13.12.2011 by Bochkanov Sergey
   39095             : *************************************************************************/
   39096           0 : void rbfv2create(ae_int_t nx,
   39097             :      ae_int_t ny,
   39098             :      rbfv2model* s,
   39099             :      ae_state *_state)
   39100             : {
   39101             :     ae_int_t i;
   39102             :     ae_int_t j;
   39103             : 
   39104           0 :     _rbfv2model_clear(s);
   39105             : 
   39106           0 :     ae_assert(nx>=1, "RBFCreate: NX<1", _state);
   39107           0 :     ae_assert(ny>=1, "RBFCreate: NY<1", _state);
   39108             :     
   39109             :     /*
   39110             :      * Serializable parameters
   39111             :      */
   39112           0 :     s->nx = nx;
   39113           0 :     s->ny = ny;
   39114           0 :     s->bf = 0;
   39115           0 :     s->nh = 0;
   39116           0 :     ae_matrix_set_length(&s->v, ny, nx+1, _state);
   39117           0 :     for(i=0; i<=ny-1; i++)
   39118             :     {
   39119           0 :         for(j=0; j<=nx; j++)
   39120             :         {
   39121           0 :             s->v.ptr.pp_double[i][j] = (double)(0);
   39122             :         }
   39123             :     }
   39124             :     
   39125             :     /*
   39126             :      * Non-serializable parameters
   39127             :      */
   39128           0 :     s->lambdareg = rbfv2_defaultlambdareg;
   39129           0 :     s->maxits = rbfv2_defaultmaxits;
   39130           0 :     s->supportr = rbfv2_defaultsupportr;
   39131           0 :     s->basisfunction = rbfv2_defaultbf;
   39132           0 : }
   39133             : 
   39134             : 
   39135             : /*************************************************************************
   39136             : This function creates buffer  structure  which  can  be  used  to  perform
   39137             : parallel  RBF  model  evaluations  (with  one  RBF  model  instance  being
   39138             : used from multiple threads, as long as  different  threads  use  different
   39139             : instances of buffer).
   39140             : 
   39141             : This buffer object can be used with  rbftscalcbuf()  function  (here  "ts"
   39142             : stands for "thread-safe", "buf" is a suffix which denotes  function  which
   39143             : reuses previously allocated output space).
   39144             : 
   39145             : How to use it:
   39146             : * create RBF model structure with rbfcreate()
   39147             : * load data, tune parameters
   39148             : * call rbfbuildmodel()
   39149             : * call rbfcreatecalcbuffer(), once per thread working with RBF model  (you
   39150             :   should call this function only AFTER call to rbfbuildmodel(), see  below
   39151             :   for more information)
   39152             : * call rbftscalcbuf() from different threads,  with  each  thread  working
   39153             :   with its own copy of buffer object.
   39154             : 
   39155             : INPUT PARAMETERS
   39156             :     S           -   RBF model
   39157             : 
   39158             : OUTPUT PARAMETERS
   39159             :     Buf         -   external buffer.
   39160             :     
   39161             :     
   39162             : IMPORTANT: buffer object should be used only with  RBF model object  which
   39163             :            was used to initialize buffer. Any attempt to use buffer   with
   39164             :            different object is dangerous - you may  get  memory  violation
   39165             :            error because sizes of internal arrays do not fit to dimensions
   39166             :            of RBF structure.
   39167             :            
   39168             : IMPORTANT: you  should  call  this function only for model which was built
   39169             :            with rbfbuildmodel() function, after successful  invocation  of
   39170             :            rbfbuildmodel().  Sizes   of   some   internal  structures  are
   39171             :            determined only after model is built, so buffer object  created
   39172             :            before model  construction  stage  will  be  useless  (and  any
   39173             :            attempt to use it will result in exception).
   39174             : 
   39175             :   -- ALGLIB --
   39176             :      Copyright 02.04.2016 by Sergey Bochkanov
   39177             : *************************************************************************/
   39178           0 : void rbfv2createcalcbuffer(rbfv2model* s,
   39179             :      rbfv2calcbuffer* buf,
   39180             :      ae_state *_state)
   39181             : {
   39182             : 
   39183           0 :     _rbfv2calcbuffer_clear(buf);
   39184             : 
   39185           0 :     rbfv2_allocatecalcbuffer(s, buf, _state);
   39186           0 : }
   39187             : 
   39188             : 
   39189             : /*************************************************************************
   39190             : This   function  builds hierarchical RBF model.
   39191             : 
   39192             : INPUT PARAMETERS:
   39193             :     X       -   array[N,S.NX], X-values
   39194             :     Y       -   array[N,S.NY], Y-values
   39195             :     ScaleVec-   array[S.NX], vector of per-dimension scales
   39196             :     N       -   points count
   39197             :     ATerm   -   linear term type, 1 for linear, 2 for constant, 3 for zero.
   39198             :     NH      -   hierarchy height
   39199             :     RBase   -   base RBF radius
   39200             :     BF      -   basis function type: 0 for Gaussian, 1 for compact
   39201             :     LambdaNS-   non-smoothness penalty coefficient. Exactly zero value means
   39202             :                 that no penalty is applied, and even system matrix does not
   39203             :                 contain penalty-related rows. Value of 1 means
   39204             :     S       -   RBF model, initialized by RBFCreate() call.
   39205             :     progress10000- variable used for progress reports, it is regularly set
   39206             :                 to the current progress multiplied by 10000, in order to
   39207             :                 get value in [0,10000] range. The rationale for such scaling
   39208             :                 is that it allows us to use integer type to store progress,
   39209             :                 which has less potential for non-atomic corruption on unprotected
   39210             :                 reads from another threads.
   39211             :                 You can read this variable from some other thread to get
   39212             :                 estimate of the current progress.
   39213             :                 Initial value of this variable is ignored, it is written by
   39214             :                 this function, but not read.
   39215             :     terminationrequest - variable used for termination requests; its initial
   39216             :                 value must be False, and you can set it to True from some
   39217             :                 other thread. This routine regularly checks this variable
   39218             :                 and will terminate model construction shortly upon discovering
   39219             :                 that termination was requested.
   39220             :     
   39221             : OUTPUT PARAMETERS:
   39222             :     S       -   updated model (for rep.terminationtype>0, unchanged otherwise)
   39223             :     Rep     -   report:
   39224             :                 * Rep.TerminationType:
   39225             :                   * -5 - non-distinct basis function centers were detected,
   39226             :                          interpolation aborted
   39227             :                   * -4 - nonconvergence of the internal SVD solver
   39228             :                   *  1 - successful termination
   39229             :                   *  8 terminated by user via rbfrequesttermination()
   39230             :                 Fields are used for debugging purposes:
   39231             :                 * Rep.IterationsCount - iterations count of the LSQR solver
   39232             :                 * Rep.NMV - number of matrix-vector products
   39233             :                 * Rep.ARows - rows count for the system matrix
   39234             :                 * Rep.ACols - columns count for the system matrix
   39235             :                 * Rep.ANNZ - number of significantly non-zero elements
   39236             :                   (elements above some algorithm-determined threshold)
   39237             : 
   39238             : NOTE:  failure  to  build  model will leave current state of the structure
   39239             : unchanged.
   39240             : 
   39241             :   -- ALGLIB --
   39242             :      Copyright 20.06.2016 by Bochkanov Sergey
   39243             : *************************************************************************/
   39244           0 : void rbfv2buildhierarchical(/* Real    */ ae_matrix* x,
   39245             :      /* Real    */ ae_matrix* y,
   39246             :      ae_int_t n,
   39247             :      /* Real    */ ae_vector* scalevec,
   39248             :      ae_int_t aterm,
   39249             :      ae_int_t nh,
   39250             :      double rbase,
   39251             :      double lambdans,
   39252             :      rbfv2model* s,
   39253             :      ae_int_t* progress10000,
   39254             :      ae_bool* terminationrequest,
   39255             :      rbfv2report* rep,
   39256             :      ae_state *_state)
   39257             : {
   39258             :     ae_frame _frame_block;
   39259             :     ae_int_t nx;
   39260             :     ae_int_t ny;
   39261             :     ae_int_t bf;
   39262             :     ae_matrix rhs;
   39263             :     ae_matrix residualy;
   39264             :     ae_matrix v;
   39265             :     ae_int_t rowsperpoint;
   39266             :     ae_vector hidx;
   39267             :     ae_vector xr;
   39268             :     ae_vector ri;
   39269             :     ae_vector kdroots;
   39270             :     ae_vector kdnodes;
   39271             :     ae_vector kdsplits;
   39272             :     ae_vector kdboxmin;
   39273             :     ae_vector kdboxmax;
   39274             :     ae_vector cw;
   39275             :     ae_vector cwrange;
   39276             :     ae_matrix curxy;
   39277             :     ae_int_t curn;
   39278             :     ae_int_t nbasis;
   39279             :     kdtree curtree;
   39280             :     kdtree globaltree;
   39281             :     ae_vector x0;
   39282             :     ae_vector x1;
   39283             :     ae_vector tags;
   39284             :     ae_vector dist;
   39285             :     ae_vector nncnt;
   39286             :     ae_vector rowsizes;
   39287             :     ae_vector diagata;
   39288             :     ae_vector prec;
   39289             :     ae_vector tmpx;
   39290             :     ae_int_t i;
   39291             :     ae_int_t j;
   39292             :     ae_int_t k;
   39293             :     ae_int_t k2;
   39294             :     ae_int_t levelidx;
   39295             :     ae_int_t offsi;
   39296             :     ae_int_t offsj;
   39297             :     double val;
   39298             :     double criticalr;
   39299             :     ae_int_t cnt;
   39300             :     double avgdiagata;
   39301             :     ae_vector avgrowsize;
   39302             :     double sumrowsize;
   39303             :     double rprogress;
   39304             :     ae_int_t maxits;
   39305             :     linlsqrstate linstate;
   39306             :     linlsqrreport lsqrrep;
   39307             :     sparsematrix sparseacrs;
   39308             :     ae_vector densew1;
   39309             :     ae_vector denseb1;
   39310             :     rbfv2calcbuffer calcbuf;
   39311             :     ae_vector vr2;
   39312             :     ae_vector voffs;
   39313             :     ae_vector rowindexes;
   39314             :     ae_vector rowvals;
   39315             :     double penalty;
   39316             : 
   39317           0 :     ae_frame_make(_state, &_frame_block);
   39318           0 :     memset(&rhs, 0, sizeof(rhs));
   39319           0 :     memset(&residualy, 0, sizeof(residualy));
   39320           0 :     memset(&v, 0, sizeof(v));
   39321           0 :     memset(&hidx, 0, sizeof(hidx));
   39322           0 :     memset(&xr, 0, sizeof(xr));
   39323           0 :     memset(&ri, 0, sizeof(ri));
   39324           0 :     memset(&kdroots, 0, sizeof(kdroots));
   39325           0 :     memset(&kdnodes, 0, sizeof(kdnodes));
   39326           0 :     memset(&kdsplits, 0, sizeof(kdsplits));
   39327           0 :     memset(&kdboxmin, 0, sizeof(kdboxmin));
   39328           0 :     memset(&kdboxmax, 0, sizeof(kdboxmax));
   39329           0 :     memset(&cw, 0, sizeof(cw));
   39330           0 :     memset(&cwrange, 0, sizeof(cwrange));
   39331           0 :     memset(&curxy, 0, sizeof(curxy));
   39332           0 :     memset(&curtree, 0, sizeof(curtree));
   39333           0 :     memset(&globaltree, 0, sizeof(globaltree));
   39334           0 :     memset(&x0, 0, sizeof(x0));
   39335           0 :     memset(&x1, 0, sizeof(x1));
   39336           0 :     memset(&tags, 0, sizeof(tags));
   39337           0 :     memset(&dist, 0, sizeof(dist));
   39338           0 :     memset(&nncnt, 0, sizeof(nncnt));
   39339           0 :     memset(&rowsizes, 0, sizeof(rowsizes));
   39340           0 :     memset(&diagata, 0, sizeof(diagata));
   39341           0 :     memset(&prec, 0, sizeof(prec));
   39342           0 :     memset(&tmpx, 0, sizeof(tmpx));
   39343           0 :     memset(&avgrowsize, 0, sizeof(avgrowsize));
   39344           0 :     memset(&linstate, 0, sizeof(linstate));
   39345           0 :     memset(&lsqrrep, 0, sizeof(lsqrrep));
   39346           0 :     memset(&sparseacrs, 0, sizeof(sparseacrs));
   39347           0 :     memset(&densew1, 0, sizeof(densew1));
   39348           0 :     memset(&denseb1, 0, sizeof(denseb1));
   39349           0 :     memset(&calcbuf, 0, sizeof(calcbuf));
   39350           0 :     memset(&vr2, 0, sizeof(vr2));
   39351           0 :     memset(&voffs, 0, sizeof(voffs));
   39352           0 :     memset(&rowindexes, 0, sizeof(rowindexes));
   39353           0 :     memset(&rowvals, 0, sizeof(rowvals));
   39354           0 :     _rbfv2report_clear(rep);
   39355           0 :     ae_matrix_init(&rhs, 0, 0, DT_REAL, _state, ae_true);
   39356           0 :     ae_matrix_init(&residualy, 0, 0, DT_REAL, _state, ae_true);
   39357           0 :     ae_matrix_init(&v, 0, 0, DT_REAL, _state, ae_true);
   39358           0 :     ae_vector_init(&hidx, 0, DT_INT, _state, ae_true);
   39359           0 :     ae_vector_init(&xr, 0, DT_REAL, _state, ae_true);
   39360           0 :     ae_vector_init(&ri, 0, DT_REAL, _state, ae_true);
   39361           0 :     ae_vector_init(&kdroots, 0, DT_INT, _state, ae_true);
   39362           0 :     ae_vector_init(&kdnodes, 0, DT_INT, _state, ae_true);
   39363           0 :     ae_vector_init(&kdsplits, 0, DT_REAL, _state, ae_true);
   39364           0 :     ae_vector_init(&kdboxmin, 0, DT_REAL, _state, ae_true);
   39365           0 :     ae_vector_init(&kdboxmax, 0, DT_REAL, _state, ae_true);
   39366           0 :     ae_vector_init(&cw, 0, DT_REAL, _state, ae_true);
   39367           0 :     ae_vector_init(&cwrange, 0, DT_INT, _state, ae_true);
   39368           0 :     ae_matrix_init(&curxy, 0, 0, DT_REAL, _state, ae_true);
   39369           0 :     _kdtree_init(&curtree, _state, ae_true);
   39370           0 :     _kdtree_init(&globaltree, _state, ae_true);
   39371           0 :     ae_vector_init(&x0, 0, DT_REAL, _state, ae_true);
   39372           0 :     ae_vector_init(&x1, 0, DT_REAL, _state, ae_true);
   39373           0 :     ae_vector_init(&tags, 0, DT_INT, _state, ae_true);
   39374           0 :     ae_vector_init(&dist, 0, DT_REAL, _state, ae_true);
   39375           0 :     ae_vector_init(&nncnt, 0, DT_INT, _state, ae_true);
   39376           0 :     ae_vector_init(&rowsizes, 0, DT_INT, _state, ae_true);
   39377           0 :     ae_vector_init(&diagata, 0, DT_REAL, _state, ae_true);
   39378           0 :     ae_vector_init(&prec, 0, DT_REAL, _state, ae_true);
   39379           0 :     ae_vector_init(&tmpx, 0, DT_REAL, _state, ae_true);
   39380           0 :     ae_vector_init(&avgrowsize, 0, DT_REAL, _state, ae_true);
   39381           0 :     _linlsqrstate_init(&linstate, _state, ae_true);
   39382           0 :     _linlsqrreport_init(&lsqrrep, _state, ae_true);
   39383           0 :     _sparsematrix_init(&sparseacrs, _state, ae_true);
   39384           0 :     ae_vector_init(&densew1, 0, DT_REAL, _state, ae_true);
   39385           0 :     ae_vector_init(&denseb1, 0, DT_REAL, _state, ae_true);
   39386           0 :     _rbfv2calcbuffer_init(&calcbuf, _state, ae_true);
   39387           0 :     ae_vector_init(&vr2, 0, DT_REAL, _state, ae_true);
   39388           0 :     ae_vector_init(&voffs, 0, DT_INT, _state, ae_true);
   39389           0 :     ae_vector_init(&rowindexes, 0, DT_INT, _state, ae_true);
   39390           0 :     ae_vector_init(&rowvals, 0, DT_REAL, _state, ae_true);
   39391             : 
   39392           0 :     ae_assert(s->nx>0, "RBFV2BuildHierarchical: incorrect NX", _state);
   39393           0 :     ae_assert(s->ny>0, "RBFV2BuildHierarchical: incorrect NY", _state);
   39394           0 :     ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "RBFV2BuildHierarchical: incorrect LambdaNS", _state);
   39395           0 :     for(j=0; j<=s->nx-1; j++)
   39396             :     {
   39397           0 :         ae_assert(ae_fp_greater(scalevec->ptr.p_double[j],(double)(0)), "RBFV2BuildHierarchical: incorrect ScaleVec", _state);
   39398             :     }
   39399           0 :     nx = s->nx;
   39400           0 :     ny = s->ny;
   39401           0 :     bf = s->basisfunction;
   39402           0 :     ae_assert(bf==0||bf==1, "RBFV2BuildHierarchical: incorrect BF", _state);
   39403             :     
   39404             :     /*
   39405             :      * Clean up communication and report fields
   39406             :      */
   39407           0 :     *progress10000 = 0;
   39408           0 :     rep->maxerror = (double)(0);
   39409           0 :     rep->rmserror = (double)(0);
   39410             :     
   39411             :     /*
   39412             :      * Quick exit when we have no points
   39413             :      */
   39414           0 :     if( n==0 )
   39415             :     {
   39416           0 :         rbfv2_zerofill(s, nx, ny, bf, _state);
   39417           0 :         rep->terminationtype = 1;
   39418           0 :         *progress10000 = 10000;
   39419           0 :         ae_frame_leave(_state);
   39420           0 :         return;
   39421             :     }
   39422             :     
   39423             :     /*
   39424             :      * First model in a sequence - linear model.
   39425             :      * Residuals from linear regression are stored in the ResidualY variable
   39426             :      * (used later to build RBF models).
   39427             :      */
   39428           0 :     ae_matrix_set_length(&residualy, n, ny, _state);
   39429           0 :     for(i=0; i<=n-1; i++)
   39430             :     {
   39431           0 :         for(j=0; j<=ny-1; j++)
   39432             :         {
   39433           0 :             residualy.ptr.pp_double[i][j] = y->ptr.pp_double[i][j];
   39434             :         }
   39435             :     }
   39436           0 :     if( !rbfv2_rbfv2buildlinearmodel(x, &residualy, n, nx, ny, aterm, &v, _state) )
   39437             :     {
   39438           0 :         rbfv2_zerofill(s, nx, ny, bf, _state);
   39439           0 :         rep->terminationtype = -5;
   39440           0 :         *progress10000 = 10000;
   39441           0 :         ae_frame_leave(_state);
   39442           0 :         return;
   39443             :     }
   39444             :     
   39445             :     /*
   39446             :      * Handle special case: multilayer model with NLayers=0.
   39447             :      * Quick exit.
   39448             :      */
   39449           0 :     if( nh==0 )
   39450             :     {
   39451           0 :         rep->terminationtype = 1;
   39452           0 :         rbfv2_zerofill(s, nx, ny, bf, _state);
   39453           0 :         for(i=0; i<=ny-1; i++)
   39454             :         {
   39455           0 :             for(j=0; j<=nx; j++)
   39456             :             {
   39457           0 :                 s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j];
   39458             :             }
   39459             :         }
   39460           0 :         rep->maxerror = (double)(0);
   39461           0 :         rep->rmserror = (double)(0);
   39462           0 :         for(i=0; i<=n-1; i++)
   39463             :         {
   39464           0 :             for(j=0; j<=ny-1; j++)
   39465             :             {
   39466           0 :                 rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(residualy.ptr.pp_double[i][j], _state), _state);
   39467           0 :                 rep->rmserror = rep->rmserror+ae_sqr(residualy.ptr.pp_double[i][j], _state);
   39468             :             }
   39469             :         }
   39470           0 :         rep->rmserror = ae_sqrt(rep->rmserror/(n*ny), _state);
   39471           0 :         *progress10000 = 10000;
   39472           0 :         ae_frame_leave(_state);
   39473           0 :         return;
   39474             :     }
   39475             :     
   39476             :     /*
   39477             :      * Penalty coefficient is set to LambdaNS*RBase^2.
   39478             :      *
   39479             :      * We use such normalization because VALUES of radial basis
   39480             :      * functions have roughly unit magnitude, but their DERIVATIVES
   39481             :      * are (roughly) inversely proportional to the radius. Thus,
   39482             :      * without additional scaling, regularization coefficient
   39483             :      * looses invariancy w.r.t. scaling of variables.
   39484             :      */
   39485           0 :     if( ae_fp_eq(lambdans,(double)(0)) )
   39486             :     {
   39487           0 :         rowsperpoint = 1;
   39488             :     }
   39489             :     else
   39490             :     {
   39491             :         
   39492             :         /*
   39493             :          * NOTE: simplified penalty function is used, which does not provide rotation invariance
   39494             :          */
   39495           0 :         rowsperpoint = 1+nx;
   39496             :     }
   39497           0 :     penalty = lambdans*ae_sqr(rbase, _state);
   39498             :     
   39499             :     /*
   39500             :      * Prepare temporary structures
   39501             :      */
   39502           0 :     ae_matrix_set_length(&rhs, n*rowsperpoint, ny, _state);
   39503           0 :     ae_matrix_set_length(&curxy, n, nx+ny, _state);
   39504           0 :     ae_vector_set_length(&x0, nx, _state);
   39505           0 :     ae_vector_set_length(&x1, nx, _state);
   39506           0 :     ae_vector_set_length(&tags, n, _state);
   39507           0 :     ae_vector_set_length(&dist, n, _state);
   39508           0 :     ae_vector_set_length(&vr2, n, _state);
   39509           0 :     ae_vector_set_length(&voffs, n, _state);
   39510           0 :     ae_vector_set_length(&nncnt, n, _state);
   39511           0 :     ae_vector_set_length(&rowsizes, n*rowsperpoint, _state);
   39512           0 :     ae_vector_set_length(&denseb1, n*rowsperpoint, _state);
   39513           0 :     for(i=0; i<=n*rowsperpoint-1; i++)
   39514             :     {
   39515           0 :         for(j=0; j<=ny-1; j++)
   39516             :         {
   39517           0 :             rhs.ptr.pp_double[i][j] = (double)(0);
   39518             :         }
   39519             :     }
   39520           0 :     for(i=0; i<=n-1; i++)
   39521             :     {
   39522           0 :         for(j=0; j<=nx-1; j++)
   39523             :         {
   39524           0 :             curxy.ptr.pp_double[i][j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j];
   39525             :         }
   39526           0 :         for(j=0; j<=ny-1; j++)
   39527             :         {
   39528           0 :             rhs.ptr.pp_double[i*rowsperpoint][j] = residualy.ptr.pp_double[i][j];
   39529             :         }
   39530           0 :         tags.ptr.p_int[i] = i;
   39531             :     }
   39532           0 :     kdtreebuildtagged(&curxy, &tags, n, nx, 0, 2, &globaltree, _state);
   39533             :     
   39534             :     /*
   39535             :      * Generate sequence of layer radii.
   39536             :      * Prepare assignment of different levels to points.
   39537             :      */
   39538           0 :     ae_assert(n>0, "RBFV2BuildHierarchical: integrity check failed", _state);
   39539           0 :     ae_vector_set_length(&ri, nh, _state);
   39540           0 :     for(levelidx=0; levelidx<=nh-1; levelidx++)
   39541             :     {
   39542           0 :         ri.ptr.p_double[levelidx] = rbase*ae_pow((double)(2), (double)(-levelidx), _state);
   39543             :     }
   39544           0 :     ae_vector_set_length(&hidx, n, _state);
   39545           0 :     ae_vector_set_length(&xr, n, _state);
   39546           0 :     for(i=0; i<=n-1; i++)
   39547             :     {
   39548           0 :         hidx.ptr.p_int[i] = nh;
   39549           0 :         xr.ptr.p_double[i] = ae_maxrealnumber;
   39550           0 :         ae_assert(ae_fp_greater(xr.ptr.p_double[i],ri.ptr.p_double[0]), "RBFV2BuildHierarchical: integrity check failed", _state);
   39551             :     }
   39552           0 :     for(levelidx=0; levelidx<=nh-1; levelidx++)
   39553             :     {
   39554             :         
   39555             :         /*
   39556             :          * Scan dataset points, for each such point that distance to nearest
   39557             :          * "support" point is larger than SupportR*Ri[LevelIdx] we:
   39558             :          * * set distance of current point to 0 (it is support now) and update HIdx
   39559             :          * * perform R-NN request with radius SupportR*Ri[LevelIdx]
   39560             :          * * for each point in request update its distance
   39561             :          */
   39562           0 :         criticalr = s->supportr*ri.ptr.p_double[levelidx];
   39563           0 :         for(i=0; i<=n-1; i++)
   39564             :         {
   39565           0 :             if( ae_fp_greater(xr.ptr.p_double[i],criticalr) )
   39566             :             {
   39567             :                 
   39568             :                 /*
   39569             :                  * Mark point as support
   39570             :                  */
   39571           0 :                 ae_assert(hidx.ptr.p_int[i]==nh, "RBFV2BuildHierarchical: integrity check failed", _state);
   39572           0 :                 hidx.ptr.p_int[i] = levelidx;
   39573           0 :                 xr.ptr.p_double[i] = (double)(0);
   39574             :                 
   39575             :                 /*
   39576             :                  * Update neighbors
   39577             :                  */
   39578           0 :                 for(j=0; j<=nx-1; j++)
   39579             :                 {
   39580           0 :                     x0.ptr.p_double[j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j];
   39581             :                 }
   39582           0 :                 k = kdtreequeryrnn(&globaltree, &x0, criticalr, ae_true, _state);
   39583           0 :                 kdtreequeryresultstags(&globaltree, &tags, _state);
   39584           0 :                 kdtreequeryresultsdistances(&globaltree, &dist, _state);
   39585           0 :                 for(j=0; j<=k-1; j++)
   39586             :                 {
   39587           0 :                     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);
   39588             :                 }
   39589             :             }
   39590             :         }
   39591             :     }
   39592             :     
   39593             :     /*
   39594             :      * Build multitree (with zero weights) according to hierarchy.
   39595             :      *
   39596             :      * NOTE: this code assumes that during every iteration kdNodes,
   39597             :      *       kdSplits and CW have size which EXACTLY fits their
   39598             :      *       contents, and that these variables are resized at each
   39599             :      *       iteration when we add new hierarchical model.
   39600             :      */
   39601           0 :     ae_vector_set_length(&kdroots, nh+1, _state);
   39602           0 :     ae_vector_set_length(&kdnodes, 0, _state);
   39603           0 :     ae_vector_set_length(&kdsplits, 0, _state);
   39604           0 :     ae_vector_set_length(&kdboxmin, nx, _state);
   39605           0 :     ae_vector_set_length(&kdboxmax, nx, _state);
   39606           0 :     ae_vector_set_length(&cw, 0, _state);
   39607           0 :     ae_vector_set_length(&cwrange, nh+1, _state);
   39608           0 :     kdtreeexplorebox(&globaltree, &kdboxmin, &kdboxmax, _state);
   39609           0 :     cwrange.ptr.p_int[0] = 0;
   39610           0 :     for(levelidx=0; levelidx<=nh-1; levelidx++)
   39611             :     {
   39612             :         
   39613             :         /*
   39614             :          * Prepare radius and root offset
   39615             :          */
   39616           0 :         kdroots.ptr.p_int[levelidx] = kdnodes.cnt;
   39617             :         
   39618             :         /*
   39619             :          * Generate LevelIdx-th tree and append to multi-tree
   39620             :          */
   39621           0 :         curn = 0;
   39622           0 :         for(i=0; i<=n-1; i++)
   39623             :         {
   39624           0 :             if( hidx.ptr.p_int[i]<=levelidx )
   39625             :             {
   39626           0 :                 for(j=0; j<=nx-1; j++)
   39627             :                 {
   39628           0 :                     curxy.ptr.pp_double[curn][j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j];
   39629             :                 }
   39630           0 :                 for(j=0; j<=ny-1; j++)
   39631             :                 {
   39632           0 :                     curxy.ptr.pp_double[curn][nx+j] = (double)(0);
   39633             :                 }
   39634           0 :                 inc(&curn, _state);
   39635             :             }
   39636             :         }
   39637           0 :         ae_assert(curn>0, "RBFV2BuildHierarchical: integrity check failed", _state);
   39638           0 :         kdtreebuild(&curxy, curn, nx, ny, 2, &curtree, _state);
   39639           0 :         rbfv2_convertandappendtree(&curtree, curn, nx, ny, &kdnodes, &kdsplits, &cw, _state);
   39640             :         
   39641             :         /*
   39642             :          * Fill entry of CWRange (we assume that length of CW exactly fits its actual size)
   39643             :          */
   39644           0 :         cwrange.ptr.p_int[levelidx+1] = cw.cnt;
   39645             :     }
   39646           0 :     kdroots.ptr.p_int[nh] = kdnodes.cnt;
   39647             :     
   39648             :     /*
   39649             :      * Prepare buffer and scaled dataset
   39650             :      */
   39651           0 :     rbfv2_allocatecalcbuffer(s, &calcbuf, _state);
   39652           0 :     for(i=0; i<=n-1; i++)
   39653             :     {
   39654           0 :         for(j=0; j<=nx-1; j++)
   39655             :         {
   39656           0 :             curxy.ptr.pp_double[i][j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j];
   39657             :         }
   39658             :     }
   39659             :     
   39660             :     /*
   39661             :      * Calculate average row sizes for each layer; these values are used
   39662             :      * for smooth progress reporting (it adds some overhead, but in most
   39663             :      * cases - insignificant one).
   39664             :      */
   39665           0 :     rvectorsetlengthatleast(&avgrowsize, nh, _state);
   39666           0 :     sumrowsize = (double)(0);
   39667           0 :     for(levelidx=0; levelidx<=nh-1; levelidx++)
   39668             :     {
   39669           0 :         cnt = 0;
   39670           0 :         for(i=0; i<=n-1; i++)
   39671             :         {
   39672           0 :             for(j=0; j<=nx-1; j++)
   39673             :             {
   39674           0 :                 x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j];
   39675             :             }
   39676           0 :             cnt = cnt+rbfv2_designmatrixrowsize(&kdnodes, &kdsplits, &cw, &ri, &kdroots, &kdboxmin, &kdboxmax, nx, ny, nh, levelidx, rbfv2nearradius(bf, _state), &x0, &calcbuf, _state);
   39677             :         }
   39678           0 :         avgrowsize.ptr.p_double[levelidx] = coalesce((double)(cnt), (double)(1), _state)/coalesce((double)(n), (double)(1), _state);
   39679           0 :         sumrowsize = sumrowsize+avgrowsize.ptr.p_double[levelidx];
   39680             :     }
   39681             :     
   39682             :     /*
   39683             :      * Build unconstrained model with LSQR solver, applied layer by layer
   39684             :      */
   39685           0 :     for(levelidx=0; levelidx<=nh-1; levelidx++)
   39686             :     {
   39687             :         
   39688             :         /*
   39689             :          * Generate A - matrix of basis functions (near radius is used)
   39690             :          *
   39691             :          * NOTE: AvgDiagATA is average value of diagonal element of A^T*A.
   39692             :          *       It is used to calculate value of Tikhonov regularization
   39693             :          *       coefficient.
   39694             :          */
   39695           0 :         nbasis = (cwrange.ptr.p_int[levelidx+1]-cwrange.ptr.p_int[levelidx])/(nx+ny);
   39696           0 :         ae_assert(cwrange.ptr.p_int[levelidx+1]-cwrange.ptr.p_int[levelidx]==nbasis*(nx+ny), "Assertion failed", _state);
   39697           0 :         for(i=0; i<=n-1; i++)
   39698             :         {
   39699           0 :             for(j=0; j<=nx-1; j++)
   39700             :             {
   39701           0 :                 x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j];
   39702             :             }
   39703           0 :             cnt = rbfv2_designmatrixrowsize(&kdnodes, &kdsplits, &cw, &ri, &kdroots, &kdboxmin, &kdboxmax, nx, ny, nh, levelidx, rbfv2nearradius(bf, _state), &x0, &calcbuf, _state);
   39704           0 :             nncnt.ptr.p_int[i] = cnt;
   39705           0 :             for(j=0; j<=rowsperpoint-1; j++)
   39706             :             {
   39707           0 :                 rowsizes.ptr.p_int[i*rowsperpoint+j] = cnt;
   39708             :             }
   39709             :         }
   39710           0 :         ivectorsetlengthatleast(&rowindexes, nbasis, _state);
   39711           0 :         rvectorsetlengthatleast(&rowvals, nbasis*rowsperpoint, _state);
   39712           0 :         rvectorsetlengthatleast(&diagata, nbasis, _state);
   39713           0 :         sparsecreatecrsbuf(n*rowsperpoint, nbasis, &rowsizes, &sparseacrs, _state);
   39714           0 :         avgdiagata = 0.0;
   39715           0 :         for(j=0; j<=nbasis-1; j++)
   39716             :         {
   39717           0 :             diagata.ptr.p_double[j] = (double)(0);
   39718             :         }
   39719           0 :         for(i=0; i<=n-1; i++)
   39720             :         {
   39721             :             
   39722             :             /*
   39723             :              * Fill design matrix row, diagonal of A^T*A
   39724             :              */
   39725           0 :             for(j=0; j<=nx-1; j++)
   39726             :             {
   39727           0 :                 x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j];
   39728             :             }
   39729           0 :             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);
   39730           0 :             ae_assert(cnt==nncnt.ptr.p_int[i], "RBFV2BuildHierarchical: integrity check failed", _state);
   39731           0 :             for(k=0; k<=rowsperpoint-1; k++)
   39732             :             {
   39733           0 :                 for(j=0; j<=cnt-1; j++)
   39734             :                 {
   39735           0 :                     val = rowvals.ptr.p_double[j*rowsperpoint+k];
   39736           0 :                     sparseset(&sparseacrs, i*rowsperpoint+k, rowindexes.ptr.p_int[j], val, _state);
   39737           0 :                     avgdiagata = avgdiagata+ae_sqr(val, _state);
   39738           0 :                     diagata.ptr.p_double[rowindexes.ptr.p_int[j]] = diagata.ptr.p_double[rowindexes.ptr.p_int[j]]+ae_sqr(val, _state);
   39739             :                 }
   39740             :             }
   39741             :             
   39742             :             /*
   39743             :              * Handle possible termination requests
   39744             :              */
   39745           0 :             if( *terminationrequest )
   39746             :             {
   39747             :                 
   39748             :                 /*
   39749             :                  * Request for termination was submitted, terminate immediately
   39750             :                  */
   39751           0 :                 rbfv2_zerofill(s, nx, ny, bf, _state);
   39752           0 :                 rep->terminationtype = 8;
   39753           0 :                 *progress10000 = 10000;
   39754           0 :                 ae_frame_leave(_state);
   39755           0 :                 return;
   39756             :             }
   39757             :         }
   39758           0 :         avgdiagata = avgdiagata/nbasis;
   39759           0 :         rvectorsetlengthatleast(&prec, nbasis, _state);
   39760           0 :         for(j=0; j<=nbasis-1; j++)
   39761             :         {
   39762           0 :             prec.ptr.p_double[j] = 1/coalesce(ae_sqrt(diagata.ptr.p_double[j], _state), (double)(1), _state);
   39763             :         }
   39764             :         
   39765             :         /*
   39766             :          * solve
   39767             :          */
   39768           0 :         maxits = coalescei(s->maxits, rbfv2_defaultmaxits, _state);
   39769           0 :         rvectorsetlengthatleast(&tmpx, nbasis, _state);
   39770           0 :         linlsqrcreate(n*rowsperpoint, nbasis, &linstate, _state);
   39771           0 :         linlsqrsetcond(&linstate, 0.0, 0.0, maxits, _state);
   39772           0 :         linlsqrsetlambdai(&linstate, ae_sqrt(s->lambdareg*avgdiagata, _state), _state);
   39773           0 :         for(j=0; j<=ny-1; j++)
   39774             :         {
   39775           0 :             for(i=0; i<=n*rowsperpoint-1; i++)
   39776             :             {
   39777           0 :                 denseb1.ptr.p_double[i] = rhs.ptr.pp_double[i][j];
   39778             :             }
   39779           0 :             linlsqrsetb(&linstate, &denseb1, _state);
   39780           0 :             linlsqrrestart(&linstate, _state);
   39781           0 :             linlsqrsetxrep(&linstate, ae_true, _state);
   39782           0 :             while(linlsqriteration(&linstate, _state))
   39783             :             {
   39784           0 :                 if( *terminationrequest )
   39785             :                 {
   39786             :                     
   39787             :                     /*
   39788             :                      * Request for termination was submitted, terminate immediately
   39789             :                      */
   39790           0 :                     rbfv2_zerofill(s, nx, ny, bf, _state);
   39791           0 :                     rep->terminationtype = 8;
   39792           0 :                     *progress10000 = 10000;
   39793           0 :                     ae_frame_leave(_state);
   39794           0 :                     return;
   39795             :                 }
   39796           0 :                 if( linstate.needmv )
   39797             :                 {
   39798           0 :                     for(i=0; i<=nbasis-1; i++)
   39799             :                     {
   39800           0 :                         tmpx.ptr.p_double[i] = prec.ptr.p_double[i]*linstate.x.ptr.p_double[i];
   39801             :                     }
   39802           0 :                     sparsemv(&sparseacrs, &tmpx, &linstate.mv, _state);
   39803           0 :                     continue;
   39804             :                 }
   39805           0 :                 if( linstate.needmtv )
   39806             :                 {
   39807           0 :                     sparsemtv(&sparseacrs, &linstate.x, &linstate.mtv, _state);
   39808           0 :                     for(i=0; i<=nbasis-1; i++)
   39809             :                     {
   39810           0 :                         linstate.mtv.ptr.p_double[i] = prec.ptr.p_double[i]*linstate.mtv.ptr.p_double[i];
   39811             :                     }
   39812           0 :                     continue;
   39813             :                 }
   39814           0 :                 if( linstate.xupdated )
   39815             :                 {
   39816           0 :                     rprogress = (double)(0);
   39817           0 :                     for(i=0; i<=levelidx-1; i++)
   39818             :                     {
   39819           0 :                         rprogress = rprogress+maxits*ny*avgrowsize.ptr.p_double[i];
   39820             :                     }
   39821           0 :                     rprogress = rprogress+(linlsqrpeekiterationscount(&linstate, _state)+j*maxits)*avgrowsize.ptr.p_double[levelidx];
   39822           0 :                     rprogress = rprogress/(sumrowsize*maxits*ny);
   39823           0 :                     rprogress = 10000*rprogress;
   39824           0 :                     rprogress = ae_maxreal(rprogress, (double)(0), _state);
   39825           0 :                     rprogress = ae_minreal(rprogress, (double)(10000), _state);
   39826           0 :                     ae_assert(*progress10000<=ae_round(rprogress, _state)+1, "HRBF: integrity check failed (progress indicator) even after +1 safeguard correction", _state);
   39827           0 :                     *progress10000 = ae_round(rprogress, _state);
   39828           0 :                     continue;
   39829             :                 }
   39830           0 :                 ae_assert(ae_false, "HRBF: unexpected request from LSQR solver", _state);
   39831             :             }
   39832           0 :             linlsqrresults(&linstate, &densew1, &lsqrrep, _state);
   39833           0 :             ae_assert(lsqrrep.terminationtype>0, "RBFV2BuildHierarchical: integrity check failed", _state);
   39834           0 :             for(i=0; i<=nbasis-1; i++)
   39835             :             {
   39836           0 :                 densew1.ptr.p_double[i] = prec.ptr.p_double[i]*densew1.ptr.p_double[i];
   39837             :             }
   39838           0 :             for(i=0; i<=nbasis-1; i++)
   39839             :             {
   39840           0 :                 offsi = cwrange.ptr.p_int[levelidx]+(nx+ny)*i;
   39841           0 :                 cw.ptr.p_double[offsi+nx+j] = densew1.ptr.p_double[i];
   39842             :             }
   39843             :         }
   39844             :         
   39845             :         /*
   39846             :          * Update residuals (far radius is used)
   39847             :          */
   39848           0 :         for(i=0; i<=n-1; i++)
   39849             :         {
   39850           0 :             for(j=0; j<=nx-1; j++)
   39851             :             {
   39852           0 :                 x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j];
   39853             :             }
   39854           0 :             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);
   39855           0 :             for(j=0; j<=cnt-1; j++)
   39856             :             {
   39857           0 :                 offsj = cwrange.ptr.p_int[levelidx]+(nx+ny)*rowindexes.ptr.p_int[j]+nx;
   39858           0 :                 for(k=0; k<=rowsperpoint-1; k++)
   39859             :                 {
   39860           0 :                     val = rowvals.ptr.p_double[j*rowsperpoint+k];
   39861           0 :                     for(k2=0; k2<=ny-1; k2++)
   39862             :                     {
   39863           0 :                         rhs.ptr.pp_double[i*rowsperpoint+k][k2] = rhs.ptr.pp_double[i*rowsperpoint+k][k2]-val*cw.ptr.p_double[offsj+k2];
   39864             :                     }
   39865             :                 }
   39866             :             }
   39867             :         }
   39868             :     }
   39869             :     
   39870             :     /*
   39871             :      * Model is built.
   39872             :      *
   39873             :      * Copy local variables by swapping, global ones (ScaleVec) are copied
   39874             :      * explicitly.
   39875             :      */
   39876           0 :     s->bf = bf;
   39877           0 :     s->nh = nh;
   39878           0 :     ae_swap_vectors(&s->ri, &ri);
   39879           0 :     ae_swap_vectors(&s->kdroots, &kdroots);
   39880           0 :     ae_swap_vectors(&s->kdnodes, &kdnodes);
   39881           0 :     ae_swap_vectors(&s->kdsplits, &kdsplits);
   39882           0 :     ae_swap_vectors(&s->kdboxmin, &kdboxmin);
   39883           0 :     ae_swap_vectors(&s->kdboxmax, &kdboxmax);
   39884           0 :     ae_swap_vectors(&s->cw, &cw);
   39885           0 :     ae_swap_matrices(&s->v, &v);
   39886           0 :     ae_vector_set_length(&s->s, nx, _state);
   39887           0 :     for(i=0; i<=nx-1; i++)
   39888             :     {
   39889           0 :         s->s.ptr.p_double[i] = scalevec->ptr.p_double[i];
   39890             :     }
   39891           0 :     rep->terminationtype = 1;
   39892             :     
   39893             :     /*
   39894             :      * Calculate maximum and RMS errors
   39895             :      */
   39896           0 :     rep->maxerror = (double)(0);
   39897           0 :     rep->rmserror = (double)(0);
   39898           0 :     for(i=0; i<=n-1; i++)
   39899             :     {
   39900           0 :         for(j=0; j<=ny-1; j++)
   39901             :         {
   39902           0 :             rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(rhs.ptr.pp_double[i*rowsperpoint][j], _state), _state);
   39903           0 :             rep->rmserror = rep->rmserror+ae_sqr(rhs.ptr.pp_double[i*rowsperpoint][j], _state);
   39904             :         }
   39905             :     }
   39906           0 :     rep->rmserror = ae_sqrt(rep->rmserror/(n*ny), _state);
   39907             :     
   39908             :     /*
   39909             :      * Update progress reports
   39910             :      */
   39911           0 :     *progress10000 = 10000;
   39912           0 :     ae_frame_leave(_state);
   39913             : }
   39914             : 
   39915             : 
   39916             : /*************************************************************************
   39917             : Serializer: allocation
   39918             : 
   39919             :   -- ALGLIB --
   39920             :      Copyright 02.02.2012 by Bochkanov Sergey
   39921             : *************************************************************************/
   39922           0 : void rbfv2alloc(ae_serializer* s, rbfv2model* model, ae_state *_state)
   39923             : {
   39924             : 
   39925             : 
   39926             :     
   39927             :     /*
   39928             :      * Data
   39929             :      */
   39930           0 :     ae_serializer_alloc_entry(s);
   39931           0 :     ae_serializer_alloc_entry(s);
   39932           0 :     ae_serializer_alloc_entry(s);
   39933           0 :     ae_serializer_alloc_entry(s);
   39934           0 :     allocrealarray(s, &model->ri, -1, _state);
   39935           0 :     allocrealarray(s, &model->s, -1, _state);
   39936           0 :     allocintegerarray(s, &model->kdroots, -1, _state);
   39937           0 :     allocintegerarray(s, &model->kdnodes, -1, _state);
   39938           0 :     allocrealarray(s, &model->kdsplits, -1, _state);
   39939           0 :     allocrealarray(s, &model->kdboxmin, -1, _state);
   39940           0 :     allocrealarray(s, &model->kdboxmax, -1, _state);
   39941           0 :     allocrealarray(s, &model->cw, -1, _state);
   39942           0 :     allocrealmatrix(s, &model->v, -1, -1, _state);
   39943           0 : }
   39944             : 
   39945             : 
   39946             : /*************************************************************************
   39947             : Serializer: serialization
   39948             : 
   39949             :   -- ALGLIB --
   39950             :      Copyright 02.02.2012 by Bochkanov Sergey
   39951             : *************************************************************************/
   39952           0 : void rbfv2serialize(ae_serializer* s, rbfv2model* model, ae_state *_state)
   39953             : {
   39954             : 
   39955             : 
   39956             :     
   39957             :     /*
   39958             :      * Data
   39959             :      */
   39960           0 :     ae_serializer_serialize_int(s, model->nx, _state);
   39961           0 :     ae_serializer_serialize_int(s, model->ny, _state);
   39962           0 :     ae_serializer_serialize_int(s, model->nh, _state);
   39963           0 :     ae_serializer_serialize_int(s, model->bf, _state);
   39964           0 :     serializerealarray(s, &model->ri, -1, _state);
   39965           0 :     serializerealarray(s, &model->s, -1, _state);
   39966           0 :     serializeintegerarray(s, &model->kdroots, -1, _state);
   39967           0 :     serializeintegerarray(s, &model->kdnodes, -1, _state);
   39968           0 :     serializerealarray(s, &model->kdsplits, -1, _state);
   39969           0 :     serializerealarray(s, &model->kdboxmin, -1, _state);
   39970           0 :     serializerealarray(s, &model->kdboxmax, -1, _state);
   39971           0 :     serializerealarray(s, &model->cw, -1, _state);
   39972           0 :     serializerealmatrix(s, &model->v, -1, -1, _state);
   39973           0 : }
   39974             : 
   39975             : 
   39976             : /*************************************************************************
   39977             : Serializer: unserialization
   39978             : 
   39979             :   -- ALGLIB --
   39980             :      Copyright 02.02.2012 by Bochkanov Sergey
   39981             : *************************************************************************/
   39982           0 : void rbfv2unserialize(ae_serializer* s,
   39983             :      rbfv2model* model,
   39984             :      ae_state *_state)
   39985             : {
   39986             :     ae_int_t nx;
   39987             :     ae_int_t ny;
   39988             : 
   39989           0 :     _rbfv2model_clear(model);
   39990             : 
   39991             :     
   39992             :     /*
   39993             :      * Unserialize primary model parameters, initialize model.
   39994             :      *
   39995             :      * It is necessary to call RBFCreate() because some internal fields
   39996             :      * which are NOT unserialized will need initialization.
   39997             :      */
   39998           0 :     ae_serializer_unserialize_int(s, &nx, _state);
   39999           0 :     ae_serializer_unserialize_int(s, &ny, _state);
   40000           0 :     rbfv2create(nx, ny, model, _state);
   40001           0 :     ae_serializer_unserialize_int(s, &model->nh, _state);
   40002           0 :     ae_serializer_unserialize_int(s, &model->bf, _state);
   40003           0 :     unserializerealarray(s, &model->ri, _state);
   40004           0 :     unserializerealarray(s, &model->s, _state);
   40005           0 :     unserializeintegerarray(s, &model->kdroots, _state);
   40006           0 :     unserializeintegerarray(s, &model->kdnodes, _state);
   40007           0 :     unserializerealarray(s, &model->kdsplits, _state);
   40008           0 :     unserializerealarray(s, &model->kdboxmin, _state);
   40009           0 :     unserializerealarray(s, &model->kdboxmax, _state);
   40010           0 :     unserializerealarray(s, &model->cw, _state);
   40011           0 :     unserializerealmatrix(s, &model->v, _state);
   40012           0 : }
   40013             : 
   40014             : 
   40015             : /*************************************************************************
   40016             : Returns far radius for basis function type
   40017             : *************************************************************************/
   40018           0 : double rbfv2farradius(ae_int_t bf, ae_state *_state)
   40019             : {
   40020             :     double result;
   40021             : 
   40022             : 
   40023           0 :     result = (double)(1);
   40024           0 :     if( bf==0 )
   40025             :     {
   40026           0 :         result = 5.0;
   40027             :     }
   40028           0 :     if( bf==1 )
   40029             :     {
   40030           0 :         result = (double)(3);
   40031             :     }
   40032           0 :     return result;
   40033             : }
   40034             : 
   40035             : 
   40036             : /*************************************************************************
   40037             : Returns near radius for basis function type
   40038             : *************************************************************************/
   40039           0 : double rbfv2nearradius(ae_int_t bf, ae_state *_state)
   40040             : {
   40041             :     double result;
   40042             : 
   40043             : 
   40044           0 :     result = (double)(1);
   40045           0 :     if( bf==0 )
   40046             :     {
   40047           0 :         result = 3.0;
   40048             :     }
   40049           0 :     if( bf==1 )
   40050             :     {
   40051           0 :         result = (double)(3);
   40052             :     }
   40053           0 :     return result;
   40054             : }
   40055             : 
   40056             : 
   40057             : /*************************************************************************
   40058             : Returns basis function value.
   40059             : Assumes that D2>=0
   40060             : *************************************************************************/
   40061           0 : double rbfv2basisfunc(ae_int_t bf, double d2, ae_state *_state)
   40062             : {
   40063             :     double v;
   40064             :     double result;
   40065             : 
   40066             : 
   40067           0 :     result = (double)(0);
   40068           0 :     if( bf==0 )
   40069             :     {
   40070           0 :         result = ae_exp(-d2, _state);
   40071           0 :         return result;
   40072             :     }
   40073           0 :     if( bf==1 )
   40074             :     {
   40075             :         
   40076             :         /*
   40077             :          * if D2<3:
   40078             :          *     Exp(1)*Exp(-D2)*Exp(-1/(1-D2/9))
   40079             :          * else:
   40080             :          *     0
   40081             :          */
   40082           0 :         v = 1-d2/9;
   40083           0 :         if( ae_fp_less_eq(v,(double)(0)) )
   40084             :         {
   40085           0 :             result = (double)(0);
   40086           0 :             return result;
   40087             :         }
   40088           0 :         result = 2.718281828459045*ae_exp(-d2, _state)*ae_exp(-1/v, _state);
   40089           0 :         return result;
   40090             :     }
   40091           0 :     ae_assert(ae_false, "RBFV2BasisFunc: unknown BF type", _state);
   40092           0 :     return result;
   40093             : }
   40094             : 
   40095             : 
   40096             : /*************************************************************************
   40097             : Returns basis function value, first and second derivatives
   40098             : Assumes that D2>=0
   40099             : *************************************************************************/
   40100           0 : void rbfv2basisfuncdiff2(ae_int_t bf,
   40101             :      double d2,
   40102             :      double* f,
   40103             :      double* df,
   40104             :      double* d2f,
   40105             :      ae_state *_state)
   40106             : {
   40107             :     double v;
   40108             : 
   40109           0 :     *f = 0;
   40110           0 :     *df = 0;
   40111           0 :     *d2f = 0;
   40112             : 
   40113           0 :     if( bf==0 )
   40114             :     {
   40115           0 :         *f = ae_exp(-d2, _state);
   40116           0 :         *df = -*f;
   40117           0 :         *d2f = *f;
   40118           0 :         return;
   40119             :     }
   40120           0 :     if( bf==1 )
   40121             :     {
   40122             :         
   40123             :         /*
   40124             :          * if D2<3:
   40125             :          *       F = Exp(1)*Exp(-D2)*Exp(-1/(1-D2/9))
   40126             :          *      dF =  -F * [pow(D2/9-1,-2)/9 + 1]
   40127             :          *     d2F = -dF * [pow(D2/9-1,-2)/9 + 1] + F*(2/81)*pow(D2/9-1,-3)
   40128             :          * else:
   40129             :          *     0
   40130             :          */
   40131           0 :         v = 1-d2/9;
   40132           0 :         if( ae_fp_less_eq(v,(double)(0)) )
   40133             :         {
   40134           0 :             *f = (double)(0);
   40135           0 :             *df = (double)(0);
   40136           0 :             *d2f = (double)(0);
   40137           0 :             return;
   40138             :         }
   40139           0 :         *f = ae_exp((double)(1), _state)*ae_exp(-d2, _state)*ae_exp(-1/v, _state);
   40140           0 :         *df = -*f*(1/(9*v*v)+1);
   40141           0 :         *d2f = -*df*(1/(9*v*v)+1)+*f*((double)2/(double)81)/(v*v*v);
   40142           0 :         return;
   40143             :     }
   40144           0 :     ae_assert(ae_false, "RBFV2BasisFuncDiff2: unknown BF type", _state);
   40145             : }
   40146             : 
   40147             : 
   40148             : /*************************************************************************
   40149             : This function calculates values of the RBF model in the given point.
   40150             : 
   40151             : This function should be used when we have NY=1 (scalar function) and  NX=1
   40152             : (1-dimensional space).
   40153             : 
   40154             : This function returns 0.0 when:
   40155             : * model is not initialized
   40156             : * NX<>1
   40157             :  *NY<>1
   40158             : 
   40159             : INPUT PARAMETERS:
   40160             :     S       -   RBF model
   40161             :     X0      -   X-coordinate, finite number
   40162             : 
   40163             : RESULT:
   40164             :     value of the model or 0.0 (as defined above)
   40165             : 
   40166             :   -- ALGLIB --
   40167             :      Copyright 13.12.2011 by Bochkanov Sergey
   40168             : *************************************************************************/
   40169           0 : double rbfv2calc1(rbfv2model* s, double x0, ae_state *_state)
   40170             : {
   40171             :     double result;
   40172             : 
   40173             : 
   40174           0 :     ae_assert(ae_isfinite(x0, _state), "RBFCalc1: invalid value for X0 (X0 is Inf)!", _state);
   40175           0 :     if( s->ny!=1||s->nx!=1 )
   40176             :     {
   40177           0 :         result = (double)(0);
   40178           0 :         return result;
   40179             :     }
   40180           0 :     result = s->v.ptr.pp_double[0][0]*x0-s->v.ptr.pp_double[0][1];
   40181           0 :     if( s->nh==0 )
   40182             :     {
   40183           0 :         return result;
   40184             :     }
   40185           0 :     rbfv2_allocatecalcbuffer(s, &s->calcbuf, _state);
   40186           0 :     s->calcbuf.x123.ptr.p_double[0] = x0;
   40187           0 :     rbfv2tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state);
   40188           0 :     result = s->calcbuf.y123.ptr.p_double[0];
   40189           0 :     return result;
   40190             : }
   40191             : 
   40192             : 
   40193             : /*************************************************************************
   40194             : This function calculates values of the RBF model in the given point.
   40195             : 
   40196             : This function should be used when we have NY=1 (scalar function) and  NX=2
   40197             : (2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If
   40198             : you have general situation (NX-dimensional space, NY-dimensional function)
   40199             : you should use general, less efficient implementation RBFCalc().
   40200             : 
   40201             : If  you  want  to  calculate  function  values  many times, consider using 
   40202             : RBFGridCalc2(), which is far more efficient than many subsequent calls  to
   40203             : RBFCalc2().
   40204             : 
   40205             : This function returns 0.0 when:
   40206             : * model is not initialized
   40207             : * NX<>2
   40208             :  *NY<>1
   40209             : 
   40210             : INPUT PARAMETERS:
   40211             :     S       -   RBF model
   40212             :     X0      -   first coordinate, finite number
   40213             :     X1      -   second coordinate, finite number
   40214             : 
   40215             : RESULT:
   40216             :     value of the model or 0.0 (as defined above)
   40217             : 
   40218             :   -- ALGLIB --
   40219             :      Copyright 13.12.2011 by Bochkanov Sergey
   40220             : *************************************************************************/
   40221           0 : double rbfv2calc2(rbfv2model* s, double x0, double x1, ae_state *_state)
   40222             : {
   40223             :     double result;
   40224             : 
   40225             : 
   40226           0 :     ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state);
   40227           0 :     ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state);
   40228           0 :     if( s->ny!=1||s->nx!=2 )
   40229             :     {
   40230           0 :         result = (double)(0);
   40231           0 :         return result;
   40232             :     }
   40233           0 :     result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2];
   40234           0 :     if( s->nh==0 )
   40235             :     {
   40236           0 :         return result;
   40237             :     }
   40238           0 :     rbfv2_allocatecalcbuffer(s, &s->calcbuf, _state);
   40239           0 :     s->calcbuf.x123.ptr.p_double[0] = x0;
   40240           0 :     s->calcbuf.x123.ptr.p_double[1] = x1;
   40241           0 :     rbfv2tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state);
   40242           0 :     result = s->calcbuf.y123.ptr.p_double[0];
   40243           0 :     return result;
   40244             : }
   40245             : 
   40246             : 
   40247             : /*************************************************************************
   40248             : This function calculates values of the RBF model in the given point.
   40249             : 
   40250             : This function should be used when we have NY=1 (scalar function) and  NX=3
   40251             : (3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If
   40252             : you have general situation (NX-dimensional space, NY-dimensional function)
   40253             : you should use general, less efficient implementation RBFCalc().
   40254             : 
   40255             : This function returns 0.0 when:
   40256             : * model is not initialized
   40257             : * NX<>3
   40258             :  *NY<>1
   40259             : 
   40260             : INPUT PARAMETERS:
   40261             :     S       -   RBF model
   40262             :     X0      -   first coordinate, finite number
   40263             :     X1      -   second coordinate, finite number
   40264             :     X2      -   third coordinate, finite number
   40265             : 
   40266             : RESULT:
   40267             :     value of the model or 0.0 (as defined above)
   40268             : 
   40269             :   -- ALGLIB --
   40270             :      Copyright 13.12.2011 by Bochkanov Sergey
   40271             : *************************************************************************/
   40272           0 : double rbfv2calc3(rbfv2model* s,
   40273             :      double x0,
   40274             :      double x1,
   40275             :      double x2,
   40276             :      ae_state *_state)
   40277             : {
   40278             :     double result;
   40279             : 
   40280             : 
   40281           0 :     ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state);
   40282           0 :     ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state);
   40283           0 :     ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state);
   40284           0 :     if( s->ny!=1||s->nx!=3 )
   40285             :     {
   40286           0 :         result = (double)(0);
   40287           0 :         return result;
   40288             :     }
   40289           0 :     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];
   40290           0 :     if( s->nh==0 )
   40291             :     {
   40292           0 :         return result;
   40293             :     }
   40294           0 :     rbfv2_allocatecalcbuffer(s, &s->calcbuf, _state);
   40295           0 :     s->calcbuf.x123.ptr.p_double[0] = x0;
   40296           0 :     s->calcbuf.x123.ptr.p_double[1] = x1;
   40297           0 :     s->calcbuf.x123.ptr.p_double[2] = x2;
   40298           0 :     rbfv2tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state);
   40299           0 :     result = s->calcbuf.y123.ptr.p_double[0];
   40300           0 :     return result;
   40301             : }
   40302             : 
   40303             : 
   40304             : /*************************************************************************
   40305             : This function calculates values of the RBF model at the given point.
   40306             : 
   40307             : Same as RBFCalc(), but does not reallocate Y when in is large enough to 
   40308             : store function values.
   40309             : 
   40310             : INPUT PARAMETERS:
   40311             :     S       -   RBF model
   40312             :     X       -   coordinates, array[NX].
   40313             :                 X may have more than NX elements, in this case only 
   40314             :                 leading NX will be used.
   40315             :     Y       -   possibly preallocated array
   40316             : 
   40317             : OUTPUT PARAMETERS:
   40318             :     Y       -   function value, array[NY]. Y is not reallocated when it
   40319             :                 is larger than NY.
   40320             : 
   40321             :   -- ALGLIB --
   40322             :      Copyright 13.12.2011 by Bochkanov Sergey
   40323             : *************************************************************************/
   40324           0 : void rbfv2calcbuf(rbfv2model* s,
   40325             :      /* Real    */ ae_vector* x,
   40326             :      /* Real    */ ae_vector* y,
   40327             :      ae_state *_state)
   40328             : {
   40329             : 
   40330             : 
   40331           0 :     rbfv2tscalcbuf(s, &s->calcbuf, x, y, _state);
   40332           0 : }
   40333             : 
   40334             : 
   40335             : /*************************************************************************
   40336             : This function calculates values of the RBF model at the given point, using
   40337             : external  buffer  object  (internal  temporaries  of  RBF  model  are  not
   40338             : modified).
   40339             : 
   40340             : This function allows to use same RBF model object  in  different  threads,
   40341             : assuming  that  different   threads  use  different  instances  of  buffer
   40342             : structure.
   40343             : 
   40344             : INPUT PARAMETERS:
   40345             :     S       -   RBF model, may be shared between different threads
   40346             :     Buf     -   buffer object created for this particular instance of  RBF
   40347             :                 model with rbfcreatecalcbuffer().
   40348             :     X       -   coordinates, array[NX].
   40349             :                 X may have more than NX elements, in this case only 
   40350             :                 leading NX will be used.
   40351             :     Y       -   possibly preallocated array
   40352             : 
   40353             : OUTPUT PARAMETERS:
   40354             :     Y       -   function value, array[NY]. Y is not reallocated when it
   40355             :                 is larger than NY.
   40356             : 
   40357             :   -- ALGLIB --
   40358             :      Copyright 13.12.2011 by Bochkanov Sergey
   40359             : *************************************************************************/
   40360           0 : void rbfv2tscalcbuf(rbfv2model* s,
   40361             :      rbfv2calcbuffer* buf,
   40362             :      /* Real    */ ae_vector* x,
   40363             :      /* Real    */ ae_vector* y,
   40364             :      ae_state *_state)
   40365             : {
   40366             :     ae_int_t i;
   40367             :     ae_int_t j;
   40368             :     ae_int_t levelidx;
   40369             :     double rcur;
   40370             :     double rquery2;
   40371             :     double invrc2;
   40372             :     ae_int_t nx;
   40373             :     ae_int_t ny;
   40374             : 
   40375             : 
   40376           0 :     ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)<NX", _state);
   40377           0 :     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state);
   40378           0 :     nx = s->nx;
   40379           0 :     ny = s->ny;
   40380             :     
   40381             :     /*
   40382             :      * Handle linear term
   40383             :      */
   40384           0 :     if( y->cnt<ny )
   40385             :     {
   40386           0 :         ae_vector_set_length(y, ny, _state);
   40387             :     }
   40388           0 :     for(i=0; i<=ny-1; i++)
   40389             :     {
   40390           0 :         y->ptr.p_double[i] = s->v.ptr.pp_double[i][nx];
   40391           0 :         for(j=0; j<=nx-1; j++)
   40392             :         {
   40393           0 :             y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j];
   40394             :         }
   40395             :     }
   40396           0 :     if( s->nh==0 )
   40397             :     {
   40398           0 :         return;
   40399             :     }
   40400             :     
   40401             :     /*
   40402             :      * Handle nonlinear term
   40403             :      */
   40404           0 :     rbfv2_allocatecalcbuffer(s, buf, _state);
   40405           0 :     for(j=0; j<=nx-1; j++)
   40406             :     {
   40407           0 :         buf->x.ptr.p_double[j] = x->ptr.p_double[j]/s->s.ptr.p_double[j];
   40408             :     }
   40409           0 :     for(levelidx=0; levelidx<=s->nh-1; levelidx++)
   40410             :     {
   40411             :         
   40412             :         /*
   40413             :          * Prepare fields of Buf required by PartialCalcRec()
   40414             :          */
   40415           0 :         buf->curdist2 = (double)(0);
   40416           0 :         for(j=0; j<=nx-1; j++)
   40417             :         {
   40418           0 :             buf->curboxmin.ptr.p_double[j] = s->kdboxmin.ptr.p_double[j];
   40419           0 :             buf->curboxmax.ptr.p_double[j] = s->kdboxmax.ptr.p_double[j];
   40420           0 :             if( ae_fp_less(buf->x.ptr.p_double[j],buf->curboxmin.ptr.p_double[j]) )
   40421             :             {
   40422           0 :                 buf->curdist2 = buf->curdist2+ae_sqr(buf->curboxmin.ptr.p_double[j]-buf->x.ptr.p_double[j], _state);
   40423             :             }
   40424             :             else
   40425             :             {
   40426           0 :                 if( ae_fp_greater(buf->x.ptr.p_double[j],buf->curboxmax.ptr.p_double[j]) )
   40427             :                 {
   40428           0 :                     buf->curdist2 = buf->curdist2+ae_sqr(buf->x.ptr.p_double[j]-buf->curboxmax.ptr.p_double[j], _state);
   40429             :                 }
   40430             :             }
   40431             :         }
   40432             :         
   40433             :         /*
   40434             :          * Call PartialCalcRec()
   40435             :          */
   40436           0 :         rcur = s->ri.ptr.p_double[levelidx];
   40437           0 :         invrc2 = 1/(rcur*rcur);
   40438           0 :         rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state);
   40439           0 :         rbfv2_partialcalcrec(s, buf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, &buf->x, y, _state);
   40440             :     }
   40441             : }
   40442             : 
   40443             : 
   40444             : /*************************************************************************
   40445             : This function calculates values of the RBF model at the regular grid.
   40446             : 
   40447             : Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J])
   40448             : 
   40449             : This function returns 0.0 when:
   40450             : * model is not initialized
   40451             : * NX<>2
   40452             :  *NY<>1
   40453             : 
   40454             : INPUT PARAMETERS:
   40455             :     S       -   RBF model
   40456             :     X0      -   array of grid nodes, first coordinates, array[N0]
   40457             :     N0      -   grid size (number of nodes) in the first dimension
   40458             :     X1      -   array of grid nodes, second coordinates, array[N1]
   40459             :     N1      -   grid size (number of nodes) in the second dimension
   40460             : 
   40461             : OUTPUT PARAMETERS:
   40462             :     Y       -   function values, array[N0,N1]. Y is out-variable and 
   40463             :                 is reallocated by this function.
   40464             :                 
   40465             : NOTE: as a special exception, this function supports unordered  arrays  X0
   40466             :       and X1. However, future versions may be  more  efficient  for  X0/X1
   40467             :       ordered by ascending.
   40468             : 
   40469             :   -- ALGLIB --
   40470             :      Copyright 13.12.2011 by Bochkanov Sergey
   40471             : *************************************************************************/
   40472           0 : void rbfv2gridcalc2(rbfv2model* s,
   40473             :      /* Real    */ ae_vector* x0,
   40474             :      ae_int_t n0,
   40475             :      /* Real    */ ae_vector* x1,
   40476             :      ae_int_t n1,
   40477             :      /* Real    */ ae_matrix* y,
   40478             :      ae_state *_state)
   40479             : {
   40480             :     ae_frame _frame_block;
   40481             :     ae_vector cpx0;
   40482             :     ae_vector cpx1;
   40483             :     ae_vector dummyx2;
   40484             :     ae_vector dummyx3;
   40485             :     ae_vector dummyflag;
   40486             :     ae_vector p01;
   40487             :     ae_vector p11;
   40488             :     ae_vector p2;
   40489             :     ae_vector vy;
   40490             :     ae_int_t i;
   40491             :     ae_int_t j;
   40492             : 
   40493           0 :     ae_frame_make(_state, &_frame_block);
   40494           0 :     memset(&cpx0, 0, sizeof(cpx0));
   40495           0 :     memset(&cpx1, 0, sizeof(cpx1));
   40496           0 :     memset(&dummyx2, 0, sizeof(dummyx2));
   40497           0 :     memset(&dummyx3, 0, sizeof(dummyx3));
   40498           0 :     memset(&dummyflag, 0, sizeof(dummyflag));
   40499           0 :     memset(&p01, 0, sizeof(p01));
   40500           0 :     memset(&p11, 0, sizeof(p11));
   40501           0 :     memset(&p2, 0, sizeof(p2));
   40502           0 :     memset(&vy, 0, sizeof(vy));
   40503           0 :     ae_matrix_clear(y);
   40504           0 :     ae_vector_init(&cpx0, 0, DT_REAL, _state, ae_true);
   40505           0 :     ae_vector_init(&cpx1, 0, DT_REAL, _state, ae_true);
   40506           0 :     ae_vector_init(&dummyx2, 0, DT_REAL, _state, ae_true);
   40507           0 :     ae_vector_init(&dummyx3, 0, DT_REAL, _state, ae_true);
   40508           0 :     ae_vector_init(&dummyflag, 0, DT_BOOL, _state, ae_true);
   40509           0 :     ae_vector_init(&p01, 0, DT_INT, _state, ae_true);
   40510           0 :     ae_vector_init(&p11, 0, DT_INT, _state, ae_true);
   40511           0 :     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
   40512           0 :     ae_vector_init(&vy, 0, DT_REAL, _state, ae_true);
   40513             : 
   40514           0 :     ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state);
   40515           0 :     ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state);
   40516           0 :     ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)<N0", _state);
   40517           0 :     ae_assert(x1->cnt>=n1, "RBFGridCalc2: Length(X1)<N1", _state);
   40518           0 :     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2: X0 contains infinite or NaN values!", _state);
   40519           0 :     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2: X1 contains infinite or NaN values!", _state);
   40520           0 :     ae_matrix_set_length(y, n0, n1, _state);
   40521           0 :     for(i=0; i<=n0-1; i++)
   40522             :     {
   40523           0 :         for(j=0; j<=n1-1; j++)
   40524             :         {
   40525           0 :             y->ptr.pp_double[i][j] = (double)(0);
   40526             :         }
   40527             :     }
   40528           0 :     if( s->ny!=1||s->nx!=2 )
   40529             :     {
   40530           0 :         ae_frame_leave(_state);
   40531           0 :         return;
   40532             :     }
   40533             :     
   40534             :     /*
   40535             :      *create and sort arrays
   40536             :      */
   40537           0 :     ae_vector_set_length(&cpx0, n0, _state);
   40538           0 :     for(i=0; i<=n0-1; i++)
   40539             :     {
   40540           0 :         cpx0.ptr.p_double[i] = x0->ptr.p_double[i];
   40541             :     }
   40542           0 :     tagsort(&cpx0, n0, &p01, &p2, _state);
   40543           0 :     ae_vector_set_length(&cpx1, n1, _state);
   40544           0 :     for(i=0; i<=n1-1; i++)
   40545             :     {
   40546           0 :         cpx1.ptr.p_double[i] = x1->ptr.p_double[i];
   40547             :     }
   40548           0 :     tagsort(&cpx1, n1, &p11, &p2, _state);
   40549           0 :     ae_vector_set_length(&dummyx2, 1, _state);
   40550           0 :     dummyx2.ptr.p_double[0] = (double)(0);
   40551           0 :     ae_vector_set_length(&dummyx3, 1, _state);
   40552           0 :     dummyx3.ptr.p_double[0] = (double)(0);
   40553           0 :     ae_vector_set_length(&vy, n0*n1, _state);
   40554           0 :     rbfv2gridcalcvx(s, &cpx0, n0, &cpx1, n1, &dummyx2, 1, &dummyx3, 1, &dummyflag, ae_false, &vy, _state);
   40555           0 :     for(i=0; i<=n0-1; i++)
   40556             :     {
   40557           0 :         for(j=0; j<=n1-1; j++)
   40558             :         {
   40559           0 :             y->ptr.pp_double[i][j] = vy.ptr.p_double[i+j*n0];
   40560             :         }
   40561             :     }
   40562           0 :     ae_frame_leave(_state);
   40563             : }
   40564             : 
   40565             : 
   40566             : /*************************************************************************
   40567             : This function is used to perform gridded calculation  for  2D,  3D  or  4D
   40568             : problems. It accepts parameters X0...X3 and counters N0...N3. If RBF model
   40569             : has dimensionality less than 4, corresponding arrays should  contain  just
   40570             : one element equal to zero, and corresponding N's should be equal to 1.
   40571             : 
   40572             : NOTE: array Y should be preallocated by caller.
   40573             : 
   40574             :   -- ALGLIB --
   40575             :      Copyright 12.07.2016 by Bochkanov Sergey
   40576             : *************************************************************************/
   40577           0 : void rbfv2gridcalcvx(rbfv2model* s,
   40578             :      /* Real    */ ae_vector* x0,
   40579             :      ae_int_t n0,
   40580             :      /* Real    */ ae_vector* x1,
   40581             :      ae_int_t n1,
   40582             :      /* Real    */ ae_vector* x2,
   40583             :      ae_int_t n2,
   40584             :      /* Real    */ ae_vector* x3,
   40585             :      ae_int_t n3,
   40586             :      /* Boolean */ ae_vector* flagy,
   40587             :      ae_bool sparsey,
   40588             :      /* Real    */ ae_vector* y,
   40589             :      ae_state *_state)
   40590             : {
   40591             :     ae_frame _frame_block;
   40592             :     ae_int_t nx;
   40593             :     ae_int_t ny;
   40594             :     ae_int_t i;
   40595             :     ae_int_t j;
   40596             :     ae_int_t k;
   40597             :     ae_vector tx;
   40598             :     ae_vector ty;
   40599             :     ae_vector z;
   40600             :     ae_int_t dstoffs;
   40601             :     ae_int_t dummy;
   40602             :     rbfv2gridcalcbuffer bufseedv2;
   40603             :     ae_shared_pool bufpool;
   40604             :     ae_int_t rowidx;
   40605             :     ae_int_t rowcnt;
   40606             :     double v;
   40607             :     double rcur;
   40608             :     ae_int_t levelidx;
   40609             :     double searchradius2;
   40610             :     ae_int_t ntrials;
   40611             :     double avgfuncpernode;
   40612             :     hqrndstate rs;
   40613             :     ae_vector blocks0;
   40614             :     ae_vector blocks1;
   40615             :     ae_vector blocks2;
   40616             :     ae_vector blocks3;
   40617             :     ae_int_t blockscnt0;
   40618             :     ae_int_t blockscnt1;
   40619             :     ae_int_t blockscnt2;
   40620             :     ae_int_t blockscnt3;
   40621             :     double blockwidth0;
   40622             :     double blockwidth1;
   40623             :     double blockwidth2;
   40624             :     double blockwidth3;
   40625             :     ae_int_t maxblocksize;
   40626             : 
   40627           0 :     ae_frame_make(_state, &_frame_block);
   40628           0 :     memset(&tx, 0, sizeof(tx));
   40629           0 :     memset(&ty, 0, sizeof(ty));
   40630           0 :     memset(&z, 0, sizeof(z));
   40631           0 :     memset(&bufseedv2, 0, sizeof(bufseedv2));
   40632           0 :     memset(&bufpool, 0, sizeof(bufpool));
   40633           0 :     memset(&rs, 0, sizeof(rs));
   40634           0 :     memset(&blocks0, 0, sizeof(blocks0));
   40635           0 :     memset(&blocks1, 0, sizeof(blocks1));
   40636           0 :     memset(&blocks2, 0, sizeof(blocks2));
   40637           0 :     memset(&blocks3, 0, sizeof(blocks3));
   40638           0 :     ae_vector_init(&tx, 0, DT_REAL, _state, ae_true);
   40639           0 :     ae_vector_init(&ty, 0, DT_REAL, _state, ae_true);
   40640           0 :     ae_vector_init(&z, 0, DT_REAL, _state, ae_true);
   40641           0 :     _rbfv2gridcalcbuffer_init(&bufseedv2, _state, ae_true);
   40642           0 :     ae_shared_pool_init(&bufpool, _state, ae_true);
   40643           0 :     _hqrndstate_init(&rs, _state, ae_true);
   40644           0 :     ae_vector_init(&blocks0, 0, DT_INT, _state, ae_true);
   40645           0 :     ae_vector_init(&blocks1, 0, DT_INT, _state, ae_true);
   40646           0 :     ae_vector_init(&blocks2, 0, DT_INT, _state, ae_true);
   40647           0 :     ae_vector_init(&blocks3, 0, DT_INT, _state, ae_true);
   40648             : 
   40649           0 :     nx = s->nx;
   40650           0 :     ny = s->ny;
   40651           0 :     hqrndseed(532, 54734, &rs, _state);
   40652             :     
   40653             :     /*
   40654             :      * Perform integrity checks
   40655             :      */
   40656           0 :     ae_assert(s->nx==2||s->nx==3, "RBFGridCalcVX: integrity check failed", _state);
   40657           0 :     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);
   40658           0 :     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);
   40659           0 :     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);
   40660             :     
   40661             :     /*
   40662             :      * Allocate arrays
   40663             :      */
   40664           0 :     ae_assert(s->nx<=4, "RBFGridCalcVX: integrity check failed", _state);
   40665           0 :     ae_vector_set_length(&z, ny, _state);
   40666           0 :     ae_vector_set_length(&tx, 4, _state);
   40667           0 :     ae_vector_set_length(&ty, ny, _state);
   40668             :     
   40669             :     /*
   40670             :      * Calculate linear term
   40671             :      */
   40672           0 :     rowcnt = n1*n2*n3;
   40673           0 :     for(rowidx=0; rowidx<=rowcnt-1; rowidx++)
   40674             :     {
   40675             :         
   40676             :         /*
   40677             :          * Calculate TX - current position
   40678             :          */
   40679           0 :         k = rowidx;
   40680           0 :         tx.ptr.p_double[0] = (double)(0);
   40681           0 :         tx.ptr.p_double[1] = x1->ptr.p_double[k%n1];
   40682           0 :         k = k/n1;
   40683           0 :         tx.ptr.p_double[2] = x2->ptr.p_double[k%n2];
   40684           0 :         k = k/n2;
   40685           0 :         tx.ptr.p_double[3] = x3->ptr.p_double[k%n3];
   40686           0 :         k = k/n3;
   40687           0 :         ae_assert(k==0, "RBFGridCalcVX: integrity check failed", _state);
   40688           0 :         for(j=0; j<=ny-1; j++)
   40689             :         {
   40690           0 :             v = s->v.ptr.pp_double[j][nx];
   40691           0 :             for(k=1; k<=nx-1; k++)
   40692             :             {
   40693           0 :                 v = v+tx.ptr.p_double[k]*s->v.ptr.pp_double[j][k];
   40694             :             }
   40695           0 :             z.ptr.p_double[j] = v;
   40696             :         }
   40697           0 :         for(i=0; i<=n0-1; i++)
   40698             :         {
   40699           0 :             dstoffs = ny*(rowidx*n0+i);
   40700           0 :             if( sparsey&&!flagy->ptr.p_bool[rowidx*n0+i] )
   40701             :             {
   40702           0 :                 for(j=0; j<=ny-1; j++)
   40703             :                 {
   40704           0 :                     y->ptr.p_double[j+dstoffs] = (double)(0);
   40705             :                 }
   40706           0 :                 continue;
   40707             :             }
   40708           0 :             v = x0->ptr.p_double[i];
   40709           0 :             for(j=0; j<=ny-1; j++)
   40710             :             {
   40711           0 :                 y->ptr.p_double[j+dstoffs] = z.ptr.p_double[j]+v*s->v.ptr.pp_double[j][0];
   40712             :             }
   40713             :         }
   40714             :     }
   40715           0 :     if( s->nh==0 )
   40716             :     {
   40717           0 :         ae_frame_leave(_state);
   40718           0 :         return;
   40719             :     }
   40720             :     
   40721             :     /*
   40722             :      * Process RBF terms, layer by layer
   40723             :      */
   40724           0 :     for(levelidx=0; levelidx<=s->nh-1; levelidx++)
   40725             :     {
   40726           0 :         rcur = s->ri.ptr.p_double[levelidx];
   40727           0 :         blockwidth0 = (double)(1);
   40728           0 :         blockwidth1 = (double)(1);
   40729           0 :         blockwidth2 = (double)(1);
   40730           0 :         blockwidth3 = (double)(1);
   40731           0 :         if( nx>=1 )
   40732             :         {
   40733           0 :             blockwidth0 = rcur*s->s.ptr.p_double[0];
   40734             :         }
   40735           0 :         if( nx>=2 )
   40736             :         {
   40737           0 :             blockwidth1 = rcur*s->s.ptr.p_double[1];
   40738             :         }
   40739           0 :         if( nx>=3 )
   40740             :         {
   40741           0 :             blockwidth2 = rcur*s->s.ptr.p_double[2];
   40742             :         }
   40743           0 :         if( nx>=4 )
   40744             :         {
   40745           0 :             blockwidth3 = rcur*s->s.ptr.p_double[3];
   40746             :         }
   40747           0 :         maxblocksize = 8;
   40748             :         
   40749             :         /*
   40750             :          * Group grid nodes into blocks according to current radius
   40751             :          */
   40752           0 :         ae_vector_set_length(&blocks0, n0+1, _state);
   40753           0 :         blockscnt0 = 0;
   40754           0 :         blocks0.ptr.p_int[0] = 0;
   40755           0 :         for(i=1; i<=n0-1; i++)
   40756             :         {
   40757           0 :             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 )
   40758             :             {
   40759           0 :                 inc(&blockscnt0, _state);
   40760           0 :                 blocks0.ptr.p_int[blockscnt0] = i;
   40761             :             }
   40762             :         }
   40763           0 :         inc(&blockscnt0, _state);
   40764           0 :         blocks0.ptr.p_int[blockscnt0] = n0;
   40765           0 :         ae_vector_set_length(&blocks1, n1+1, _state);
   40766           0 :         blockscnt1 = 0;
   40767           0 :         blocks1.ptr.p_int[0] = 0;
   40768           0 :         for(i=1; i<=n1-1; i++)
   40769             :         {
   40770           0 :             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 )
   40771             :             {
   40772           0 :                 inc(&blockscnt1, _state);
   40773           0 :                 blocks1.ptr.p_int[blockscnt1] = i;
   40774             :             }
   40775             :         }
   40776           0 :         inc(&blockscnt1, _state);
   40777           0 :         blocks1.ptr.p_int[blockscnt1] = n1;
   40778           0 :         ae_vector_set_length(&blocks2, n2+1, _state);
   40779           0 :         blockscnt2 = 0;
   40780           0 :         blocks2.ptr.p_int[0] = 0;
   40781           0 :         for(i=1; i<=n2-1; i++)
   40782             :         {
   40783           0 :             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 )
   40784             :             {
   40785           0 :                 inc(&blockscnt2, _state);
   40786           0 :                 blocks2.ptr.p_int[blockscnt2] = i;
   40787             :             }
   40788             :         }
   40789           0 :         inc(&blockscnt2, _state);
   40790           0 :         blocks2.ptr.p_int[blockscnt2] = n2;
   40791           0 :         ae_vector_set_length(&blocks3, n3+1, _state);
   40792           0 :         blockscnt3 = 0;
   40793           0 :         blocks3.ptr.p_int[0] = 0;
   40794           0 :         for(i=1; i<=n3-1; i++)
   40795             :         {
   40796           0 :             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 )
   40797             :             {
   40798           0 :                 inc(&blockscnt3, _state);
   40799           0 :                 blocks3.ptr.p_int[blockscnt3] = i;
   40800             :             }
   40801             :         }
   40802           0 :         inc(&blockscnt3, _state);
   40803           0 :         blocks3.ptr.p_int[blockscnt3] = n3;
   40804             :         
   40805             :         /*
   40806             :          * Prepare seed for shared pool
   40807             :          */
   40808           0 :         rbfv2_allocatecalcbuffer(s, &bufseedv2.calcbuf, _state);
   40809           0 :         ae_shared_pool_set_seed(&bufpool, &bufseedv2, sizeof(bufseedv2), _rbfv2gridcalcbuffer_init, _rbfv2gridcalcbuffer_init_copy, _rbfv2gridcalcbuffer_destroy, _state);
   40810             :         
   40811             :         /*
   40812             :          * Determine average number of neighbor per node
   40813             :          */
   40814           0 :         searchradius2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state);
   40815           0 :         ntrials = 100;
   40816           0 :         avgfuncpernode = 0.0;
   40817           0 :         for(i=0; i<=ntrials-1; i++)
   40818             :         {
   40819           0 :             tx.ptr.p_double[0] = x0->ptr.p_double[hqrnduniformi(&rs, n0, _state)];
   40820           0 :             tx.ptr.p_double[1] = x1->ptr.p_double[hqrnduniformi(&rs, n1, _state)];
   40821           0 :             tx.ptr.p_double[2] = x2->ptr.p_double[hqrnduniformi(&rs, n2, _state)];
   40822           0 :             tx.ptr.p_double[3] = x3->ptr.p_double[hqrnduniformi(&rs, n3, _state)];
   40823           0 :             rbfv2_preparepartialquery(&tx, &s->kdboxmin, &s->kdboxmax, nx, &bufseedv2.calcbuf, &dummy, _state);
   40824           0 :             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;
   40825             :         }
   40826             :         
   40827             :         /*
   40828             :          * Perform calculation in multithreaded mode
   40829             :          */
   40830           0 :         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);
   40831             :     }
   40832           0 :     ae_frame_leave(_state);
   40833             : }
   40834             : 
   40835             : 
   40836           0 : void rbfv2partialgridcalcrec(rbfv2model* s,
   40837             :      /* Real    */ ae_vector* x0,
   40838             :      ae_int_t n0,
   40839             :      /* Real    */ ae_vector* x1,
   40840             :      ae_int_t n1,
   40841             :      /* Real    */ ae_vector* x2,
   40842             :      ae_int_t n2,
   40843             :      /* Real    */ ae_vector* x3,
   40844             :      ae_int_t n3,
   40845             :      /* Integer */ ae_vector* blocks0,
   40846             :      ae_int_t block0a,
   40847             :      ae_int_t block0b,
   40848             :      /* Integer */ ae_vector* blocks1,
   40849             :      ae_int_t block1a,
   40850             :      ae_int_t block1b,
   40851             :      /* Integer */ ae_vector* blocks2,
   40852             :      ae_int_t block2a,
   40853             :      ae_int_t block2b,
   40854             :      /* Integer */ ae_vector* blocks3,
   40855             :      ae_int_t block3a,
   40856             :      ae_int_t block3b,
   40857             :      /* Boolean */ ae_vector* flagy,
   40858             :      ae_bool sparsey,
   40859             :      ae_int_t levelidx,
   40860             :      double avgfuncpernode,
   40861             :      ae_shared_pool* bufpool,
   40862             :      /* Real    */ ae_vector* y,
   40863             :      ae_state *_state)
   40864             : {
   40865             :     ae_frame _frame_block;
   40866             :     ae_int_t nx;
   40867             :     ae_int_t ny;
   40868             :     ae_int_t k;
   40869             :     ae_int_t l;
   40870             :     ae_int_t blkidx;
   40871             :     ae_int_t blkcnt;
   40872             :     ae_int_t nodeidx;
   40873             :     ae_int_t nodescnt;
   40874             :     ae_int_t rowidx;
   40875             :     ae_int_t rowscnt;
   40876             :     ae_int_t i0;
   40877             :     ae_int_t i1;
   40878             :     ae_int_t i2;
   40879             :     ae_int_t i3;
   40880             :     ae_int_t j0;
   40881             :     ae_int_t j1;
   40882             :     ae_int_t j2;
   40883             :     ae_int_t j3;
   40884             :     double rcur;
   40885             :     double invrc2;
   40886             :     double rquery2;
   40887             :     double rfar2;
   40888             :     ae_int_t dstoffs;
   40889             :     ae_int_t srcoffs;
   40890             :     ae_int_t dummy;
   40891             :     double rowwidth;
   40892             :     double maxrowwidth;
   40893             :     double problemcost;
   40894             :     ae_int_t maxbs;
   40895             :     ae_int_t midpoint;
   40896             :     ae_bool emptyrow;
   40897             :     rbfv2gridcalcbuffer *buf;
   40898             :     ae_smart_ptr _buf;
   40899             : 
   40900           0 :     ae_frame_make(_state, &_frame_block);
   40901           0 :     memset(&_buf, 0, sizeof(_buf));
   40902           0 :     ae_smart_ptr_init(&_buf, (void**)&buf, _state, ae_true);
   40903             : 
   40904           0 :     nx = s->nx;
   40905           0 :     ny = s->ny;
   40906             :     
   40907             :     /*
   40908             :      * Integrity checks
   40909             :      */
   40910           0 :     ae_assert(s->nx==2||s->nx==3, "RBFV2PartialGridCalcRec: integrity check failed", _state);
   40911             :     
   40912             :     /*
   40913             :      * Try to split large problem
   40914             :      */
   40915           0 :     problemcost = s->ny*2*(avgfuncpernode+1);
   40916           0 :     problemcost = problemcost*(blocks0->ptr.p_int[block0b]-blocks0->ptr.p_int[block0a]);
   40917           0 :     problemcost = problemcost*(blocks1->ptr.p_int[block1b]-blocks1->ptr.p_int[block1a]);
   40918           0 :     problemcost = problemcost*(blocks2->ptr.p_int[block2b]-blocks2->ptr.p_int[block2a]);
   40919           0 :     problemcost = problemcost*(blocks3->ptr.p_int[block3b]-blocks3->ptr.p_int[block3a]);
   40920           0 :     maxbs = 0;
   40921           0 :     maxbs = ae_maxint(maxbs, block0b-block0a, _state);
   40922           0 :     maxbs = ae_maxint(maxbs, block1b-block1a, _state);
   40923           0 :     maxbs = ae_maxint(maxbs, block2b-block2a, _state);
   40924           0 :     maxbs = ae_maxint(maxbs, block3b-block3a, _state);
   40925           0 :     if( ae_fp_greater_eq(problemcost*rbfv2_complexitymultiplier,smpactivationlevel(_state)) )
   40926             :     {
   40927           0 :         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) )
   40928             :         {
   40929           0 :             ae_frame_leave(_state);
   40930           0 :             return;
   40931             :         }
   40932             :     }
   40933           0 :     if( ae_fp_greater_eq(problemcost*rbfv2_complexitymultiplier,spawnlevel(_state))&&maxbs>=2 )
   40934             :     {
   40935           0 :         if( block0b-block0a==maxbs )
   40936             :         {
   40937           0 :             midpoint = block0a+maxbs/2;
   40938           0 :             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);
   40939           0 :             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);
   40940           0 :             ae_frame_leave(_state);
   40941           0 :             return;
   40942             :         }
   40943           0 :         if( block1b-block1a==maxbs )
   40944             :         {
   40945           0 :             midpoint = block1a+maxbs/2;
   40946           0 :             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);
   40947           0 :             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);
   40948           0 :             ae_frame_leave(_state);
   40949           0 :             return;
   40950             :         }
   40951           0 :         if( block2b-block2a==maxbs )
   40952             :         {
   40953           0 :             midpoint = block2a+maxbs/2;
   40954           0 :             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);
   40955           0 :             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);
   40956           0 :             ae_frame_leave(_state);
   40957           0 :             return;
   40958             :         }
   40959           0 :         if( block3b-block3a==maxbs )
   40960             :         {
   40961           0 :             midpoint = block3a+maxbs/2;
   40962           0 :             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);
   40963           0 :             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);
   40964           0 :             ae_frame_leave(_state);
   40965           0 :             return;
   40966             :         }
   40967           0 :         ae_assert(ae_false, "RBFV2PartialGridCalcRec: integrity check failed", _state);
   40968             :     }
   40969             :     
   40970             :     /*
   40971             :      * Retrieve buffer object from pool (it will be returned later)
   40972             :      */
   40973           0 :     ae_shared_pool_retrieve(bufpool, &_buf, _state);
   40974             :     
   40975             :     /*
   40976             :      * Calculate RBF model
   40977             :      */
   40978           0 :     ae_assert(nx<=4, "RBFV2PartialGridCalcRec: integrity check failed", _state);
   40979           0 :     ae_vector_set_length(&buf->tx, 4, _state);
   40980           0 :     ae_vector_set_length(&buf->cx, 4, _state);
   40981           0 :     ae_vector_set_length(&buf->ty, ny, _state);
   40982           0 :     rcur = s->ri.ptr.p_double[levelidx];
   40983           0 :     invrc2 = 1/(rcur*rcur);
   40984           0 :     blkcnt = (block3b-block3a)*(block2b-block2a)*(block1b-block1a)*(block0b-block0a);
   40985           0 :     for(blkidx=0; blkidx<=blkcnt-1; blkidx++)
   40986             :     {
   40987             :         
   40988             :         /*
   40989             :          * Select block (I0,I1,I2,I3).
   40990             :          *
   40991             :          * NOTE: for problems with NX<4 corresponding I_? are zero.
   40992             :          */
   40993           0 :         k = blkidx;
   40994           0 :         i0 = block0a+k%(block0b-block0a);
   40995           0 :         k = k/(block0b-block0a);
   40996           0 :         i1 = block1a+k%(block1b-block1a);
   40997           0 :         k = k/(block1b-block1a);
   40998           0 :         i2 = block2a+k%(block2b-block2a);
   40999           0 :         k = k/(block2b-block2a);
   41000           0 :         i3 = block3a+k%(block3b-block3a);
   41001           0 :         k = k/(block3b-block3a);
   41002           0 :         ae_assert(k==0, "RBFV2PartialGridCalcRec: integrity check failed", _state);
   41003             :         
   41004             :         /*
   41005             :          * We partitioned grid into blocks and selected block with
   41006             :          * index (I0,I1,I2,I3). This block is a 4D cube (some dimensions
   41007             :          * may be zero) of nodes with indexes (J0,J1,J2,J3), which is
   41008             :          * further partitioned into a set of rows, each row corresponding
   41009             :          * to indexes J1...J3 being fixed.
   41010             :          *
   41011             :          * We process block row by row, and each row may be handled
   41012             :          * by either "generic" (nodes are processed separately) or
   41013             :          * batch algorithm (that's the reason to use rows, after all).
   41014             :          *
   41015             :          *
   41016             :          * Process nodes of the block
   41017             :          */
   41018           0 :         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]);
   41019           0 :         for(rowidx=0; rowidx<=rowscnt-1; rowidx++)
   41020             :         {
   41021             :             
   41022             :             /*
   41023             :              * Find out node indexes (*,J1,J2,J3).
   41024             :              *
   41025             :              * NOTE: for problems with NX<4 corresponding J_? are zero.
   41026             :              */
   41027           0 :             k = rowidx;
   41028           0 :             j1 = blocks1->ptr.p_int[i1]+k%(blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1]);
   41029           0 :             k = k/(blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1]);
   41030           0 :             j2 = blocks2->ptr.p_int[i2]+k%(blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2]);
   41031           0 :             k = k/(blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2]);
   41032           0 :             j3 = blocks3->ptr.p_int[i3]+k%(blocks3->ptr.p_int[i3+1]-blocks3->ptr.p_int[i3]);
   41033           0 :             k = k/(blocks3->ptr.p_int[i3+1]-blocks3->ptr.p_int[i3]);
   41034           0 :             ae_assert(k==0, "RBFV2PartialGridCalcRec: integrity check failed", _state);
   41035             :             
   41036             :             /*
   41037             :              * Analyze row, skip completely empty rows
   41038             :              */
   41039           0 :             nodescnt = blocks0->ptr.p_int[i0+1]-blocks0->ptr.p_int[i0];
   41040           0 :             srcoffs = blocks0->ptr.p_int[i0]+(j1+(j2+j3*n2)*n1)*n0;
   41041           0 :             emptyrow = ae_true;
   41042           0 :             for(nodeidx=0; nodeidx<=nodescnt-1; nodeidx++)
   41043             :             {
   41044           0 :                 emptyrow = emptyrow&&(sparsey&&!flagy->ptr.p_bool[srcoffs+nodeidx]);
   41045             :             }
   41046           0 :             if( emptyrow )
   41047             :             {
   41048           0 :                 continue;
   41049             :             }
   41050             :             
   41051             :             /*
   41052             :              * Process row - use either "batch" (rowsize>1) or "generic"
   41053             :              * (row size is 1) algorithm.
   41054             :              *
   41055             :              * NOTE: "generic" version may also be used as fallback code for
   41056             :              *       situations when we do not want to use batch code.
   41057             :              */
   41058           0 :             maxrowwidth = 0.5*rbfv2nearradius(s->bf, _state)*rcur*s->s.ptr.p_double[0];
   41059           0 :             rowwidth = x0->ptr.p_double[blocks0->ptr.p_int[i0+1]-1]-x0->ptr.p_double[blocks0->ptr.p_int[i0]];
   41060           0 :             if( nodescnt>1&&ae_fp_less_eq(rowwidth,maxrowwidth) )
   41061             :             {
   41062             :                 
   41063             :                 /*
   41064             :                  * "Batch" code which processes entire row at once, saving
   41065             :                  * some time in kd-tree search code.
   41066             :                  */
   41067           0 :                 rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state)+0.5*rowwidth/s->s.ptr.p_double[0], _state);
   41068           0 :                 rfar2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state);
   41069           0 :                 j0 = blocks0->ptr.p_int[i0];
   41070           0 :                 if( nx>0 )
   41071             :                 {
   41072           0 :                     buf->cx.ptr.p_double[0] = (x0->ptr.p_double[j0]+0.5*rowwidth)/s->s.ptr.p_double[0];
   41073             :                 }
   41074           0 :                 if( nx>1 )
   41075             :                 {
   41076           0 :                     buf->cx.ptr.p_double[1] = x1->ptr.p_double[j1]/s->s.ptr.p_double[1];
   41077             :                 }
   41078           0 :                 if( nx>2 )
   41079             :                 {
   41080           0 :                     buf->cx.ptr.p_double[2] = x2->ptr.p_double[j2]/s->s.ptr.p_double[2];
   41081             :                 }
   41082           0 :                 if( nx>3 )
   41083             :                 {
   41084           0 :                     buf->cx.ptr.p_double[3] = x3->ptr.p_double[j3]/s->s.ptr.p_double[3];
   41085             :                 }
   41086           0 :                 srcoffs = j0+(j1+(j2+j3*n2)*n1)*n0;
   41087           0 :                 dstoffs = ny*srcoffs;
   41088           0 :                 rvectorsetlengthatleast(&buf->rx, nodescnt, _state);
   41089           0 :                 bvectorsetlengthatleast(&buf->rf, nodescnt, _state);
   41090           0 :                 rvectorsetlengthatleast(&buf->ry, nodescnt*ny, _state);
   41091           0 :                 for(nodeidx=0; nodeidx<=nodescnt-1; nodeidx++)
   41092             :                 {
   41093           0 :                     buf->rx.ptr.p_double[nodeidx] = x0->ptr.p_double[j0+nodeidx]/s->s.ptr.p_double[0];
   41094           0 :                     buf->rf.ptr.p_bool[nodeidx] = !sparsey||flagy->ptr.p_bool[srcoffs+nodeidx];
   41095             :                 }
   41096           0 :                 for(k=0; k<=nodescnt*ny-1; k++)
   41097             :                 {
   41098           0 :                     buf->ry.ptr.p_double[k] = (double)(0);
   41099             :                 }
   41100           0 :                 rbfv2_preparepartialquery(&buf->cx, &s->kdboxmin, &s->kdboxmax, nx, &buf->calcbuf, &dummy, _state);
   41101           0 :                 rbfv2_partialrowcalcrec(s, &buf->calcbuf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, rfar2, &buf->cx, &buf->rx, &buf->rf, nodescnt, &buf->ry, _state);
   41102           0 :                 for(k=0; k<=nodescnt*ny-1; k++)
   41103             :                 {
   41104           0 :                     y->ptr.p_double[dstoffs+k] = y->ptr.p_double[dstoffs+k]+buf->ry.ptr.p_double[k];
   41105             :                 }
   41106             :             }
   41107             :             else
   41108             :             {
   41109             :                 
   41110             :                 /*
   41111             :                  * "Generic" code. Although we usually move here
   41112             :                  * only when NodesCnt=1, we still use a loop on
   41113             :                  * NodeIdx just to be able to use this branch as
   41114             :                  * fallback code without any modifications.
   41115             :                  */
   41116           0 :                 rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state);
   41117           0 :                 for(nodeidx=0; nodeidx<=nodescnt-1; nodeidx++)
   41118             :                 {
   41119             :                     
   41120             :                     /*
   41121             :                      * Prepare TX - current point
   41122             :                      */
   41123           0 :                     j0 = blocks0->ptr.p_int[i0]+nodeidx;
   41124           0 :                     if( nx>0 )
   41125             :                     {
   41126           0 :                         buf->tx.ptr.p_double[0] = x0->ptr.p_double[j0]/s->s.ptr.p_double[0];
   41127             :                     }
   41128           0 :                     if( nx>1 )
   41129             :                     {
   41130           0 :                         buf->tx.ptr.p_double[1] = x1->ptr.p_double[j1]/s->s.ptr.p_double[1];
   41131             :                     }
   41132           0 :                     if( nx>2 )
   41133             :                     {
   41134           0 :                         buf->tx.ptr.p_double[2] = x2->ptr.p_double[j2]/s->s.ptr.p_double[2];
   41135             :                     }
   41136           0 :                     if( nx>3 )
   41137             :                     {
   41138           0 :                         buf->tx.ptr.p_double[3] = x3->ptr.p_double[j3]/s->s.ptr.p_double[3];
   41139             :                     }
   41140             :                     
   41141             :                     /*
   41142             :                      * Evaluate and add to Y
   41143             :                      */
   41144           0 :                     srcoffs = j0+(j1+(j2+j3*n2)*n1)*n0;
   41145           0 :                     dstoffs = ny*srcoffs;
   41146           0 :                     for(l=0; l<=ny-1; l++)
   41147             :                     {
   41148           0 :                         buf->ty.ptr.p_double[l] = (double)(0);
   41149             :                     }
   41150           0 :                     if( !sparsey||flagy->ptr.p_bool[srcoffs] )
   41151             :                     {
   41152           0 :                         rbfv2_preparepartialquery(&buf->tx, &s->kdboxmin, &s->kdboxmax, nx, &buf->calcbuf, &dummy, _state);
   41153           0 :                         rbfv2_partialcalcrec(s, &buf->calcbuf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, &buf->tx, &buf->ty, _state);
   41154             :                     }
   41155           0 :                     for(l=0; l<=ny-1; l++)
   41156             :                     {
   41157           0 :                         y->ptr.p_double[dstoffs+l] = y->ptr.p_double[dstoffs+l]+buf->ty.ptr.p_double[l];
   41158             :                     }
   41159             :                 }
   41160             :             }
   41161             :         }
   41162             :     }
   41163             :     
   41164             :     /*
   41165             :      * Recycle buffer object back to pool
   41166             :      */
   41167           0 :     ae_shared_pool_recycle(bufpool, &_buf, _state);
   41168           0 :     ae_frame_leave(_state);
   41169             : }
   41170             : 
   41171             : 
   41172             : /*************************************************************************
   41173             : Serial stub for GPL edition.
   41174             : *************************************************************************/
   41175           0 : ae_bool _trypexec_rbfv2partialgridcalcrec(rbfv2model* s,
   41176             :     /* Real    */ ae_vector* x0,
   41177             :     ae_int_t n0,
   41178             :     /* Real    */ ae_vector* x1,
   41179             :     ae_int_t n1,
   41180             :     /* Real    */ ae_vector* x2,
   41181             :     ae_int_t n2,
   41182             :     /* Real    */ ae_vector* x3,
   41183             :     ae_int_t n3,
   41184             :     /* Integer */ ae_vector* blocks0,
   41185             :     ae_int_t block0a,
   41186             :     ae_int_t block0b,
   41187             :     /* Integer */ ae_vector* blocks1,
   41188             :     ae_int_t block1a,
   41189             :     ae_int_t block1b,
   41190             :     /* Integer */ ae_vector* blocks2,
   41191             :     ae_int_t block2a,
   41192             :     ae_int_t block2b,
   41193             :     /* Integer */ ae_vector* blocks3,
   41194             :     ae_int_t block3a,
   41195             :     ae_int_t block3b,
   41196             :     /* Boolean */ ae_vector* flagy,
   41197             :     ae_bool sparsey,
   41198             :     ae_int_t levelidx,
   41199             :     double avgfuncpernode,
   41200             :     ae_shared_pool* bufpool,
   41201             :     /* Real    */ ae_vector* y,
   41202             :     ae_state *_state)
   41203             : {
   41204           0 :     return ae_false;
   41205             : }
   41206             : 
   41207             : 
   41208             : /*************************************************************************
   41209             : This function "unpacks" RBF model by extracting its coefficients.
   41210             : 
   41211             : INPUT PARAMETERS:
   41212             :     S       -   RBF model
   41213             : 
   41214             : OUTPUT PARAMETERS:
   41215             :     NX      -   dimensionality of argument
   41216             :     NY      -   dimensionality of the target function
   41217             :     XWR     -   model information, array[NC,NX+NY+1].
   41218             :                 One row of the array corresponds to one basis function:
   41219             :                 * first NX columns  - coordinates of the center 
   41220             :                 * next NY columns   - weights, one per dimension of the 
   41221             :                                       function being modelled
   41222             :                 * last NX columns   - radii, per dimension
   41223             :     NC      -   number of the centers
   41224             :     V       -   polynomial  term , array[NY,NX+1]. One row per one 
   41225             :                 dimension of the function being modelled. First NX 
   41226             :                 elements are linear coefficients, V[NX] is equal to the 
   41227             :                 constant part.
   41228             : 
   41229             :   -- ALGLIB --
   41230             :      Copyright 13.12.2011 by Bochkanov Sergey
   41231             : *************************************************************************/
   41232           0 : void rbfv2unpack(rbfv2model* s,
   41233             :      ae_int_t* nx,
   41234             :      ae_int_t* ny,
   41235             :      /* Real    */ ae_matrix* xwr,
   41236             :      ae_int_t* nc,
   41237             :      /* Real    */ ae_matrix* v,
   41238             :      ae_state *_state)
   41239             : {
   41240             :     ae_int_t i;
   41241             :     ae_int_t ncactual;
   41242             : 
   41243           0 :     *nx = 0;
   41244           0 :     *ny = 0;
   41245           0 :     ae_matrix_clear(xwr);
   41246           0 :     *nc = 0;
   41247           0 :     ae_matrix_clear(v);
   41248             : 
   41249           0 :     *nx = s->nx;
   41250           0 :     *ny = s->ny;
   41251           0 :     *nc = 0;
   41252             :     
   41253             :     /*
   41254             :      * Fill V
   41255             :      */
   41256           0 :     ae_matrix_set_length(v, s->ny, s->nx+1, _state);
   41257           0 :     for(i=0; i<=s->ny-1; i++)
   41258             :     {
   41259           0 :         ae_v_move(&v->ptr.pp_double[i][0], 1, &s->v.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx));
   41260             :     }
   41261             :     
   41262             :     /*
   41263             :      * Fill XWR
   41264             :      */
   41265           0 :     ae_assert(s->cw.cnt%(s->nx+s->ny)==0, "RBFV2Unpack: integrity error", _state);
   41266           0 :     *nc = s->cw.cnt/(s->nx+s->ny);
   41267           0 :     ncactual = 0;
   41268           0 :     if( *nc>0 )
   41269             :     {
   41270           0 :         ae_matrix_set_length(xwr, *nc, s->nx+s->ny+s->nx, _state);
   41271           0 :         for(i=0; i<=s->nh-1; i++)
   41272             :         {
   41273           0 :             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);
   41274             :         }
   41275             :     }
   41276           0 :     ae_assert(*nc==ncactual, "RBFV2Unpack: integrity error", _state);
   41277           0 : }
   41278             : 
   41279             : 
   41280           0 : static ae_bool rbfv2_rbfv2buildlinearmodel(/* Real    */ ae_matrix* x,
   41281             :      /* Real    */ ae_matrix* y,
   41282             :      ae_int_t n,
   41283             :      ae_int_t nx,
   41284             :      ae_int_t ny,
   41285             :      ae_int_t modeltype,
   41286             :      /* Real    */ ae_matrix* v,
   41287             :      ae_state *_state)
   41288             : {
   41289             :     ae_frame _frame_block;
   41290             :     ae_vector tmpy;
   41291             :     ae_matrix a;
   41292             :     double scaling;
   41293             :     ae_vector shifting;
   41294             :     double mn;
   41295             :     double mx;
   41296             :     ae_vector c;
   41297             :     lsfitreport rep;
   41298             :     ae_int_t i;
   41299             :     ae_int_t j;
   41300             :     ae_int_t k;
   41301             :     ae_int_t info;
   41302             :     ae_bool result;
   41303             : 
   41304           0 :     ae_frame_make(_state, &_frame_block);
   41305           0 :     memset(&tmpy, 0, sizeof(tmpy));
   41306           0 :     memset(&a, 0, sizeof(a));
   41307           0 :     memset(&shifting, 0, sizeof(shifting));
   41308           0 :     memset(&c, 0, sizeof(c));
   41309           0 :     memset(&rep, 0, sizeof(rep));
   41310           0 :     ae_matrix_clear(v);
   41311           0 :     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
   41312           0 :     ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true);
   41313           0 :     ae_vector_init(&shifting, 0, DT_REAL, _state, ae_true);
   41314           0 :     ae_vector_init(&c, 0, DT_REAL, _state, ae_true);
   41315           0 :     _lsfitreport_init(&rep, _state, ae_true);
   41316             : 
   41317           0 :     ae_assert(n>=0, "BuildLinearModel: N<0", _state);
   41318           0 :     ae_assert(nx>0, "BuildLinearModel: NX<=0", _state);
   41319           0 :     ae_assert(ny>0, "BuildLinearModel: NY<=0", _state);
   41320             :     
   41321             :     /*
   41322             :      * Handle degenerate case (N=0)
   41323             :      */
   41324           0 :     result = ae_true;
   41325           0 :     ae_matrix_set_length(v, ny, nx+1, _state);
   41326           0 :     if( n==0 )
   41327             :     {
   41328           0 :         for(j=0; j<=nx; j++)
   41329             :         {
   41330           0 :             for(i=0; i<=ny-1; i++)
   41331             :             {
   41332           0 :                 v->ptr.pp_double[i][j] = (double)(0);
   41333             :             }
   41334             :         }
   41335           0 :         ae_frame_leave(_state);
   41336           0 :         return result;
   41337             :     }
   41338             :     
   41339             :     /*
   41340             :      * Allocate temporaries
   41341             :      */
   41342           0 :     ae_vector_set_length(&tmpy, n, _state);
   41343             :     
   41344             :     /*
   41345             :      * General linear model.
   41346             :      */
   41347           0 :     if( modeltype==1 )
   41348             :     {
   41349             :         
   41350             :         /*
   41351             :          * Calculate scaling/shifting, transform variables, prepare LLS problem
   41352             :          */
   41353           0 :         ae_matrix_set_length(&a, n, nx+1, _state);
   41354           0 :         ae_vector_set_length(&shifting, nx, _state);
   41355           0 :         scaling = (double)(0);
   41356           0 :         for(i=0; i<=nx-1; i++)
   41357             :         {
   41358           0 :             mn = x->ptr.pp_double[0][i];
   41359           0 :             mx = mn;
   41360           0 :             for(j=1; j<=n-1; j++)
   41361             :             {
   41362           0 :                 if( ae_fp_greater(mn,x->ptr.pp_double[j][i]) )
   41363             :                 {
   41364           0 :                     mn = x->ptr.pp_double[j][i];
   41365             :                 }
   41366           0 :                 if( ae_fp_less(mx,x->ptr.pp_double[j][i]) )
   41367             :                 {
   41368           0 :                     mx = x->ptr.pp_double[j][i];
   41369             :                 }
   41370             :             }
   41371           0 :             scaling = ae_maxreal(scaling, mx-mn, _state);
   41372           0 :             shifting.ptr.p_double[i] = 0.5*(mx+mn);
   41373             :         }
   41374           0 :         if( ae_fp_eq(scaling,(double)(0)) )
   41375             :         {
   41376           0 :             scaling = (double)(1);
   41377             :         }
   41378             :         else
   41379             :         {
   41380           0 :             scaling = 0.5*scaling;
   41381             :         }
   41382           0 :         for(i=0; i<=n-1; i++)
   41383             :         {
   41384           0 :             for(j=0; j<=nx-1; j++)
   41385             :             {
   41386           0 :                 a.ptr.pp_double[i][j] = (x->ptr.pp_double[i][j]-shifting.ptr.p_double[j])/scaling;
   41387             :             }
   41388             :         }
   41389           0 :         for(i=0; i<=n-1; i++)
   41390             :         {
   41391           0 :             a.ptr.pp_double[i][nx] = (double)(1);
   41392             :         }
   41393             :         
   41394             :         /*
   41395             :          * Solve linear system in transformed variables, make backward 
   41396             :          */
   41397           0 :         for(i=0; i<=ny-1; i++)
   41398             :         {
   41399           0 :             for(j=0; j<=n-1; j++)
   41400             :             {
   41401           0 :                 tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i];
   41402             :             }
   41403           0 :             lsfitlinear(&tmpy, &a, n, nx+1, &info, &c, &rep, _state);
   41404           0 :             if( info<=0 )
   41405             :             {
   41406           0 :                 result = ae_false;
   41407           0 :                 ae_frame_leave(_state);
   41408           0 :                 return result;
   41409             :             }
   41410           0 :             for(j=0; j<=nx-1; j++)
   41411             :             {
   41412           0 :                 v->ptr.pp_double[i][j] = c.ptr.p_double[j]/scaling;
   41413             :             }
   41414           0 :             v->ptr.pp_double[i][nx] = c.ptr.p_double[nx];
   41415           0 :             for(j=0; j<=nx-1; j++)
   41416             :             {
   41417           0 :                 v->ptr.pp_double[i][nx] = v->ptr.pp_double[i][nx]-shifting.ptr.p_double[j]*v->ptr.pp_double[i][j];
   41418             :             }
   41419           0 :             for(j=0; j<=n-1; j++)
   41420             :             {
   41421           0 :                 for(k=0; k<=nx-1; k++)
   41422             :                 {
   41423           0 :                     y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-x->ptr.pp_double[j][k]*v->ptr.pp_double[i][k];
   41424             :                 }
   41425           0 :                 y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][nx];
   41426             :             }
   41427             :         }
   41428           0 :         ae_frame_leave(_state);
   41429           0 :         return result;
   41430             :     }
   41431             :     
   41432             :     /*
   41433             :      * Constant model, very simple
   41434             :      */
   41435           0 :     if( modeltype==2 )
   41436             :     {
   41437           0 :         for(i=0; i<=ny-1; i++)
   41438             :         {
   41439           0 :             for(j=0; j<=nx; j++)
   41440             :             {
   41441           0 :                 v->ptr.pp_double[i][j] = (double)(0);
   41442             :             }
   41443           0 :             for(j=0; j<=n-1; j++)
   41444             :             {
   41445           0 :                 v->ptr.pp_double[i][nx] = v->ptr.pp_double[i][nx]+y->ptr.pp_double[j][i];
   41446             :             }
   41447           0 :             if( n>0 )
   41448             :             {
   41449           0 :                 v->ptr.pp_double[i][nx] = v->ptr.pp_double[i][nx]/n;
   41450             :             }
   41451           0 :             for(j=0; j<=n-1; j++)
   41452             :             {
   41453           0 :                 y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][nx];
   41454             :             }
   41455             :         }
   41456           0 :         ae_frame_leave(_state);
   41457           0 :         return result;
   41458             :     }
   41459             :     
   41460             :     /*
   41461             :      * Zero model
   41462             :      */
   41463           0 :     ae_assert(modeltype==3, "BuildLinearModel: unknown model type", _state);
   41464           0 :     for(i=0; i<=ny-1; i++)
   41465             :     {
   41466           0 :         for(j=0; j<=nx; j++)
   41467             :         {
   41468           0 :             v->ptr.pp_double[i][j] = (double)(0);
   41469             :         }
   41470             :     }
   41471           0 :     ae_frame_leave(_state);
   41472           0 :     return result;
   41473             : }
   41474             : 
   41475             : 
   41476             : /*************************************************************************
   41477             : Reallocates calcBuf if necessary, reuses previously allocated space if
   41478             : possible.
   41479             : 
   41480             :   -- ALGLIB --
   41481             :      Copyright 20.06.2016 by Sergey Bochkanov
   41482             : *************************************************************************/
   41483           0 : static void rbfv2_allocatecalcbuffer(rbfv2model* s,
   41484             :      rbfv2calcbuffer* buf,
   41485             :      ae_state *_state)
   41486             : {
   41487             : 
   41488             : 
   41489           0 :     if( buf->x.cnt<s->nx )
   41490             :     {
   41491           0 :         ae_vector_set_length(&buf->x, s->nx, _state);
   41492             :     }
   41493           0 :     if( buf->curboxmin.cnt<s->nx )
   41494             :     {
   41495           0 :         ae_vector_set_length(&buf->curboxmin, s->nx, _state);
   41496             :     }
   41497           0 :     if( buf->curboxmax.cnt<s->nx )
   41498             :     {
   41499           0 :         ae_vector_set_length(&buf->curboxmax, s->nx, _state);
   41500             :     }
   41501           0 :     if( buf->x123.cnt<s->nx )
   41502             :     {
   41503           0 :         ae_vector_set_length(&buf->x123, s->nx, _state);
   41504             :     }
   41505           0 :     if( buf->y123.cnt<s->ny )
   41506             :     {
   41507           0 :         ae_vector_set_length(&buf->y123, s->ny, _state);
   41508             :     }
   41509           0 : }
   41510             : 
   41511             : 
   41512             : /*************************************************************************
   41513             : Extracts structure (and XY-values too) from  kd-tree  built  for  a  small
   41514             : subset of points and appends it to multi-tree.
   41515             : 
   41516             : 
   41517             :   -- ALGLIB --
   41518             :      Copyright 20.06.2016 by Sergey Bochkanov
   41519             : *************************************************************************/
   41520           0 : static void rbfv2_convertandappendtree(kdtree* curtree,
   41521             :      ae_int_t n,
   41522             :      ae_int_t nx,
   41523             :      ae_int_t ny,
   41524             :      /* Integer */ ae_vector* kdnodes,
   41525             :      /* Real    */ ae_vector* kdsplits,
   41526             :      /* Real    */ ae_vector* cw,
   41527             :      ae_state *_state)
   41528             : {
   41529             :     ae_frame _frame_block;
   41530             :     ae_int_t nodesbase;
   41531             :     ae_int_t splitsbase;
   41532             :     ae_int_t cwbase;
   41533             :     ae_vector localnodes;
   41534             :     ae_vector localsplits;
   41535             :     ae_vector localcw;
   41536             :     ae_matrix xybuf;
   41537             :     ae_int_t localnodessize;
   41538             :     ae_int_t localsplitssize;
   41539             :     ae_int_t localcwsize;
   41540             :     ae_int_t i;
   41541             : 
   41542           0 :     ae_frame_make(_state, &_frame_block);
   41543           0 :     memset(&localnodes, 0, sizeof(localnodes));
   41544           0 :     memset(&localsplits, 0, sizeof(localsplits));
   41545           0 :     memset(&localcw, 0, sizeof(localcw));
   41546           0 :     memset(&xybuf, 0, sizeof(xybuf));
   41547           0 :     ae_vector_init(&localnodes, 0, DT_INT, _state, ae_true);
   41548           0 :     ae_vector_init(&localsplits, 0, DT_REAL, _state, ae_true);
   41549           0 :     ae_vector_init(&localcw, 0, DT_REAL, _state, ae_true);
   41550           0 :     ae_matrix_init(&xybuf, 0, 0, DT_REAL, _state, ae_true);
   41551             : 
   41552             :     
   41553             :     /*
   41554             :      * Calculate base offsets
   41555             :      */
   41556           0 :     nodesbase = kdnodes->cnt;
   41557           0 :     splitsbase = kdsplits->cnt;
   41558           0 :     cwbase = cw->cnt;
   41559             :     
   41560             :     /*
   41561             :      * Prepare local copy of tree
   41562             :      */
   41563           0 :     ae_vector_set_length(&localnodes, n*rbfv2_maxnodesize, _state);
   41564           0 :     ae_vector_set_length(&localsplits, n, _state);
   41565           0 :     ae_vector_set_length(&localcw, (nx+ny)*n, _state);
   41566           0 :     localnodessize = 0;
   41567           0 :     localsplitssize = 0;
   41568           0 :     localcwsize = 0;
   41569           0 :     rbfv2_converttreerec(curtree, n, nx, ny, 0, nodesbase, splitsbase, cwbase, &localnodes, &localnodessize, &localsplits, &localsplitssize, &localcw, &localcwsize, &xybuf, _state);
   41570             :     
   41571             :     /*
   41572             :      * Append to multi-tree
   41573             :      */
   41574           0 :     ivectorresize(kdnodes, kdnodes->cnt+localnodessize, _state);
   41575           0 :     rvectorresize(kdsplits, kdsplits->cnt+localsplitssize, _state);
   41576           0 :     rvectorresize(cw, cw->cnt+localcwsize, _state);
   41577           0 :     for(i=0; i<=localnodessize-1; i++)
   41578             :     {
   41579           0 :         kdnodes->ptr.p_int[nodesbase+i] = localnodes.ptr.p_int[i];
   41580             :     }
   41581           0 :     for(i=0; i<=localsplitssize-1; i++)
   41582             :     {
   41583           0 :         kdsplits->ptr.p_double[splitsbase+i] = localsplits.ptr.p_double[i];
   41584             :     }
   41585           0 :     for(i=0; i<=localcwsize-1; i++)
   41586             :     {
   41587           0 :         cw->ptr.p_double[cwbase+i] = localcw.ptr.p_double[i];
   41588             :     }
   41589           0 :     ae_frame_leave(_state);
   41590           0 : }
   41591             : 
   41592             : 
   41593             : /*************************************************************************
   41594             : Recurrent tree conversion
   41595             : 
   41596             :     CurTree         -   tree to convert
   41597             :     N, NX, NY       -   dataset metrics
   41598             :     NodeOffset      -   offset of current tree node, 0 for root
   41599             :     NodesBase       -   a value which is added to intra-tree node indexes;
   41600             :                         although this tree is stored in separate array, it
   41601             :                         is intended to be stored in the larger tree,  with
   41602             :                         localNodes being moved to offset NodesBase.
   41603             :     SplitsBase      -   similarly, offset of localSplits in the final tree
   41604             :     CWBase          -   similarly, offset of localCW in the final tree
   41605             : *************************************************************************/
   41606           0 : static void rbfv2_converttreerec(kdtree* curtree,
   41607             :      ae_int_t n,
   41608             :      ae_int_t nx,
   41609             :      ae_int_t ny,
   41610             :      ae_int_t nodeoffset,
   41611             :      ae_int_t nodesbase,
   41612             :      ae_int_t splitsbase,
   41613             :      ae_int_t cwbase,
   41614             :      /* Integer */ ae_vector* localnodes,
   41615             :      ae_int_t* localnodessize,
   41616             :      /* Real    */ ae_vector* localsplits,
   41617             :      ae_int_t* localsplitssize,
   41618             :      /* Real    */ ae_vector* localcw,
   41619             :      ae_int_t* localcwsize,
   41620             :      /* Real    */ ae_matrix* xybuf,
   41621             :      ae_state *_state)
   41622             : {
   41623             :     ae_int_t i;
   41624             :     ae_int_t j;
   41625             :     ae_int_t nodetype;
   41626             :     ae_int_t cnt;
   41627             :     ae_int_t d;
   41628             :     double s;
   41629             :     ae_int_t nodele;
   41630             :     ae_int_t nodege;
   41631             :     ae_int_t oldnodessize;
   41632             : 
   41633             : 
   41634           0 :     kdtreeexplorenodetype(curtree, nodeoffset, &nodetype, _state);
   41635             :     
   41636             :     /*
   41637             :      * Leaf node
   41638             :      */
   41639           0 :     if( nodetype==0 )
   41640             :     {
   41641           0 :         kdtreeexploreleaf(curtree, nodeoffset, xybuf, &cnt, _state);
   41642           0 :         ae_assert(localnodes->cnt>=*localnodessize+2, "ConvertTreeRec: integrity check failed", _state);
   41643           0 :         ae_assert(localcw->cnt>=*localcwsize+cnt*(nx+ny), "ConvertTreeRec: integrity check failed", _state);
   41644           0 :         localnodes->ptr.p_int[*localnodessize+0] = cnt;
   41645           0 :         localnodes->ptr.p_int[*localnodessize+1] = cwbase+(*localcwsize);
   41646           0 :         *localnodessize = *localnodessize+2;
   41647           0 :         for(i=0; i<=cnt-1; i++)
   41648             :         {
   41649           0 :             for(j=0; j<=nx+ny-1; j++)
   41650             :             {
   41651           0 :                 localcw->ptr.p_double[*localcwsize+i*(nx+ny)+j] = xybuf->ptr.pp_double[i][j];
   41652             :             }
   41653             :         }
   41654           0 :         *localcwsize = *localcwsize+cnt*(nx+ny);
   41655           0 :         return;
   41656             :     }
   41657             :     
   41658             :     /*
   41659             :      * Split node
   41660             :      */
   41661           0 :     if( nodetype==1 )
   41662             :     {
   41663           0 :         kdtreeexploresplit(curtree, nodeoffset, &d, &s, &nodele, &nodege, _state);
   41664           0 :         ae_assert(localnodes->cnt>=*localnodessize+rbfv2_maxnodesize, "ConvertTreeRec: integrity check failed", _state);
   41665           0 :         ae_assert(localsplits->cnt>=*localsplitssize+1, "ConvertTreeRec: integrity check failed", _state);
   41666           0 :         oldnodessize = *localnodessize;
   41667           0 :         localnodes->ptr.p_int[*localnodessize+0] = 0;
   41668           0 :         localnodes->ptr.p_int[*localnodessize+1] = d;
   41669           0 :         localnodes->ptr.p_int[*localnodessize+2] = splitsbase+(*localsplitssize);
   41670           0 :         localnodes->ptr.p_int[*localnodessize+3] = -1;
   41671           0 :         localnodes->ptr.p_int[*localnodessize+4] = -1;
   41672           0 :         *localnodessize = *localnodessize+5;
   41673           0 :         localsplits->ptr.p_double[*localsplitssize+0] = s;
   41674           0 :         *localsplitssize = *localsplitssize+1;
   41675           0 :         localnodes->ptr.p_int[oldnodessize+3] = nodesbase+(*localnodessize);
   41676           0 :         rbfv2_converttreerec(curtree, n, nx, ny, nodele, nodesbase, splitsbase, cwbase, localnodes, localnodessize, localsplits, localsplitssize, localcw, localcwsize, xybuf, _state);
   41677           0 :         localnodes->ptr.p_int[oldnodessize+4] = nodesbase+(*localnodessize);
   41678           0 :         rbfv2_converttreerec(curtree, n, nx, ny, nodege, nodesbase, splitsbase, cwbase, localnodes, localnodessize, localsplits, localsplitssize, localcw, localcwsize, xybuf, _state);
   41679           0 :         return;
   41680             :     }
   41681             :     
   41682             :     /*
   41683             :      * Integrity error
   41684             :      */
   41685           0 :     ae_assert(ae_false, "ConvertTreeRec: integrity check failed", _state);
   41686             : }
   41687             : 
   41688             : 
   41689             : /*************************************************************************
   41690             : This function performs partial calculation of  hierarchical  model:  given
   41691             : evaluation point X and partially computed value Y, it updates Y by  values
   41692             : computed using part of multi-tree given by RootIdx.
   41693             : 
   41694             : INPUT PARAMETERS:
   41695             :     S       -   V2 model
   41696             :     Buf     -   calc-buffer, this function uses following fields:
   41697             :                 * Buf.CurBoxMin - should be set by caller
   41698             :                 * Buf.CurBoxMax - should be set by caller
   41699             :                 * Buf.CurDist2  - squared distance from X to current bounding box,
   41700             :                   should be set by caller
   41701             :     RootIdx -   offset of partial kd-tree
   41702             :     InvR2   -   1/R^2, where R is basis function radius
   41703             :     QueryR2 -   squared query radius, usually it is (R*FarRadius(BasisFunction))^2
   41704             :     X       -   evaluation point, array[NX]
   41705             :     Y       -   partial value, array[NY]
   41706             :     
   41707             : OUTPUT PARAMETERS
   41708             :     Y       -   updated partial value
   41709             : 
   41710             :   -- ALGLIB --
   41711             :      Copyright 20.06.2016 by Bochkanov Sergey
   41712             : *************************************************************************/
   41713           0 : static void rbfv2_partialcalcrec(rbfv2model* s,
   41714             :      rbfv2calcbuffer* buf,
   41715             :      ae_int_t rootidx,
   41716             :      double invr2,
   41717             :      double queryr2,
   41718             :      /* Real    */ ae_vector* x,
   41719             :      /* Real    */ ae_vector* y,
   41720             :      ae_state *_state)
   41721             : {
   41722             :     ae_int_t i;
   41723             :     ae_int_t j;
   41724             :     double ptdist2;
   41725             :     double v;
   41726             :     double v0;
   41727             :     double v1;
   41728             :     ae_int_t cwoffs;
   41729             :     ae_int_t cwcnt;
   41730             :     ae_int_t itemoffs;
   41731             :     double arg;
   41732             :     double val;
   41733             :     ae_int_t d;
   41734             :     double split;
   41735             :     ae_int_t childle;
   41736             :     ae_int_t childge;
   41737             :     ae_int_t childoffs;
   41738             :     ae_bool updatemin;
   41739             :     double prevdist2;
   41740             :     double t1;
   41741             :     ae_int_t nx;
   41742             :     ae_int_t ny;
   41743             : 
   41744             : 
   41745           0 :     nx = s->nx;
   41746           0 :     ny = s->ny;
   41747             :     
   41748             :     /*
   41749             :      * Helps to avoid spurious warnings
   41750             :      */
   41751           0 :     val = (double)(0);
   41752             :     
   41753             :     /*
   41754             :      * Leaf node.
   41755             :      */
   41756           0 :     if( s->kdnodes.ptr.p_int[rootidx]>0 )
   41757             :     {
   41758           0 :         cwcnt = s->kdnodes.ptr.p_int[rootidx+0];
   41759           0 :         cwoffs = s->kdnodes.ptr.p_int[rootidx+1];
   41760           0 :         for(i=0; i<=cwcnt-1; i++)
   41761             :         {
   41762             :             
   41763             :             /*
   41764             :              * Calculate distance
   41765             :              */
   41766           0 :             itemoffs = cwoffs+i*(nx+ny);
   41767           0 :             ptdist2 = (double)(0);
   41768           0 :             for(j=0; j<=nx-1; j++)
   41769             :             {
   41770           0 :                 v = s->cw.ptr.p_double[itemoffs+j]-x->ptr.p_double[j];
   41771           0 :                 ptdist2 = ptdist2+v*v;
   41772             :             }
   41773             :             
   41774             :             /*
   41775             :              * Skip points if distance too large
   41776             :              */
   41777           0 :             if( ptdist2>=queryr2 )
   41778             :             {
   41779           0 :                 continue;
   41780             :             }
   41781             :             
   41782             :             /*
   41783             :              * Update Y
   41784             :              */
   41785           0 :             arg = ptdist2*invr2;
   41786           0 :             if( s->bf==0 )
   41787             :             {
   41788           0 :                 val = ae_exp(-arg, _state);
   41789             :             }
   41790             :             else
   41791             :             {
   41792           0 :                 if( s->bf==1 )
   41793             :                 {
   41794           0 :                     val = rbfv2basisfunc(s->bf, arg, _state);
   41795             :                 }
   41796             :                 else
   41797             :                 {
   41798           0 :                     ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state);
   41799             :                 }
   41800             :             }
   41801           0 :             itemoffs = itemoffs+nx;
   41802           0 :             for(j=0; j<=ny-1; j++)
   41803             :             {
   41804           0 :                 y->ptr.p_double[j] = y->ptr.p_double[j]+val*s->cw.ptr.p_double[itemoffs+j];
   41805             :             }
   41806             :         }
   41807           0 :         return;
   41808             :     }
   41809             :     
   41810             :     /*
   41811             :      * Simple split
   41812             :      */
   41813           0 :     if( s->kdnodes.ptr.p_int[rootidx]==0 )
   41814             :     {
   41815             :         
   41816             :         /*
   41817             :          * Load:
   41818             :          * * D      dimension to split
   41819             :          * * Split  split position
   41820             :          * * ChildLE, ChildGE - indexes of childs
   41821             :          */
   41822           0 :         d = s->kdnodes.ptr.p_int[rootidx+1];
   41823           0 :         split = s->kdsplits.ptr.p_double[s->kdnodes.ptr.p_int[rootidx+2]];
   41824           0 :         childle = s->kdnodes.ptr.p_int[rootidx+3];
   41825           0 :         childge = s->kdnodes.ptr.p_int[rootidx+4];
   41826             :         
   41827             :         /*
   41828             :          * Navigate through childs
   41829             :          */
   41830           0 :         for(i=0; i<=1; i++)
   41831             :         {
   41832             :             
   41833             :             /*
   41834             :              * Select child to process:
   41835             :              * * ChildOffs      current child offset in Nodes[]
   41836             :              * * UpdateMin      whether minimum or maximum value
   41837             :              *                  of bounding box is changed on update
   41838             :              */
   41839           0 :             updatemin = i!=0;
   41840           0 :             if( i==0 )
   41841             :             {
   41842           0 :                 childoffs = childle;
   41843             :             }
   41844             :             else
   41845             :             {
   41846           0 :                 childoffs = childge;
   41847             :             }
   41848             :             
   41849             :             /*
   41850             :              * Update bounding box and current distance
   41851             :              */
   41852           0 :             prevdist2 = buf->curdist2;
   41853           0 :             t1 = x->ptr.p_double[d];
   41854           0 :             if( updatemin )
   41855             :             {
   41856           0 :                 v = buf->curboxmin.ptr.p_double[d];
   41857           0 :                 if( t1<=split )
   41858             :                 {
   41859           0 :                     v0 = v-t1;
   41860           0 :                     if( v0<0 )
   41861             :                     {
   41862           0 :                         v0 = (double)(0);
   41863             :                     }
   41864           0 :                     v1 = split-t1;
   41865           0 :                     buf->curdist2 = buf->curdist2-v0*v0+v1*v1;
   41866             :                 }
   41867           0 :                 buf->curboxmin.ptr.p_double[d] = split;
   41868             :             }
   41869             :             else
   41870             :             {
   41871           0 :                 v = buf->curboxmax.ptr.p_double[d];
   41872           0 :                 if( t1>=split )
   41873             :                 {
   41874           0 :                     v0 = t1-v;
   41875           0 :                     if( v0<0 )
   41876             :                     {
   41877           0 :                         v0 = (double)(0);
   41878             :                     }
   41879           0 :                     v1 = t1-split;
   41880           0 :                     buf->curdist2 = buf->curdist2-v0*v0+v1*v1;
   41881             :                 }
   41882           0 :                 buf->curboxmax.ptr.p_double[d] = split;
   41883             :             }
   41884             :             
   41885             :             /*
   41886             :              * Decide: to dive into cell or not to dive
   41887             :              */
   41888           0 :             if( buf->curdist2<queryr2 )
   41889             :             {
   41890           0 :                 rbfv2_partialcalcrec(s, buf, childoffs, invr2, queryr2, x, y, _state);
   41891             :             }
   41892             :             
   41893             :             /*
   41894             :              * Restore bounding box and distance
   41895             :              */
   41896           0 :             if( updatemin )
   41897             :             {
   41898           0 :                 buf->curboxmin.ptr.p_double[d] = v;
   41899             :             }
   41900             :             else
   41901             :             {
   41902           0 :                 buf->curboxmax.ptr.p_double[d] = v;
   41903             :             }
   41904           0 :             buf->curdist2 = prevdist2;
   41905             :         }
   41906           0 :         return;
   41907             :     }
   41908             :     
   41909             :     /*
   41910             :      * Integrity failure
   41911             :      */
   41912           0 :     ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state);
   41913             : }
   41914             : 
   41915             : 
   41916             : /*************************************************************************
   41917             : This function performs same operation as partialcalcrec(), but  for entire
   41918             : row of the grid. "Row" is a set of nodes (x0,x1,x2,x3) which share x1..x3,
   41919             : but have different x0's. (note: for 2D/3D problems x2..x3 are zero).
   41920             : 
   41921             : Row is given by:
   41922             : * central point XC, which is located at the center of the row, and used to
   41923             :   perform kd-tree requests
   41924             : * set of x0 coordinates stored in RX array (array may be unordered, but it
   41925             :   is expected that spread of x0  is  no  more  than  R;  function  may  be
   41926             :   inefficient for larger spreads).
   41927             : * set of YFlag values stored in RF
   41928             : 
   41929             : INPUT PARAMETERS:
   41930             :     S       -   V2 model
   41931             :     Buf     -   calc-buffer, this function uses following fields:
   41932             :                 * Buf.CurBoxMin - should be set by caller
   41933             :                 * Buf.CurBoxMax - should be set by caller
   41934             :                 * Buf.CurDist2  - squared distance from X to current bounding box,
   41935             :                   should be set by caller
   41936             :     RootIdx -   offset of partial kd-tree
   41937             :     InvR2   -   1/R^2, where R is basis function radius
   41938             :     RQuery2 -   squared query radius, usually it is (R*FarRadius(BasisFunction)+0.5*RowWidth)^2,
   41939             :                 where RowWidth is its spatial  extent  (after  scaling  of
   41940             :                 variables). This radius is used to perform  initial  query
   41941             :                 for neighbors of CX.
   41942             :     RFar2   -   squared far radius; far radius is used to perform actual
   41943             :                 filtering of results of query made with RQuery2.
   41944             :     CX      -   central point, array[NX], used for queries
   41945             :     RX      -   x0 coordinates, array[RowSize]
   41946             :     RF      -   sparsity flags, array[RowSize]
   41947             :     RowSize -   row size in elements
   41948             :     RY      -   input partial value, array[NY]
   41949             :     
   41950             : OUTPUT PARAMETERS
   41951             :     RY      -   updated partial value (function adds its results to RY)
   41952             : 
   41953             :   -- ALGLIB --
   41954             :      Copyright 20.06.2016 by Bochkanov Sergey
   41955             : *************************************************************************/
   41956           0 : static void rbfv2_partialrowcalcrec(rbfv2model* s,
   41957             :      rbfv2calcbuffer* buf,
   41958             :      ae_int_t rootidx,
   41959             :      double invr2,
   41960             :      double rquery2,
   41961             :      double rfar2,
   41962             :      /* Real    */ ae_vector* cx,
   41963             :      /* Real    */ ae_vector* rx,
   41964             :      /* Boolean */ ae_vector* rf,
   41965             :      ae_int_t rowsize,
   41966             :      /* Real    */ ae_vector* ry,
   41967             :      ae_state *_state)
   41968             : {
   41969             :     ae_int_t i;
   41970             :     ae_int_t j;
   41971             :     ae_int_t i0;
   41972             :     ae_int_t i1;
   41973             :     double partialptdist2;
   41974             :     double ptdist2;
   41975             :     double v;
   41976             :     double v0;
   41977             :     double v1;
   41978             :     ae_int_t cwoffs;
   41979             :     ae_int_t cwcnt;
   41980             :     ae_int_t itemoffs;
   41981             :     ae_int_t woffs;
   41982             :     double val;
   41983             :     ae_int_t d;
   41984             :     double split;
   41985             :     ae_int_t childle;
   41986             :     ae_int_t childge;
   41987             :     ae_int_t childoffs;
   41988             :     ae_bool updatemin;
   41989             :     double prevdist2;
   41990             :     double t1;
   41991             :     ae_int_t nx;
   41992             :     ae_int_t ny;
   41993             : 
   41994             : 
   41995           0 :     nx = s->nx;
   41996           0 :     ny = s->ny;
   41997             :     
   41998             :     /*
   41999             :      * Leaf node.
   42000             :      */
   42001           0 :     if( s->kdnodes.ptr.p_int[rootidx]>0 )
   42002             :     {
   42003           0 :         cwcnt = s->kdnodes.ptr.p_int[rootidx+0];
   42004           0 :         cwoffs = s->kdnodes.ptr.p_int[rootidx+1];
   42005           0 :         for(i0=0; i0<=cwcnt-1; i0++)
   42006             :         {
   42007             :             
   42008             :             /*
   42009             :              * Calculate partial distance (components from 1 to NX-1)
   42010             :              */
   42011           0 :             itemoffs = cwoffs+i0*(nx+ny);
   42012           0 :             partialptdist2 = (double)(0);
   42013           0 :             for(j=1; j<=nx-1; j++)
   42014             :             {
   42015           0 :                 v = s->cw.ptr.p_double[itemoffs+j]-cx->ptr.p_double[j];
   42016           0 :                 partialptdist2 = partialptdist2+v*v;
   42017             :             }
   42018             :             
   42019             :             /*
   42020             :              * Process each element of the row
   42021             :              */
   42022           0 :             for(i1=0; i1<=rowsize-1; i1++)
   42023             :             {
   42024           0 :                 if( rf->ptr.p_bool[i1] )
   42025             :                 {
   42026             :                     
   42027             :                     /*
   42028             :                      * Calculate distance
   42029             :                      */
   42030           0 :                     v = s->cw.ptr.p_double[itemoffs]-rx->ptr.p_double[i1];
   42031           0 :                     ptdist2 = partialptdist2+v*v;
   42032             :                     
   42033             :                     /*
   42034             :                      * Skip points if distance too large
   42035             :                      */
   42036           0 :                     if( ptdist2>=rfar2 )
   42037             :                     {
   42038           0 :                         continue;
   42039             :                     }
   42040             :                     
   42041             :                     /*
   42042             :                      * Update Y
   42043             :                      */
   42044           0 :                     val = rbfv2basisfunc(s->bf, ptdist2*invr2, _state);
   42045           0 :                     woffs = itemoffs+nx;
   42046           0 :                     for(j=0; j<=ny-1; j++)
   42047             :                     {
   42048           0 :                         ry->ptr.p_double[j+i1*ny] = ry->ptr.p_double[j+i1*ny]+val*s->cw.ptr.p_double[woffs+j];
   42049             :                     }
   42050             :                 }
   42051             :             }
   42052             :         }
   42053           0 :         return;
   42054             :     }
   42055             :     
   42056             :     /*
   42057             :      * Simple split
   42058             :      */
   42059           0 :     if( s->kdnodes.ptr.p_int[rootidx]==0 )
   42060             :     {
   42061             :         
   42062             :         /*
   42063             :          * Load:
   42064             :          * * D      dimension to split
   42065             :          * * Split  split position
   42066             :          * * ChildLE, ChildGE - indexes of childs
   42067             :          */
   42068           0 :         d = s->kdnodes.ptr.p_int[rootidx+1];
   42069           0 :         split = s->kdsplits.ptr.p_double[s->kdnodes.ptr.p_int[rootidx+2]];
   42070           0 :         childle = s->kdnodes.ptr.p_int[rootidx+3];
   42071           0 :         childge = s->kdnodes.ptr.p_int[rootidx+4];
   42072             :         
   42073             :         /*
   42074             :          * Navigate through childs
   42075             :          */
   42076           0 :         for(i=0; i<=1; i++)
   42077             :         {
   42078             :             
   42079             :             /*
   42080             :              * Select child to process:
   42081             :              * * ChildOffs      current child offset in Nodes[]
   42082             :              * * UpdateMin      whether minimum or maximum value
   42083             :              *                  of bounding box is changed on update
   42084             :              */
   42085           0 :             updatemin = i!=0;
   42086           0 :             if( i==0 )
   42087             :             {
   42088           0 :                 childoffs = childle;
   42089             :             }
   42090             :             else
   42091             :             {
   42092           0 :                 childoffs = childge;
   42093             :             }
   42094             :             
   42095             :             /*
   42096             :              * Update bounding box and current distance
   42097             :              */
   42098           0 :             prevdist2 = buf->curdist2;
   42099           0 :             t1 = cx->ptr.p_double[d];
   42100           0 :             if( updatemin )
   42101             :             {
   42102           0 :                 v = buf->curboxmin.ptr.p_double[d];
   42103           0 :                 if( t1<=split )
   42104             :                 {
   42105           0 :                     v0 = v-t1;
   42106           0 :                     if( v0<0 )
   42107             :                     {
   42108           0 :                         v0 = (double)(0);
   42109             :                     }
   42110           0 :                     v1 = split-t1;
   42111           0 :                     buf->curdist2 = buf->curdist2-v0*v0+v1*v1;
   42112             :                 }
   42113           0 :                 buf->curboxmin.ptr.p_double[d] = split;
   42114             :             }
   42115             :             else
   42116             :             {
   42117           0 :                 v = buf->curboxmax.ptr.p_double[d];
   42118           0 :                 if( t1>=split )
   42119             :                 {
   42120           0 :                     v0 = t1-v;
   42121           0 :                     if( v0<0 )
   42122             :                     {
   42123           0 :                         v0 = (double)(0);
   42124             :                     }
   42125           0 :                     v1 = t1-split;
   42126           0 :                     buf->curdist2 = buf->curdist2-v0*v0+v1*v1;
   42127             :                 }
   42128           0 :                 buf->curboxmax.ptr.p_double[d] = split;
   42129             :             }
   42130             :             
   42131             :             /*
   42132             :              * Decide: to dive into cell or not to dive
   42133             :              */
   42134           0 :             if( buf->curdist2<rquery2 )
   42135             :             {
   42136           0 :                 rbfv2_partialrowcalcrec(s, buf, childoffs, invr2, rquery2, rfar2, cx, rx, rf, rowsize, ry, _state);
   42137             :             }
   42138             :             
   42139             :             /*
   42140             :              * Restore bounding box and distance
   42141             :              */
   42142           0 :             if( updatemin )
   42143             :             {
   42144           0 :                 buf->curboxmin.ptr.p_double[d] = v;
   42145             :             }
   42146             :             else
   42147             :             {
   42148           0 :                 buf->curboxmax.ptr.p_double[d] = v;
   42149             :             }
   42150           0 :             buf->curdist2 = prevdist2;
   42151             :         }
   42152           0 :         return;
   42153             :     }
   42154             :     
   42155             :     /*
   42156             :      * Integrity failure
   42157             :      */
   42158           0 :     ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state);
   42159             : }
   42160             : 
   42161             : 
   42162             : /*************************************************************************
   42163             : This function prepares partial query
   42164             : 
   42165             : INPUT PARAMETERS:
   42166             :     X       -   query point
   42167             :     kdBoxMin, kdBoxMax - current bounding box
   42168             :     NX      -   problem size
   42169             :     Buf     -   preallocated buffer; this function just loads data, but
   42170             :                 does not allocate place for them.
   42171             :     Cnt     -   counter variable which is set to zery by this function, as
   42172             :                 convenience, and to remember about necessity to zero counter
   42173             :                 prior to calling partialqueryrec().
   42174             :     
   42175             : OUTPUT PARAMETERS
   42176             :     Buf     -   calc-buffer:
   42177             :                 * Buf.CurBoxMin - current box
   42178             :                 * Buf.CurBoxMax - current box
   42179             :                 * Buf.CurDist2  - squared distance from X to current box
   42180             :     Cnt     -   set to zero
   42181             : 
   42182             :   -- ALGLIB --
   42183             :      Copyright 20.06.2016 by Bochkanov Sergey
   42184             : *************************************************************************/
   42185           0 : static void rbfv2_preparepartialquery(/* Real    */ ae_vector* x,
   42186             :      /* Real    */ ae_vector* kdboxmin,
   42187             :      /* Real    */ ae_vector* kdboxmax,
   42188             :      ae_int_t nx,
   42189             :      rbfv2calcbuffer* buf,
   42190             :      ae_int_t* cnt,
   42191             :      ae_state *_state)
   42192             : {
   42193             :     ae_int_t j;
   42194             : 
   42195             : 
   42196           0 :     *cnt = 0;
   42197           0 :     buf->curdist2 = (double)(0);
   42198           0 :     for(j=0; j<=nx-1; j++)
   42199             :     {
   42200           0 :         buf->curboxmin.ptr.p_double[j] = kdboxmin->ptr.p_double[j];
   42201           0 :         buf->curboxmax.ptr.p_double[j] = kdboxmax->ptr.p_double[j];
   42202           0 :         if( ae_fp_less(x->ptr.p_double[j],buf->curboxmin.ptr.p_double[j]) )
   42203             :         {
   42204           0 :             buf->curdist2 = buf->curdist2+ae_sqr(buf->curboxmin.ptr.p_double[j]-x->ptr.p_double[j], _state);
   42205             :         }
   42206             :         else
   42207             :         {
   42208           0 :             if( ae_fp_greater(x->ptr.p_double[j],buf->curboxmax.ptr.p_double[j]) )
   42209             :             {
   42210           0 :                 buf->curdist2 = buf->curdist2+ae_sqr(x->ptr.p_double[j]-buf->curboxmax.ptr.p_double[j], _state);
   42211             :             }
   42212             :         }
   42213             :     }
   42214           0 : }
   42215             : 
   42216             : 
   42217             : /*************************************************************************
   42218             : This function performs partial (for just one subtree of multi-tree)  query
   42219             : for neighbors located in R-sphere around X. It returns  squared  distances
   42220             : from X to points and offsets in S.CW[] array for points being found.
   42221             : 
   42222             : INPUT PARAMETERS:
   42223             :     kdNodes, kdSplits, CW, NX, NY - corresponding fields of V2 model
   42224             :     Buf     -   calc-buffer, this function uses following fields:
   42225             :                 * Buf.CurBoxMin - should be set by caller
   42226             :                 * Buf.CurBoxMax - should be set by caller
   42227             :                 * Buf.CurDist2  - squared distance from X to current
   42228             :                   bounding box, should be set by caller
   42229             :                 You may use preparepartialquery() function to initialize
   42230             :                 these fields.
   42231             :     RootIdx -   offset of partial kd-tree
   42232             :     QueryR2 -   squared query radius
   42233             :     X       -   array[NX], point being queried
   42234             :     R2      -   preallocated output buffer; it is caller's responsibility
   42235             :                 to make sure that R2 has enough space.
   42236             :     Offs    -   preallocated output buffer; it is caller's responsibility
   42237             :                 to make sure that Offs has enough space.
   42238             :     K       -   MUST BE ZERO ON INITIAL CALL. This variable is incremented,
   42239             :                 not set. So, any no-zero value will result in the incorrect
   42240             :                 points count being returned.
   42241             :     
   42242             : OUTPUT PARAMETERS
   42243             :     R2      -   squared distances in first K elements
   42244             :     Offs    -   offsets in S.CW in first K elements
   42245             :     K       -   points count
   42246             : 
   42247             :   -- ALGLIB --
   42248             :      Copyright 20.06.2016 by Bochkanov Sergey
   42249             : *************************************************************************/
   42250           0 : static void rbfv2_partialqueryrec(/* Integer */ ae_vector* kdnodes,
   42251             :      /* Real    */ ae_vector* kdsplits,
   42252             :      /* Real    */ ae_vector* cw,
   42253             :      ae_int_t nx,
   42254             :      ae_int_t ny,
   42255             :      rbfv2calcbuffer* buf,
   42256             :      ae_int_t rootidx,
   42257             :      double queryr2,
   42258             :      /* Real    */ ae_vector* x,
   42259             :      /* Real    */ ae_vector* r2,
   42260             :      /* Integer */ ae_vector* offs,
   42261             :      ae_int_t* k,
   42262             :      ae_state *_state)
   42263             : {
   42264             :     ae_int_t i;
   42265             :     ae_int_t j;
   42266             :     double ptdist2;
   42267             :     double v;
   42268             :     ae_int_t cwoffs;
   42269             :     ae_int_t cwcnt;
   42270             :     ae_int_t itemoffs;
   42271             :     ae_int_t d;
   42272             :     double split;
   42273             :     ae_int_t childle;
   42274             :     ae_int_t childge;
   42275             :     ae_int_t childoffs;
   42276             :     ae_bool updatemin;
   42277             :     double prevdist2;
   42278             :     double t1;
   42279             : 
   42280             : 
   42281             :     
   42282             :     /*
   42283             :      * Leaf node.
   42284             :      */
   42285           0 :     if( kdnodes->ptr.p_int[rootidx]>0 )
   42286             :     {
   42287           0 :         cwcnt = kdnodes->ptr.p_int[rootidx+0];
   42288           0 :         cwoffs = kdnodes->ptr.p_int[rootidx+1];
   42289           0 :         for(i=0; i<=cwcnt-1; i++)
   42290             :         {
   42291             :             
   42292             :             /*
   42293             :              * Calculate distance
   42294             :              */
   42295           0 :             itemoffs = cwoffs+i*(nx+ny);
   42296           0 :             ptdist2 = (double)(0);
   42297           0 :             for(j=0; j<=nx-1; j++)
   42298             :             {
   42299           0 :                 v = cw->ptr.p_double[itemoffs+j]-x->ptr.p_double[j];
   42300           0 :                 ptdist2 = ptdist2+v*v;
   42301             :             }
   42302             :             
   42303             :             /*
   42304             :              * Skip points if distance too large
   42305             :              */
   42306           0 :             if( ae_fp_greater_eq(ptdist2,queryr2) )
   42307             :             {
   42308           0 :                 continue;
   42309             :             }
   42310             :             
   42311             :             /*
   42312             :              * Output
   42313             :              */
   42314           0 :             r2->ptr.p_double[*k] = ptdist2;
   42315           0 :             offs->ptr.p_int[*k] = itemoffs;
   42316           0 :             *k = *k+1;
   42317             :         }
   42318           0 :         return;
   42319             :     }
   42320             :     
   42321             :     /*
   42322             :      * Simple split
   42323             :      */
   42324           0 :     if( kdnodes->ptr.p_int[rootidx]==0 )
   42325             :     {
   42326             :         
   42327             :         /*
   42328             :          * Load:
   42329             :          * * D      dimension to split
   42330             :          * * Split  split position
   42331             :          * * ChildLE, ChildGE - indexes of childs
   42332             :          */
   42333           0 :         d = kdnodes->ptr.p_int[rootidx+1];
   42334           0 :         split = kdsplits->ptr.p_double[kdnodes->ptr.p_int[rootidx+2]];
   42335           0 :         childle = kdnodes->ptr.p_int[rootidx+3];
   42336           0 :         childge = kdnodes->ptr.p_int[rootidx+4];
   42337             :         
   42338             :         /*
   42339             :          * Navigate through childs
   42340             :          */
   42341           0 :         for(i=0; i<=1; i++)
   42342             :         {
   42343             :             
   42344             :             /*
   42345             :              * Select child to process:
   42346             :              * * ChildOffs      current child offset in Nodes[]
   42347             :              * * UpdateMin      whether minimum or maximum value
   42348             :              *                  of bounding box is changed on update
   42349             :              */
   42350           0 :             updatemin = i!=0;
   42351           0 :             if( i==0 )
   42352             :             {
   42353           0 :                 childoffs = childle;
   42354             :             }
   42355             :             else
   42356             :             {
   42357           0 :                 childoffs = childge;
   42358             :             }
   42359             :             
   42360             :             /*
   42361             :              * Update bounding box and current distance
   42362             :              */
   42363           0 :             prevdist2 = buf->curdist2;
   42364           0 :             t1 = x->ptr.p_double[d];
   42365           0 :             if( updatemin )
   42366             :             {
   42367           0 :                 v = buf->curboxmin.ptr.p_double[d];
   42368           0 :                 if( ae_fp_less_eq(t1,split) )
   42369             :                 {
   42370           0 :                     buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(v-t1, (double)(0), _state), _state)+ae_sqr(split-t1, _state);
   42371             :                 }
   42372           0 :                 buf->curboxmin.ptr.p_double[d] = split;
   42373             :             }
   42374             :             else
   42375             :             {
   42376           0 :                 v = buf->curboxmax.ptr.p_double[d];
   42377           0 :                 if( ae_fp_greater_eq(t1,split) )
   42378             :                 {
   42379           0 :                     buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(t1-v, (double)(0), _state), _state)+ae_sqr(t1-split, _state);
   42380             :                 }
   42381           0 :                 buf->curboxmax.ptr.p_double[d] = split;
   42382             :             }
   42383             :             
   42384             :             /*
   42385             :              * Decide: to dive into cell or not to dive
   42386             :              */
   42387           0 :             if( ae_fp_less(buf->curdist2,queryr2) )
   42388             :             {
   42389           0 :                 rbfv2_partialqueryrec(kdnodes, kdsplits, cw, nx, ny, buf, childoffs, queryr2, x, r2, offs, k, _state);
   42390             :             }
   42391             :             
   42392             :             /*
   42393             :              * Restore bounding box and distance
   42394             :              */
   42395           0 :             if( updatemin )
   42396             :             {
   42397           0 :                 buf->curboxmin.ptr.p_double[d] = v;
   42398             :             }
   42399             :             else
   42400             :             {
   42401           0 :                 buf->curboxmax.ptr.p_double[d] = v;
   42402             :             }
   42403           0 :             buf->curdist2 = prevdist2;
   42404             :         }
   42405           0 :         return;
   42406             :     }
   42407             :     
   42408             :     /*
   42409             :      * Integrity failure
   42410             :      */
   42411           0 :     ae_assert(ae_false, "PartialQueryRec: integrity check failed", _state);
   42412             : }
   42413             : 
   42414             : 
   42415             : /*************************************************************************
   42416             : This function performs  partial  (for  just  one  subtree  of  multi-tree)
   42417             : counting of neighbors located in R-sphere around X.
   42418             : 
   42419             : This function does not guarantee consistency of results with other partial
   42420             : queries, it should be used only to get approximate estimates (well, we  do
   42421             : not  use   approximate   algorithms,  but  rounding  errors  may  give  us
   42422             : inconsistent results in just-at-the-boundary cases).
   42423             : 
   42424             : INPUT PARAMETERS:
   42425             :     kdNodes, kdSplits, CW, NX, NY - corresponding fields of V2 model
   42426             :     Buf     -   calc-buffer, this function uses following fields:
   42427             :                 * Buf.CurBoxMin - should be set by caller
   42428             :                 * Buf.CurBoxMax - should be set by caller
   42429             :                 * Buf.CurDist2  - squared distance from X to current
   42430             :                   bounding box, should be set by caller
   42431             :                 You may use preparepartialquery() function to initialize
   42432             :                 these fields.
   42433             :     RootIdx -   offset of partial kd-tree
   42434             :     QueryR2 -   squared query radius
   42435             :     X       -   array[NX], point being queried
   42436             :     
   42437             : RESULT:
   42438             :     points count
   42439             : 
   42440             :   -- ALGLIB --
   42441             :      Copyright 20.06.2016 by Bochkanov Sergey
   42442             : *************************************************************************/
   42443           0 : static ae_int_t rbfv2_partialcountrec(/* Integer */ ae_vector* kdnodes,
   42444             :      /* Real    */ ae_vector* kdsplits,
   42445             :      /* Real    */ ae_vector* cw,
   42446             :      ae_int_t nx,
   42447             :      ae_int_t ny,
   42448             :      rbfv2calcbuffer* buf,
   42449             :      ae_int_t rootidx,
   42450             :      double queryr2,
   42451             :      /* Real    */ ae_vector* x,
   42452             :      ae_state *_state)
   42453             : {
   42454             :     ae_int_t i;
   42455             :     ae_int_t j;
   42456             :     double ptdist2;
   42457             :     double v;
   42458             :     ae_int_t cwoffs;
   42459             :     ae_int_t cwcnt;
   42460             :     ae_int_t itemoffs;
   42461             :     ae_int_t d;
   42462             :     double split;
   42463             :     ae_int_t childle;
   42464             :     ae_int_t childge;
   42465             :     ae_int_t childoffs;
   42466             :     ae_bool updatemin;
   42467             :     double prevdist2;
   42468             :     double t1;
   42469             :     ae_int_t result;
   42470             : 
   42471             : 
   42472           0 :     result = 0;
   42473             :     
   42474             :     /*
   42475             :      * Leaf node.
   42476             :      */
   42477           0 :     if( kdnodes->ptr.p_int[rootidx]>0 )
   42478             :     {
   42479           0 :         cwcnt = kdnodes->ptr.p_int[rootidx+0];
   42480           0 :         cwoffs = kdnodes->ptr.p_int[rootidx+1];
   42481           0 :         for(i=0; i<=cwcnt-1; i++)
   42482             :         {
   42483             :             
   42484             :             /*
   42485             :              * Calculate distance
   42486             :              */
   42487           0 :             itemoffs = cwoffs+i*(nx+ny);
   42488           0 :             ptdist2 = (double)(0);
   42489           0 :             for(j=0; j<=nx-1; j++)
   42490             :             {
   42491           0 :                 v = cw->ptr.p_double[itemoffs+j]-x->ptr.p_double[j];
   42492           0 :                 ptdist2 = ptdist2+v*v;
   42493             :             }
   42494             :             
   42495             :             /*
   42496             :              * Skip points if distance too large
   42497             :              */
   42498           0 :             if( ae_fp_greater_eq(ptdist2,queryr2) )
   42499             :             {
   42500           0 :                 continue;
   42501             :             }
   42502             :             
   42503             :             /*
   42504             :              * Output
   42505             :              */
   42506           0 :             result = result+1;
   42507             :         }
   42508           0 :         return result;
   42509             :     }
   42510             :     
   42511             :     /*
   42512             :      * Simple split
   42513             :      */
   42514           0 :     if( kdnodes->ptr.p_int[rootidx]==0 )
   42515             :     {
   42516             :         
   42517             :         /*
   42518             :          * Load:
   42519             :          * * D      dimension to split
   42520             :          * * Split  split position
   42521             :          * * ChildLE, ChildGE - indexes of childs
   42522             :          */
   42523           0 :         d = kdnodes->ptr.p_int[rootidx+1];
   42524           0 :         split = kdsplits->ptr.p_double[kdnodes->ptr.p_int[rootidx+2]];
   42525           0 :         childle = kdnodes->ptr.p_int[rootidx+3];
   42526           0 :         childge = kdnodes->ptr.p_int[rootidx+4];
   42527             :         
   42528             :         /*
   42529             :          * Navigate through childs
   42530             :          */
   42531           0 :         for(i=0; i<=1; i++)
   42532             :         {
   42533             :             
   42534             :             /*
   42535             :              * Select child to process:
   42536             :              * * ChildOffs      current child offset in Nodes[]
   42537             :              * * UpdateMin      whether minimum or maximum value
   42538             :              *                  of bounding box is changed on update
   42539             :              */
   42540           0 :             updatemin = i!=0;
   42541           0 :             if( i==0 )
   42542             :             {
   42543           0 :                 childoffs = childle;
   42544             :             }
   42545             :             else
   42546             :             {
   42547           0 :                 childoffs = childge;
   42548             :             }
   42549             :             
   42550             :             /*
   42551             :              * Update bounding box and current distance
   42552             :              */
   42553           0 :             prevdist2 = buf->curdist2;
   42554           0 :             t1 = x->ptr.p_double[d];
   42555           0 :             if( updatemin )
   42556             :             {
   42557           0 :                 v = buf->curboxmin.ptr.p_double[d];
   42558           0 :                 if( ae_fp_less_eq(t1,split) )
   42559             :                 {
   42560           0 :                     buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(v-t1, (double)(0), _state), _state)+ae_sqr(split-t1, _state);
   42561             :                 }
   42562           0 :                 buf->curboxmin.ptr.p_double[d] = split;
   42563             :             }
   42564             :             else
   42565             :             {
   42566           0 :                 v = buf->curboxmax.ptr.p_double[d];
   42567           0 :                 if( ae_fp_greater_eq(t1,split) )
   42568             :                 {
   42569           0 :                     buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(t1-v, (double)(0), _state), _state)+ae_sqr(t1-split, _state);
   42570             :                 }
   42571           0 :                 buf->curboxmax.ptr.p_double[d] = split;
   42572             :             }
   42573             :             
   42574             :             /*
   42575             :              * Decide: to dive into cell or not to dive
   42576             :              */
   42577           0 :             if( ae_fp_less(buf->curdist2,queryr2) )
   42578             :             {
   42579           0 :                 result = result+rbfv2_partialcountrec(kdnodes, kdsplits, cw, nx, ny, buf, childoffs, queryr2, x, _state);
   42580             :             }
   42581             :             
   42582             :             /*
   42583             :              * Restore bounding box and distance
   42584             :              */
   42585           0 :             if( updatemin )
   42586             :             {
   42587           0 :                 buf->curboxmin.ptr.p_double[d] = v;
   42588             :             }
   42589             :             else
   42590             :             {
   42591           0 :                 buf->curboxmax.ptr.p_double[d] = v;
   42592             :             }
   42593           0 :             buf->curdist2 = prevdist2;
   42594             :         }
   42595           0 :         return result;
   42596             :     }
   42597             :     
   42598             :     /*
   42599             :      * Integrity failure
   42600             :      */
   42601           0 :     ae_assert(ae_false, "PartialCountRec: integrity check failed", _state);
   42602           0 :     return result;
   42603             : }
   42604             : 
   42605             : 
   42606             : /*************************************************************************
   42607             : This function performs partial (for just one subtree of multi-tree) unpack
   42608             : for RBF model. It appends center coordinates,  weights  and  per-dimension
   42609             : radii (according to current scaling) to preallocated output array.
   42610             : 
   42611             : INPUT PARAMETERS:
   42612             :     kdNodes, kdSplits, CW, S, NX, NY - corresponding fields of V2 model
   42613             :     RootIdx -   offset of partial kd-tree
   42614             :     R       -   radius for current partial tree
   42615             :     XWR     -   preallocated output buffer; it is caller's responsibility
   42616             :                 to make sure that XWR has enough space. First K rows are
   42617             :                 already occupied.
   42618             :     K       -   number of already occupied rows in XWR.
   42619             :     
   42620             : OUTPUT PARAMETERS
   42621             :     XWR     -   updated XWR
   42622             :     K       -   updated rows count
   42623             : 
   42624             :   -- ALGLIB --
   42625             :      Copyright 20.06.2016 by Bochkanov Sergey
   42626             : *************************************************************************/
   42627           0 : static void rbfv2_partialunpackrec(/* Integer */ ae_vector* kdnodes,
   42628             :      /* Real    */ ae_vector* kdsplits,
   42629             :      /* Real    */ ae_vector* cw,
   42630             :      /* Real    */ ae_vector* s,
   42631             :      ae_int_t nx,
   42632             :      ae_int_t ny,
   42633             :      ae_int_t rootidx,
   42634             :      double r,
   42635             :      /* Real    */ ae_matrix* xwr,
   42636             :      ae_int_t* k,
   42637             :      ae_state *_state)
   42638             : {
   42639             :     ae_int_t i;
   42640             :     ae_int_t j;
   42641             :     ae_int_t childle;
   42642             :     ae_int_t childge;
   42643             :     ae_int_t itemoffs;
   42644             :     ae_int_t cwoffs;
   42645             :     ae_int_t cwcnt;
   42646             : 
   42647             : 
   42648             :     
   42649             :     /*
   42650             :      * Leaf node.
   42651             :      */
   42652           0 :     if( kdnodes->ptr.p_int[rootidx]>0 )
   42653             :     {
   42654           0 :         cwcnt = kdnodes->ptr.p_int[rootidx+0];
   42655           0 :         cwoffs = kdnodes->ptr.p_int[rootidx+1];
   42656           0 :         for(i=0; i<=cwcnt-1; i++)
   42657             :         {
   42658           0 :             itemoffs = cwoffs+i*(nx+ny);
   42659           0 :             for(j=0; j<=nx+ny-1; j++)
   42660             :             {
   42661           0 :                 xwr->ptr.pp_double[*k][j] = cw->ptr.p_double[itemoffs+j];
   42662             :             }
   42663           0 :             for(j=0; j<=nx-1; j++)
   42664             :             {
   42665           0 :                 xwr->ptr.pp_double[*k][j] = xwr->ptr.pp_double[*k][j]*s->ptr.p_double[j];
   42666             :             }
   42667           0 :             for(j=0; j<=nx-1; j++)
   42668             :             {
   42669           0 :                 xwr->ptr.pp_double[*k][nx+ny+j] = r*s->ptr.p_double[j];
   42670             :             }
   42671           0 :             *k = *k+1;
   42672             :         }
   42673           0 :         return;
   42674             :     }
   42675             :     
   42676             :     /*
   42677             :      * Simple split
   42678             :      */
   42679           0 :     if( kdnodes->ptr.p_int[rootidx]==0 )
   42680             :     {
   42681             :         
   42682             :         /*
   42683             :          * Load:
   42684             :          * * ChildLE, ChildGE - indexes of childs
   42685             :          */
   42686           0 :         childle = kdnodes->ptr.p_int[rootidx+3];
   42687           0 :         childge = kdnodes->ptr.p_int[rootidx+4];
   42688             :         
   42689             :         /*
   42690             :          * Process both parts of split
   42691             :          */
   42692           0 :         rbfv2_partialunpackrec(kdnodes, kdsplits, cw, s, nx, ny, childle, r, xwr, k, _state);
   42693           0 :         rbfv2_partialunpackrec(kdnodes, kdsplits, cw, s, nx, ny, childge, r, xwr, k, _state);
   42694           0 :         return;
   42695             :     }
   42696             :     
   42697             :     /*
   42698             :      * Integrity failure
   42699             :      */
   42700           0 :     ae_assert(ae_false, "PartialUnpackRec: integrity check failed", _state);
   42701             : }
   42702             : 
   42703             : 
   42704             : /*************************************************************************
   42705             : This function returns size of design matrix row for evaluation point X0,
   42706             : given:
   42707             : * query radius multiplier (either RBFV2NearRadius() or RBFV2FarRadius())
   42708             : * hierarchy level: value in [0,NH) for single-level model, or negative
   42709             :   value for multilevel model (all levels of hierarchy in single matrix,
   42710             :   like one used by nonnegative RBF)
   42711             : 
   42712             : INPUT PARAMETERS:
   42713             :     kdNodes, kdSplits, CW, Ri, kdRoots, kdBoxMin, kdBoxMax, NX, NY, NH - corresponding fields of V2 model
   42714             :     Level   -   value in [0,NH) for single-level design matrix, negative
   42715             :                 value for multilevel design matrix
   42716             :     RCoeff  -   radius coefficient, either RBFV2NearRadius() or RBFV2FarRadius()
   42717             :     X0      -   query point
   42718             :     CalcBuf -   buffer for PreparePartialQuery(), allocated by caller
   42719             :     
   42720             : RESULT:
   42721             :     row size
   42722             : 
   42723             :   -- ALGLIB --
   42724             :      Copyright 28.09.2016 by Bochkanov Sergey
   42725             : *************************************************************************/
   42726           0 : static ae_int_t rbfv2_designmatrixrowsize(/* Integer */ ae_vector* kdnodes,
   42727             :      /* Real    */ ae_vector* kdsplits,
   42728             :      /* Real    */ ae_vector* cw,
   42729             :      /* Real    */ ae_vector* ri,
   42730             :      /* Integer */ ae_vector* kdroots,
   42731             :      /* Real    */ ae_vector* kdboxmin,
   42732             :      /* Real    */ ae_vector* kdboxmax,
   42733             :      ae_int_t nx,
   42734             :      ae_int_t ny,
   42735             :      ae_int_t nh,
   42736             :      ae_int_t level,
   42737             :      double rcoeff,
   42738             :      /* Real    */ ae_vector* x0,
   42739             :      rbfv2calcbuffer* calcbuf,
   42740             :      ae_state *_state)
   42741             : {
   42742             :     ae_int_t dummy;
   42743             :     ae_int_t levelidx;
   42744             :     ae_int_t level0;
   42745             :     ae_int_t level1;
   42746             :     double curradius2;
   42747             :     ae_int_t result;
   42748             : 
   42749             : 
   42750           0 :     ae_assert(nh>0, "DesignMatrixRowSize: integrity failure", _state);
   42751           0 :     if( level>=0 )
   42752             :     {
   42753           0 :         level0 = level;
   42754           0 :         level1 = level;
   42755             :     }
   42756             :     else
   42757             :     {
   42758           0 :         level0 = 0;
   42759           0 :         level1 = nh-1;
   42760             :     }
   42761           0 :     result = 0;
   42762           0 :     for(levelidx=level0; levelidx<=level1; levelidx++)
   42763             :     {
   42764           0 :         curradius2 = ae_sqr(ri->ptr.p_double[levelidx]*rcoeff, _state);
   42765           0 :         rbfv2_preparepartialquery(x0, kdboxmin, kdboxmax, nx, calcbuf, &dummy, _state);
   42766           0 :         result = result+rbfv2_partialcountrec(kdnodes, kdsplits, cw, nx, ny, calcbuf, kdroots->ptr.p_int[levelidx], curradius2, x0, _state);
   42767             :     }
   42768           0 :     return result;
   42769             : }
   42770             : 
   42771             : 
   42772             : /*************************************************************************
   42773             : This function generates design matrix row for evaluation point X0, given:
   42774             : * query radius multiplier (either RBFV2NearRadius() or RBFV2FarRadius())
   42775             : * hierarchy level: value in [0,NH) for single-level model, or negative
   42776             :   value for multilevel model (all levels of hierarchy in single matrix,
   42777             :   like one used by nonnegative RBF)
   42778             : 
   42779             : INPUT PARAMETERS:
   42780             :     kdNodes, kdSplits, CW, Ri, kdRoots, kdBoxMin, kdBoxMax, NX, NY, NH - corresponding fields of V2 model
   42781             : 
   42782             :     CWRange -   internal array[NH+1] used by RBF construction function,
   42783             :                 stores ranges of CW occupied by NH trees.
   42784             :     Level   -   value in [0,NH) for single-level design matrix, negative
   42785             :                 value for multilevel design matrix
   42786             :     BF      -   basis function type
   42787             :     RCoeff  -   radius coefficient, either RBFV2NearRadius() or RBFV2FarRadius()
   42788             :     RowsPerPoint-equal to:
   42789             :                 * 1 for unpenalized regression model
   42790             :                 * 1+NX for basic form of nonsmoothness penalty
   42791             :     Penalty -   nonsmoothness penalty coefficient
   42792             :     
   42793             :     X0      -   query point
   42794             :     
   42795             :     CalcBuf -   buffer for PreparePartialQuery(), allocated by caller
   42796             :     R2      -   preallocated temporary buffer, size is at least NPoints;
   42797             :                 it is caller's responsibility to make sure that R2 has enough space.
   42798             :     Offs    -   preallocated temporary buffer; size is at least NPoints;
   42799             :                 it is caller's responsibility to make sure that Offs has enough space.
   42800             :     K       -   MUST BE ZERO ON INITIAL CALL. This variable is incremented,
   42801             :                 not set. So, any no-zero value will result in the incorrect
   42802             :                 points count being returned.
   42803             :     RowIdx  -   preallocated array, at least RowSize elements
   42804             :     RowVal  -   preallocated array, at least RowSize*RowsPerPoint elements
   42805             :     
   42806             : RESULT:
   42807             :     RowIdx  -   RowSize elements are filled with column indexes of non-zero
   42808             :                 design matrix entries
   42809             :     RowVal  -   RowSize*RowsPerPoint elements are filled with design matrix
   42810             :                 values, with column RowIdx[0] being stored in first RowsPerPoint
   42811             :                 elements of RowVal, column RowIdx[1] being stored in next
   42812             :                 RowsPerPoint elements, and so on.
   42813             :                 
   42814             :                 First element in contiguous set of RowsPerPoint elements
   42815             :                 corresponds to 
   42816             :                 
   42817             :     RowSize -   number of columns per row
   42818             : 
   42819             :   -- ALGLIB --
   42820             :      Copyright 28.09.2016 by Bochkanov Sergey
   42821             : *************************************************************************/
   42822           0 : static void rbfv2_designmatrixgeneraterow(/* Integer */ ae_vector* kdnodes,
   42823             :      /* Real    */ ae_vector* kdsplits,
   42824             :      /* Real    */ ae_vector* cw,
   42825             :      /* Real    */ ae_vector* ri,
   42826             :      /* Integer */ ae_vector* kdroots,
   42827             :      /* Real    */ ae_vector* kdboxmin,
   42828             :      /* Real    */ ae_vector* kdboxmax,
   42829             :      /* Integer */ ae_vector* cwrange,
   42830             :      ae_int_t nx,
   42831             :      ae_int_t ny,
   42832             :      ae_int_t nh,
   42833             :      ae_int_t level,
   42834             :      ae_int_t bf,
   42835             :      double rcoeff,
   42836             :      ae_int_t rowsperpoint,
   42837             :      double penalty,
   42838             :      /* Real    */ ae_vector* x0,
   42839             :      rbfv2calcbuffer* calcbuf,
   42840             :      /* Real    */ ae_vector* tmpr2,
   42841             :      /* Integer */ ae_vector* tmpoffs,
   42842             :      /* Integer */ ae_vector* rowidx,
   42843             :      /* Real    */ ae_vector* rowval,
   42844             :      ae_int_t* rowsize,
   42845             :      ae_state *_state)
   42846             : {
   42847             :     ae_int_t j;
   42848             :     ae_int_t k;
   42849             :     ae_int_t cnt;
   42850             :     ae_int_t levelidx;
   42851             :     ae_int_t level0;
   42852             :     ae_int_t level1;
   42853             :     double invri2;
   42854             :     double curradius2;
   42855             :     double val;
   42856             :     double dval;
   42857             :     double d2val;
   42858             : 
   42859           0 :     *rowsize = 0;
   42860             : 
   42861           0 :     ae_assert(nh>0, "DesignMatrixGenerateRow: integrity failure (a)", _state);
   42862           0 :     ae_assert(rowsperpoint==1||rowsperpoint==1+nx, "DesignMatrixGenerateRow: integrity failure (b)", _state);
   42863           0 :     if( level>=0 )
   42864             :     {
   42865           0 :         level0 = level;
   42866           0 :         level1 = level;
   42867             :     }
   42868             :     else
   42869             :     {
   42870           0 :         level0 = 0;
   42871           0 :         level1 = nh-1;
   42872             :     }
   42873           0 :     *rowsize = 0;
   42874           0 :     for(levelidx=level0; levelidx<=level1; levelidx++)
   42875             :     {
   42876           0 :         curradius2 = ae_sqr(ri->ptr.p_double[levelidx]*rcoeff, _state);
   42877           0 :         invri2 = 1/ae_sqr(ri->ptr.p_double[levelidx], _state);
   42878           0 :         rbfv2_preparepartialquery(x0, kdboxmin, kdboxmax, nx, calcbuf, &cnt, _state);
   42879           0 :         rbfv2_partialqueryrec(kdnodes, kdsplits, cw, nx, ny, calcbuf, kdroots->ptr.p_int[levelidx], curradius2, x0, tmpr2, tmpoffs, &cnt, _state);
   42880           0 :         ae_assert(tmpr2->cnt>=cnt, "DesignMatrixRowSize: integrity failure (c)", _state);
   42881           0 :         ae_assert(tmpoffs->cnt>=cnt, "DesignMatrixRowSize: integrity failure (d)", _state);
   42882           0 :         ae_assert(rowidx->cnt>=*rowsize+cnt, "DesignMatrixRowSize: integrity failure (e)", _state);
   42883           0 :         ae_assert(rowval->cnt>=rowsperpoint*(*rowsize+cnt), "DesignMatrixRowSize: integrity failure (f)", _state);
   42884           0 :         for(j=0; j<=cnt-1; j++)
   42885             :         {
   42886             :             
   42887             :             /*
   42888             :              * Generate element corresponding to fitting error.
   42889             :              * Store derivative information which may be required later.
   42890             :              */
   42891           0 :             ae_assert((tmpoffs->ptr.p_int[j]-cwrange->ptr.p_int[level0])%(nx+ny)==0, "DesignMatrixRowSize: integrity failure (g)", _state);
   42892           0 :             rbfv2basisfuncdiff2(bf, tmpr2->ptr.p_double[j]*invri2, &val, &dval, &d2val, _state);
   42893           0 :             rowidx->ptr.p_int[*rowsize+j] = (tmpoffs->ptr.p_int[j]-cwrange->ptr.p_int[level0])/(nx+ny);
   42894           0 :             rowval->ptr.p_double[(*rowsize+j)*rowsperpoint+0] = val;
   42895           0 :             if( rowsperpoint==1 )
   42896             :             {
   42897           0 :                 continue;
   42898             :             }
   42899             :             
   42900             :             /*
   42901             :              * Generate elements corresponding to nonsmoothness penalty
   42902             :              */
   42903           0 :             ae_assert(rowsperpoint==1+nx, "DesignMatrixRowSize: integrity failure (h)", _state);
   42904           0 :             for(k=0; k<=nx-1; k++)
   42905             :             {
   42906           0 :                 rowval->ptr.p_double[(*rowsize+j)*rowsperpoint+1+k] = penalty*(dval*2*invri2+d2val*ae_sqr(2*(x0->ptr.p_double[k]-cw->ptr.p_double[tmpoffs->ptr.p_int[j]+k])*invri2, _state));
   42907             :             }
   42908             :         }
   42909             :         
   42910             :         /*
   42911             :          * Update columns counter
   42912             :          */
   42913           0 :         *rowsize = *rowsize+cnt;
   42914             :     }
   42915           0 : }
   42916             : 
   42917             : 
   42918             : /*************************************************************************
   42919             : This function fills RBF model by zeros.
   42920             : 
   42921             :   -- ALGLIB --
   42922             :      Copyright 17.11.2018 by Bochkanov Sergey
   42923             : *************************************************************************/
   42924           0 : static void rbfv2_zerofill(rbfv2model* s,
   42925             :      ae_int_t nx,
   42926             :      ae_int_t ny,
   42927             :      ae_int_t bf,
   42928             :      ae_state *_state)
   42929             : {
   42930             :     ae_int_t i;
   42931             :     ae_int_t j;
   42932             : 
   42933             : 
   42934           0 :     s->bf = bf;
   42935           0 :     s->nh = 0;
   42936           0 :     ae_vector_set_length(&s->ri, 0, _state);
   42937           0 :     ae_vector_set_length(&s->s, 0, _state);
   42938           0 :     ae_vector_set_length(&s->kdroots, 0, _state);
   42939           0 :     ae_vector_set_length(&s->kdnodes, 0, _state);
   42940           0 :     ae_vector_set_length(&s->kdsplits, 0, _state);
   42941           0 :     ae_vector_set_length(&s->kdboxmin, 0, _state);
   42942           0 :     ae_vector_set_length(&s->kdboxmax, 0, _state);
   42943           0 :     ae_vector_set_length(&s->cw, 0, _state);
   42944           0 :     ae_matrix_set_length(&s->v, ny, nx+1, _state);
   42945           0 :     for(i=0; i<=ny-1; i++)
   42946             :     {
   42947           0 :         for(j=0; j<=nx; j++)
   42948             :         {
   42949           0 :             s->v.ptr.pp_double[i][j] = (double)(0);
   42950             :         }
   42951             :     }
   42952           0 : }
   42953             : 
   42954             : 
   42955           0 : void _rbfv2calcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic)
   42956             : {
   42957           0 :     rbfv2calcbuffer *p = (rbfv2calcbuffer*)_p;
   42958           0 :     ae_touch_ptr((void*)p);
   42959           0 :     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
   42960           0 :     ae_vector_init(&p->curboxmin, 0, DT_REAL, _state, make_automatic);
   42961           0 :     ae_vector_init(&p->curboxmax, 0, DT_REAL, _state, make_automatic);
   42962           0 :     ae_vector_init(&p->x123, 0, DT_REAL, _state, make_automatic);
   42963           0 :     ae_vector_init(&p->y123, 0, DT_REAL, _state, make_automatic);
   42964           0 : }
   42965             : 
   42966             : 
   42967           0 : void _rbfv2calcbuffer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   42968             : {
   42969           0 :     rbfv2calcbuffer *dst = (rbfv2calcbuffer*)_dst;
   42970           0 :     rbfv2calcbuffer *src = (rbfv2calcbuffer*)_src;
   42971           0 :     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
   42972           0 :     ae_vector_init_copy(&dst->curboxmin, &src->curboxmin, _state, make_automatic);
   42973           0 :     ae_vector_init_copy(&dst->curboxmax, &src->curboxmax, _state, make_automatic);
   42974           0 :     dst->curdist2 = src->curdist2;
   42975           0 :     ae_vector_init_copy(&dst->x123, &src->x123, _state, make_automatic);
   42976           0 :     ae_vector_init_copy(&dst->y123, &src->y123, _state, make_automatic);
   42977           0 : }
   42978             : 
   42979             : 
   42980           0 : void _rbfv2calcbuffer_clear(void* _p)
   42981             : {
   42982           0 :     rbfv2calcbuffer *p = (rbfv2calcbuffer*)_p;
   42983           0 :     ae_touch_ptr((void*)p);
   42984           0 :     ae_vector_clear(&p->x);
   42985           0 :     ae_vector_clear(&p->curboxmin);
   42986           0 :     ae_vector_clear(&p->curboxmax);
   42987           0 :     ae_vector_clear(&p->x123);
   42988           0 :     ae_vector_clear(&p->y123);
   42989           0 : }
   42990             : 
   42991             : 
   42992           0 : void _rbfv2calcbuffer_destroy(void* _p)
   42993             : {
   42994           0 :     rbfv2calcbuffer *p = (rbfv2calcbuffer*)_p;
   42995           0 :     ae_touch_ptr((void*)p);
   42996           0 :     ae_vector_destroy(&p->x);
   42997           0 :     ae_vector_destroy(&p->curboxmin);
   42998           0 :     ae_vector_destroy(&p->curboxmax);
   42999           0 :     ae_vector_destroy(&p->x123);
   43000           0 :     ae_vector_destroy(&p->y123);
   43001           0 : }
   43002             : 
   43003             : 
   43004           0 : void _rbfv2model_init(void* _p, ae_state *_state, ae_bool make_automatic)
   43005             : {
   43006           0 :     rbfv2model *p = (rbfv2model*)_p;
   43007           0 :     ae_touch_ptr((void*)p);
   43008           0 :     ae_vector_init(&p->ri, 0, DT_REAL, _state, make_automatic);
   43009           0 :     ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic);
   43010           0 :     ae_vector_init(&p->kdroots, 0, DT_INT, _state, make_automatic);
   43011           0 :     ae_vector_init(&p->kdnodes, 0, DT_INT, _state, make_automatic);
   43012           0 :     ae_vector_init(&p->kdsplits, 0, DT_REAL, _state, make_automatic);
   43013           0 :     ae_vector_init(&p->kdboxmin, 0, DT_REAL, _state, make_automatic);
   43014           0 :     ae_vector_init(&p->kdboxmax, 0, DT_REAL, _state, make_automatic);
   43015           0 :     ae_vector_init(&p->cw, 0, DT_REAL, _state, make_automatic);
   43016           0 :     ae_matrix_init(&p->v, 0, 0, DT_REAL, _state, make_automatic);
   43017           0 :     _rbfv2calcbuffer_init(&p->calcbuf, _state, make_automatic);
   43018           0 : }
   43019             : 
   43020             : 
   43021           0 : void _rbfv2model_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   43022             : {
   43023           0 :     rbfv2model *dst = (rbfv2model*)_dst;
   43024           0 :     rbfv2model *src = (rbfv2model*)_src;
   43025           0 :     dst->ny = src->ny;
   43026           0 :     dst->nx = src->nx;
   43027           0 :     dst->bf = src->bf;
   43028           0 :     dst->nh = src->nh;
   43029           0 :     ae_vector_init_copy(&dst->ri, &src->ri, _state, make_automatic);
   43030           0 :     ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic);
   43031           0 :     ae_vector_init_copy(&dst->kdroots, &src->kdroots, _state, make_automatic);
   43032           0 :     ae_vector_init_copy(&dst->kdnodes, &src->kdnodes, _state, make_automatic);
   43033           0 :     ae_vector_init_copy(&dst->kdsplits, &src->kdsplits, _state, make_automatic);
   43034           0 :     ae_vector_init_copy(&dst->kdboxmin, &src->kdboxmin, _state, make_automatic);
   43035           0 :     ae_vector_init_copy(&dst->kdboxmax, &src->kdboxmax, _state, make_automatic);
   43036           0 :     ae_vector_init_copy(&dst->cw, &src->cw, _state, make_automatic);
   43037           0 :     ae_matrix_init_copy(&dst->v, &src->v, _state, make_automatic);
   43038           0 :     dst->lambdareg = src->lambdareg;
   43039           0 :     dst->maxits = src->maxits;
   43040           0 :     dst->supportr = src->supportr;
   43041           0 :     dst->basisfunction = src->basisfunction;
   43042           0 :     _rbfv2calcbuffer_init_copy(&dst->calcbuf, &src->calcbuf, _state, make_automatic);
   43043           0 : }
   43044             : 
   43045             : 
   43046           0 : void _rbfv2model_clear(void* _p)
   43047             : {
   43048           0 :     rbfv2model *p = (rbfv2model*)_p;
   43049           0 :     ae_touch_ptr((void*)p);
   43050           0 :     ae_vector_clear(&p->ri);
   43051           0 :     ae_vector_clear(&p->s);
   43052           0 :     ae_vector_clear(&p->kdroots);
   43053           0 :     ae_vector_clear(&p->kdnodes);
   43054           0 :     ae_vector_clear(&p->kdsplits);
   43055           0 :     ae_vector_clear(&p->kdboxmin);
   43056           0 :     ae_vector_clear(&p->kdboxmax);
   43057           0 :     ae_vector_clear(&p->cw);
   43058           0 :     ae_matrix_clear(&p->v);
   43059           0 :     _rbfv2calcbuffer_clear(&p->calcbuf);
   43060           0 : }
   43061             : 
   43062             : 
   43063           0 : void _rbfv2model_destroy(void* _p)
   43064             : {
   43065           0 :     rbfv2model *p = (rbfv2model*)_p;
   43066           0 :     ae_touch_ptr((void*)p);
   43067           0 :     ae_vector_destroy(&p->ri);
   43068           0 :     ae_vector_destroy(&p->s);
   43069           0 :     ae_vector_destroy(&p->kdroots);
   43070           0 :     ae_vector_destroy(&p->kdnodes);
   43071           0 :     ae_vector_destroy(&p->kdsplits);
   43072           0 :     ae_vector_destroy(&p->kdboxmin);
   43073           0 :     ae_vector_destroy(&p->kdboxmax);
   43074           0 :     ae_vector_destroy(&p->cw);
   43075           0 :     ae_matrix_destroy(&p->v);
   43076           0 :     _rbfv2calcbuffer_destroy(&p->calcbuf);
   43077           0 : }
   43078             : 
   43079             : 
   43080           0 : void _rbfv2gridcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic)
   43081             : {
   43082           0 :     rbfv2gridcalcbuffer *p = (rbfv2gridcalcbuffer*)_p;
   43083           0 :     ae_touch_ptr((void*)p);
   43084           0 :     _rbfv2calcbuffer_init(&p->calcbuf, _state, make_automatic);
   43085           0 :     ae_vector_init(&p->cx, 0, DT_REAL, _state, make_automatic);
   43086           0 :     ae_vector_init(&p->rx, 0, DT_REAL, _state, make_automatic);
   43087           0 :     ae_vector_init(&p->ry, 0, DT_REAL, _state, make_automatic);
   43088           0 :     ae_vector_init(&p->tx, 0, DT_REAL, _state, make_automatic);
   43089           0 :     ae_vector_init(&p->ty, 0, DT_REAL, _state, make_automatic);
   43090           0 :     ae_vector_init(&p->rf, 0, DT_BOOL, _state, make_automatic);
   43091           0 : }
   43092             : 
   43093             : 
   43094           0 : void _rbfv2gridcalcbuffer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   43095             : {
   43096           0 :     rbfv2gridcalcbuffer *dst = (rbfv2gridcalcbuffer*)_dst;
   43097           0 :     rbfv2gridcalcbuffer *src = (rbfv2gridcalcbuffer*)_src;
   43098           0 :     _rbfv2calcbuffer_init_copy(&dst->calcbuf, &src->calcbuf, _state, make_automatic);
   43099           0 :     ae_vector_init_copy(&dst->cx, &src->cx, _state, make_automatic);
   43100           0 :     ae_vector_init_copy(&dst->rx, &src->rx, _state, make_automatic);
   43101           0 :     ae_vector_init_copy(&dst->ry, &src->ry, _state, make_automatic);
   43102           0 :     ae_vector_init_copy(&dst->tx, &src->tx, _state, make_automatic);
   43103           0 :     ae_vector_init_copy(&dst->ty, &src->ty, _state, make_automatic);
   43104           0 :     ae_vector_init_copy(&dst->rf, &src->rf, _state, make_automatic);
   43105           0 : }
   43106             : 
   43107             : 
   43108           0 : void _rbfv2gridcalcbuffer_clear(void* _p)
   43109             : {
   43110           0 :     rbfv2gridcalcbuffer *p = (rbfv2gridcalcbuffer*)_p;
   43111           0 :     ae_touch_ptr((void*)p);
   43112           0 :     _rbfv2calcbuffer_clear(&p->calcbuf);
   43113           0 :     ae_vector_clear(&p->cx);
   43114           0 :     ae_vector_clear(&p->rx);
   43115           0 :     ae_vector_clear(&p->ry);
   43116           0 :     ae_vector_clear(&p->tx);
   43117           0 :     ae_vector_clear(&p->ty);
   43118           0 :     ae_vector_clear(&p->rf);
   43119           0 : }
   43120             : 
   43121             : 
   43122           0 : void _rbfv2gridcalcbuffer_destroy(void* _p)
   43123             : {
   43124           0 :     rbfv2gridcalcbuffer *p = (rbfv2gridcalcbuffer*)_p;
   43125           0 :     ae_touch_ptr((void*)p);
   43126           0 :     _rbfv2calcbuffer_destroy(&p->calcbuf);
   43127           0 :     ae_vector_destroy(&p->cx);
   43128           0 :     ae_vector_destroy(&p->rx);
   43129           0 :     ae_vector_destroy(&p->ry);
   43130           0 :     ae_vector_destroy(&p->tx);
   43131           0 :     ae_vector_destroy(&p->ty);
   43132           0 :     ae_vector_destroy(&p->rf);
   43133           0 : }
   43134             : 
   43135             : 
   43136           0 : void _rbfv2report_init(void* _p, ae_state *_state, ae_bool make_automatic)
   43137             : {
   43138           0 :     rbfv2report *p = (rbfv2report*)_p;
   43139           0 :     ae_touch_ptr((void*)p);
   43140           0 : }
   43141             : 
   43142             : 
   43143           0 : void _rbfv2report_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   43144             : {
   43145           0 :     rbfv2report *dst = (rbfv2report*)_dst;
   43146           0 :     rbfv2report *src = (rbfv2report*)_src;
   43147           0 :     dst->terminationtype = src->terminationtype;
   43148           0 :     dst->maxerror = src->maxerror;
   43149           0 :     dst->rmserror = src->rmserror;
   43150           0 : }
   43151             : 
   43152             : 
   43153           0 : void _rbfv2report_clear(void* _p)
   43154             : {
   43155           0 :     rbfv2report *p = (rbfv2report*)_p;
   43156           0 :     ae_touch_ptr((void*)p);
   43157           0 : }
   43158             : 
   43159             : 
   43160           0 : void _rbfv2report_destroy(void* _p)
   43161             : {
   43162           0 :     rbfv2report *p = (rbfv2report*)_p;
   43163           0 :     ae_touch_ptr((void*)p);
   43164           0 : }
   43165             : 
   43166             : 
   43167             : #endif
   43168             : #if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD)
   43169             : 
   43170             : 
   43171             : /*************************************************************************
   43172             : This subroutine calculates the value of the bilinear or bicubic spline  at
   43173             : the given point X.
   43174             : 
   43175             : Input parameters:
   43176             :     C   -   2D spline object.
   43177             :             Built by spline2dbuildbilinearv or spline2dbuildbicubicv.
   43178             :     X, Y-   point
   43179             : 
   43180             : Result:
   43181             :     S(x,y)
   43182             : 
   43183             :   -- ALGLIB PROJECT --
   43184             :      Copyright 05.07.2007 by Bochkanov Sergey
   43185             : *************************************************************************/
   43186           0 : double spline2dcalc(spline2dinterpolant* c,
   43187             :      double x,
   43188             :      double y,
   43189             :      ae_state *_state)
   43190             : {
   43191             :     ae_int_t ix;
   43192             :     ae_int_t iy;
   43193             :     ae_int_t l;
   43194             :     ae_int_t r;
   43195             :     ae_int_t h;
   43196             :     double t;
   43197             :     double dt;
   43198             :     double u;
   43199             :     double du;
   43200             :     double y1;
   43201             :     double y2;
   43202             :     double y3;
   43203             :     double y4;
   43204             :     ae_int_t s1;
   43205             :     ae_int_t s2;
   43206             :     ae_int_t s3;
   43207             :     ae_int_t s4;
   43208             :     ae_int_t sfx;
   43209             :     ae_int_t sfy;
   43210             :     ae_int_t sfxy;
   43211             :     double t2;
   43212             :     double t3;
   43213             :     double u2;
   43214             :     double u3;
   43215             :     double ht00;
   43216             :     double ht01;
   43217             :     double ht10;
   43218             :     double ht11;
   43219             :     double hu00;
   43220             :     double hu01;
   43221             :     double hu10;
   43222             :     double hu11;
   43223             :     double result;
   43224             : 
   43225             : 
   43226           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalc: incorrect C (incorrect parameter C.SType)", _state);
   43227           0 :     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalc: X or Y contains NaN or Infinite value", _state);
   43228           0 :     if( c->d!=1 )
   43229             :     {
   43230           0 :         result = (double)(0);
   43231           0 :         return result;
   43232             :     }
   43233             :     
   43234             :     /*
   43235             :      * Determine evaluation interval
   43236             :      */
   43237           0 :     l = 0;
   43238           0 :     r = c->n-1;
   43239           0 :     while(l!=r-1)
   43240             :     {
   43241           0 :         h = (l+r)/2;
   43242           0 :         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
   43243             :         {
   43244           0 :             r = h;
   43245             :         }
   43246             :         else
   43247             :         {
   43248           0 :             l = h;
   43249             :         }
   43250             :     }
   43251           0 :     dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
   43252           0 :     t = (x-c->x.ptr.p_double[l])*dt;
   43253           0 :     ix = l;
   43254           0 :     l = 0;
   43255           0 :     r = c->m-1;
   43256           0 :     while(l!=r-1)
   43257             :     {
   43258           0 :         h = (l+r)/2;
   43259           0 :         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
   43260             :         {
   43261           0 :             r = h;
   43262             :         }
   43263             :         else
   43264             :         {
   43265           0 :             l = h;
   43266             :         }
   43267             :     }
   43268           0 :     du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
   43269           0 :     u = (y-c->y.ptr.p_double[l])*du;
   43270           0 :     iy = l;
   43271             :     
   43272             :     /*
   43273             :      * Bilinear interpolation
   43274             :      */
   43275           0 :     if( c->stype==-1 )
   43276             :     {
   43277           0 :         y1 = c->f.ptr.p_double[c->n*iy+ix];
   43278           0 :         y2 = c->f.ptr.p_double[c->n*iy+(ix+1)];
   43279           0 :         y3 = c->f.ptr.p_double[c->n*(iy+1)+(ix+1)];
   43280           0 :         y4 = c->f.ptr.p_double[c->n*(iy+1)+ix];
   43281           0 :         result = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4;
   43282           0 :         return result;
   43283             :     }
   43284             :     
   43285             :     /*
   43286             :      * Bicubic interpolation:
   43287             :      * * calculate Hermite basis for dimensions X and Y (variables T and U),
   43288             :      *   here HTij means basis function whose I-th derivative has value 1 at T=J.
   43289             :      *   Same for HUij.
   43290             :      * * after initial calculation, apply scaling by DT/DU to the basis
   43291             :      * * calculate using stored table of second derivatives
   43292             :      */
   43293           0 :     ae_assert(c->stype==-3, "Spline2DCalc: integrity check failed", _state);
   43294           0 :     sfx = c->n*c->m;
   43295           0 :     sfy = 2*c->n*c->m;
   43296           0 :     sfxy = 3*c->n*c->m;
   43297           0 :     s1 = c->n*iy+ix;
   43298           0 :     s2 = c->n*iy+(ix+1);
   43299           0 :     s3 = c->n*(iy+1)+ix;
   43300           0 :     s4 = c->n*(iy+1)+(ix+1);
   43301           0 :     t2 = t*t;
   43302           0 :     t3 = t*t2;
   43303           0 :     u2 = u*u;
   43304           0 :     u3 = u*u2;
   43305           0 :     ht00 = 2*t3-3*t2+1;
   43306           0 :     ht10 = t3-2*t2+t;
   43307           0 :     ht01 = -2*t3+3*t2;
   43308           0 :     ht11 = t3-t2;
   43309           0 :     hu00 = 2*u3-3*u2+1;
   43310           0 :     hu10 = u3-2*u2+u;
   43311           0 :     hu01 = -2*u3+3*u2;
   43312           0 :     hu11 = u3-u2;
   43313           0 :     ht10 = ht10/dt;
   43314           0 :     ht11 = ht11/dt;
   43315           0 :     hu10 = hu10/du;
   43316           0 :     hu11 = hu11/du;
   43317           0 :     result = (double)(0);
   43318           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;
   43319           0 :     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;
   43320           0 :     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;
   43321           0 :     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;
   43322           0 :     return result;
   43323             : }
   43324             : 
   43325             : 
   43326             : /*************************************************************************
   43327             : This subroutine calculates the value of the bilinear or bicubic spline  at
   43328             : the given point X and its derivatives.
   43329             : 
   43330             : Input parameters:
   43331             :     C   -   spline interpolant.
   43332             :     X, Y-   point
   43333             : 
   43334             : Output parameters:
   43335             :     F   -   S(x,y)
   43336             :     FX  -   dS(x,y)/dX
   43337             :     FY  -   dS(x,y)/dY
   43338             :     FXY -   d2S(x,y)/dXdY
   43339             : 
   43340             :   -- ALGLIB PROJECT --
   43341             :      Copyright 05.07.2007 by Bochkanov Sergey
   43342             : *************************************************************************/
   43343           0 : void spline2ddiff(spline2dinterpolant* c,
   43344             :      double x,
   43345             :      double y,
   43346             :      double* f,
   43347             :      double* fx,
   43348             :      double* fy,
   43349             :      double* fxy,
   43350             :      ae_state *_state)
   43351             : {
   43352             :     double t;
   43353             :     double dt;
   43354             :     double u;
   43355             :     double du;
   43356             :     ae_int_t ix;
   43357             :     ae_int_t iy;
   43358             :     ae_int_t l;
   43359             :     ae_int_t r;
   43360             :     ae_int_t h;
   43361             :     ae_int_t s1;
   43362             :     ae_int_t s2;
   43363             :     ae_int_t s3;
   43364             :     ae_int_t s4;
   43365             :     ae_int_t sfx;
   43366             :     ae_int_t sfy;
   43367             :     ae_int_t sfxy;
   43368             :     double y1;
   43369             :     double y2;
   43370             :     double y3;
   43371             :     double y4;
   43372             :     double v0;
   43373             :     double v1;
   43374             :     double v2;
   43375             :     double v3;
   43376             :     double t2;
   43377             :     double t3;
   43378             :     double u2;
   43379             :     double u3;
   43380             :     double ht00;
   43381             :     double ht01;
   43382             :     double ht10;
   43383             :     double ht11;
   43384             :     double hu00;
   43385             :     double hu01;
   43386             :     double hu10;
   43387             :     double hu11;
   43388             :     double dht00;
   43389             :     double dht01;
   43390             :     double dht10;
   43391             :     double dht11;
   43392             :     double dhu00;
   43393             :     double dhu01;
   43394             :     double dhu10;
   43395             :     double dhu11;
   43396             : 
   43397           0 :     *f = 0;
   43398           0 :     *fx = 0;
   43399           0 :     *fy = 0;
   43400           0 :     *fxy = 0;
   43401             : 
   43402           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline2DDiff: incorrect C (incorrect parameter C.SType)", _state);
   43403           0 :     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DDiff: X or Y contains NaN or Infinite value", _state);
   43404             :     
   43405             :     /*
   43406             :      * Prepare F, dF/dX, dF/dY, d2F/dXdY
   43407             :      */
   43408           0 :     *f = (double)(0);
   43409           0 :     *fx = (double)(0);
   43410           0 :     *fy = (double)(0);
   43411           0 :     *fxy = (double)(0);
   43412           0 :     if( c->d!=1 )
   43413             :     {
   43414           0 :         return;
   43415             :     }
   43416             :     
   43417             :     /*
   43418             :      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
   43419             :      */
   43420           0 :     l = 0;
   43421           0 :     r = c->n-1;
   43422           0 :     while(l!=r-1)
   43423             :     {
   43424           0 :         h = (l+r)/2;
   43425           0 :         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
   43426             :         {
   43427           0 :             r = h;
   43428             :         }
   43429             :         else
   43430             :         {
   43431           0 :             l = h;
   43432             :         }
   43433             :     }
   43434           0 :     t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
   43435           0 :     dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
   43436           0 :     ix = l;
   43437             :     
   43438             :     /*
   43439             :      * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included)
   43440             :      */
   43441           0 :     l = 0;
   43442           0 :     r = c->m-1;
   43443           0 :     while(l!=r-1)
   43444             :     {
   43445           0 :         h = (l+r)/2;
   43446           0 :         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
   43447             :         {
   43448           0 :             r = h;
   43449             :         }
   43450             :         else
   43451             :         {
   43452           0 :             l = h;
   43453             :         }
   43454             :     }
   43455           0 :     u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
   43456           0 :     du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
   43457           0 :     iy = l;
   43458             :     
   43459             :     /*
   43460             :      * Bilinear interpolation
   43461             :      */
   43462           0 :     if( c->stype==-1 )
   43463             :     {
   43464           0 :         y1 = c->f.ptr.p_double[c->n*iy+ix];
   43465           0 :         y2 = c->f.ptr.p_double[c->n*iy+(ix+1)];
   43466           0 :         y3 = c->f.ptr.p_double[c->n*(iy+1)+(ix+1)];
   43467           0 :         y4 = c->f.ptr.p_double[c->n*(iy+1)+ix];
   43468           0 :         *f = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4;
   43469           0 :         *fx = (-(1-u)*y1+(1-u)*y2+u*y3-u*y4)*dt;
   43470           0 :         *fy = (-(1-t)*y1-t*y2+t*y3+(1-t)*y4)*du;
   43471           0 :         *fxy = (y1-y2+y3-y4)*du*dt;
   43472           0 :         return;
   43473             :     }
   43474             :     
   43475             :     /*
   43476             :      * Bicubic interpolation
   43477             :      */
   43478           0 :     if( c->stype==-3 )
   43479             :     {
   43480           0 :         sfx = c->n*c->m;
   43481           0 :         sfy = 2*c->n*c->m;
   43482           0 :         sfxy = 3*c->n*c->m;
   43483           0 :         s1 = c->n*iy+ix;
   43484           0 :         s2 = c->n*iy+(ix+1);
   43485           0 :         s3 = c->n*(iy+1)+ix;
   43486           0 :         s4 = c->n*(iy+1)+(ix+1);
   43487           0 :         t2 = t*t;
   43488           0 :         t3 = t*t2;
   43489           0 :         u2 = u*u;
   43490           0 :         u3 = u*u2;
   43491           0 :         ht00 = 2*t3-3*t2+1;
   43492           0 :         ht10 = t3-2*t2+t;
   43493           0 :         ht01 = -2*t3+3*t2;
   43494           0 :         ht11 = t3-t2;
   43495           0 :         hu00 = 2*u3-3*u2+1;
   43496           0 :         hu10 = u3-2*u2+u;
   43497           0 :         hu01 = -2*u3+3*u2;
   43498           0 :         hu11 = u3-u2;
   43499           0 :         ht10 = ht10/dt;
   43500           0 :         ht11 = ht11/dt;
   43501           0 :         hu10 = hu10/du;
   43502           0 :         hu11 = hu11/du;
   43503           0 :         dht00 = 6*t2-6*t;
   43504           0 :         dht10 = 3*t2-4*t+1;
   43505           0 :         dht01 = -6*t2+6*t;
   43506           0 :         dht11 = 3*t2-2*t;
   43507           0 :         dhu00 = 6*u2-6*u;
   43508           0 :         dhu10 = 3*u2-4*u+1;
   43509           0 :         dhu01 = -6*u2+6*u;
   43510           0 :         dhu11 = 3*u2-2*u;
   43511           0 :         dht00 = dht00*dt;
   43512           0 :         dht01 = dht01*dt;
   43513           0 :         dhu00 = dhu00*du;
   43514           0 :         dhu01 = dhu01*du;
   43515           0 :         *f = (double)(0);
   43516           0 :         *fx = (double)(0);
   43517           0 :         *fy = (double)(0);
   43518           0 :         *fxy = (double)(0);
   43519           0 :         v0 = c->f.ptr.p_double[s1];
   43520           0 :         v1 = c->f.ptr.p_double[s2];
   43521           0 :         v2 = c->f.ptr.p_double[s3];
   43522           0 :         v3 = c->f.ptr.p_double[s4];
   43523           0 :         *f = *f+v0*ht00*hu00+v1*ht01*hu00+v2*ht00*hu01+v3*ht01*hu01;
   43524           0 :         *fx = *fx+v0*dht00*hu00+v1*dht01*hu00+v2*dht00*hu01+v3*dht01*hu01;
   43525           0 :         *fy = *fy+v0*ht00*dhu00+v1*ht01*dhu00+v2*ht00*dhu01+v3*ht01*dhu01;
   43526           0 :         *fxy = *fxy+v0*dht00*dhu00+v1*dht01*dhu00+v2*dht00*dhu01+v3*dht01*dhu01;
   43527           0 :         v0 = c->f.ptr.p_double[sfx+s1];
   43528           0 :         v1 = c->f.ptr.p_double[sfx+s2];
   43529           0 :         v2 = c->f.ptr.p_double[sfx+s3];
   43530           0 :         v3 = c->f.ptr.p_double[sfx+s4];
   43531           0 :         *f = *f+v0*ht10*hu00+v1*ht11*hu00+v2*ht10*hu01+v3*ht11*hu01;
   43532           0 :         *fx = *fx+v0*dht10*hu00+v1*dht11*hu00+v2*dht10*hu01+v3*dht11*hu01;
   43533           0 :         *fy = *fy+v0*ht10*dhu00+v1*ht11*dhu00+v2*ht10*dhu01+v3*ht11*dhu01;
   43534           0 :         *fxy = *fxy+v0*dht10*dhu00+v1*dht11*dhu00+v2*dht10*dhu01+v3*dht11*dhu01;
   43535           0 :         v0 = c->f.ptr.p_double[sfy+s1];
   43536           0 :         v1 = c->f.ptr.p_double[sfy+s2];
   43537           0 :         v2 = c->f.ptr.p_double[sfy+s3];
   43538           0 :         v3 = c->f.ptr.p_double[sfy+s4];
   43539           0 :         *f = *f+v0*ht00*hu10+v1*ht01*hu10+v2*ht00*hu11+v3*ht01*hu11;
   43540           0 :         *fx = *fx+v0*dht00*hu10+v1*dht01*hu10+v2*dht00*hu11+v3*dht01*hu11;
   43541           0 :         *fy = *fy+v0*ht00*dhu10+v1*ht01*dhu10+v2*ht00*dhu11+v3*ht01*dhu11;
   43542           0 :         *fxy = *fxy+v0*dht00*dhu10+v1*dht01*dhu10+v2*dht00*dhu11+v3*dht01*dhu11;
   43543           0 :         v0 = c->f.ptr.p_double[sfxy+s1];
   43544           0 :         v1 = c->f.ptr.p_double[sfxy+s2];
   43545           0 :         v2 = c->f.ptr.p_double[sfxy+s3];
   43546           0 :         v3 = c->f.ptr.p_double[sfxy+s4];
   43547           0 :         *f = *f+v0*ht10*hu10+v1*ht11*hu10+v2*ht10*hu11+v3*ht11*hu11;
   43548           0 :         *fx = *fx+v0*dht10*hu10+v1*dht11*hu10+v2*dht10*hu11+v3*dht11*hu11;
   43549           0 :         *fy = *fy+v0*ht10*dhu10+v1*ht11*dhu10+v2*ht10*dhu11+v3*ht11*dhu11;
   43550           0 :         *fxy = *fxy+v0*dht10*dhu10+v1*dht11*dhu10+v2*dht10*dhu11+v3*dht11*dhu11;
   43551           0 :         return;
   43552             :     }
   43553             : }
   43554             : 
   43555             : 
   43556             : /*************************************************************************
   43557             : This subroutine calculates bilinear or bicubic vector-valued spline at the
   43558             : given point (X,Y).
   43559             : 
   43560             : If you need just some specific component of vector-valued spline, you  can
   43561             : use spline2dcalcvi() function.
   43562             : 
   43563             : INPUT PARAMETERS:
   43564             :     C   -   spline interpolant.
   43565             :     X, Y-   point
   43566             :     F   -   output buffer, possibly preallocated array. In case array size
   43567             :             is large enough to store result, it is not reallocated.  Array
   43568             :             which is too short will be reallocated
   43569             : 
   43570             : OUTPUT PARAMETERS:
   43571             :     F   -   array[D] (or larger) which stores function values
   43572             : 
   43573             :   -- ALGLIB PROJECT --
   43574             :      Copyright 01.02.2018 by Bochkanov Sergey
   43575             : *************************************************************************/
   43576           0 : void spline2dcalcvbuf(spline2dinterpolant* c,
   43577             :      double x,
   43578             :      double y,
   43579             :      /* Real    */ ae_vector* f,
   43580             :      ae_state *_state)
   43581             : {
   43582             :     ae_int_t ix;
   43583             :     ae_int_t iy;
   43584             :     ae_int_t l;
   43585             :     ae_int_t r;
   43586             :     ae_int_t h;
   43587             :     ae_int_t i;
   43588             :     double t;
   43589             :     double dt;
   43590             :     double u;
   43591             :     double du;
   43592             :     double y1;
   43593             :     double y2;
   43594             :     double y3;
   43595             :     double y4;
   43596             :     ae_int_t s1;
   43597             :     ae_int_t s2;
   43598             :     ae_int_t s3;
   43599             :     ae_int_t s4;
   43600             :     ae_int_t sfx;
   43601             :     ae_int_t sfy;
   43602             :     ae_int_t sfxy;
   43603             :     double t2;
   43604             :     double t3;
   43605             :     double u2;
   43606             :     double u3;
   43607             :     double ht00;
   43608             :     double ht01;
   43609             :     double ht10;
   43610             :     double ht11;
   43611             :     double hu00;
   43612             :     double hu01;
   43613             :     double hu10;
   43614             :     double hu11;
   43615             : 
   43616             : 
   43617           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcVBuf: incorrect C (incorrect parameter C.SType)", _state);
   43618           0 :     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcVBuf: X or Y contains NaN or Infinite value", _state);
   43619             :     
   43620             :     /*
   43621             :      * Allocate place for output
   43622             :      */
   43623           0 :     rvectorsetlengthatleast(f, c->d, _state);
   43624             :     
   43625             :     /*
   43626             :      * Determine evaluation interval
   43627             :      */
   43628           0 :     l = 0;
   43629           0 :     r = c->n-1;
   43630           0 :     while(l!=r-1)
   43631             :     {
   43632           0 :         h = (l+r)/2;
   43633           0 :         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
   43634             :         {
   43635           0 :             r = h;
   43636             :         }
   43637             :         else
   43638             :         {
   43639           0 :             l = h;
   43640             :         }
   43641             :     }
   43642           0 :     dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
   43643           0 :     t = (x-c->x.ptr.p_double[l])*dt;
   43644           0 :     ix = l;
   43645           0 :     l = 0;
   43646           0 :     r = c->m-1;
   43647           0 :     while(l!=r-1)
   43648             :     {
   43649           0 :         h = (l+r)/2;
   43650           0 :         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
   43651             :         {
   43652           0 :             r = h;
   43653             :         }
   43654             :         else
   43655             :         {
   43656           0 :             l = h;
   43657             :         }
   43658             :     }
   43659           0 :     du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
   43660           0 :     u = (y-c->y.ptr.p_double[l])*du;
   43661           0 :     iy = l;
   43662             :     
   43663             :     /*
   43664             :      * Bilinear interpolation
   43665             :      */
   43666           0 :     if( c->stype==-1 )
   43667             :     {
   43668           0 :         for(i=0; i<=c->d-1; i++)
   43669             :         {
   43670           0 :             y1 = c->f.ptr.p_double[c->d*(c->n*iy+ix)+i];
   43671           0 :             y2 = c->f.ptr.p_double[c->d*(c->n*iy+(ix+1))+i];
   43672           0 :             y3 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+(ix+1))+i];
   43673           0 :             y4 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+ix)+i];
   43674           0 :             f->ptr.p_double[i] = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4;
   43675             :         }
   43676           0 :         return;
   43677             :     }
   43678             :     
   43679             :     /*
   43680             :      * Bicubic interpolation:
   43681             :      * * calculate Hermite basis for dimensions X and Y (variables T and U),
   43682             :      *   here HTij means basis function whose I-th derivative has value 1 at T=J.
   43683             :      *   Same for HUij.
   43684             :      * * after initial calculation, apply scaling by DT/DU to the basis
   43685             :      * * calculate using stored table of second derivatives
   43686             :      */
   43687           0 :     ae_assert(c->stype==-3, "Spline2DCalc: integrity check failed", _state);
   43688           0 :     sfx = c->n*c->m*c->d;
   43689           0 :     sfy = 2*c->n*c->m*c->d;
   43690           0 :     sfxy = 3*c->n*c->m*c->d;
   43691           0 :     s1 = (c->n*iy+ix)*c->d;
   43692           0 :     s2 = (c->n*iy+(ix+1))*c->d;
   43693           0 :     s3 = (c->n*(iy+1)+ix)*c->d;
   43694           0 :     s4 = (c->n*(iy+1)+(ix+1))*c->d;
   43695           0 :     t2 = t*t;
   43696           0 :     t3 = t*t2;
   43697           0 :     u2 = u*u;
   43698           0 :     u3 = u*u2;
   43699           0 :     ht00 = 2*t3-3*t2+1;
   43700           0 :     ht10 = t3-2*t2+t;
   43701           0 :     ht01 = -2*t3+3*t2;
   43702           0 :     ht11 = t3-t2;
   43703           0 :     hu00 = 2*u3-3*u2+1;
   43704           0 :     hu10 = u3-2*u2+u;
   43705           0 :     hu01 = -2*u3+3*u2;
   43706           0 :     hu11 = u3-u2;
   43707           0 :     ht10 = ht10/dt;
   43708           0 :     ht11 = ht11/dt;
   43709           0 :     hu10 = hu10/du;
   43710           0 :     hu11 = hu11/du;
   43711           0 :     for(i=0; i<=c->d-1; i++)
   43712             :     {
   43713             :         
   43714             :         /*
   43715             :          * Calculate I-th component
   43716             :          */
   43717           0 :         f->ptr.p_double[i] = (double)(0);
   43718           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;
   43719           0 :         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;
   43720           0 :         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;
   43721           0 :         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;
   43722             :         
   43723             :         /*
   43724             :          * Advance source indexes
   43725             :          */
   43726           0 :         s1 = s1+1;
   43727           0 :         s2 = s2+1;
   43728           0 :         s3 = s3+1;
   43729           0 :         s4 = s4+1;
   43730             :     }
   43731             : }
   43732             : 
   43733             : 
   43734             : /*************************************************************************
   43735             : This subroutine calculates specific component of vector-valued bilinear or
   43736             : bicubic spline at the given point (X,Y).
   43737             : 
   43738             : INPUT PARAMETERS:
   43739             :     C   -   spline interpolant.
   43740             :     X, Y-   point
   43741             :     I   -   component index, in [0,D). An exception is generated for out
   43742             :             of range values.
   43743             : 
   43744             : RESULT:
   43745             :     value of I-th component
   43746             : 
   43747             :   -- ALGLIB PROJECT --
   43748             :      Copyright 01.02.2018 by Bochkanov Sergey
   43749             : *************************************************************************/
   43750           0 : double spline2dcalcvi(spline2dinterpolant* c,
   43751             :      double x,
   43752             :      double y,
   43753             :      ae_int_t i,
   43754             :      ae_state *_state)
   43755             : {
   43756             :     ae_int_t ix;
   43757             :     ae_int_t iy;
   43758             :     ae_int_t l;
   43759             :     ae_int_t r;
   43760             :     ae_int_t h;
   43761             :     double t;
   43762             :     double dt;
   43763             :     double u;
   43764             :     double du;
   43765             :     double y1;
   43766             :     double y2;
   43767             :     double y3;
   43768             :     double y4;
   43769             :     ae_int_t s1;
   43770             :     ae_int_t s2;
   43771             :     ae_int_t s3;
   43772             :     ae_int_t s4;
   43773             :     ae_int_t sfx;
   43774             :     ae_int_t sfy;
   43775             :     ae_int_t sfxy;
   43776             :     double t2;
   43777             :     double t3;
   43778             :     double u2;
   43779             :     double u3;
   43780             :     double ht00;
   43781             :     double ht01;
   43782             :     double ht10;
   43783             :     double ht11;
   43784             :     double hu00;
   43785             :     double hu01;
   43786             :     double hu10;
   43787             :     double hu11;
   43788             :     double result;
   43789             : 
   43790             : 
   43791           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcVi: incorrect C (incorrect parameter C.SType)", _state);
   43792           0 :     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcVi: X or Y contains NaN or Infinite value", _state);
   43793           0 :     ae_assert(i>=0&&i<c->d, "Spline2DCalcVi: incorrect I (I<0 or I>=D)", _state);
   43794             :     
   43795             :     /*
   43796             :      * Determine evaluation interval
   43797             :      */
   43798           0 :     l = 0;
   43799           0 :     r = c->n-1;
   43800           0 :     while(l!=r-1)
   43801             :     {
   43802           0 :         h = (l+r)/2;
   43803           0 :         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
   43804             :         {
   43805           0 :             r = h;
   43806             :         }
   43807             :         else
   43808             :         {
   43809           0 :             l = h;
   43810             :         }
   43811             :     }
   43812           0 :     dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
   43813           0 :     t = (x-c->x.ptr.p_double[l])*dt;
   43814           0 :     ix = l;
   43815           0 :     l = 0;
   43816           0 :     r = c->m-1;
   43817           0 :     while(l!=r-1)
   43818             :     {
   43819           0 :         h = (l+r)/2;
   43820           0 :         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
   43821             :         {
   43822           0 :             r = h;
   43823             :         }
   43824             :         else
   43825             :         {
   43826           0 :             l = h;
   43827             :         }
   43828             :     }
   43829           0 :     du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
   43830           0 :     u = (y-c->y.ptr.p_double[l])*du;
   43831           0 :     iy = l;
   43832             :     
   43833             :     /*
   43834             :      * Bilinear interpolation
   43835             :      */
   43836           0 :     if( c->stype==-1 )
   43837             :     {
   43838           0 :         y1 = c->f.ptr.p_double[c->d*(c->n*iy+ix)+i];
   43839           0 :         y2 = c->f.ptr.p_double[c->d*(c->n*iy+(ix+1))+i];
   43840           0 :         y3 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+(ix+1))+i];
   43841           0 :         y4 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+ix)+i];
   43842           0 :         result = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4;
   43843           0 :         return result;
   43844             :     }
   43845             :     
   43846             :     /*
   43847             :      * Bicubic interpolation:
   43848             :      * * calculate Hermite basis for dimensions X and Y (variables T and U),
   43849             :      *   here HTij means basis function whose I-th derivative has value 1 at T=J.
   43850             :      *   Same for HUij.
   43851             :      * * after initial calculation, apply scaling by DT/DU to the basis
   43852             :      * * calculate using stored table of second derivatives
   43853             :      */
   43854           0 :     ae_assert(c->stype==-3, "Spline2DCalc: integrity check failed", _state);
   43855           0 :     sfx = c->n*c->m*c->d;
   43856           0 :     sfy = 2*c->n*c->m*c->d;
   43857           0 :     sfxy = 3*c->n*c->m*c->d;
   43858           0 :     s1 = (c->n*iy+ix)*c->d;
   43859           0 :     s2 = (c->n*iy+(ix+1))*c->d;
   43860           0 :     s3 = (c->n*(iy+1)+ix)*c->d;
   43861           0 :     s4 = (c->n*(iy+1)+(ix+1))*c->d;
   43862           0 :     t2 = t*t;
   43863           0 :     t3 = t*t2;
   43864           0 :     u2 = u*u;
   43865           0 :     u3 = u*u2;
   43866           0 :     ht00 = 2*t3-3*t2+1;
   43867           0 :     ht10 = t3-2*t2+t;
   43868           0 :     ht01 = -2*t3+3*t2;
   43869           0 :     ht11 = t3-t2;
   43870           0 :     hu00 = 2*u3-3*u2+1;
   43871           0 :     hu10 = u3-2*u2+u;
   43872           0 :     hu01 = -2*u3+3*u2;
   43873           0 :     hu11 = u3-u2;
   43874           0 :     ht10 = ht10/dt;
   43875           0 :     ht11 = ht11/dt;
   43876           0 :     hu10 = hu10/du;
   43877           0 :     hu11 = hu11/du;
   43878             :     
   43879             :     /*
   43880             :      * Advance source indexes to I-th position
   43881             :      */
   43882           0 :     s1 = s1+i;
   43883           0 :     s2 = s2+i;
   43884           0 :     s3 = s3+i;
   43885           0 :     s4 = s4+i;
   43886             :     
   43887             :     /*
   43888             :      * Calculate I-th component
   43889             :      */
   43890           0 :     result = (double)(0);
   43891           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;
   43892           0 :     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;
   43893           0 :     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;
   43894           0 :     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;
   43895           0 :     return result;
   43896             : }
   43897             : 
   43898             : 
   43899             : /*************************************************************************
   43900             : This subroutine calculates bilinear or bicubic vector-valued spline at the
   43901             : given point (X,Y).
   43902             : 
   43903             : INPUT PARAMETERS:
   43904             :     C   -   spline interpolant.
   43905             :     X, Y-   point
   43906             : 
   43907             : OUTPUT PARAMETERS:
   43908             :     F   -   array[D] which stores function values.  F is out-parameter and
   43909             :             it  is  reallocated  after  call to this function. In case you
   43910             :             want  to    reuse  previously  allocated  F,   you   may   use
   43911             :             Spline2DCalcVBuf(),  which  reallocates  F only when it is too
   43912             :             small.
   43913             : 
   43914             :   -- ALGLIB PROJECT --
   43915             :      Copyright 16.04.2012 by Bochkanov Sergey
   43916             : *************************************************************************/
   43917           0 : void spline2dcalcv(spline2dinterpolant* c,
   43918             :      double x,
   43919             :      double y,
   43920             :      /* Real    */ ae_vector* f,
   43921             :      ae_state *_state)
   43922             : {
   43923             : 
   43924           0 :     ae_vector_clear(f);
   43925             : 
   43926           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcV: incorrect C (incorrect parameter C.SType)", _state);
   43927           0 :     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcV: either X=NaN/Infinite or Y=NaN/Infinite", _state);
   43928           0 :     spline2dcalcvbuf(c, x, y, f, _state);
   43929           0 : }
   43930             : 
   43931             : 
   43932             : /*************************************************************************
   43933             : This subroutine calculates value of  specific  component  of  bilinear  or
   43934             : bicubic vector-valued spline and its derivatives.
   43935             : 
   43936             : Input parameters:
   43937             :     C   -   spline interpolant.
   43938             :     X, Y-   point
   43939             :     I   -   component index, in [0,D)
   43940             : 
   43941             : Output parameters:
   43942             :     F   -   S(x,y)
   43943             :     FX  -   dS(x,y)/dX
   43944             :     FY  -   dS(x,y)/dY
   43945             :     FXY -   d2S(x,y)/dXdY
   43946             : 
   43947             :   -- ALGLIB PROJECT --
   43948             :      Copyright 05.07.2007 by Bochkanov Sergey
   43949             : *************************************************************************/
   43950           0 : void spline2ddiffvi(spline2dinterpolant* c,
   43951             :      double x,
   43952             :      double y,
   43953             :      ae_int_t i,
   43954             :      double* f,
   43955             :      double* fx,
   43956             :      double* fy,
   43957             :      double* fxy,
   43958             :      ae_state *_state)
   43959             : {
   43960             :     ae_int_t d;
   43961             :     double t;
   43962             :     double dt;
   43963             :     double u;
   43964             :     double du;
   43965             :     ae_int_t ix;
   43966             :     ae_int_t iy;
   43967             :     ae_int_t l;
   43968             :     ae_int_t r;
   43969             :     ae_int_t h;
   43970             :     ae_int_t s1;
   43971             :     ae_int_t s2;
   43972             :     ae_int_t s3;
   43973             :     ae_int_t s4;
   43974             :     ae_int_t sfx;
   43975             :     ae_int_t sfy;
   43976             :     ae_int_t sfxy;
   43977             :     double y1;
   43978             :     double y2;
   43979             :     double y3;
   43980             :     double y4;
   43981             :     double v0;
   43982             :     double v1;
   43983             :     double v2;
   43984             :     double v3;
   43985             :     double t2;
   43986             :     double t3;
   43987             :     double u2;
   43988             :     double u3;
   43989             :     double ht00;
   43990             :     double ht01;
   43991             :     double ht10;
   43992             :     double ht11;
   43993             :     double hu00;
   43994             :     double hu01;
   43995             :     double hu10;
   43996             :     double hu11;
   43997             :     double dht00;
   43998             :     double dht01;
   43999             :     double dht10;
   44000             :     double dht11;
   44001             :     double dhu00;
   44002             :     double dhu01;
   44003             :     double dhu10;
   44004             :     double dhu11;
   44005             : 
   44006           0 :     *f = 0;
   44007           0 :     *fx = 0;
   44008           0 :     *fy = 0;
   44009           0 :     *fxy = 0;
   44010             : 
   44011           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline2DDiffVI: incorrect C (incorrect parameter C.SType)", _state);
   44012           0 :     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DDiffVI: X or Y contains NaN or Infinite value", _state);
   44013           0 :     ae_assert(i>=0&&i<c->d, "Spline2DDiffVI: I<0 or I>=D", _state);
   44014             :     
   44015             :     /*
   44016             :      * Prepare F, dF/dX, dF/dY, d2F/dXdY
   44017             :      */
   44018           0 :     *f = (double)(0);
   44019           0 :     *fx = (double)(0);
   44020           0 :     *fy = (double)(0);
   44021           0 :     *fxy = (double)(0);
   44022           0 :     d = c->d;
   44023             :     
   44024             :     /*
   44025             :      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
   44026             :      */
   44027           0 :     l = 0;
   44028           0 :     r = c->n-1;
   44029           0 :     while(l!=r-1)
   44030             :     {
   44031           0 :         h = (l+r)/2;
   44032           0 :         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
   44033             :         {
   44034           0 :             r = h;
   44035             :         }
   44036             :         else
   44037             :         {
   44038           0 :             l = h;
   44039             :         }
   44040             :     }
   44041           0 :     t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
   44042           0 :     dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
   44043           0 :     ix = l;
   44044             :     
   44045             :     /*
   44046             :      * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included)
   44047             :      */
   44048           0 :     l = 0;
   44049           0 :     r = c->m-1;
   44050           0 :     while(l!=r-1)
   44051             :     {
   44052           0 :         h = (l+r)/2;
   44053           0 :         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
   44054             :         {
   44055           0 :             r = h;
   44056             :         }
   44057             :         else
   44058             :         {
   44059           0 :             l = h;
   44060             :         }
   44061             :     }
   44062           0 :     u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
   44063           0 :     du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
   44064           0 :     iy = l;
   44065             :     
   44066             :     /*
   44067             :      * Bilinear interpolation
   44068             :      */
   44069           0 :     if( c->stype==-1 )
   44070             :     {
   44071           0 :         y1 = c->f.ptr.p_double[d*(c->n*iy+ix)+i];
   44072           0 :         y2 = c->f.ptr.p_double[d*(c->n*iy+(ix+1))+i];
   44073           0 :         y3 = c->f.ptr.p_double[d*(c->n*(iy+1)+(ix+1))+i];
   44074           0 :         y4 = c->f.ptr.p_double[d*(c->n*(iy+1)+ix)+i];
   44075           0 :         *f = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4;
   44076           0 :         *fx = (-(1-u)*y1+(1-u)*y2+u*y3-u*y4)*dt;
   44077           0 :         *fy = (-(1-t)*y1-t*y2+t*y3+(1-t)*y4)*du;
   44078           0 :         *fxy = (y1-y2+y3-y4)*du*dt;
   44079           0 :         return;
   44080             :     }
   44081             :     
   44082             :     /*
   44083             :      * Bicubic interpolation
   44084             :      */
   44085           0 :     if( c->stype==-3 )
   44086             :     {
   44087           0 :         sfx = c->n*c->m*d;
   44088           0 :         sfy = 2*c->n*c->m*d;
   44089           0 :         sfxy = 3*c->n*c->m*d;
   44090           0 :         s1 = d*(c->n*iy+ix)+i;
   44091           0 :         s2 = d*(c->n*iy+(ix+1))+i;
   44092           0 :         s3 = d*(c->n*(iy+1)+ix)+i;
   44093           0 :         s4 = d*(c->n*(iy+1)+(ix+1))+i;
   44094           0 :         t2 = t*t;
   44095           0 :         t3 = t*t2;
   44096           0 :         u2 = u*u;
   44097           0 :         u3 = u*u2;
   44098           0 :         ht00 = 2*t3-3*t2+1;
   44099           0 :         ht10 = t3-2*t2+t;
   44100           0 :         ht01 = -2*t3+3*t2;
   44101           0 :         ht11 = t3-t2;
   44102           0 :         hu00 = 2*u3-3*u2+1;
   44103           0 :         hu10 = u3-2*u2+u;
   44104           0 :         hu01 = -2*u3+3*u2;
   44105           0 :         hu11 = u3-u2;
   44106           0 :         ht10 = ht10/dt;
   44107           0 :         ht11 = ht11/dt;
   44108           0 :         hu10 = hu10/du;
   44109           0 :         hu11 = hu11/du;
   44110           0 :         dht00 = 6*t2-6*t;
   44111           0 :         dht10 = 3*t2-4*t+1;
   44112           0 :         dht01 = -6*t2+6*t;
   44113           0 :         dht11 = 3*t2-2*t;
   44114           0 :         dhu00 = 6*u2-6*u;
   44115           0 :         dhu10 = 3*u2-4*u+1;
   44116           0 :         dhu01 = -6*u2+6*u;
   44117           0 :         dhu11 = 3*u2-2*u;
   44118           0 :         dht00 = dht00*dt;
   44119           0 :         dht01 = dht01*dt;
   44120           0 :         dhu00 = dhu00*du;
   44121           0 :         dhu01 = dhu01*du;
   44122           0 :         *f = (double)(0);
   44123           0 :         *fx = (double)(0);
   44124           0 :         *fy = (double)(0);
   44125           0 :         *fxy = (double)(0);
   44126           0 :         v0 = c->f.ptr.p_double[s1];
   44127           0 :         v1 = c->f.ptr.p_double[s2];
   44128           0 :         v2 = c->f.ptr.p_double[s3];
   44129           0 :         v3 = c->f.ptr.p_double[s4];
   44130           0 :         *f = *f+v0*ht00*hu00+v1*ht01*hu00+v2*ht00*hu01+v3*ht01*hu01;
   44131           0 :         *fx = *fx+v0*dht00*hu00+v1*dht01*hu00+v2*dht00*hu01+v3*dht01*hu01;
   44132           0 :         *fy = *fy+v0*ht00*dhu00+v1*ht01*dhu00+v2*ht00*dhu01+v3*ht01*dhu01;
   44133           0 :         *fxy = *fxy+v0*dht00*dhu00+v1*dht01*dhu00+v2*dht00*dhu01+v3*dht01*dhu01;
   44134           0 :         v0 = c->f.ptr.p_double[sfx+s1];
   44135           0 :         v1 = c->f.ptr.p_double[sfx+s2];
   44136           0 :         v2 = c->f.ptr.p_double[sfx+s3];
   44137           0 :         v3 = c->f.ptr.p_double[sfx+s4];
   44138           0 :         *f = *f+v0*ht10*hu00+v1*ht11*hu00+v2*ht10*hu01+v3*ht11*hu01;
   44139           0 :         *fx = *fx+v0*dht10*hu00+v1*dht11*hu00+v2*dht10*hu01+v3*dht11*hu01;
   44140           0 :         *fy = *fy+v0*ht10*dhu00+v1*ht11*dhu00+v2*ht10*dhu01+v3*ht11*dhu01;
   44141           0 :         *fxy = *fxy+v0*dht10*dhu00+v1*dht11*dhu00+v2*dht10*dhu01+v3*dht11*dhu01;
   44142           0 :         v0 = c->f.ptr.p_double[sfy+s1];
   44143           0 :         v1 = c->f.ptr.p_double[sfy+s2];
   44144           0 :         v2 = c->f.ptr.p_double[sfy+s3];
   44145           0 :         v3 = c->f.ptr.p_double[sfy+s4];
   44146           0 :         *f = *f+v0*ht00*hu10+v1*ht01*hu10+v2*ht00*hu11+v3*ht01*hu11;
   44147           0 :         *fx = *fx+v0*dht00*hu10+v1*dht01*hu10+v2*dht00*hu11+v3*dht01*hu11;
   44148           0 :         *fy = *fy+v0*ht00*dhu10+v1*ht01*dhu10+v2*ht00*dhu11+v3*ht01*dhu11;
   44149           0 :         *fxy = *fxy+v0*dht00*dhu10+v1*dht01*dhu10+v2*dht00*dhu11+v3*dht01*dhu11;
   44150           0 :         v0 = c->f.ptr.p_double[sfxy+s1];
   44151           0 :         v1 = c->f.ptr.p_double[sfxy+s2];
   44152           0 :         v2 = c->f.ptr.p_double[sfxy+s3];
   44153           0 :         v3 = c->f.ptr.p_double[sfxy+s4];
   44154           0 :         *f = *f+v0*ht10*hu10+v1*ht11*hu10+v2*ht10*hu11+v3*ht11*hu11;
   44155           0 :         *fx = *fx+v0*dht10*hu10+v1*dht11*hu10+v2*dht10*hu11+v3*dht11*hu11;
   44156           0 :         *fy = *fy+v0*ht10*dhu10+v1*ht11*dhu10+v2*ht10*dhu11+v3*ht11*dhu11;
   44157           0 :         *fxy = *fxy+v0*dht10*dhu10+v1*dht11*dhu10+v2*dht10*dhu11+v3*dht11*dhu11;
   44158           0 :         return;
   44159             :     }
   44160             : }
   44161             : 
   44162             : 
   44163             : /*************************************************************************
   44164             : This subroutine performs linear transformation of the spline argument.
   44165             : 
   44166             : Input parameters:
   44167             :     C       -   spline interpolant
   44168             :     AX, BX  -   transformation coefficients: x = A*t + B
   44169             :     AY, BY  -   transformation coefficients: y = A*u + B
   44170             : Result:
   44171             :     C   -   transformed spline
   44172             : 
   44173             :   -- ALGLIB PROJECT --
   44174             :      Copyright 30.06.2007 by Bochkanov Sergey
   44175             : *************************************************************************/
   44176           0 : void spline2dlintransxy(spline2dinterpolant* c,
   44177             :      double ax,
   44178             :      double bx,
   44179             :      double ay,
   44180             :      double by,
   44181             :      ae_state *_state)
   44182             : {
   44183             :     ae_frame _frame_block;
   44184             :     ae_vector x;
   44185             :     ae_vector y;
   44186             :     ae_vector f;
   44187             :     ae_vector v;
   44188             :     ae_int_t i;
   44189             :     ae_int_t j;
   44190             :     ae_int_t k;
   44191             : 
   44192           0 :     ae_frame_make(_state, &_frame_block);
   44193           0 :     memset(&x, 0, sizeof(x));
   44194           0 :     memset(&y, 0, sizeof(y));
   44195           0 :     memset(&f, 0, sizeof(f));
   44196           0 :     memset(&v, 0, sizeof(v));
   44197           0 :     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
   44198           0 :     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
   44199           0 :     ae_vector_init(&f, 0, DT_REAL, _state, ae_true);
   44200           0 :     ae_vector_init(&v, 0, DT_REAL, _state, ae_true);
   44201             : 
   44202           0 :     ae_assert(c->stype==-3||c->stype==-1, "Spline2DLinTransXY: incorrect C (incorrect parameter C.SType)", _state);
   44203           0 :     ae_assert(ae_isfinite(ax, _state), "Spline2DLinTransXY: AX is infinite or NaN", _state);
   44204           0 :     ae_assert(ae_isfinite(bx, _state), "Spline2DLinTransXY: BX is infinite or NaN", _state);
   44205           0 :     ae_assert(ae_isfinite(ay, _state), "Spline2DLinTransXY: AY is infinite or NaN", _state);
   44206           0 :     ae_assert(ae_isfinite(by, _state), "Spline2DLinTransXY: BY is infinite or NaN", _state);
   44207           0 :     ae_vector_set_length(&x, c->n, _state);
   44208           0 :     ae_vector_set_length(&y, c->m, _state);
   44209           0 :     ae_vector_set_length(&f, c->m*c->n*c->d, _state);
   44210           0 :     for(j=0; j<=c->n-1; j++)
   44211             :     {
   44212           0 :         x.ptr.p_double[j] = c->x.ptr.p_double[j];
   44213             :     }
   44214           0 :     for(i=0; i<=c->m-1; i++)
   44215             :     {
   44216           0 :         y.ptr.p_double[i] = c->y.ptr.p_double[i];
   44217             :     }
   44218           0 :     for(i=0; i<=c->m-1; i++)
   44219             :     {
   44220           0 :         for(j=0; j<=c->n-1; j++)
   44221             :         {
   44222           0 :             for(k=0; k<=c->d-1; k++)
   44223             :             {
   44224           0 :                 f.ptr.p_double[c->d*(i*c->n+j)+k] = c->f.ptr.p_double[c->d*(i*c->n+j)+k];
   44225             :             }
   44226             :         }
   44227             :     }
   44228             :     
   44229             :     /*
   44230             :      * Handle different combinations of AX/AY
   44231             :      */
   44232           0 :     if( ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)) )
   44233             :     {
   44234           0 :         for(i=0; i<=c->m-1; i++)
   44235             :         {
   44236           0 :             spline2dcalcvbuf(c, bx, y.ptr.p_double[i], &v, _state);
   44237           0 :             y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay;
   44238           0 :             for(j=0; j<=c->n-1; j++)
   44239             :             {
   44240           0 :                 for(k=0; k<=c->d-1; k++)
   44241             :                 {
   44242           0 :                     f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k];
   44243             :                 }
   44244             :             }
   44245             :         }
   44246             :     }
   44247           0 :     if( ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)) )
   44248             :     {
   44249           0 :         for(j=0; j<=c->n-1; j++)
   44250             :         {
   44251           0 :             spline2dcalcvbuf(c, x.ptr.p_double[j], by, &v, _state);
   44252           0 :             x.ptr.p_double[j] = (x.ptr.p_double[j]-bx)/ax;
   44253           0 :             for(i=0; i<=c->m-1; i++)
   44254             :             {
   44255           0 :                 for(k=0; k<=c->d-1; k++)
   44256             :                 {
   44257           0 :                     f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k];
   44258             :                 }
   44259             :             }
   44260             :         }
   44261             :     }
   44262           0 :     if( ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)) )
   44263             :     {
   44264           0 :         for(j=0; j<=c->n-1; j++)
   44265             :         {
   44266           0 :             x.ptr.p_double[j] = (x.ptr.p_double[j]-bx)/ax;
   44267             :         }
   44268           0 :         for(i=0; i<=c->m-1; i++)
   44269             :         {
   44270           0 :             y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay;
   44271             :         }
   44272             :     }
   44273           0 :     if( ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)) )
   44274             :     {
   44275           0 :         spline2dcalcvbuf(c, bx, by, &v, _state);
   44276           0 :         for(i=0; i<=c->m-1; i++)
   44277             :         {
   44278           0 :             for(j=0; j<=c->n-1; j++)
   44279             :             {
   44280           0 :                 for(k=0; k<=c->d-1; k++)
   44281             :                 {
   44282           0 :                     f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k];
   44283             :                 }
   44284             :             }
   44285             :         }
   44286             :     }
   44287             :     
   44288             :     /*
   44289             :      * Rebuild spline
   44290             :      */
   44291           0 :     if( c->stype==-3 )
   44292             :     {
   44293           0 :         spline2dbuildbicubicv(&x, c->n, &y, c->m, &f, c->d, c, _state);
   44294             :     }
   44295           0 :     if( c->stype==-1 )
   44296             :     {
   44297           0 :         spline2dbuildbilinearv(&x, c->n, &y, c->m, &f, c->d, c, _state);
   44298             :     }
   44299           0 :     ae_frame_leave(_state);
   44300           0 : }
   44301             : 
   44302             : 
   44303             : /*************************************************************************
   44304             : This subroutine performs linear transformation of the spline.
   44305             : 
   44306             : Input parameters:
   44307             :     C   -   spline interpolant.
   44308             :     A, B-   transformation coefficients: S2(x,y) = A*S(x,y) + B
   44309             :     
   44310             : Output parameters:
   44311             :     C   -   transformed spline
   44312             : 
   44313             :   -- ALGLIB PROJECT --
   44314             :      Copyright 30.06.2007 by Bochkanov Sergey
   44315             : *************************************************************************/
   44316           0 : void spline2dlintransf(spline2dinterpolant* c,
   44317             :      double a,
   44318             :      double b,
   44319             :      ae_state *_state)
   44320             : {
   44321             :     ae_frame _frame_block;
   44322             :     ae_vector x;
   44323             :     ae_vector y;
   44324             :     ae_vector f;
   44325             :     ae_int_t i;
   44326             :     ae_int_t j;
   44327             : 
   44328           0 :     ae_frame_make(_state, &_frame_block);
   44329           0 :     memset(&x, 0, sizeof(x));
   44330           0 :     memset(&y, 0, sizeof(y));
   44331           0 :     memset(&f, 0, sizeof(f));
   44332           0 :     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
   44333           0 :     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
   44334           0 :     ae_vector_init(&f, 0, DT_REAL, _state, ae_true);
   44335             : 
   44336           0 :     ae_assert(c->stype==-3||c->stype==-1, "Spline2DLinTransF: incorrect C (incorrect parameter C.SType)", _state);
   44337           0 :     ae_vector_set_length(&x, c->n, _state);
   44338           0 :     ae_vector_set_length(&y, c->m, _state);
   44339           0 :     ae_vector_set_length(&f, c->m*c->n*c->d, _state);
   44340           0 :     for(j=0; j<=c->n-1; j++)
   44341             :     {
   44342           0 :         x.ptr.p_double[j] = c->x.ptr.p_double[j];
   44343             :     }
   44344           0 :     for(i=0; i<=c->m-1; i++)
   44345             :     {
   44346           0 :         y.ptr.p_double[i] = c->y.ptr.p_double[i];
   44347             :     }
   44348           0 :     for(i=0; i<=c->m*c->n*c->d-1; i++)
   44349             :     {
   44350           0 :         f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b;
   44351             :     }
   44352           0 :     if( c->stype==-3 )
   44353             :     {
   44354           0 :         spline2dbuildbicubicv(&x, c->n, &y, c->m, &f, c->d, c, _state);
   44355             :     }
   44356           0 :     if( c->stype==-1 )
   44357             :     {
   44358           0 :         spline2dbuildbilinearv(&x, c->n, &y, c->m, &f, c->d, c, _state);
   44359             :     }
   44360           0 :     ae_frame_leave(_state);
   44361           0 : }
   44362             : 
   44363             : 
   44364             : /*************************************************************************
   44365             : This subroutine makes the copy of the spline model.
   44366             : 
   44367             : Input parameters:
   44368             :     C   -   spline interpolant
   44369             : 
   44370             : Output parameters:
   44371             :     CC  -   spline copy
   44372             : 
   44373             :   -- ALGLIB PROJECT --
   44374             :      Copyright 29.06.2007 by Bochkanov Sergey
   44375             : *************************************************************************/
   44376           0 : void spline2dcopy(spline2dinterpolant* c,
   44377             :      spline2dinterpolant* cc,
   44378             :      ae_state *_state)
   44379             : {
   44380             :     ae_int_t tblsize;
   44381             : 
   44382           0 :     _spline2dinterpolant_clear(cc);
   44383             : 
   44384           0 :     ae_assert(c->stype==-1||c->stype==-3, "Spline2DCopy: incorrect C (incorrect parameter C.SType)", _state);
   44385           0 :     cc->n = c->n;
   44386           0 :     cc->m = c->m;
   44387           0 :     cc->d = c->d;
   44388           0 :     cc->stype = c->stype;
   44389           0 :     tblsize = -1;
   44390           0 :     if( c->stype==-3 )
   44391             :     {
   44392           0 :         tblsize = 4*c->n*c->m*c->d;
   44393             :     }
   44394           0 :     if( c->stype==-1 )
   44395             :     {
   44396           0 :         tblsize = c->n*c->m*c->d;
   44397             :     }
   44398           0 :     ae_assert(tblsize>0, "Spline2DCopy: internal error", _state);
   44399           0 :     ae_vector_set_length(&cc->x, cc->n, _state);
   44400           0 :     ae_vector_set_length(&cc->y, cc->m, _state);
   44401           0 :     ae_vector_set_length(&cc->f, tblsize, _state);
   44402           0 :     ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1));
   44403           0 :     ae_v_move(&cc->y.ptr.p_double[0], 1, &c->y.ptr.p_double[0], 1, ae_v_len(0,cc->m-1));
   44404           0 :     ae_v_move(&cc->f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,tblsize-1));
   44405           0 : }
   44406             : 
   44407             : 
   44408             : /*************************************************************************
   44409             : Bicubic spline resampling
   44410             : 
   44411             : Input parameters:
   44412             :     A           -   function values at the old grid,
   44413             :                     array[0..OldHeight-1, 0..OldWidth-1]
   44414             :     OldHeight   -   old grid height, OldHeight>1
   44415             :     OldWidth    -   old grid width, OldWidth>1
   44416             :     NewHeight   -   new grid height, NewHeight>1
   44417             :     NewWidth    -   new grid width, NewWidth>1
   44418             :     
   44419             : Output parameters:
   44420             :     B           -   function values at the new grid,
   44421             :                     array[0..NewHeight-1, 0..NewWidth-1]
   44422             : 
   44423             :   -- ALGLIB routine --
   44424             :      15 May, 2007
   44425             :      Copyright by Bochkanov Sergey
   44426             : *************************************************************************/
   44427           0 : void spline2dresamplebicubic(/* Real    */ ae_matrix* a,
   44428             :      ae_int_t oldheight,
   44429             :      ae_int_t oldwidth,
   44430             :      /* Real    */ ae_matrix* b,
   44431             :      ae_int_t newheight,
   44432             :      ae_int_t newwidth,
   44433             :      ae_state *_state)
   44434             : {
   44435             :     ae_frame _frame_block;
   44436             :     ae_matrix buf;
   44437             :     ae_vector x;
   44438             :     ae_vector y;
   44439             :     spline1dinterpolant c;
   44440             :     ae_int_t mw;
   44441             :     ae_int_t mh;
   44442             :     ae_int_t i;
   44443             :     ae_int_t j;
   44444             : 
   44445           0 :     ae_frame_make(_state, &_frame_block);
   44446           0 :     memset(&buf, 0, sizeof(buf));
   44447           0 :     memset(&x, 0, sizeof(x));
   44448           0 :     memset(&y, 0, sizeof(y));
   44449           0 :     memset(&c, 0, sizeof(c));
   44450           0 :     ae_matrix_clear(b);
   44451           0 :     ae_matrix_init(&buf, 0, 0, DT_REAL, _state, ae_true);
   44452           0 :     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
   44453           0 :     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
   44454           0 :     _spline1dinterpolant_init(&c, _state, ae_true);
   44455             : 
   44456           0 :     ae_assert(oldwidth>1&&oldheight>1, "Spline2DResampleBicubic: width/height less than 1", _state);
   44457           0 :     ae_assert(newwidth>1&&newheight>1, "Spline2DResampleBicubic: width/height less than 1", _state);
   44458             :     
   44459             :     /*
   44460             :      * Prepare
   44461             :      */
   44462           0 :     mw = ae_maxint(oldwidth, newwidth, _state);
   44463           0 :     mh = ae_maxint(oldheight, newheight, _state);
   44464           0 :     ae_matrix_set_length(b, newheight, newwidth, _state);
   44465           0 :     ae_matrix_set_length(&buf, oldheight, newwidth, _state);
   44466           0 :     ae_vector_set_length(&x, ae_maxint(mw, mh, _state), _state);
   44467           0 :     ae_vector_set_length(&y, ae_maxint(mw, mh, _state), _state);
   44468             :     
   44469             :     /*
   44470             :      * Horizontal interpolation
   44471             :      */
   44472           0 :     for(i=0; i<=oldheight-1; i++)
   44473             :     {
   44474             :         
   44475             :         /*
   44476             :          * Fill X, Y
   44477             :          */
   44478           0 :         for(j=0; j<=oldwidth-1; j++)
   44479             :         {
   44480           0 :             x.ptr.p_double[j] = (double)j/(double)(oldwidth-1);
   44481           0 :             y.ptr.p_double[j] = a->ptr.pp_double[i][j];
   44482             :         }
   44483             :         
   44484             :         /*
   44485             :          * Interpolate and place result into temporary matrix
   44486             :          */
   44487           0 :         spline1dbuildcubic(&x, &y, oldwidth, 0, 0.0, 0, 0.0, &c, _state);
   44488           0 :         for(j=0; j<=newwidth-1; j++)
   44489             :         {
   44490           0 :             buf.ptr.pp_double[i][j] = spline1dcalc(&c, (double)j/(double)(newwidth-1), _state);
   44491             :         }
   44492             :     }
   44493             :     
   44494             :     /*
   44495             :      * Vertical interpolation
   44496             :      */
   44497           0 :     for(j=0; j<=newwidth-1; j++)
   44498             :     {
   44499             :         
   44500             :         /*
   44501             :          * Fill X, Y
   44502             :          */
   44503           0 :         for(i=0; i<=oldheight-1; i++)
   44504             :         {
   44505           0 :             x.ptr.p_double[i] = (double)i/(double)(oldheight-1);
   44506           0 :             y.ptr.p_double[i] = buf.ptr.pp_double[i][j];
   44507             :         }
   44508             :         
   44509             :         /*
   44510             :          * Interpolate and place result into B
   44511             :          */
   44512           0 :         spline1dbuildcubic(&x, &y, oldheight, 0, 0.0, 0, 0.0, &c, _state);
   44513           0 :         for(i=0; i<=newheight-1; i++)
   44514             :         {
   44515           0 :             b->ptr.pp_double[i][j] = spline1dcalc(&c, (double)i/(double)(newheight-1), _state);
   44516             :         }
   44517             :     }
   44518           0 :     ae_frame_leave(_state);
   44519           0 : }
   44520             : 
   44521             : 
   44522             : /*************************************************************************
   44523             : Bilinear spline resampling
   44524             : 
   44525             : Input parameters:
   44526             :     A           -   function values at the old grid,
   44527             :                     array[0..OldHeight-1, 0..OldWidth-1]
   44528             :     OldHeight   -   old grid height, OldHeight>1
   44529             :     OldWidth    -   old grid width, OldWidth>1
   44530             :     NewHeight   -   new grid height, NewHeight>1
   44531             :     NewWidth    -   new grid width, NewWidth>1
   44532             : 
   44533             : Output parameters:
   44534             :     B           -   function values at the new grid,
   44535             :                     array[0..NewHeight-1, 0..NewWidth-1]
   44536             : 
   44537             :   -- ALGLIB routine --
   44538             :      09.07.2007
   44539             :      Copyright by Bochkanov Sergey
   44540             : *************************************************************************/
   44541           0 : void spline2dresamplebilinear(/* Real    */ ae_matrix* a,
   44542             :      ae_int_t oldheight,
   44543             :      ae_int_t oldwidth,
   44544             :      /* Real    */ ae_matrix* b,
   44545             :      ae_int_t newheight,
   44546             :      ae_int_t newwidth,
   44547             :      ae_state *_state)
   44548             : {
   44549             :     ae_int_t l;
   44550             :     ae_int_t c;
   44551             :     double t;
   44552             :     double u;
   44553             :     ae_int_t i;
   44554             :     ae_int_t j;
   44555             : 
   44556           0 :     ae_matrix_clear(b);
   44557             : 
   44558           0 :     ae_assert(oldwidth>1&&oldheight>1, "Spline2DResampleBilinear: width/height less than 1", _state);
   44559           0 :     ae_assert(newwidth>1&&newheight>1, "Spline2DResampleBilinear: width/height less than 1", _state);
   44560           0 :     ae_matrix_set_length(b, newheight, newwidth, _state);
   44561           0 :     for(i=0; i<=newheight-1; i++)
   44562             :     {
   44563           0 :         for(j=0; j<=newwidth-1; j++)
   44564             :         {
   44565           0 :             l = i*(oldheight-1)/(newheight-1);
   44566           0 :             if( l==oldheight-1 )
   44567             :             {
   44568           0 :                 l = oldheight-2;
   44569             :             }
   44570           0 :             u = (double)i/(double)(newheight-1)*(oldheight-1)-l;
   44571           0 :             c = j*(oldwidth-1)/(newwidth-1);
   44572           0 :             if( c==oldwidth-1 )
   44573             :             {
   44574           0 :                 c = oldwidth-2;
   44575             :             }
   44576           0 :             t = (double)(j*(oldwidth-1))/(double)(newwidth-1)-c;
   44577           0 :             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];
   44578             :         }
   44579             :     }
   44580           0 : }
   44581             : 
   44582             : 
   44583             : /*************************************************************************
   44584             : This subroutine builds bilinear vector-valued spline.
   44585             : 
   44586             : Input parameters:
   44587             :     X   -   spline abscissas, array[0..N-1]
   44588             :     Y   -   spline ordinates, array[0..M-1]
   44589             :     F   -   function values, array[0..M*N*D-1]:
   44590             :             * first D elements store D values at (X[0],Y[0])
   44591             :             * next D elements store D values at (X[1],Y[0])
   44592             :             * general form - D function values at (X[i],Y[j]) are stored
   44593             :               at F[D*(J*N+I)...D*(J*N+I)+D-1].
   44594             :     M,N -   grid size, M>=2, N>=2
   44595             :     D   -   vector dimension, D>=1
   44596             : 
   44597             : Output parameters:
   44598             :     C   -   spline interpolant
   44599             : 
   44600             :   -- ALGLIB PROJECT --
   44601             :      Copyright 16.04.2012 by Bochkanov Sergey
   44602             : *************************************************************************/
   44603           0 : void spline2dbuildbilinearv(/* Real    */ ae_vector* x,
   44604             :      ae_int_t n,
   44605             :      /* Real    */ ae_vector* y,
   44606             :      ae_int_t m,
   44607             :      /* Real    */ ae_vector* f,
   44608             :      ae_int_t d,
   44609             :      spline2dinterpolant* c,
   44610             :      ae_state *_state)
   44611             : {
   44612             :     double t;
   44613             :     ae_int_t i;
   44614             :     ae_int_t j;
   44615             :     ae_int_t k;
   44616             :     ae_int_t i0;
   44617             : 
   44618           0 :     _spline2dinterpolant_clear(c);
   44619             : 
   44620           0 :     ae_assert(n>=2, "Spline2DBuildBilinearV: N is less then 2", _state);
   44621           0 :     ae_assert(m>=2, "Spline2DBuildBilinearV: M is less then 2", _state);
   44622           0 :     ae_assert(d>=1, "Spline2DBuildBilinearV: invalid argument D (D<1)", _state);
   44623           0 :     ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinearV: length of X or Y is too short (Length(X/Y)<N/M)", _state);
   44624           0 :     ae_assert(isfinitevector(x, n, _state)&&isfinitevector(y, m, _state), "Spline2DBuildBilinearV: X or Y contains NaN or Infinite value", _state);
   44625           0 :     k = n*m*d;
   44626           0 :     ae_assert(f->cnt>=k, "Spline2DBuildBilinearV: length of F is too short (Length(F)<N*M*D)", _state);
   44627           0 :     ae_assert(isfinitevector(f, k, _state), "Spline2DBuildBilinearV: F contains NaN or Infinite value", _state);
   44628             :     
   44629             :     /*
   44630             :      * Fill interpolant
   44631             :      */
   44632           0 :     c->n = n;
   44633           0 :     c->m = m;
   44634           0 :     c->d = d;
   44635           0 :     c->stype = -1;
   44636           0 :     ae_vector_set_length(&c->x, c->n, _state);
   44637           0 :     ae_vector_set_length(&c->y, c->m, _state);
   44638           0 :     ae_vector_set_length(&c->f, k, _state);
   44639           0 :     for(i=0; i<=c->n-1; i++)
   44640             :     {
   44641           0 :         c->x.ptr.p_double[i] = x->ptr.p_double[i];
   44642             :     }
   44643           0 :     for(i=0; i<=c->m-1; i++)
   44644             :     {
   44645           0 :         c->y.ptr.p_double[i] = y->ptr.p_double[i];
   44646             :     }
   44647           0 :     for(i=0; i<=k-1; i++)
   44648             :     {
   44649           0 :         c->f.ptr.p_double[i] = f->ptr.p_double[i];
   44650             :     }
   44651             :     
   44652             :     /*
   44653             :      * Sort points
   44654             :      */
   44655           0 :     for(j=0; j<=c->n-1; j++)
   44656             :     {
   44657           0 :         k = j;
   44658           0 :         for(i=j+1; i<=c->n-1; i++)
   44659             :         {
   44660           0 :             if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) )
   44661             :             {
   44662           0 :                 k = i;
   44663             :             }
   44664             :         }
   44665           0 :         if( k!=j )
   44666             :         {
   44667           0 :             for(i=0; i<=c->m-1; i++)
   44668             :             {
   44669           0 :                 for(i0=0; i0<=c->d-1; i0++)
   44670             :                 {
   44671           0 :                     t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0];
   44672           0 :                     c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(i*c->n+k)+i0];
   44673           0 :                     c->f.ptr.p_double[c->d*(i*c->n+k)+i0] = t;
   44674             :                 }
   44675             :             }
   44676           0 :             t = c->x.ptr.p_double[j];
   44677           0 :             c->x.ptr.p_double[j] = c->x.ptr.p_double[k];
   44678           0 :             c->x.ptr.p_double[k] = t;
   44679             :         }
   44680             :     }
   44681           0 :     for(i=0; i<=c->m-1; i++)
   44682             :     {
   44683           0 :         k = i;
   44684           0 :         for(j=i+1; j<=c->m-1; j++)
   44685             :         {
   44686           0 :             if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) )
   44687             :             {
   44688           0 :                 k = j;
   44689             :             }
   44690             :         }
   44691           0 :         if( k!=i )
   44692             :         {
   44693           0 :             for(j=0; j<=c->n-1; j++)
   44694             :             {
   44695           0 :                 for(i0=0; i0<=c->d-1; i0++)
   44696             :                 {
   44697           0 :                     t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0];
   44698           0 :                     c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(k*c->n+j)+i0];
   44699           0 :                     c->f.ptr.p_double[c->d*(k*c->n+j)+i0] = t;
   44700             :                 }
   44701             :             }
   44702           0 :             t = c->y.ptr.p_double[i];
   44703           0 :             c->y.ptr.p_double[i] = c->y.ptr.p_double[k];
   44704           0 :             c->y.ptr.p_double[k] = t;
   44705             :         }
   44706             :     }
   44707           0 : }
   44708             : 
   44709             : 
   44710             : /*************************************************************************
   44711             : This subroutine builds bicubic vector-valued spline.
   44712             : 
   44713             : Input parameters:
   44714             :     X   -   spline abscissas, array[0..N-1]
   44715             :     Y   -   spline ordinates, array[0..M-1]
   44716             :     F   -   function values, array[0..M*N*D-1]:
   44717             :             * first D elements store D values at (X[0],Y[0])
   44718             :             * next D elements store D values at (X[1],Y[0])
   44719             :             * general form - D function values at (X[i],Y[j]) are stored
   44720             :               at F[D*(J*N+I)...D*(J*N+I)+D-1].
   44721             :     M,N -   grid size, M>=2, N>=2
   44722             :     D   -   vector dimension, D>=1
   44723             : 
   44724             : Output parameters:
   44725             :     C   -   spline interpolant
   44726             : 
   44727             :   -- ALGLIB PROJECT --
   44728             :      Copyright 16.04.2012 by Bochkanov Sergey
   44729             : *************************************************************************/
   44730           0 : void spline2dbuildbicubicv(/* Real    */ ae_vector* x,
   44731             :      ae_int_t n,
   44732             :      /* Real    */ ae_vector* y,
   44733             :      ae_int_t m,
   44734             :      /* Real    */ ae_vector* f,
   44735             :      ae_int_t d,
   44736             :      spline2dinterpolant* c,
   44737             :      ae_state *_state)
   44738             : {
   44739             :     ae_frame _frame_block;
   44740             :     ae_vector _f;
   44741             :     ae_matrix tf;
   44742             :     ae_matrix dx;
   44743             :     ae_matrix dy;
   44744             :     ae_matrix dxy;
   44745             :     double t;
   44746             :     ae_int_t i;
   44747             :     ae_int_t j;
   44748             :     ae_int_t k;
   44749             :     ae_int_t di;
   44750             : 
   44751           0 :     ae_frame_make(_state, &_frame_block);
   44752           0 :     memset(&_f, 0, sizeof(_f));
   44753           0 :     memset(&tf, 0, sizeof(tf));
   44754           0 :     memset(&dx, 0, sizeof(dx));
   44755           0 :     memset(&dy, 0, sizeof(dy));
   44756           0 :     memset(&dxy, 0, sizeof(dxy));
   44757           0 :     ae_vector_init_copy(&_f, f, _state, ae_true);
   44758           0 :     f = &_f;
   44759           0 :     _spline2dinterpolant_clear(c);
   44760           0 :     ae_matrix_init(&tf, 0, 0, DT_REAL, _state, ae_true);
   44761           0 :     ae_matrix_init(&dx, 0, 0, DT_REAL, _state, ae_true);
   44762           0 :     ae_matrix_init(&dy, 0, 0, DT_REAL, _state, ae_true);
   44763           0 :     ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true);
   44764             : 
   44765           0 :     ae_assert(n>=2, "Spline2DBuildBicubicV: N is less than 2", _state);
   44766           0 :     ae_assert(m>=2, "Spline2DBuildBicubicV: M is less than 2", _state);
   44767           0 :     ae_assert(d>=1, "Spline2DBuildBicubicV: invalid argument D (D<1)", _state);
   44768           0 :     ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubicV: length of X or Y is too short (Length(X/Y)<N/M)", _state);
   44769           0 :     ae_assert(isfinitevector(x, n, _state)&&isfinitevector(y, m, _state), "Spline2DBuildBicubicV: X or Y contains NaN or Infinite value", _state);
   44770           0 :     k = n*m*d;
   44771           0 :     ae_assert(f->cnt>=k, "Spline2DBuildBicubicV: length of F is too short (Length(F)<N*M*D)", _state);
   44772           0 :     ae_assert(isfinitevector(f, k, _state), "Spline2DBuildBicubicV: F contains NaN or Infinite value", _state);
   44773             :     
   44774             :     /*
   44775             :      * Fill interpolant:
   44776             :      *  F[0]...F[N*M*D-1]:
   44777             :      *      f(i,j) table. f(0,0), f(0, 1), f(0,2) and so on...
   44778             :      *  F[N*M*D]...F[2*N*M*D-1]:
   44779             :      *      df(i,j)/dx table.
   44780             :      *  F[2*N*M*D]...F[3*N*M*D-1]:
   44781             :      *      df(i,j)/dy table.
   44782             :      *  F[3*N*M*D]...F[4*N*M*D-1]:
   44783             :      *      d2f(i,j)/dxdy table.
   44784             :      */
   44785           0 :     c->d = d;
   44786           0 :     c->n = n;
   44787           0 :     c->m = m;
   44788           0 :     c->stype = -3;
   44789           0 :     k = 4*k;
   44790           0 :     ae_vector_set_length(&c->x, c->n, _state);
   44791           0 :     ae_vector_set_length(&c->y, c->m, _state);
   44792           0 :     ae_vector_set_length(&c->f, k, _state);
   44793           0 :     ae_matrix_set_length(&tf, c->m, c->n, _state);
   44794           0 :     for(i=0; i<=c->n-1; i++)
   44795             :     {
   44796           0 :         c->x.ptr.p_double[i] = x->ptr.p_double[i];
   44797             :     }
   44798           0 :     for(i=0; i<=c->m-1; i++)
   44799             :     {
   44800           0 :         c->y.ptr.p_double[i] = y->ptr.p_double[i];
   44801             :     }
   44802             :     
   44803             :     /*
   44804             :      * Sort points
   44805             :      */
   44806           0 :     for(j=0; j<=c->n-1; j++)
   44807             :     {
   44808           0 :         k = j;
   44809           0 :         for(i=j+1; i<=c->n-1; i++)
   44810             :         {
   44811           0 :             if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) )
   44812             :             {
   44813           0 :                 k = i;
   44814             :             }
   44815             :         }
   44816           0 :         if( k!=j )
   44817             :         {
   44818           0 :             for(i=0; i<=c->m-1; i++)
   44819             :             {
   44820           0 :                 for(di=0; di<=c->d-1; di++)
   44821             :                 {
   44822           0 :                     t = f->ptr.p_double[c->d*(i*c->n+j)+di];
   44823           0 :                     f->ptr.p_double[c->d*(i*c->n+j)+di] = f->ptr.p_double[c->d*(i*c->n+k)+di];
   44824           0 :                     f->ptr.p_double[c->d*(i*c->n+k)+di] = t;
   44825             :                 }
   44826             :             }
   44827           0 :             t = c->x.ptr.p_double[j];
   44828           0 :             c->x.ptr.p_double[j] = c->x.ptr.p_double[k];
   44829           0 :             c->x.ptr.p_double[k] = t;
   44830             :         }
   44831             :     }
   44832           0 :     for(i=0; i<=c->m-1; i++)
   44833             :     {
   44834           0 :         k = i;
   44835           0 :         for(j=i+1; j<=c->m-1; j++)
   44836             :         {
   44837           0 :             if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) )
   44838             :             {
   44839           0 :                 k = j;
   44840             :             }
   44841             :         }
   44842           0 :         if( k!=i )
   44843             :         {
   44844           0 :             for(j=0; j<=c->n-1; j++)
   44845             :             {
   44846           0 :                 for(di=0; di<=c->d-1; di++)
   44847             :                 {
   44848           0 :                     t = f->ptr.p_double[c->d*(i*c->n+j)+di];
   44849           0 :                     f->ptr.p_double[c->d*(i*c->n+j)+di] = f->ptr.p_double[c->d*(k*c->n+j)+di];
   44850           0 :                     f->ptr.p_double[c->d*(k*c->n+j)+di] = t;
   44851             :                 }
   44852             :             }
   44853           0 :             t = c->y.ptr.p_double[i];
   44854           0 :             c->y.ptr.p_double[i] = c->y.ptr.p_double[k];
   44855           0 :             c->y.ptr.p_double[k] = t;
   44856             :         }
   44857             :     }
   44858           0 :     for(di=0; di<=c->d-1; di++)
   44859             :     {
   44860           0 :         for(i=0; i<=c->m-1; i++)
   44861             :         {
   44862           0 :             for(j=0; j<=c->n-1; j++)
   44863             :             {
   44864           0 :                 tf.ptr.pp_double[i][j] = f->ptr.p_double[c->d*(i*c->n+j)+di];
   44865             :             }
   44866             :         }
   44867           0 :         spline2d_bicubiccalcderivatives(&tf, &c->x, &c->y, c->m, c->n, &dx, &dy, &dxy, _state);
   44868           0 :         for(i=0; i<=c->m-1; i++)
   44869             :         {
   44870           0 :             for(j=0; j<=c->n-1; j++)
   44871             :             {
   44872           0 :                 k = c->d*(i*c->n+j)+di;
   44873           0 :                 c->f.ptr.p_double[k] = tf.ptr.pp_double[i][j];
   44874           0 :                 c->f.ptr.p_double[c->n*c->m*c->d+k] = dx.ptr.pp_double[i][j];
   44875           0 :                 c->f.ptr.p_double[2*c->n*c->m*c->d+k] = dy.ptr.pp_double[i][j];
   44876           0 :                 c->f.ptr.p_double[3*c->n*c->m*c->d+k] = dxy.ptr.pp_double[i][j];
   44877             :             }
   44878             :         }
   44879             :     }
   44880           0 :     ae_frame_leave(_state);
   44881           0 : }
   44882             : 
   44883             : 
   44884             : /*************************************************************************
   44885             : This subroutine unpacks two-dimensional spline into the coefficients table
   44886             : 
   44887             : Input parameters:
   44888             :     C   -   spline interpolant.
   44889             : 
   44890             : Result:
   44891             :     M, N-   grid size (x-axis and y-axis)
   44892             :     D   -   number of components
   44893             :     Tbl -   coefficients table, unpacked format,
   44894             :             D - components: [0..(N-1)*(M-1)*D-1, 0..19].
   44895             :             For T=0..D-1 (component index), I = 0...N-2 (x index),
   44896             :             J=0..M-2 (y index):
   44897             :                 K :=  T + I*D + J*D*(N-1)
   44898             :                 
   44899             :                 K-th row stores decomposition for T-th component of the
   44900             :                 vector-valued function
   44901             :                 
   44902             :                 Tbl[K,0] = X[i]
   44903             :                 Tbl[K,1] = X[i+1]
   44904             :                 Tbl[K,2] = Y[j]
   44905             :                 Tbl[K,3] = Y[j+1]
   44906             :                 Tbl[K,4] = C00
   44907             :                 Tbl[K,5] = C01
   44908             :                 Tbl[K,6] = C02
   44909             :                 Tbl[K,7] = C03
   44910             :                 Tbl[K,8] = C10
   44911             :                 Tbl[K,9] = C11
   44912             :                 ...
   44913             :                 Tbl[K,19] = C33
   44914             :             On each grid square spline is equals to:
   44915             :                 S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3)
   44916             :                 t = x-x[j]
   44917             :                 u = y-y[i]
   44918             : 
   44919             :   -- ALGLIB PROJECT --
   44920             :      Copyright 16.04.2012 by Bochkanov Sergey
   44921             : *************************************************************************/
   44922           0 : void spline2dunpackv(spline2dinterpolant* c,
   44923             :      ae_int_t* m,
   44924             :      ae_int_t* n,
   44925             :      ae_int_t* d,
   44926             :      /* Real    */ ae_matrix* tbl,
   44927             :      ae_state *_state)
   44928             : {
   44929             :     ae_int_t k;
   44930             :     ae_int_t p;
   44931             :     ae_int_t ci;
   44932             :     ae_int_t cj;
   44933             :     ae_int_t s1;
   44934             :     ae_int_t s2;
   44935             :     ae_int_t s3;
   44936             :     ae_int_t s4;
   44937             :     ae_int_t sfx;
   44938             :     ae_int_t sfy;
   44939             :     ae_int_t sfxy;
   44940             :     double y1;
   44941             :     double y2;
   44942             :     double y3;
   44943             :     double y4;
   44944             :     double dt;
   44945             :     double du;
   44946             :     ae_int_t i;
   44947             :     ae_int_t j;
   44948             :     ae_int_t k0;
   44949             : 
   44950           0 :     *m = 0;
   44951           0 :     *n = 0;
   44952           0 :     *d = 0;
   44953           0 :     ae_matrix_clear(tbl);
   44954             : 
   44955           0 :     ae_assert(c->stype==-3||c->stype==-1, "Spline2DUnpackV: incorrect C (incorrect parameter C.SType)", _state);
   44956           0 :     *n = c->n;
   44957           0 :     *m = c->m;
   44958           0 :     *d = c->d;
   44959           0 :     ae_matrix_set_length(tbl, (*n-1)*(*m-1)*(*d), 20, _state);
   44960           0 :     sfx = *n*(*m)*(*d);
   44961           0 :     sfy = 2*(*n)*(*m)*(*d);
   44962           0 :     sfxy = 3*(*n)*(*m)*(*d);
   44963           0 :     for(i=0; i<=*m-2; i++)
   44964             :     {
   44965           0 :         for(j=0; j<=*n-2; j++)
   44966             :         {
   44967           0 :             for(k=0; k<=*d-1; k++)
   44968             :             {
   44969           0 :                 p = *d*(i*(*n-1)+j)+k;
   44970           0 :                 tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[j];
   44971           0 :                 tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[j+1];
   44972           0 :                 tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[i];
   44973           0 :                 tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[i+1];
   44974           0 :                 dt = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]);
   44975           0 :                 du = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]);
   44976             :                 
   44977             :                 /*
   44978             :                  * Bilinear interpolation
   44979             :                  */
   44980           0 :                 if( c->stype==-1 )
   44981             :                 {
   44982           0 :                     for(k0=4; k0<=19; k0++)
   44983             :                     {
   44984           0 :                         tbl->ptr.pp_double[p][k0] = (double)(0);
   44985             :                     }
   44986           0 :                     y1 = c->f.ptr.p_double[*d*(*n*i+j)+k];
   44987           0 :                     y2 = c->f.ptr.p_double[*d*(*n*i+(j+1))+k];
   44988           0 :                     y3 = c->f.ptr.p_double[*d*(*n*(i+1)+(j+1))+k];
   44989           0 :                     y4 = c->f.ptr.p_double[*d*(*n*(i+1)+j)+k];
   44990           0 :                     tbl->ptr.pp_double[p][4] = y1;
   44991           0 :                     tbl->ptr.pp_double[p][4+1*4+0] = y2-y1;
   44992           0 :                     tbl->ptr.pp_double[p][4+0*4+1] = y4-y1;
   44993           0 :                     tbl->ptr.pp_double[p][4+1*4+1] = y3-y2-y4+y1;
   44994             :                 }
   44995             :                 
   44996             :                 /*
   44997             :                  * Bicubic interpolation
   44998             :                  */
   44999           0 :                 if( c->stype==-3 )
   45000             :                 {
   45001           0 :                     s1 = *d*(*n*i+j)+k;
   45002           0 :                     s2 = *d*(*n*i+(j+1))+k;
   45003           0 :                     s3 = *d*(*n*(i+1)+(j+1))+k;
   45004           0 :                     s4 = *d*(*n*(i+1)+j)+k;
   45005           0 :                     tbl->ptr.pp_double[p][4+0*4+0] = c->f.ptr.p_double[s1];
   45006           0 :                     tbl->ptr.pp_double[p][4+0*4+1] = c->f.ptr.p_double[sfy+s1]/du;
   45007           0 :                     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;
   45008           0 :                     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;
   45009           0 :                     tbl->ptr.pp_double[p][4+1*4+0] = c->f.ptr.p_double[sfx+s1]/dt;
   45010           0 :                     tbl->ptr.pp_double[p][4+1*4+1] = c->f.ptr.p_double[sfxy+s1]/(dt*du);
   45011           0 :                     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);
   45012           0 :                     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);
   45013           0 :                     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;
   45014           0 :                     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);
   45015           0 :                     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);
   45016           0 :                     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);
   45017           0 :                     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;
   45018           0 :                     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);
   45019           0 :                     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);
   45020           0 :                     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);
   45021             :                 }
   45022             :                 
   45023             :                 /*
   45024             :                  * Rescale Cij
   45025             :                  */
   45026           0 :                 for(ci=0; ci<=3; ci++)
   45027             :                 {
   45028           0 :                     for(cj=0; cj<=3; cj++)
   45029             :                     {
   45030           0 :                         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);
   45031             :                     }
   45032             :                 }
   45033             :             }
   45034             :         }
   45035             :     }
   45036           0 : }
   45037             : 
   45038             : 
   45039             : /*************************************************************************
   45040             : This subroutine was deprecated in ALGLIB 3.6.0
   45041             : 
   45042             : We recommend you to switch  to  Spline2DBuildBilinearV(),  which  is  more
   45043             : flexible and accepts its arguments in more convenient order.
   45044             : 
   45045             :   -- ALGLIB PROJECT --
   45046             :      Copyright 05.07.2007 by Bochkanov Sergey
   45047             : *************************************************************************/
   45048           0 : void spline2dbuildbilinear(/* Real    */ ae_vector* x,
   45049             :      /* Real    */ ae_vector* y,
   45050             :      /* Real    */ ae_matrix* f,
   45051             :      ae_int_t m,
   45052             :      ae_int_t n,
   45053             :      spline2dinterpolant* c,
   45054             :      ae_state *_state)
   45055             : {
   45056             :     double t;
   45057             :     ae_int_t i;
   45058             :     ae_int_t j;
   45059             :     ae_int_t k;
   45060             : 
   45061           0 :     _spline2dinterpolant_clear(c);
   45062             : 
   45063           0 :     ae_assert(n>=2, "Spline2DBuildBilinear: N<2", _state);
   45064           0 :     ae_assert(m>=2, "Spline2DBuildBilinear: M<2", _state);
   45065           0 :     ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinear: length of X or Y is too short (Length(X/Y)<N/M)", _state);
   45066           0 :     ae_assert(isfinitevector(x, n, _state)&&isfinitevector(y, m, _state), "Spline2DBuildBilinear: X or Y contains NaN or Infinite value", _state);
   45067           0 :     ae_assert(f->rows>=m&&f->cols>=n, "Spline2DBuildBilinear: size of F is too small (rows(F)<M or cols(F)<N)", _state);
   45068           0 :     ae_assert(apservisfinitematrix(f, m, n, _state), "Spline2DBuildBilinear: F contains NaN or Infinite value", _state);
   45069             :     
   45070             :     /*
   45071             :      * Fill interpolant
   45072             :      */
   45073           0 :     c->n = n;
   45074           0 :     c->m = m;
   45075           0 :     c->d = 1;
   45076           0 :     c->stype = -1;
   45077           0 :     ae_vector_set_length(&c->x, c->n, _state);
   45078           0 :     ae_vector_set_length(&c->y, c->m, _state);
   45079           0 :     ae_vector_set_length(&c->f, c->n*c->m, _state);
   45080           0 :     for(i=0; i<=c->n-1; i++)
   45081             :     {
   45082           0 :         c->x.ptr.p_double[i] = x->ptr.p_double[i];
   45083             :     }
   45084           0 :     for(i=0; i<=c->m-1; i++)
   45085             :     {
   45086           0 :         c->y.ptr.p_double[i] = y->ptr.p_double[i];
   45087             :     }
   45088           0 :     for(i=0; i<=c->m-1; i++)
   45089             :     {
   45090           0 :         for(j=0; j<=c->n-1; j++)
   45091             :         {
   45092           0 :             c->f.ptr.p_double[i*c->n+j] = f->ptr.pp_double[i][j];
   45093             :         }
   45094             :     }
   45095             :     
   45096             :     /*
   45097             :      * Sort points
   45098             :      */
   45099           0 :     for(j=0; j<=c->n-1; j++)
   45100             :     {
   45101           0 :         k = j;
   45102           0 :         for(i=j+1; i<=c->n-1; i++)
   45103             :         {
   45104           0 :             if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) )
   45105             :             {
   45106           0 :                 k = i;
   45107             :             }
   45108             :         }
   45109           0 :         if( k!=j )
   45110             :         {
   45111           0 :             for(i=0; i<=c->m-1; i++)
   45112             :             {
   45113           0 :                 t = c->f.ptr.p_double[i*c->n+j];
   45114           0 :                 c->f.ptr.p_double[i*c->n+j] = c->f.ptr.p_double[i*c->n+k];
   45115           0 :                 c->f.ptr.p_double[i*c->n+k] = t;
   45116             :             }
   45117           0 :             t = c->x.ptr.p_double[j];
   45118           0 :             c->x.ptr.p_double[j] = c->x.ptr.p_double[k];
   45119           0 :             c->x.ptr.p_double[k] = t;
   45120             :         }
   45121             :     }
   45122           0 :     for(i=0; i<=c->m-1; i++)
   45123             :     {
   45124           0 :         k = i;
   45125           0 :         for(j=i+1; j<=c->m-1; j++)
   45126             :         {
   45127           0 :             if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) )
   45128             :             {
   45129           0 :                 k = j;
   45130             :             }
   45131             :         }
   45132           0 :         if( k!=i )
   45133             :         {
   45134           0 :             for(j=0; j<=c->n-1; j++)
   45135             :             {
   45136           0 :                 t = c->f.ptr.p_double[i*c->n+j];
   45137           0 :                 c->f.ptr.p_double[i*c->n+j] = c->f.ptr.p_double[k*c->n+j];
   45138           0 :                 c->f.ptr.p_double[k*c->n+j] = t;
   45139             :             }
   45140           0 :             t = c->y.ptr.p_double[i];
   45141           0 :             c->y.ptr.p_double[i] = c->y.ptr.p_double[k];
   45142           0 :             c->y.ptr.p_double[k] = t;
   45143             :         }
   45144             :     }
   45145           0 : }
   45146             : 
   45147             : 
   45148             : /*************************************************************************
   45149             : This subroutine was deprecated in ALGLIB 3.6.0
   45150             : 
   45151             : We recommend you to switch  to  Spline2DBuildBicubicV(),  which  is  more
   45152             : flexible and accepts its arguments in more convenient order.
   45153             : 
   45154             :   -- ALGLIB PROJECT --
   45155             :      Copyright 05.07.2007 by Bochkanov Sergey
   45156             : *************************************************************************/
   45157           0 : void spline2dbuildbicubic(/* Real    */ ae_vector* x,
   45158             :      /* Real    */ ae_vector* y,
   45159             :      /* Real    */ ae_matrix* f,
   45160             :      ae_int_t m,
   45161             :      ae_int_t n,
   45162             :      spline2dinterpolant* c,
   45163             :      ae_state *_state)
   45164             : {
   45165             :     ae_frame _frame_block;
   45166             :     ae_matrix _f;
   45167             :     ae_int_t sfx;
   45168             :     ae_int_t sfy;
   45169             :     ae_int_t sfxy;
   45170             :     ae_matrix dx;
   45171             :     ae_matrix dy;
   45172             :     ae_matrix dxy;
   45173             :     double t;
   45174             :     ae_int_t i;
   45175             :     ae_int_t j;
   45176             :     ae_int_t k;
   45177             : 
   45178           0 :     ae_frame_make(_state, &_frame_block);
   45179           0 :     memset(&_f, 0, sizeof(_f));
   45180           0 :     memset(&dx, 0, sizeof(dx));
   45181           0 :     memset(&dy, 0, sizeof(dy));
   45182           0 :     memset(&dxy, 0, sizeof(dxy));
   45183           0 :     ae_matrix_init_copy(&_f, f, _state, ae_true);
   45184           0 :     f = &_f;
   45185           0 :     _spline2dinterpolant_clear(c);
   45186           0 :     ae_matrix_init(&dx, 0, 0, DT_REAL, _state, ae_true);
   45187           0 :     ae_matrix_init(&dy, 0, 0, DT_REAL, _state, ae_true);
   45188           0 :     ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true);
   45189             : 
   45190           0 :     ae_assert(n>=2, "Spline2DBuildBicubicSpline: N<2", _state);
   45191           0 :     ae_assert(m>=2, "Spline2DBuildBicubicSpline: M<2", _state);
   45192           0 :     ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubic: length of X or Y is too short (Length(X/Y)<N/M)", _state);
   45193           0 :     ae_assert(isfinitevector(x, n, _state)&&isfinitevector(y, m, _state), "Spline2DBuildBicubic: X or Y contains NaN or Infinite value", _state);
   45194           0 :     ae_assert(f->rows>=m&&f->cols>=n, "Spline2DBuildBicubic: size of F is too small (rows(F)<M or cols(F)<N)", _state);
   45195           0 :     ae_assert(apservisfinitematrix(f, m, n, _state), "Spline2DBuildBicubic: F contains NaN or Infinite value", _state);
   45196             :     
   45197             :     /*
   45198             :      * Fill interpolant:
   45199             :      *  F[0]...F[N*M-1]:
   45200             :      *      f(i,j) table. f(0,0), f(0, 1), f(0,2) and so on...
   45201             :      *  F[N*M]...F[2*N*M-1]:
   45202             :      *      df(i,j)/dx table.
   45203             :      *  F[2*N*M]...F[3*N*M-1]:
   45204             :      *      df(i,j)/dy table.
   45205             :      *  F[3*N*M]...F[4*N*M-1]:
   45206             :      *      d2f(i,j)/dxdy table.
   45207             :      */
   45208           0 :     c->d = 1;
   45209           0 :     c->n = n;
   45210           0 :     c->m = m;
   45211           0 :     c->stype = -3;
   45212           0 :     sfx = c->n*c->m;
   45213           0 :     sfy = 2*c->n*c->m;
   45214           0 :     sfxy = 3*c->n*c->m;
   45215           0 :     ae_vector_set_length(&c->x, c->n, _state);
   45216           0 :     ae_vector_set_length(&c->y, c->m, _state);
   45217           0 :     ae_vector_set_length(&c->f, 4*c->n*c->m, _state);
   45218           0 :     for(i=0; i<=c->n-1; i++)
   45219             :     {
   45220           0 :         c->x.ptr.p_double[i] = x->ptr.p_double[i];
   45221             :     }
   45222           0 :     for(i=0; i<=c->m-1; i++)
   45223             :     {
   45224           0 :         c->y.ptr.p_double[i] = y->ptr.p_double[i];
   45225             :     }
   45226             :     
   45227             :     /*
   45228             :      * Sort points
   45229             :      */
   45230           0 :     for(j=0; j<=c->n-1; j++)
   45231             :     {
   45232           0 :         k = j;
   45233           0 :         for(i=j+1; i<=c->n-1; i++)
   45234             :         {
   45235           0 :             if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) )
   45236             :             {
   45237           0 :                 k = i;
   45238             :             }
   45239             :         }
   45240           0 :         if( k!=j )
   45241             :         {
   45242           0 :             for(i=0; i<=c->m-1; i++)
   45243             :             {
   45244           0 :                 t = f->ptr.pp_double[i][j];
   45245           0 :                 f->ptr.pp_double[i][j] = f->ptr.pp_double[i][k];
   45246           0 :                 f->ptr.pp_double[i][k] = t;
   45247             :             }
   45248           0 :             t = c->x.ptr.p_double[j];
   45249           0 :             c->x.ptr.p_double[j] = c->x.ptr.p_double[k];
   45250           0 :             c->x.ptr.p_double[k] = t;
   45251             :         }
   45252             :     }
   45253           0 :     for(i=0; i<=c->m-1; i++)
   45254             :     {
   45255           0 :         k = i;
   45256           0 :         for(j=i+1; j<=c->m-1; j++)
   45257             :         {
   45258           0 :             if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) )
   45259             :             {
   45260           0 :                 k = j;
   45261             :             }
   45262             :         }
   45263           0 :         if( k!=i )
   45264             :         {
   45265           0 :             for(j=0; j<=c->n-1; j++)
   45266             :             {
   45267           0 :                 t = f->ptr.pp_double[i][j];
   45268           0 :                 f->ptr.pp_double[i][j] = f->ptr.pp_double[k][j];
   45269           0 :                 f->ptr.pp_double[k][j] = t;
   45270             :             }
   45271           0 :             t = c->y.ptr.p_double[i];
   45272           0 :             c->y.ptr.p_double[i] = c->y.ptr.p_double[k];
   45273           0 :             c->y.ptr.p_double[k] = t;
   45274             :         }
   45275             :     }
   45276           0 :     spline2d_bicubiccalcderivatives(f, &c->x, &c->y, c->m, c->n, &dx, &dy, &dxy, _state);
   45277           0 :     for(i=0; i<=c->m-1; i++)
   45278             :     {
   45279           0 :         for(j=0; j<=c->n-1; j++)
   45280             :         {
   45281           0 :             k = i*c->n+j;
   45282           0 :             c->f.ptr.p_double[k] = f->ptr.pp_double[i][j];
   45283           0 :             c->f.ptr.p_double[sfx+k] = dx.ptr.pp_double[i][j];
   45284           0 :             c->f.ptr.p_double[sfy+k] = dy.ptr.pp_double[i][j];
   45285           0 :             c->f.ptr.p_double[sfxy+k] = dxy.ptr.pp_double[i][j];
   45286             :         }
   45287             :     }
   45288           0 :     ae_frame_leave(_state);
   45289           0 : }
   45290             : 
   45291             : 
   45292             : /*************************************************************************
   45293             : This subroutine was deprecated in ALGLIB 3.6.0
   45294             : 
   45295             : We recommend you to switch  to  Spline2DUnpackV(),  which is more flexible
   45296             : and accepts its arguments in more convenient order.
   45297             : 
   45298             :   -- ALGLIB PROJECT --
   45299             :      Copyright 29.06.2007 by Bochkanov Sergey
   45300             : *************************************************************************/
   45301           0 : void spline2dunpack(spline2dinterpolant* c,
   45302             :      ae_int_t* m,
   45303             :      ae_int_t* n,
   45304             :      /* Real    */ ae_matrix* tbl,
   45305             :      ae_state *_state)
   45306             : {
   45307             :     ae_int_t k;
   45308             :     ae_int_t p;
   45309             :     ae_int_t ci;
   45310             :     ae_int_t cj;
   45311             :     ae_int_t s1;
   45312             :     ae_int_t s2;
   45313             :     ae_int_t s3;
   45314             :     ae_int_t s4;
   45315             :     ae_int_t sfx;
   45316             :     ae_int_t sfy;
   45317             :     ae_int_t sfxy;
   45318             :     double y1;
   45319             :     double y2;
   45320             :     double y3;
   45321             :     double y4;
   45322             :     double dt;
   45323             :     double du;
   45324             :     ae_int_t i;
   45325             :     ae_int_t j;
   45326             : 
   45327           0 :     *m = 0;
   45328           0 :     *n = 0;
   45329           0 :     ae_matrix_clear(tbl);
   45330             : 
   45331           0 :     ae_assert(c->stype==-3||c->stype==-1, "Spline2DUnpack: incorrect C (incorrect parameter C.SType)", _state);
   45332           0 :     if( c->d!=1 )
   45333             :     {
   45334           0 :         *n = 0;
   45335           0 :         *m = 0;
   45336           0 :         return;
   45337             :     }
   45338           0 :     *n = c->n;
   45339           0 :     *m = c->m;
   45340           0 :     ae_matrix_set_length(tbl, (*n-1)*(*m-1), 20, _state);
   45341           0 :     sfx = *n*(*m);
   45342           0 :     sfy = 2*(*n)*(*m);
   45343           0 :     sfxy = 3*(*n)*(*m);
   45344             :     
   45345             :     /*
   45346             :      * Fill
   45347             :      */
   45348           0 :     for(i=0; i<=*m-2; i++)
   45349             :     {
   45350           0 :         for(j=0; j<=*n-2; j++)
   45351             :         {
   45352           0 :             p = i*(*n-1)+j;
   45353           0 :             tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[j];
   45354           0 :             tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[j+1];
   45355           0 :             tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[i];
   45356           0 :             tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[i+1];
   45357           0 :             dt = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]);
   45358           0 :             du = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]);
   45359             :             
   45360             :             /*
   45361             :              * Bilinear interpolation
   45362             :              */
   45363           0 :             if( c->stype==-1 )
   45364             :             {
   45365           0 :                 for(k=4; k<=19; k++)
   45366             :                 {
   45367           0 :                     tbl->ptr.pp_double[p][k] = (double)(0);
   45368             :                 }
   45369           0 :                 y1 = c->f.ptr.p_double[*n*i+j];
   45370           0 :                 y2 = c->f.ptr.p_double[*n*i+(j+1)];
   45371           0 :                 y3 = c->f.ptr.p_double[*n*(i+1)+(j+1)];
   45372           0 :                 y4 = c->f.ptr.p_double[*n*(i+1)+j];
   45373           0 :                 tbl->ptr.pp_double[p][4] = y1;
   45374           0 :                 tbl->ptr.pp_double[p][4+1*4+0] = y2-y1;
   45375           0 :                 tbl->ptr.pp_double[p][4+0*4+1] = y4-y1;
   45376           0 :                 tbl->ptr.pp_double[p][4+1*4+1] = y3-y2-y4+y1;
   45377             :             }
   45378             :             
   45379             :             /*
   45380             :              * Bicubic interpolation
   45381             :              */
   45382           0 :             if( c->stype==-3 )
   45383             :             {
   45384           0 :                 s1 = *n*i+j;
   45385           0 :                 s2 = *n*i+(j+1);
   45386           0 :                 s3 = *n*(i+1)+(j+1);
   45387           0 :                 s4 = *n*(i+1)+j;
   45388           0 :                 tbl->ptr.pp_double[p][4+0*4+0] = c->f.ptr.p_double[s1];
   45389           0 :                 tbl->ptr.pp_double[p][4+0*4+1] = c->f.ptr.p_double[sfy+s1]/du;
   45390           0 :                 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;
   45391           0 :                 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;
   45392           0 :                 tbl->ptr.pp_double[p][4+1*4+0] = c->f.ptr.p_double[sfx+s1]/dt;
   45393           0 :                 tbl->ptr.pp_double[p][4+1*4+1] = c->f.ptr.p_double[sfxy+s1]/(dt*du);
   45394           0 :                 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);
   45395           0 :                 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);
   45396           0 :                 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;
   45397           0 :                 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);
   45398           0 :                 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);
   45399           0 :                 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);
   45400           0 :                 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;
   45401           0 :                 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);
   45402           0 :                 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);
   45403           0 :                 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);
   45404             :             }
   45405             :             
   45406             :             /*
   45407             :              * Rescale Cij
   45408             :              */
   45409           0 :             for(ci=0; ci<=3; ci++)
   45410             :             {
   45411           0 :                 for(cj=0; cj<=3; cj++)
   45412             :                 {
   45413           0 :                     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);
   45414             :                 }
   45415             :             }
   45416             :         }
   45417             :     }
   45418             : }
   45419             : 
   45420             : 
   45421             : /*************************************************************************
   45422             : This subroutine creates least squares solver used to  fit  2D  splines  to
   45423             : irregularly sampled (scattered) data.
   45424             : 
   45425             : Solver object is used to perform spline fits as follows:
   45426             : * solver object is created with spline2dbuildercreate() function
   45427             : * dataset is added with spline2dbuildersetpoints() function
   45428             : * fit area is chosen:
   45429             :   * spline2dbuildersetarea()     - for user-defined area
   45430             :   * spline2dbuildersetareaauto() - for automatically chosen area
   45431             : * number of grid nodes is chosen with spline2dbuildersetgrid()
   45432             : * prior term is chosen with one of the following functions:
   45433             :   * spline2dbuildersetlinterm()   to set linear prior
   45434             :   * spline2dbuildersetconstterm() to set constant prior
   45435             :   * spline2dbuildersetzeroterm()  to set zero prior
   45436             :   * spline2dbuildersetuserterm()  to set user-defined constant prior
   45437             : * solver algorithm is chosen with either:
   45438             :   * spline2dbuildersetalgoblocklls() - BlockLLS algorithm, medium-scale problems
   45439             :   * spline2dbuildersetalgofastddm()  - FastDDM algorithm, large-scale problems
   45440             : * finally, fitting itself is performed with spline2dfit() function.
   45441             : 
   45442             : Most of the steps above can be omitted,  solver  is  configured with  good
   45443             : defaults. The minimum is to call:
   45444             : * spline2dbuildercreate() to create solver object
   45445             : * spline2dbuildersetpoints() to specify dataset
   45446             : * spline2dbuildersetgrid() to tell how many nodes you need
   45447             : * spline2dfit() to perform fit
   45448             : 
   45449             :   ! COMMERCIAL EDITION OF ALGLIB:
   45450             :   ! 
   45451             :   ! Commercial Edition of ALGLIB includes following important improvements
   45452             :   ! of this function:
   45453             :   ! * high-performance native backend with same C# interface (C# version)
   45454             :   ! * multithreading support (C++ and C# versions)
   45455             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   45456             :   !   (C++ and C# versions, x86/x64 platform)
   45457             :   ! 
   45458             :   ! We recommend you to read 'Working with commercial version' section  of
   45459             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   45460             :   ! related features provided by commercial edition of ALGLIB.
   45461             : 
   45462             : INPUT PARAMETERS:
   45463             :     D   -   positive number, number of Y-components: D=1 for simple scalar
   45464             :             fit, D>1 for vector-valued spline fitting.
   45465             :     
   45466             : OUTPUT PARAMETERS:
   45467             :     S   -   solver object
   45468             : 
   45469             :   -- ALGLIB PROJECT --
   45470             :      Copyright 29.01.2018 by Bochkanov Sergey
   45471             : *************************************************************************/
   45472           0 : void spline2dbuildercreate(ae_int_t d,
   45473             :      spline2dbuilder* state,
   45474             :      ae_state *_state)
   45475             : {
   45476             : 
   45477           0 :     _spline2dbuilder_clear(state);
   45478             : 
   45479           0 :     ae_assert(d>=1, "Spline2DBuilderCreate: D<=0", _state);
   45480             :     
   45481             :     /*
   45482             :      * NOTES:
   45483             :      *
   45484             :      * 1. Prior term is set to linear one (good default option)
   45485             :      * 2. Solver is set to BlockLLS - good enough for small-scale problems.
   45486             :      * 3. Refinement rounds: 5; enough to get good convergence.
   45487             :      */
   45488           0 :     state->priorterm = 1;
   45489           0 :     state->priortermval = (double)(0);
   45490           0 :     state->areatype = 0;
   45491           0 :     state->gridtype = 0;
   45492           0 :     state->smoothing = 0.0;
   45493           0 :     state->nlayers = 0;
   45494           0 :     state->solvertype = 1;
   45495           0 :     state->npoints = 0;
   45496           0 :     state->d = d;
   45497           0 :     state->sx = 1.0;
   45498           0 :     state->sy = 1.0;
   45499           0 :     state->lsqrcnt = 5;
   45500             :     
   45501             :     /*
   45502             :      * Algorithm settings
   45503             :      */
   45504           0 :     state->adddegreeoffreedom = ae_true;
   45505           0 :     state->maxcoresize = 16;
   45506           0 :     state->interfacesize = 5;
   45507           0 : }
   45508             : 
   45509             : 
   45510             : /*************************************************************************
   45511             : This function sets constant prior term (model is a sum of  bicubic  spline
   45512             : and global prior, which can be linear, constant, user-defined  constant or
   45513             : zero).
   45514             : 
   45515             : Constant prior term is determined by least squares fitting.
   45516             : 
   45517             : INPUT PARAMETERS:
   45518             :     S       -   spline builder
   45519             :     V       -   value for user-defined prior
   45520             : 
   45521             :   -- ALGLIB --
   45522             :      Copyright 01.02.2018 by Bochkanov Sergey
   45523             : *************************************************************************/
   45524           0 : void spline2dbuildersetuserterm(spline2dbuilder* state,
   45525             :      double v,
   45526             :      ae_state *_state)
   45527             : {
   45528             : 
   45529             : 
   45530           0 :     ae_assert(ae_isfinite(v, _state), "Spline2DBuilderSetUserTerm: infinite/NAN value passed", _state);
   45531           0 :     state->priorterm = 0;
   45532           0 :     state->priortermval = v;
   45533           0 : }
   45534             : 
   45535             : 
   45536             : /*************************************************************************
   45537             : This function sets linear prior term (model is a sum of bicubic spline and
   45538             : global  prior,  which  can  be  linear, constant, user-defined constant or
   45539             : zero).
   45540             : 
   45541             : Linear prior term is determined by least squares fitting.
   45542             : 
   45543             : INPUT PARAMETERS:
   45544             :     S       -   spline builder
   45545             : 
   45546             :   -- ALGLIB --
   45547             :      Copyright 01.02.2018 by Bochkanov Sergey
   45548             : *************************************************************************/
   45549           0 : void spline2dbuildersetlinterm(spline2dbuilder* state, ae_state *_state)
   45550             : {
   45551             : 
   45552             : 
   45553           0 :     state->priorterm = 1;
   45554           0 : }
   45555             : 
   45556             : 
   45557             : /*************************************************************************
   45558             : This function sets constant prior term (model is a sum of  bicubic  spline
   45559             : and global prior, which can be linear, constant, user-defined  constant or
   45560             : zero).
   45561             : 
   45562             : Constant prior term is determined by least squares fitting.
   45563             : 
   45564             : INPUT PARAMETERS:
   45565             :     S       -   spline builder
   45566             : 
   45567             :   -- ALGLIB --
   45568             :      Copyright 01.02.2018 by Bochkanov Sergey
   45569             : *************************************************************************/
   45570           0 : void spline2dbuildersetconstterm(spline2dbuilder* state, ae_state *_state)
   45571             : {
   45572             : 
   45573             : 
   45574           0 :     state->priorterm = 2;
   45575           0 : }
   45576             : 
   45577             : 
   45578             : /*************************************************************************
   45579             : This function sets zero prior term (model is a sum of bicubic  spline  and
   45580             : global  prior,  which  can  be  linear, constant, user-defined constant or
   45581             : zero).
   45582             : 
   45583             : INPUT PARAMETERS:
   45584             :     S       -   spline builder
   45585             : 
   45586             :   -- ALGLIB --
   45587             :      Copyright 01.02.2018 by Bochkanov Sergey
   45588             : *************************************************************************/
   45589           0 : void spline2dbuildersetzeroterm(spline2dbuilder* state, ae_state *_state)
   45590             : {
   45591             : 
   45592             : 
   45593           0 :     state->priorterm = 3;
   45594           0 : }
   45595             : 
   45596             : 
   45597             : /*************************************************************************
   45598             : This function adds dataset to the builder object.
   45599             : 
   45600             : This function overrides results of the previous calls, i.e. multiple calls
   45601             : of this function will result in only the last set being added.
   45602             : 
   45603             : INPUT PARAMETERS:
   45604             :     S       -   spline 2D builder object
   45605             :     XY      -   points, array[N,2+D]. One  row  corresponds to  one  point
   45606             :                 in the dataset. First 2  elements  are  coordinates,  next
   45607             :                 D  elements are function values. Array may  be larger than 
   45608             :                 specified, in  this  case  only leading [N,NX+NY] elements 
   45609             :                 will be used.
   45610             :     N       -   number of points in the dataset
   45611             : 
   45612             :   -- ALGLIB --
   45613             :      Copyright 05.02.2018 by Bochkanov Sergey
   45614             : *************************************************************************/
   45615           0 : void spline2dbuildersetpoints(spline2dbuilder* state,
   45616             :      /* Real    */ ae_matrix* xy,
   45617             :      ae_int_t n,
   45618             :      ae_state *_state)
   45619             : {
   45620             :     ae_int_t i;
   45621             :     ae_int_t j;
   45622             :     ae_int_t ew;
   45623             : 
   45624             : 
   45625           0 :     ae_assert(n>0, "Spline2DBuilderSetPoints: N<0", _state);
   45626           0 :     ae_assert(xy->rows>=n, "Spline2DBuilderSetPoints: Rows(XY)<N", _state);
   45627           0 :     ae_assert(xy->cols>=2+state->d, "Spline2DBuilderSetPoints: Cols(XY)<NX+NY", _state);
   45628           0 :     ae_assert(apservisfinitematrix(xy, n, 2+state->d, _state), "Spline2DBuilderSetPoints: XY contains infinite or NaN values!", _state);
   45629           0 :     state->npoints = n;
   45630           0 :     ew = 2+state->d;
   45631           0 :     rvectorsetlengthatleast(&state->xy, n*ew, _state);
   45632           0 :     for(i=0; i<=n-1; i++)
   45633             :     {
   45634           0 :         for(j=0; j<=ew-1; j++)
   45635             :         {
   45636           0 :             state->xy.ptr.p_double[i*ew+j] = xy->ptr.pp_double[i][j];
   45637             :         }
   45638             :     }
   45639           0 : }
   45640             : 
   45641             : 
   45642             : /*************************************************************************
   45643             : This function sets area where 2D spline interpolant is built. "Auto" means
   45644             : that area extent is determined automatically from dataset extent.
   45645             : 
   45646             : INPUT PARAMETERS:
   45647             :     S       -   spline 2D builder object
   45648             : 
   45649             :   -- ALGLIB --
   45650             :      Copyright 05.02.2018 by Bochkanov Sergey
   45651             : *************************************************************************/
   45652           0 : void spline2dbuildersetareaauto(spline2dbuilder* state, ae_state *_state)
   45653             : {
   45654             : 
   45655             : 
   45656           0 :     state->areatype = 0;
   45657           0 : }
   45658             : 
   45659             : 
   45660             : /*************************************************************************
   45661             : This  function  sets  area  where  2D  spline  interpolant  is   built  to
   45662             : user-defined one: [XA,XB]*[YA,YB]
   45663             : 
   45664             : INPUT PARAMETERS:
   45665             :     S       -   spline 2D builder object
   45666             :     XA,XB   -   spatial extent in the first (X) dimension, XA<XB
   45667             :     YA,YB   -   spatial extent in the second (Y) dimension, YA<YB
   45668             : 
   45669             :   -- ALGLIB --
   45670             :      Copyright 05.02.2018 by Bochkanov Sergey
   45671             : *************************************************************************/
   45672           0 : void spline2dbuildersetarea(spline2dbuilder* state,
   45673             :      double xa,
   45674             :      double xb,
   45675             :      double ya,
   45676             :      double yb,
   45677             :      ae_state *_state)
   45678             : {
   45679             : 
   45680             : 
   45681           0 :     ae_assert(ae_isfinite(xa, _state), "Spline2DBuilderSetArea: XA is not finite", _state);
   45682           0 :     ae_assert(ae_isfinite(xb, _state), "Spline2DBuilderSetArea: XB is not finite", _state);
   45683           0 :     ae_assert(ae_isfinite(ya, _state), "Spline2DBuilderSetArea: YA is not finite", _state);
   45684           0 :     ae_assert(ae_isfinite(yb, _state), "Spline2DBuilderSetArea: YB is not finite", _state);
   45685           0 :     ae_assert(ae_fp_less(xa,xb), "Spline2DBuilderSetArea: XA>=XB", _state);
   45686           0 :     ae_assert(ae_fp_less(ya,yb), "Spline2DBuilderSetArea: YA>=YB", _state);
   45687           0 :     state->areatype = 1;
   45688           0 :     state->xa = xa;
   45689           0 :     state->xb = xb;
   45690           0 :     state->ya = ya;
   45691           0 :     state->yb = yb;
   45692           0 : }
   45693             : 
   45694             : 
   45695             : /*************************************************************************
   45696             : This  function  sets  nodes  count  for  2D spline interpolant. Fitting is
   45697             : performed on area defined with one of the "setarea"  functions;  this  one
   45698             : sets number of nodes placed upon the fitting area.
   45699             : 
   45700             : INPUT PARAMETERS:
   45701             :     S       -   spline 2D builder object
   45702             :     KX      -   nodes count for the first (X) dimension; fitting  interval
   45703             :                 [XA,XB] is separated into KX-1 subintervals, with KX nodes
   45704             :                 created at the boundaries.
   45705             :     KY      -   nodes count for the first (Y) dimension; fitting  interval
   45706             :                 [YA,YB] is separated into KY-1 subintervals, with KY nodes
   45707             :                 created at the boundaries.
   45708             : 
   45709             : NOTE: at  least  4  nodes  is  created in each dimension, so KX and KY are
   45710             :       silently increased if needed.
   45711             : 
   45712             :   -- ALGLIB --
   45713             :      Copyright 05.02.2018 by Bochkanov Sergey
   45714             : *************************************************************************/
   45715           0 : void spline2dbuildersetgrid(spline2dbuilder* state,
   45716             :      ae_int_t kx,
   45717             :      ae_int_t ky,
   45718             :      ae_state *_state)
   45719             : {
   45720             : 
   45721             : 
   45722           0 :     ae_assert(kx>0, "Spline2DBuilderSetGridSizePrecisely: KX<=0", _state);
   45723           0 :     ae_assert(ky>0, "Spline2DBuilderSetGridSizePrecisely: KY<=0", _state);
   45724           0 :     state->gridtype = 1;
   45725           0 :     state->kx = ae_maxint(kx, 4, _state);
   45726           0 :     state->ky = ae_maxint(ky, 4, _state);
   45727           0 : }
   45728             : 
   45729             : 
   45730             : /*************************************************************************
   45731             : This  function  allows  you to choose least squares solver used to perform
   45732             : fitting. This function sets solver algorithm to "FastDDM", which  performs
   45733             : fast parallel fitting by splitting problem into smaller chunks and merging
   45734             : results together.
   45735             : 
   45736             : This solver is optimized for large-scale problems, starting  from  256x256
   45737             : grids, and up to 10000x10000 grids. Of course, it will  work  for  smaller
   45738             : grids too.
   45739             : 
   45740             : More detailed description of the algorithm is given below:
   45741             : * algorithm generates hierarchy  of  nested  grids,  ranging  from  ~16x16
   45742             :   (topmost "layer" of the model) to ~KX*KY one (final layer). Upper layers
   45743             :   model global behavior of the function, lower layers are  used  to  model
   45744             :   fine details. Moving from layer to layer doubles grid density.
   45745             : * fitting  is  started  from  topmost  layer, subsequent layers are fitted
   45746             :   using residuals from previous ones.
   45747             : * user may choose to skip generation of upper layers and generate  only  a
   45748             :   few bottom ones, which  will  result  in  much  better  performance  and
   45749             :   parallelization efficiency, at the cost of algorithm inability to "patch"
   45750             :   large holes in the dataset.
   45751             : * every layer is regularized using progressively increasing regularization
   45752             :   coefficient; thus, increasing  LambdaV  penalizes  fine  details  first,
   45753             :   leaving lower frequencies almost intact for a while.
   45754             : * after fitting is done, all layers are merged together into  one  bicubic
   45755             :   spline
   45756             :   
   45757             : IMPORTANT: regularization coefficient used by  this  solver  is  different
   45758             :            from the one used by  BlockLLS.  Latter  utilizes  nonlinearity
   45759             :            penalty,  which  is  global  in  nature  (large  regularization
   45760             :            results in global linear trend being  extracted);  this  solver
   45761             :            uses another, localized form of penalty, which is suitable  for
   45762             :            parallel processing.
   45763             : 
   45764             : Notes on memory and performance:
   45765             : * memory requirements: most memory is consumed  during  modeling   of  the
   45766             :   higher layers; ~[512*NPoints] bytes is required for a  model  with  full
   45767             :   hierarchy of grids being generated. However, if you skip a  few  topmost
   45768             :   layers, you will get nearly constant (wrt. points count and  grid  size)
   45769             :   memory consumption.
   45770             : * serial running time: O(K*K)+O(NPoints) for a KxK grid
   45771             : * parallelism potential: good. You may get  nearly  linear  speed-up  when
   45772             :   performing fitting with just a few layers. Adding more layers results in
   45773             :   model becoming more global, which somewhat  reduces  efficiency  of  the
   45774             :   parallel code.
   45775             : 
   45776             :   ! COMMERCIAL EDITION OF ALGLIB:
   45777             :   ! 
   45778             :   ! Commercial Edition of ALGLIB includes following important improvements
   45779             :   ! of this function:
   45780             :   ! * high-performance native backend with same C# interface (C# version)
   45781             :   ! * multithreading support (C++ and C# versions)
   45782             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   45783             :   !   (C++ and C# versions, x86/x64 platform)
   45784             :   ! 
   45785             :   ! We recommend you to read 'Working with commercial version' section  of
   45786             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   45787             :   ! related features provided by commercial edition of ALGLIB.
   45788             : 
   45789             : INPUT PARAMETERS:
   45790             :     S       -   spline 2D builder object
   45791             :     NLayers -   number of layers in the model:
   45792             :                 * NLayers>=1 means that up  to  chosen  number  of  bottom
   45793             :                   layers is fitted
   45794             :                 * NLayers=0 means that maximum number of layers is  chosen
   45795             :                   (according to current grid size)
   45796             :                 * NLayers<=-1 means that up to |NLayers| topmost layers is
   45797             :                   skipped
   45798             :                 Recommendations:
   45799             :                 * good "default" value is 2 layers
   45800             :                 * you may need  more  layers,  if  your  dataset  is  very
   45801             :                   irregular and you want to "patch"  large  holes.  For  a
   45802             :                   grid step H (equal to AreaWidth/GridSize) you may expect
   45803             :                   that last layer reproduces variations at distance H (and
   45804             :                   can patch holes that wide); that higher  layers  operate
   45805             :                   at distances 2*H, 4*H, 8*H and so on.
   45806             :                 * good value for "bullletproof" mode is  NLayers=0,  which
   45807             :                   results in complete hierarchy of layers being generated.
   45808             :     LambdaV -   regularization coefficient, chosen in such a way  that  it
   45809             :                 penalizes bottom layers (fine details) first.
   45810             :                 LambdaV>=0, zero value means that no penalty is applied.
   45811             : 
   45812             :   -- ALGLIB --
   45813             :      Copyright 05.02.2018 by Bochkanov Sergey
   45814             : *************************************************************************/
   45815           0 : void spline2dbuildersetalgofastddm(spline2dbuilder* state,
   45816             :      ae_int_t nlayers,
   45817             :      double lambdav,
   45818             :      ae_state *_state)
   45819             : {
   45820             : 
   45821             : 
   45822           0 :     ae_assert(ae_isfinite(lambdav, _state), "Spline2DBuilderSetAlgoFastDDM: LambdaV is not finite value", _state);
   45823           0 :     ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "Spline2DBuilderSetAlgoFastDDM: LambdaV<0", _state);
   45824           0 :     state->solvertype = 3;
   45825           0 :     state->nlayers = nlayers;
   45826           0 :     state->smoothing = lambdav;
   45827           0 : }
   45828             : 
   45829             : 
   45830             : /*************************************************************************
   45831             : This  function  allows  you to choose least squares solver used to perform
   45832             : fitting. This function sets solver algorithm to "BlockLLS", which performs
   45833             : least squares fitting  with  fast  sparse  direct  solver,  with  optional
   45834             : nonsmoothness penalty being applied.
   45835             : 
   45836             : Nonlinearity penalty has the following form:
   45837             : 
   45838             :                           [                                            ]
   45839             :     P() ~ Lambda* integral[ (d2S/dx2)^2 + 2*(d2S/dxdy)^2 + (d2S/dy2)^2 ]dxdy
   45840             :                           [                                            ]
   45841             :                   
   45842             : here integral is calculated over entire grid, and "~" means "proportional"
   45843             : because integral is normalized after calcilation. Extremely  large  values
   45844             : of Lambda result in linear fit being performed.
   45845             : 
   45846             : NOTE: this algorithm is the most robust and controllable one,  but  it  is
   45847             :       limited by 512x512 grids and (say) up to 1.000.000 points.  However,
   45848             :       ALGLIB has one more  spline  solver:  FastDDM  algorithm,  which  is
   45849             :       intended for really large-scale problems (in 10M-100M range). FastDDM
   45850             :       algorithm also has better parallelism properties.
   45851             :       
   45852             : More information on BlockLLS solver:
   45853             : * memory requirements: ~[32*K^3+256*NPoints]  bytes  for  KxK  grid   with
   45854             :   NPoints-sized dataset
   45855             : * serial running time: O(K^4+NPoints)
   45856             : * parallelism potential: limited. You may get some sublinear gain when
   45857             :   working with large grids (K's in 256..512 range)
   45858             : 
   45859             :   ! COMMERCIAL EDITION OF ALGLIB:
   45860             :   ! 
   45861             :   ! Commercial Edition of ALGLIB includes following important improvements
   45862             :   ! of this function:
   45863             :   ! * high-performance native backend with same C# interface (C# version)
   45864             :   ! * multithreading support (C++ and C# versions)
   45865             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   45866             :   !   (C++ and C# versions, x86/x64 platform)
   45867             :   ! 
   45868             :   ! We recommend you to read 'Working with commercial version' section  of
   45869             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   45870             :   ! related features provided by commercial edition of ALGLIB.
   45871             : 
   45872             : INPUT PARAMETERS:
   45873             :     S       -   spline 2D builder object
   45874             :     LambdaNS-   non-negative value:
   45875             :                 * positive value means that some smoothing is applied
   45876             :                 * zero value means  that  no  smoothing  is  applied,  and
   45877             :                   corresponding entries of design matrix  are  numerically
   45878             :                   zero and dropped from consideration.
   45879             : 
   45880             :   -- ALGLIB --
   45881             :      Copyright 05.02.2018 by Bochkanov Sergey
   45882             : *************************************************************************/
   45883           0 : void spline2dbuildersetalgoblocklls(spline2dbuilder* state,
   45884             :      double lambdans,
   45885             :      ae_state *_state)
   45886             : {
   45887             : 
   45888             : 
   45889           0 :     ae_assert(ae_isfinite(lambdans, _state), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS is not finite value", _state);
   45890           0 :     ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS<0", _state);
   45891           0 :     state->solvertype = 1;
   45892           0 :     state->smoothing = lambdans;
   45893           0 : }
   45894             : 
   45895             : 
   45896             : /*************************************************************************
   45897             : This  function  allows  you to choose least squares solver used to perform
   45898             : fitting. This function sets solver algorithm to "NaiveLLS".
   45899             : 
   45900             : IMPORTANT: NaiveLLS is NOT intended to be used in  real  life  code!  This
   45901             :            algorithm solves problem by generated dense (K^2)x(K^2+NPoints)
   45902             :            matrix and solves  linear  least  squares  problem  with  dense
   45903             :            solver.
   45904             :            
   45905             :            It is here just  to  test  BlockLLS  against  reference  solver
   45906             :            (and maybe for someone trying to compare well optimized  solver
   45907             :            against straightforward approach to the LLS problem).
   45908             : 
   45909             : More information on naive LLS solver:
   45910             : * memory requirements: ~[8*K^4+256*NPoints] bytes for KxK grid.
   45911             : * serial running time: O(K^6+NPoints) for KxK grid
   45912             : * when compared with BlockLLS,  NaiveLLS  has ~K  larger memory demand and
   45913             :   ~K^2  larger running time.
   45914             : 
   45915             : INPUT PARAMETERS:
   45916             :     S       -   spline 2D builder object
   45917             :     LambdaNS-   nonsmoothness penalty
   45918             : 
   45919             :   -- ALGLIB --
   45920             :      Copyright 05.02.2018 by Bochkanov Sergey
   45921             : *************************************************************************/
   45922           0 : void spline2dbuildersetalgonaivells(spline2dbuilder* state,
   45923             :      double lambdans,
   45924             :      ae_state *_state)
   45925             : {
   45926             : 
   45927             : 
   45928           0 :     ae_assert(ae_isfinite(lambdans, _state), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS is not finite value", _state);
   45929           0 :     ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS<0", _state);
   45930           0 :     state->solvertype = 2;
   45931           0 :     state->smoothing = lambdans;
   45932           0 : }
   45933             : 
   45934             : 
   45935             : /*************************************************************************
   45936             : This function fits bicubic spline to current dataset, using current  area/
   45937             : grid and current LLS solver.
   45938             : 
   45939             :   ! COMMERCIAL EDITION OF ALGLIB:
   45940             :   ! 
   45941             :   ! Commercial Edition of ALGLIB includes following important improvements
   45942             :   ! of this function:
   45943             :   ! * high-performance native backend with same C# interface (C# version)
   45944             :   ! * multithreading support (C++ and C# versions)
   45945             :   ! * hardware vendor (Intel) implementations of linear algebra primitives
   45946             :   !   (C++ and C# versions, x86/x64 platform)
   45947             :   ! 
   45948             :   ! We recommend you to read 'Working with commercial version' section  of
   45949             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   45950             :   ! related features provided by commercial edition of ALGLIB.
   45951             : 
   45952             : INPUT PARAMETERS:
   45953             :     State   -   spline 2D builder object
   45954             : 
   45955             : OUTPUT PARAMETERS:
   45956             :     S       -   2D spline, fit result
   45957             :     Rep     -   fitting report, which provides some additional info  about
   45958             :                 errors, R2 coefficient and so on.
   45959             : 
   45960             :   -- ALGLIB --
   45961             :      Copyright 05.02.2018 by Bochkanov Sergey
   45962             : *************************************************************************/
   45963           0 : void spline2dfit(spline2dbuilder* state,
   45964             :      spline2dinterpolant* s,
   45965             :      spline2dfitreport* rep,
   45966             :      ae_state *_state)
   45967             : {
   45968             :     ae_frame _frame_block;
   45969             :     double xa;
   45970             :     double xb;
   45971             :     double ya;
   45972             :     double yb;
   45973             :     double xaraw;
   45974             :     double xbraw;
   45975             :     double yaraw;
   45976             :     double ybraw;
   45977             :     ae_int_t kx;
   45978             :     ae_int_t ky;
   45979             :     double hx;
   45980             :     double hy;
   45981             :     double invhx;
   45982             :     double invhy;
   45983             :     ae_int_t gridexpansion;
   45984             :     ae_int_t nzwidth;
   45985             :     ae_int_t bfrad;
   45986             :     ae_int_t npoints;
   45987             :     ae_int_t d;
   45988             :     ae_int_t ew;
   45989             :     ae_int_t i;
   45990             :     ae_int_t j;
   45991             :     ae_int_t k;
   45992             :     double v;
   45993             :     ae_int_t k0;
   45994             :     ae_int_t k1;
   45995             :     double vx;
   45996             :     double vy;
   45997             :     ae_int_t arows;
   45998             :     ae_int_t acopied;
   45999             :     ae_int_t basecasex;
   46000             :     ae_int_t basecasey;
   46001             :     double eps;
   46002             :     ae_vector xywork;
   46003             :     ae_matrix vterm;
   46004             :     ae_vector tmpx;
   46005             :     ae_vector tmpy;
   46006             :     ae_vector tmp0;
   46007             :     ae_vector tmp1;
   46008             :     ae_vector meany;
   46009             :     ae_vector xyindex;
   46010             :     ae_vector tmpi;
   46011             :     spline1dinterpolant basis1;
   46012             :     sparsematrix av;
   46013             :     sparsematrix ah;
   46014             :     spline2dxdesignmatrix xdesignmatrix;
   46015             :     ae_vector z;
   46016             :     spline2dblockllsbuf blockllsbuf;
   46017             :     ae_int_t sfx;
   46018             :     ae_int_t sfy;
   46019             :     ae_int_t sfxy;
   46020             :     double tss;
   46021             :     ae_int_t dstidx;
   46022             : 
   46023           0 :     ae_frame_make(_state, &_frame_block);
   46024           0 :     memset(&xywork, 0, sizeof(xywork));
   46025           0 :     memset(&vterm, 0, sizeof(vterm));
   46026           0 :     memset(&tmpx, 0, sizeof(tmpx));
   46027           0 :     memset(&tmpy, 0, sizeof(tmpy));
   46028           0 :     memset(&tmp0, 0, sizeof(tmp0));
   46029           0 :     memset(&tmp1, 0, sizeof(tmp1));
   46030           0 :     memset(&meany, 0, sizeof(meany));
   46031           0 :     memset(&xyindex, 0, sizeof(xyindex));
   46032           0 :     memset(&tmpi, 0, sizeof(tmpi));
   46033           0 :     memset(&basis1, 0, sizeof(basis1));
   46034           0 :     memset(&av, 0, sizeof(av));
   46035           0 :     memset(&ah, 0, sizeof(ah));
   46036           0 :     memset(&xdesignmatrix, 0, sizeof(xdesignmatrix));
   46037           0 :     memset(&z, 0, sizeof(z));
   46038           0 :     memset(&blockllsbuf, 0, sizeof(blockllsbuf));
   46039           0 :     _spline2dinterpolant_clear(s);
   46040           0 :     _spline2dfitreport_clear(rep);
   46041           0 :     ae_vector_init(&xywork, 0, DT_REAL, _state, ae_true);
   46042           0 :     ae_matrix_init(&vterm, 0, 0, DT_REAL, _state, ae_true);
   46043           0 :     ae_vector_init(&tmpx, 0, DT_REAL, _state, ae_true);
   46044           0 :     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
   46045           0 :     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
   46046           0 :     ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true);
   46047           0 :     ae_vector_init(&meany, 0, DT_REAL, _state, ae_true);
   46048           0 :     ae_vector_init(&xyindex, 0, DT_INT, _state, ae_true);
   46049           0 :     ae_vector_init(&tmpi, 0, DT_INT, _state, ae_true);
   46050           0 :     _spline1dinterpolant_init(&basis1, _state, ae_true);
   46051           0 :     _sparsematrix_init(&av, _state, ae_true);
   46052           0 :     _sparsematrix_init(&ah, _state, ae_true);
   46053           0 :     _spline2dxdesignmatrix_init(&xdesignmatrix, _state, ae_true);
   46054           0 :     ae_vector_init(&z, 0, DT_REAL, _state, ae_true);
   46055           0 :     _spline2dblockllsbuf_init(&blockllsbuf, _state, ae_true);
   46056             : 
   46057           0 :     nzwidth = 4;
   46058           0 :     bfrad = 2;
   46059           0 :     npoints = state->npoints;
   46060           0 :     d = state->d;
   46061           0 :     ew = 2+d;
   46062             :     
   46063             :     /*
   46064             :      * Integrity checks
   46065             :      */
   46066           0 :     ae_assert(ae_fp_eq(state->sx,(double)(1)), "Spline2DFit: integrity error", _state);
   46067           0 :     ae_assert(ae_fp_eq(state->sy,(double)(1)), "Spline2DFit: integrity error", _state);
   46068             :     
   46069             :     /*
   46070             :      * Determine actual area size and grid step
   46071             :      *
   46072             :      * NOTE: initialize vars by zeros in order to avoid spurious
   46073             :      *       compiler warnings.
   46074             :      */
   46075           0 :     xa = (double)(0);
   46076           0 :     xb = (double)(0);
   46077           0 :     ya = (double)(0);
   46078           0 :     yb = (double)(0);
   46079           0 :     if( state->areatype==0 )
   46080             :     {
   46081           0 :         if( npoints>0 )
   46082             :         {
   46083           0 :             xa = state->xy.ptr.p_double[0];
   46084           0 :             xb = state->xy.ptr.p_double[0];
   46085           0 :             ya = state->xy.ptr.p_double[1];
   46086           0 :             yb = state->xy.ptr.p_double[1];
   46087           0 :             for(i=1; i<=npoints-1; i++)
   46088             :             {
   46089           0 :                 xa = ae_minreal(xa, state->xy.ptr.p_double[i*ew+0], _state);
   46090           0 :                 xb = ae_maxreal(xb, state->xy.ptr.p_double[i*ew+0], _state);
   46091           0 :                 ya = ae_minreal(ya, state->xy.ptr.p_double[i*ew+1], _state);
   46092           0 :                 yb = ae_maxreal(yb, state->xy.ptr.p_double[i*ew+1], _state);
   46093             :             }
   46094             :         }
   46095             :         else
   46096             :         {
   46097           0 :             xa = (double)(-1);
   46098           0 :             xb = (double)(1);
   46099           0 :             ya = (double)(-1);
   46100           0 :             yb = (double)(1);
   46101             :         }
   46102             :     }
   46103             :     else
   46104             :     {
   46105           0 :         if( state->areatype==1 )
   46106             :         {
   46107           0 :             xa = state->xa;
   46108           0 :             xb = state->xb;
   46109           0 :             ya = state->ya;
   46110           0 :             yb = state->yb;
   46111             :         }
   46112             :         else
   46113             :         {
   46114           0 :             ae_assert(ae_false, "Assertion failed", _state);
   46115             :         }
   46116             :     }
   46117           0 :     if( ae_fp_eq(xa,xb) )
   46118             :     {
   46119           0 :         v = xa;
   46120           0 :         if( ae_fp_greater_eq(v,(double)(0)) )
   46121             :         {
   46122           0 :             xa = v/2-1;
   46123           0 :             xb = v*2+1;
   46124             :         }
   46125             :         else
   46126             :         {
   46127           0 :             xa = v*2-1;
   46128           0 :             xb = v/2+1;
   46129             :         }
   46130             :     }
   46131           0 :     if( ae_fp_eq(ya,yb) )
   46132             :     {
   46133           0 :         v = ya;
   46134           0 :         if( ae_fp_greater_eq(v,(double)(0)) )
   46135             :         {
   46136           0 :             ya = v/2-1;
   46137           0 :             yb = v*2+1;
   46138             :         }
   46139             :         else
   46140             :         {
   46141           0 :             ya = v*2-1;
   46142           0 :             yb = v/2+1;
   46143             :         }
   46144             :     }
   46145           0 :     ae_assert(ae_fp_less(xa,xb), "Spline2DFit: integrity error", _state);
   46146           0 :     ae_assert(ae_fp_less(ya,yb), "Spline2DFit: integrity error", _state);
   46147           0 :     kx = 0;
   46148           0 :     ky = 0;
   46149           0 :     if( state->gridtype==0 )
   46150             :     {
   46151           0 :         kx = 4;
   46152           0 :         ky = 4;
   46153             :     }
   46154             :     else
   46155             :     {
   46156           0 :         if( state->gridtype==1 )
   46157             :         {
   46158           0 :             kx = state->kx;
   46159           0 :             ky = state->ky;
   46160             :         }
   46161             :         else
   46162             :         {
   46163           0 :             ae_assert(ae_false, "Assertion failed", _state);
   46164             :         }
   46165             :     }
   46166           0 :     ae_assert(kx>0, "Spline2DFit: integrity error", _state);
   46167           0 :     ae_assert(ky>0, "Spline2DFit: integrity error", _state);
   46168           0 :     basecasex = -1;
   46169           0 :     basecasey = -1;
   46170           0 :     if( state->solvertype==3 )
   46171             :     {
   46172             :         
   46173             :         /*
   46174             :          * Large-scale solver with special requirements to grid size.
   46175             :          */
   46176           0 :         kx = ae_maxint(kx, nzwidth, _state);
   46177           0 :         ky = ae_maxint(ky, nzwidth, _state);
   46178           0 :         k = 1;
   46179           0 :         while(imin2(kx, ky, _state)>state->maxcoresize+1)
   46180             :         {
   46181           0 :             kx = idivup(kx-1, 2, _state)+1;
   46182           0 :             ky = idivup(ky-1, 2, _state)+1;
   46183           0 :             k = k+1;
   46184             :         }
   46185           0 :         basecasex = kx-1;
   46186           0 :         k0 = 1;
   46187           0 :         while(kx>state->maxcoresize+1)
   46188             :         {
   46189           0 :             basecasex = idivup(kx-1, 2, _state);
   46190           0 :             kx = basecasex+1;
   46191           0 :             k0 = k0+1;
   46192             :         }
   46193           0 :         while(k0>1)
   46194             :         {
   46195           0 :             kx = (kx-1)*2+1;
   46196           0 :             k0 = k0-1;
   46197             :         }
   46198           0 :         basecasey = ky-1;
   46199           0 :         k1 = 1;
   46200           0 :         while(ky>state->maxcoresize+1)
   46201             :         {
   46202           0 :             basecasey = idivup(ky-1, 2, _state);
   46203           0 :             ky = basecasey+1;
   46204           0 :             k1 = k1+1;
   46205             :         }
   46206           0 :         while(k1>1)
   46207             :         {
   46208           0 :             ky = (ky-1)*2+1;
   46209           0 :             k1 = k1-1;
   46210             :         }
   46211           0 :         while(k>1)
   46212             :         {
   46213           0 :             kx = (kx-1)*2+1;
   46214           0 :             ky = (ky-1)*2+1;
   46215           0 :             k = k-1;
   46216             :         }
   46217             :         
   46218             :         /*
   46219             :          * Grid is NOT expanded. We have very strict requirements on
   46220             :          * grid size, and we do not want to overcomplicate it by
   46221             :          * playing with grid size in order to add one more degree of
   46222             :          * freedom. It is not relevant for such large tasks.
   46223             :          */
   46224           0 :         gridexpansion = 0;
   46225             :     }
   46226             :     else
   46227             :     {
   46228             :         
   46229             :         /*
   46230             :          * Medium-scale solvers which are tolerant to grid size.
   46231             :          */
   46232           0 :         kx = ae_maxint(kx, nzwidth, _state);
   46233           0 :         ky = ae_maxint(ky, nzwidth, _state);
   46234             :         
   46235             :         /*
   46236             :          * Grid is expanded by 1 in order to add one more effective degree
   46237             :          * of freedom to the spline. Having additional nodes outside of the
   46238             :          * area allows us to emulate changes in the derivative at the bound
   46239             :          * without having specialized "boundary" version of the basis function.
   46240             :          */
   46241           0 :         if( state->adddegreeoffreedom )
   46242             :         {
   46243           0 :             gridexpansion = 1;
   46244             :         }
   46245             :         else
   46246             :         {
   46247           0 :             gridexpansion = 0;
   46248             :         }
   46249             :     }
   46250           0 :     hx = coalesce(xb-xa, 1.0, _state)/(kx-1);
   46251           0 :     hy = coalesce(yb-ya, 1.0, _state)/(ky-1);
   46252           0 :     invhx = 1/hx;
   46253           0 :     invhy = 1/hy;
   46254             :     
   46255             :     /*
   46256             :      * We determined "raw" grid size. Now perform a grid correction according
   46257             :      * to current grid expansion size.
   46258             :      */
   46259           0 :     xaraw = xa;
   46260           0 :     yaraw = ya;
   46261           0 :     xbraw = xb;
   46262           0 :     ybraw = yb;
   46263           0 :     xa = xa-hx*gridexpansion;
   46264           0 :     ya = ya-hy*gridexpansion;
   46265           0 :     xb = xb+hx*gridexpansion;
   46266           0 :     yb = yb+hy*gridexpansion;
   46267           0 :     kx = kx+2*gridexpansion;
   46268           0 :     ky = ky+2*gridexpansion;
   46269             :     
   46270             :     /*
   46271             :      * Create output spline using transformed (unit-scale)
   46272             :      * coordinates, fill by zero values
   46273             :      */
   46274           0 :     s->d = d;
   46275           0 :     s->n = kx;
   46276           0 :     s->m = ky;
   46277           0 :     s->stype = -3;
   46278           0 :     sfx = s->n*s->m*d;
   46279           0 :     sfy = 2*s->n*s->m*d;
   46280           0 :     sfxy = 3*s->n*s->m*d;
   46281           0 :     ae_vector_set_length(&s->x, s->n, _state);
   46282           0 :     ae_vector_set_length(&s->y, s->m, _state);
   46283           0 :     ae_vector_set_length(&s->f, 4*s->n*s->m*d, _state);
   46284           0 :     for(i=0; i<=s->n-1; i++)
   46285             :     {
   46286           0 :         s->x.ptr.p_double[i] = (double)(i);
   46287             :     }
   46288           0 :     for(i=0; i<=s->m-1; i++)
   46289             :     {
   46290           0 :         s->y.ptr.p_double[i] = (double)(i);
   46291             :     }
   46292           0 :     for(i=0; i<=4*s->n*s->m*d-1; i++)
   46293             :     {
   46294           0 :         s->f.ptr.p_double[i] = 0.0;
   46295             :     }
   46296             :     
   46297             :     /*
   46298             :      * Create local copy of dataset (only points in the grid are copied;
   46299             :      * we allow small step out of the grid, by Eps*H, in order to deal
   46300             :      * with numerical rounding errors).
   46301             :      *
   46302             :      * An additional copy of Y-values is created at columns beyond 2+J;
   46303             :      * it is preserved during all transformations. This copy is used
   46304             :      * to calculate error-related metrics.
   46305             :      *
   46306             :      * Calculate mean(Y), TSS
   46307             :      */
   46308           0 :     ae_vector_set_length(&meany, d, _state);
   46309           0 :     for(j=0; j<=d-1; j++)
   46310             :     {
   46311           0 :         meany.ptr.p_double[j] = (double)(0);
   46312             :     }
   46313           0 :     rvectorsetlengthatleast(&xywork, npoints*ew, _state);
   46314           0 :     acopied = 0;
   46315           0 :     eps = 1.0E-6;
   46316           0 :     for(i=0; i<=npoints-1; i++)
   46317             :     {
   46318           0 :         vx = state->xy.ptr.p_double[i*ew+0];
   46319           0 :         vy = state->xy.ptr.p_double[i*ew+1];
   46320           0 :         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) )
   46321             :         {
   46322           0 :             xywork.ptr.p_double[acopied*ew+0] = (vx-xa)*invhx;
   46323           0 :             xywork.ptr.p_double[acopied*ew+1] = (vy-ya)*invhy;
   46324           0 :             for(j=0; j<=d-1; j++)
   46325             :             {
   46326           0 :                 v = state->xy.ptr.p_double[i*ew+2+j];
   46327           0 :                 xywork.ptr.p_double[acopied*ew+2+j] = v;
   46328           0 :                 meany.ptr.p_double[j] = meany.ptr.p_double[j]+v;
   46329             :             }
   46330           0 :             acopied = acopied+1;
   46331             :         }
   46332             :     }
   46333           0 :     npoints = acopied;
   46334           0 :     for(j=0; j<=d-1; j++)
   46335             :     {
   46336           0 :         meany.ptr.p_double[j] = meany.ptr.p_double[j]/coalesce((double)(npoints), (double)(1), _state);
   46337             :     }
   46338           0 :     tss = 0.0;
   46339           0 :     for(i=0; i<=npoints-1; i++)
   46340             :     {
   46341           0 :         for(j=0; j<=d-1; j++)
   46342             :         {
   46343           0 :             tss = tss+ae_sqr(xywork.ptr.p_double[i*ew+2+j]-meany.ptr.p_double[j], _state);
   46344             :         }
   46345             :     }
   46346           0 :     tss = coalesce(tss, 1.0, _state);
   46347             :     
   46348             :     /*
   46349             :      * Handle prior term.
   46350             :      * Modify output spline.
   46351             :      * Quick exit if dataset is empty.
   46352             :      */
   46353           0 :     buildpriorterm1(&xywork, npoints, 2, d, state->priorterm, state->priortermval, &vterm, _state);
   46354           0 :     if( npoints==0 )
   46355             :     {
   46356             :         
   46357             :         /*
   46358             :          * Quick exit
   46359             :          */
   46360           0 :         for(k=0; k<=s->n*s->m-1; k++)
   46361             :         {
   46362           0 :             k0 = k%s->n;
   46363           0 :             k1 = k/s->n;
   46364           0 :             for(j=0; j<=d-1; j++)
   46365             :             {
   46366           0 :                 dstidx = d*(k1*s->n+k0)+j;
   46367           0 :                 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];
   46368           0 :                 s->f.ptr.p_double[sfx+dstidx] = s->f.ptr.p_double[sfx+dstidx]+vterm.ptr.pp_double[j][0];
   46369           0 :                 s->f.ptr.p_double[sfy+dstidx] = s->f.ptr.p_double[sfy+dstidx]+vterm.ptr.pp_double[j][1];
   46370             :             }
   46371             :         }
   46372           0 :         for(i=0; i<=s->n-1; i++)
   46373             :         {
   46374           0 :             s->x.ptr.p_double[i] = s->x.ptr.p_double[i]*hx+xa;
   46375             :         }
   46376           0 :         for(i=0; i<=s->m-1; i++)
   46377             :         {
   46378           0 :             s->y.ptr.p_double[i] = s->y.ptr.p_double[i]*hy+ya;
   46379             :         }
   46380           0 :         for(i=0; i<=s->n*s->m*d-1; i++)
   46381             :         {
   46382           0 :             s->f.ptr.p_double[sfx+i] = s->f.ptr.p_double[sfx+i]*invhx;
   46383           0 :             s->f.ptr.p_double[sfy+i] = s->f.ptr.p_double[sfy+i]*invhy;
   46384           0 :             s->f.ptr.p_double[sfxy+i] = s->f.ptr.p_double[sfxy+i]*invhx*invhy;
   46385             :         }
   46386           0 :         rep->rmserror = (double)(0);
   46387           0 :         rep->avgerror = (double)(0);
   46388           0 :         rep->maxerror = (double)(0);
   46389           0 :         rep->r2 = 1.0;
   46390           0 :         ae_frame_leave(_state);
   46391           0 :         return;
   46392             :     }
   46393             :     
   46394             :     /*
   46395             :      * Build 1D compact basis function
   46396             :      * Generate design matrix
   46397             :      */
   46398           0 :     ae_vector_set_length(&tmpx, 7, _state);
   46399           0 :     ae_vector_set_length(&tmpy, 7, _state);
   46400           0 :     tmpx.ptr.p_double[0] = (double)(-3);
   46401           0 :     tmpx.ptr.p_double[1] = (double)(-2);
   46402           0 :     tmpx.ptr.p_double[2] = (double)(-1);
   46403           0 :     tmpx.ptr.p_double[3] = (double)(0);
   46404           0 :     tmpx.ptr.p_double[4] = (double)(1);
   46405           0 :     tmpx.ptr.p_double[5] = (double)(2);
   46406           0 :     tmpx.ptr.p_double[6] = (double)(3);
   46407           0 :     tmpy.ptr.p_double[0] = (double)(0);
   46408           0 :     tmpy.ptr.p_double[1] = (double)(0);
   46409           0 :     tmpy.ptr.p_double[2] = (double)1/(double)12;
   46410           0 :     tmpy.ptr.p_double[3] = (double)2/(double)6;
   46411           0 :     tmpy.ptr.p_double[4] = (double)1/(double)12;
   46412           0 :     tmpy.ptr.p_double[5] = (double)(0);
   46413           0 :     tmpy.ptr.p_double[6] = (double)(0);
   46414           0 :     spline1dbuildcubic(&tmpx, &tmpy, tmpx.cnt, 2, 0.0, 2, 0.0, &basis1, _state);
   46415             :     
   46416             :     /*
   46417             :      * Solve.
   46418             :      * Update spline.
   46419             :      */
   46420           0 :     if( state->solvertype==1 )
   46421             :     {
   46422             :         
   46423             :         /*
   46424             :          * BlockLLS
   46425             :          */
   46426           0 :         spline2d_reorderdatasetandbuildindex(&xywork, npoints, d, &tmp0, 0, kx, ky, &xyindex, &tmpi, _state);
   46427           0 :         spline2d_xdesigngenerate(&xywork, &xyindex, 0, kx, kx, 0, ky, ky, d, spline2d_lambdaregblocklls, state->smoothing, &basis1, &xdesignmatrix, _state);
   46428           0 :         spline2d_blockllsfit(&xdesignmatrix, state->lsqrcnt, &z, rep, tss, &blockllsbuf, _state);
   46429           0 :         spline2d_updatesplinetable(&z, kx, ky, d, &basis1, bfrad, &s->f, s->m, s->n, 1, _state);
   46430             :     }
   46431             :     else
   46432             :     {
   46433           0 :         if( state->solvertype==2 )
   46434             :         {
   46435             :             
   46436             :             /*
   46437             :              * NaiveLLS, reference implementation
   46438             :              */
   46439           0 :             spline2d_generatedesignmatrix(&xywork, npoints, d, kx, ky, state->smoothing, spline2d_lambdaregblocklls, &basis1, &av, &ah, &arows, _state);
   46440           0 :             spline2d_naivellsfit(&av, &ah, arows, &xywork, kx, ky, npoints, d, state->lsqrcnt, &z, rep, tss, _state);
   46441           0 :             spline2d_updatesplinetable(&z, kx, ky, d, &basis1, bfrad, &s->f, s->m, s->n, 1, _state);
   46442             :         }
   46443             :         else
   46444             :         {
   46445           0 :             if( state->solvertype==3 )
   46446             :             {
   46447             :                 
   46448             :                 /*
   46449             :                  * FastDDM method
   46450             :                  */
   46451           0 :                 ae_assert(basecasex>0, "Spline2DFit: integrity error", _state);
   46452           0 :                 ae_assert(basecasey>0, "Spline2DFit: integrity error", _state);
   46453           0 :                 spline2d_fastddmfit(&xywork, npoints, d, kx, ky, basecasex, basecasey, state->maxcoresize, state->interfacesize, state->nlayers, state->smoothing, state->lsqrcnt, &basis1, s, rep, tss, _state);
   46454             :             }
   46455             :             else
   46456             :             {
   46457           0 :                 ae_assert(ae_false, "Spline2DFit: integrity error", _state);
   46458             :             }
   46459             :         }
   46460             :     }
   46461             :     
   46462             :     /*
   46463             :      * Append prior term.
   46464             :      * Transform spline to original coordinates
   46465             :      */
   46466           0 :     for(k=0; k<=s->n*s->m-1; k++)
   46467             :     {
   46468           0 :         k0 = k%s->n;
   46469           0 :         k1 = k/s->n;
   46470           0 :         for(j=0; j<=d-1; j++)
   46471             :         {
   46472           0 :             dstidx = d*(k1*s->n+k0)+j;
   46473           0 :             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];
   46474           0 :             s->f.ptr.p_double[sfx+dstidx] = s->f.ptr.p_double[sfx+dstidx]+vterm.ptr.pp_double[j][0];
   46475           0 :             s->f.ptr.p_double[sfy+dstidx] = s->f.ptr.p_double[sfy+dstidx]+vterm.ptr.pp_double[j][1];
   46476             :         }
   46477             :     }
   46478           0 :     for(i=0; i<=s->n-1; i++)
   46479             :     {
   46480           0 :         s->x.ptr.p_double[i] = s->x.ptr.p_double[i]*hx+xa;
   46481             :     }
   46482           0 :     for(i=0; i<=s->m-1; i++)
   46483             :     {
   46484           0 :         s->y.ptr.p_double[i] = s->y.ptr.p_double[i]*hy+ya;
   46485             :     }
   46486           0 :     for(i=0; i<=s->n*s->m*d-1; i++)
   46487             :     {
   46488           0 :         s->f.ptr.p_double[sfx+i] = s->f.ptr.p_double[sfx+i]*invhx;
   46489           0 :         s->f.ptr.p_double[sfy+i] = s->f.ptr.p_double[sfy+i]*invhy;
   46490           0 :         s->f.ptr.p_double[sfxy+i] = s->f.ptr.p_double[sfxy+i]*invhx*invhy;
   46491             :     }
   46492           0 :     ae_frame_leave(_state);
   46493             : }
   46494             : 
   46495             : 
   46496             : /*************************************************************************
   46497             : Serializer: allocation
   46498             : 
   46499             :   -- ALGLIB --
   46500             :      Copyright 28.02.2018 by Bochkanov Sergey
   46501             : *************************************************************************/
   46502           0 : void spline2dalloc(ae_serializer* s,
   46503             :      spline2dinterpolant* spline,
   46504             :      ae_state *_state)
   46505             : {
   46506             : 
   46507             : 
   46508             :     
   46509             :     /*
   46510             :      * Header
   46511             :      */
   46512           0 :     ae_serializer_alloc_entry(s);
   46513             :     
   46514             :     /*
   46515             :      * Data
   46516             :      */
   46517           0 :     ae_serializer_alloc_entry(s);
   46518           0 :     ae_serializer_alloc_entry(s);
   46519           0 :     ae_serializer_alloc_entry(s);
   46520           0 :     ae_serializer_alloc_entry(s);
   46521           0 :     allocrealarray(s, &spline->x, -1, _state);
   46522           0 :     allocrealarray(s, &spline->y, -1, _state);
   46523           0 :     allocrealarray(s, &spline->f, -1, _state);
   46524           0 : }
   46525             : 
   46526             : 
   46527             : /*************************************************************************
   46528             : Serializer: serialization
   46529             : 
   46530             :   -- ALGLIB --
   46531             :      Copyright 28.02.2018 by Bochkanov Sergey
   46532             : *************************************************************************/
   46533           0 : void spline2dserialize(ae_serializer* s,
   46534             :      spline2dinterpolant* spline,
   46535             :      ae_state *_state)
   46536             : {
   46537             : 
   46538             : 
   46539             :     
   46540             :     /*
   46541             :      * Header
   46542             :      */
   46543           0 :     ae_serializer_serialize_int(s, getspline2dserializationcode(_state), _state);
   46544             :     
   46545             :     /*
   46546             :      * Data
   46547             :      */
   46548           0 :     ae_serializer_serialize_int(s, spline->stype, _state);
   46549           0 :     ae_serializer_serialize_int(s, spline->n, _state);
   46550           0 :     ae_serializer_serialize_int(s, spline->m, _state);
   46551           0 :     ae_serializer_serialize_int(s, spline->d, _state);
   46552           0 :     serializerealarray(s, &spline->x, -1, _state);
   46553           0 :     serializerealarray(s, &spline->y, -1, _state);
   46554           0 :     serializerealarray(s, &spline->f, -1, _state);
   46555           0 : }
   46556             : 
   46557             : 
   46558             : /*************************************************************************
   46559             : Serializer: unserialization
   46560             : 
   46561             :   -- ALGLIB --
   46562             :      Copyright 28.02.2018 by Bochkanov Sergey
   46563             : *************************************************************************/
   46564           0 : void spline2dunserialize(ae_serializer* s,
   46565             :      spline2dinterpolant* spline,
   46566             :      ae_state *_state)
   46567             : {
   46568             :     ae_int_t scode;
   46569             : 
   46570           0 :     _spline2dinterpolant_clear(spline);
   46571             : 
   46572             :     
   46573             :     /*
   46574             :      * Header
   46575             :      */
   46576           0 :     ae_serializer_unserialize_int(s, &scode, _state);
   46577           0 :     ae_assert(scode==getspline2dserializationcode(_state), "Spline2DUnserialize: stream header corrupted", _state);
   46578             :     
   46579             :     /*
   46580             :      * Data
   46581             :      */
   46582           0 :     ae_serializer_unserialize_int(s, &spline->stype, _state);
   46583           0 :     ae_serializer_unserialize_int(s, &spline->n, _state);
   46584           0 :     ae_serializer_unserialize_int(s, &spline->m, _state);
   46585           0 :     ae_serializer_unserialize_int(s, &spline->d, _state);
   46586           0 :     unserializerealarray(s, &spline->x, _state);
   46587           0 :     unserializerealarray(s, &spline->y, _state);
   46588           0 :     unserializerealarray(s, &spline->f, _state);
   46589           0 : }
   46590             : 
   46591             : 
   46592             : /*************************************************************************
   46593             : Internal subroutine.
   46594             : Calculation of the first derivatives and the cross-derivative.
   46595             : *************************************************************************/
   46596           0 : static void spline2d_bicubiccalcderivatives(/* Real    */ ae_matrix* a,
   46597             :      /* Real    */ ae_vector* x,
   46598             :      /* Real    */ ae_vector* y,
   46599             :      ae_int_t m,
   46600             :      ae_int_t n,
   46601             :      /* Real    */ ae_matrix* dx,
   46602             :      /* Real    */ ae_matrix* dy,
   46603             :      /* Real    */ ae_matrix* dxy,
   46604             :      ae_state *_state)
   46605             : {
   46606             :     ae_frame _frame_block;
   46607             :     ae_int_t i;
   46608             :     ae_int_t j;
   46609             :     ae_vector xt;
   46610             :     ae_vector ft;
   46611             :     double s;
   46612             :     double ds;
   46613             :     double d2s;
   46614             :     spline1dinterpolant c;
   46615             : 
   46616           0 :     ae_frame_make(_state, &_frame_block);
   46617           0 :     memset(&xt, 0, sizeof(xt));
   46618           0 :     memset(&ft, 0, sizeof(ft));
   46619           0 :     memset(&c, 0, sizeof(c));
   46620           0 :     ae_matrix_clear(dx);
   46621           0 :     ae_matrix_clear(dy);
   46622           0 :     ae_matrix_clear(dxy);
   46623           0 :     ae_vector_init(&xt, 0, DT_REAL, _state, ae_true);
   46624           0 :     ae_vector_init(&ft, 0, DT_REAL, _state, ae_true);
   46625           0 :     _spline1dinterpolant_init(&c, _state, ae_true);
   46626             : 
   46627           0 :     ae_matrix_set_length(dx, m, n, _state);
   46628           0 :     ae_matrix_set_length(dy, m, n, _state);
   46629           0 :     ae_matrix_set_length(dxy, m, n, _state);
   46630             :     
   46631             :     /*
   46632             :      * dF/dX
   46633             :      */
   46634           0 :     ae_vector_set_length(&xt, n, _state);
   46635           0 :     ae_vector_set_length(&ft, n, _state);
   46636           0 :     for(i=0; i<=m-1; i++)
   46637             :     {
   46638           0 :         for(j=0; j<=n-1; j++)
   46639             :         {
   46640           0 :             xt.ptr.p_double[j] = x->ptr.p_double[j];
   46641           0 :             ft.ptr.p_double[j] = a->ptr.pp_double[i][j];
   46642             :         }
   46643           0 :         spline1dbuildcubic(&xt, &ft, n, 0, 0.0, 0, 0.0, &c, _state);
   46644           0 :         for(j=0; j<=n-1; j++)
   46645             :         {
   46646           0 :             spline1ddiff(&c, x->ptr.p_double[j], &s, &ds, &d2s, _state);
   46647           0 :             dx->ptr.pp_double[i][j] = ds;
   46648             :         }
   46649             :     }
   46650             :     
   46651             :     /*
   46652             :      * dF/dY
   46653             :      */
   46654           0 :     ae_vector_set_length(&xt, m, _state);
   46655           0 :     ae_vector_set_length(&ft, m, _state);
   46656           0 :     for(j=0; j<=n-1; j++)
   46657             :     {
   46658           0 :         for(i=0; i<=m-1; i++)
   46659             :         {
   46660           0 :             xt.ptr.p_double[i] = y->ptr.p_double[i];
   46661           0 :             ft.ptr.p_double[i] = a->ptr.pp_double[i][j];
   46662             :         }
   46663           0 :         spline1dbuildcubic(&xt, &ft, m, 0, 0.0, 0, 0.0, &c, _state);
   46664           0 :         for(i=0; i<=m-1; i++)
   46665             :         {
   46666           0 :             spline1ddiff(&c, y->ptr.p_double[i], &s, &ds, &d2s, _state);
   46667           0 :             dy->ptr.pp_double[i][j] = ds;
   46668             :         }
   46669             :     }
   46670             :     
   46671             :     /*
   46672             :      * d2F/dXdY
   46673             :      */
   46674           0 :     ae_vector_set_length(&xt, n, _state);
   46675           0 :     ae_vector_set_length(&ft, n, _state);
   46676           0 :     for(i=0; i<=m-1; i++)
   46677             :     {
   46678           0 :         for(j=0; j<=n-1; j++)
   46679             :         {
   46680           0 :             xt.ptr.p_double[j] = x->ptr.p_double[j];
   46681           0 :             ft.ptr.p_double[j] = dy->ptr.pp_double[i][j];
   46682             :         }
   46683           0 :         spline1dbuildcubic(&xt, &ft, n, 0, 0.0, 0, 0.0, &c, _state);
   46684           0 :         for(j=0; j<=n-1; j++)
   46685             :         {
   46686           0 :             spline1ddiff(&c, x->ptr.p_double[j], &s, &ds, &d2s, _state);
   46687           0 :             dxy->ptr.pp_double[i][j] = ds;
   46688             :         }
   46689             :     }
   46690           0 :     ae_frame_leave(_state);
   46691           0 : }
   46692             : 
   46693             : 
   46694             : /*************************************************************************
   46695             : This function generates design matrix for the problem (in fact, two design
   46696             : matrices are generated: "vertical" one and transposed (horizontal) one.
   46697             : 
   46698             : INPUT PARAMETERS:
   46699             :     XY          -   array[NPoints*(2+D)]; dataset after scaling  in  such
   46700             :                     way that grid step is equal to 1.0 in both dimensions.
   46701             :     NPoints     -   dataset size, NPoints>=1
   46702             :     KX, KY      -   grid size, KX,KY>=4
   46703             :     Smoothing   -   nonlinearity penalty coefficient, >=0
   46704             :     LambdaReg   -   regularization coefficient, >=0
   46705             :     Basis1      -   basis spline, expected to be non-zero only at [-2,+2]
   46706             :     AV, AH      -   possibly preallocated buffers
   46707             : 
   46708             : OUTPUT PARAMETERS:
   46709             :     AV          -   sparse matrix[ARows,KX*KY]; design matrix
   46710             :     AH          -   transpose of AV
   46711             :     ARows       -   number of rows in design matrix
   46712             :     
   46713             :   -- ALGLIB --
   46714             :      Copyright 05.02.2018 by Bochkanov Sergey
   46715             : *************************************************************************/
   46716           0 : static void spline2d_generatedesignmatrix(/* Real    */ ae_vector* xy,
   46717             :      ae_int_t npoints,
   46718             :      ae_int_t d,
   46719             :      ae_int_t kx,
   46720             :      ae_int_t ky,
   46721             :      double smoothing,
   46722             :      double lambdareg,
   46723             :      spline1dinterpolant* basis1,
   46724             :      sparsematrix* av,
   46725             :      sparsematrix* ah,
   46726             :      ae_int_t* arows,
   46727             :      ae_state *_state)
   46728             : {
   46729             :     ae_frame _frame_block;
   46730             :     ae_int_t nzwidth;
   46731             :     ae_int_t nzshift;
   46732             :     ae_int_t ew;
   46733             :     ae_int_t i;
   46734             :     ae_int_t j0;
   46735             :     ae_int_t j1;
   46736             :     ae_int_t k0;
   46737             :     ae_int_t k1;
   46738             :     ae_int_t dstidx;
   46739             :     double v;
   46740             :     double v0;
   46741             :     double v1;
   46742             :     double v2;
   46743             :     double w0;
   46744             :     double w1;
   46745             :     double w2;
   46746             :     ae_vector crx;
   46747             :     ae_vector cry;
   46748             :     ae_vector nrs;
   46749             :     ae_matrix d2x;
   46750             :     ae_matrix d2y;
   46751             :     ae_matrix dxy;
   46752             : 
   46753           0 :     ae_frame_make(_state, &_frame_block);
   46754           0 :     memset(&crx, 0, sizeof(crx));
   46755           0 :     memset(&cry, 0, sizeof(cry));
   46756           0 :     memset(&nrs, 0, sizeof(nrs));
   46757           0 :     memset(&d2x, 0, sizeof(d2x));
   46758           0 :     memset(&d2y, 0, sizeof(d2y));
   46759           0 :     memset(&dxy, 0, sizeof(dxy));
   46760           0 :     *arows = 0;
   46761           0 :     ae_vector_init(&crx, 0, DT_INT, _state, ae_true);
   46762           0 :     ae_vector_init(&cry, 0, DT_INT, _state, ae_true);
   46763           0 :     ae_vector_init(&nrs, 0, DT_INT, _state, ae_true);
   46764           0 :     ae_matrix_init(&d2x, 0, 0, DT_REAL, _state, ae_true);
   46765           0 :     ae_matrix_init(&d2y, 0, 0, DT_REAL, _state, ae_true);
   46766           0 :     ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true);
   46767             : 
   46768           0 :     nzwidth = 4;
   46769           0 :     nzshift = 1;
   46770           0 :     ae_assert(npoints>0, "Spline2DFit: integrity check failed", _state);
   46771           0 :     ae_assert(kx>=nzwidth, "Spline2DFit: integrity check failed", _state);
   46772           0 :     ae_assert(ky>=nzwidth, "Spline2DFit: integrity check failed", _state);
   46773           0 :     ew = 2+d;
   46774             :     
   46775             :     /*
   46776             :      * Determine canonical rectangle for every point. Every point of the dataset is
   46777             :      * influenced by at most NZWidth*NZWidth basis functions, which form NZWidth*NZWidth
   46778             :      * canonical rectangle.
   46779             :      *
   46780             :      * Thus, we have (KX-NZWidth+1)*(KY-NZWidth+1) overlapping canonical rectangles.
   46781             :      * Assigning every point to its rectangle simplifies creation of sparse basis
   46782             :      * matrix at the next steps.
   46783             :      */
   46784           0 :     ae_vector_set_length(&crx, npoints, _state);
   46785           0 :     ae_vector_set_length(&cry, npoints, _state);
   46786           0 :     for(i=0; i<=npoints-1; i++)
   46787             :     {
   46788           0 :         crx.ptr.p_int[i] = iboundval(ae_ifloor(xy->ptr.p_double[i*ew+0], _state)-nzshift, 0, kx-nzwidth, _state);
   46789           0 :         cry.ptr.p_int[i] = iboundval(ae_ifloor(xy->ptr.p_double[i*ew+1], _state)-nzshift, 0, ky-nzwidth, _state);
   46790             :     }
   46791             :     
   46792             :     /*
   46793             :      * Create vertical and horizontal design matrices 
   46794             :      */
   46795           0 :     *arows = npoints+kx*ky;
   46796           0 :     if( ae_fp_neq(smoothing,0.0) )
   46797             :     {
   46798           0 :         ae_assert(ae_fp_greater(smoothing,0.0), "Spline2DFit: integrity check failed", _state);
   46799           0 :         *arows = *arows+3*(kx-2)*(ky-2);
   46800             :     }
   46801           0 :     ae_vector_set_length(&nrs, *arows, _state);
   46802           0 :     dstidx = 0;
   46803           0 :     for(i=0; i<=npoints-1; i++)
   46804             :     {
   46805           0 :         nrs.ptr.p_int[dstidx+i] = nzwidth*nzwidth;
   46806             :     }
   46807           0 :     dstidx = dstidx+npoints;
   46808           0 :     for(i=0; i<=kx*ky-1; i++)
   46809             :     {
   46810           0 :         nrs.ptr.p_int[dstidx+i] = 1;
   46811             :     }
   46812           0 :     dstidx = dstidx+kx*ky;
   46813           0 :     if( ae_fp_neq(smoothing,0.0) )
   46814             :     {
   46815           0 :         for(i=0; i<=3*(kx-2)*(ky-2)-1; i++)
   46816             :         {
   46817           0 :             nrs.ptr.p_int[dstidx+i] = 3*3;
   46818             :         }
   46819           0 :         dstidx = dstidx+3*(kx-2)*(ky-2);
   46820             :     }
   46821           0 :     ae_assert(dstidx==(*arows), "Spline2DFit: integrity check failed", _state);
   46822           0 :     sparsecreatecrs(*arows, kx*ky, &nrs, av, _state);
   46823           0 :     dstidx = 0;
   46824           0 :     for(i=0; i<=npoints-1; i++)
   46825             :     {
   46826           0 :         for(j1=0; j1<=nzwidth-1; j1++)
   46827             :         {
   46828           0 :             for(j0=0; j0<=nzwidth-1; j0++)
   46829             :             {
   46830           0 :                 v0 = spline1dcalc(basis1, xy->ptr.p_double[i*ew+0]-(crx.ptr.p_int[i]+j0), _state);
   46831           0 :                 v1 = spline1dcalc(basis1, xy->ptr.p_double[i*ew+1]-(cry.ptr.p_int[i]+j1), _state);
   46832           0 :                 sparseset(av, dstidx+i, (cry.ptr.p_int[i]+j1)*kx+(crx.ptr.p_int[i]+j0), v0*v1, _state);
   46833             :             }
   46834             :         }
   46835             :     }
   46836           0 :     dstidx = dstidx+npoints;
   46837           0 :     for(i=0; i<=kx*ky-1; i++)
   46838             :     {
   46839           0 :         sparseset(av, dstidx+i, i, lambdareg, _state);
   46840             :     }
   46841           0 :     dstidx = dstidx+kx*ky;
   46842           0 :     if( ae_fp_neq(smoothing,0.0) )
   46843             :     {
   46844             :         
   46845             :         /*
   46846             :          * Smoothing is applied. Because all grid nodes are same,
   46847             :          * we apply same smoothing kernel, which is calculated only
   46848             :          * once at the beginning of design matrix generation.
   46849             :          */
   46850           0 :         ae_matrix_set_length(&d2x, 3, 3, _state);
   46851           0 :         ae_matrix_set_length(&d2y, 3, 3, _state);
   46852           0 :         ae_matrix_set_length(&dxy, 3, 3, _state);
   46853           0 :         for(j1=0; j1<=2; j1++)
   46854             :         {
   46855           0 :             for(j0=0; j0<=2; j0++)
   46856             :             {
   46857           0 :                 d2x.ptr.pp_double[j0][j1] = 0.0;
   46858           0 :                 d2y.ptr.pp_double[j0][j1] = 0.0;
   46859           0 :                 dxy.ptr.pp_double[j0][j1] = 0.0;
   46860             :             }
   46861             :         }
   46862           0 :         for(k1=0; k1<=2; k1++)
   46863             :         {
   46864           0 :             for(k0=0; k0<=2; k0++)
   46865             :             {
   46866           0 :                 spline1ddiff(basis1, (double)(-(k0-1)), &v0, &v1, &v2, _state);
   46867           0 :                 spline1ddiff(basis1, (double)(-(k1-1)), &w0, &w1, &w2, _state);
   46868           0 :                 d2x.ptr.pp_double[k0][k1] = d2x.ptr.pp_double[k0][k1]+v2*w0;
   46869           0 :                 d2y.ptr.pp_double[k0][k1] = d2y.ptr.pp_double[k0][k1]+w2*v0;
   46870           0 :                 dxy.ptr.pp_double[k0][k1] = dxy.ptr.pp_double[k0][k1]+v1*w1;
   46871             :             }
   46872             :         }
   46873             :         
   46874             :         /*
   46875             :          * Now, kernel is ready - apply it to all inner nodes of the grid.
   46876             :          */
   46877           0 :         for(j1=1; j1<=ky-2; j1++)
   46878             :         {
   46879           0 :             for(j0=1; j0<=kx-2; j0++)
   46880             :             {
   46881             :                 
   46882             :                 /*
   46883             :                  * d2F/dx2 term
   46884             :                  */
   46885           0 :                 v = smoothing;
   46886           0 :                 for(k1=-1; k1<=1; k1++)
   46887             :                 {
   46888           0 :                     for(k0=-1; k0<=1; k0++)
   46889             :                     {
   46890           0 :                         sparseset(av, dstidx, (j1+k1)*kx+(j0+k0), v*d2x.ptr.pp_double[1+k0][1+k1], _state);
   46891             :                     }
   46892             :                 }
   46893           0 :                 dstidx = dstidx+1;
   46894             :                 
   46895             :                 /*
   46896             :                  * d2F/dy2 term
   46897             :                  */
   46898           0 :                 v = smoothing;
   46899           0 :                 for(k1=-1; k1<=1; k1++)
   46900             :                 {
   46901           0 :                     for(k0=-1; k0<=1; k0++)
   46902             :                     {
   46903           0 :                         sparseset(av, dstidx, (j1+k1)*kx+(j0+k0), v*d2y.ptr.pp_double[1+k0][1+k1], _state);
   46904             :                     }
   46905             :                 }
   46906           0 :                 dstidx = dstidx+1;
   46907             :                 
   46908             :                 /*
   46909             :                  * 2*d2F/dxdy term
   46910             :                  */
   46911           0 :                 v = ae_sqrt((double)(2), _state)*smoothing;
   46912           0 :                 for(k1=-1; k1<=1; k1++)
   46913             :                 {
   46914           0 :                     for(k0=-1; k0<=1; k0++)
   46915             :                     {
   46916           0 :                         sparseset(av, dstidx, (j1+k1)*kx+(j0+k0), v*dxy.ptr.pp_double[1+k0][1+k1], _state);
   46917             :                     }
   46918             :                 }
   46919           0 :                 dstidx = dstidx+1;
   46920             :             }
   46921             :         }
   46922             :     }
   46923           0 :     ae_assert(dstidx==(*arows), "Spline2DFit: integrity check failed", _state);
   46924           0 :     sparsecopy(av, ah, _state);
   46925           0 :     sparsetransposecrs(ah, _state);
   46926           0 :     ae_frame_leave(_state);
   46927           0 : }
   46928             : 
   46929             : 
   46930             : /*************************************************************************
   46931             : This function updates table of spline values/derivatives using coefficients
   46932             : for a layer of basis functions.
   46933             :     
   46934             :   -- ALGLIB --
   46935             :      Copyright 05.02.2018 by Bochkanov Sergey
   46936             : *************************************************************************/
   46937           0 : static void spline2d_updatesplinetable(/* Real    */ ae_vector* z,
   46938             :      ae_int_t kx,
   46939             :      ae_int_t ky,
   46940             :      ae_int_t d,
   46941             :      spline1dinterpolant* basis1,
   46942             :      ae_int_t bfrad,
   46943             :      /* Real    */ ae_vector* ftbl,
   46944             :      ae_int_t m,
   46945             :      ae_int_t n,
   46946             :      ae_int_t scalexy,
   46947             :      ae_state *_state)
   46948             : {
   46949             :     ae_int_t k;
   46950             :     ae_int_t k0;
   46951             :     ae_int_t k1;
   46952             :     ae_int_t j;
   46953             :     ae_int_t j0;
   46954             :     ae_int_t j1;
   46955             :     ae_int_t j0a;
   46956             :     ae_int_t j0b;
   46957             :     ae_int_t j1a;
   46958             :     ae_int_t j1b;
   46959             :     double v;
   46960             :     double v0;
   46961             :     double v1;
   46962             :     double v01;
   46963             :     double v11;
   46964             :     double rdummy;
   46965             :     ae_int_t dstidx;
   46966             :     ae_int_t sfx;
   46967             :     ae_int_t sfy;
   46968             :     ae_int_t sfxy;
   46969             :     double invscalexy;
   46970             : 
   46971             : 
   46972           0 :     ae_assert(n==(kx-1)*scalexy+1, "Spline2DFit.UpdateSplineTable: integrity check failed", _state);
   46973           0 :     ae_assert(m==(ky-1)*scalexy+1, "Spline2DFit.UpdateSplineTable: integrity check failed", _state);
   46974           0 :     invscalexy = (double)1/(double)scalexy;
   46975           0 :     sfx = n*m*d;
   46976           0 :     sfy = 2*n*m*d;
   46977           0 :     sfxy = 3*n*m*d;
   46978           0 :     for(k=0; k<=kx*ky-1; k++)
   46979             :     {
   46980           0 :         k0 = k%kx;
   46981           0 :         k1 = k/kx;
   46982           0 :         j0a = iboundval(k0*scalexy-(bfrad*scalexy-1), 0, n-1, _state);
   46983           0 :         j0b = iboundval(k0*scalexy+(bfrad*scalexy-1), 0, n-1, _state);
   46984           0 :         j1a = iboundval(k1*scalexy-(bfrad*scalexy-1), 0, m-1, _state);
   46985           0 :         j1b = iboundval(k1*scalexy+(bfrad*scalexy-1), 0, m-1, _state);
   46986           0 :         for(j1=j1a; j1<=j1b; j1++)
   46987             :         {
   46988           0 :             spline1ddiff(basis1, (j1-k1*scalexy)*invscalexy, &v1, &v11, &rdummy, _state);
   46989           0 :             v11 = v11*invscalexy;
   46990           0 :             for(j0=j0a; j0<=j0b; j0++)
   46991             :             {
   46992           0 :                 spline1ddiff(basis1, (j0-k0*scalexy)*invscalexy, &v0, &v01, &rdummy, _state);
   46993           0 :                 v01 = v01*invscalexy;
   46994           0 :                 for(j=0; j<=d-1; j++)
   46995             :                 {
   46996           0 :                     dstidx = d*(j1*n+j0)+j;
   46997           0 :                     v = z->ptr.p_double[j*kx*ky+k];
   46998           0 :                     ftbl->ptr.p_double[dstidx] = ftbl->ptr.p_double[dstidx]+v0*v1*v;
   46999           0 :                     ftbl->ptr.p_double[sfx+dstidx] = ftbl->ptr.p_double[sfx+dstidx]+v01*v1*v;
   47000           0 :                     ftbl->ptr.p_double[sfy+dstidx] = ftbl->ptr.p_double[sfy+dstidx]+v0*v11*v;
   47001           0 :                     ftbl->ptr.p_double[sfxy+dstidx] = ftbl->ptr.p_double[sfxy+dstidx]+v01*v11*v;
   47002             :                 }
   47003             :             }
   47004             :         }
   47005             :     }
   47006           0 : }
   47007             : 
   47008             : 
   47009             : /*************************************************************************
   47010             : This function performs fitting with FastDDM solver.
   47011             : Internal function, never use it directly.
   47012             : 
   47013             : INPUT PARAMETERS:
   47014             :     XY          -   array[NPoints*(2+D)], dataset; destroyed in process
   47015             :     KX, KY      -   grid size
   47016             :     TileSize    -   tile size
   47017             :     InterfaceSize-  interface size
   47018             :     NPoints     -   points count
   47019             :     D           -   number of components in vector-valued spline, D>=1
   47020             :     LSQRCnt     -   number of iterations, non-zero:
   47021             :                     * LSQRCnt>0 means that specified amount of  preconditioned
   47022             :                       LSQR  iterations  will  be  performed  to solve problem;
   47023             :                       usually  we  need  2..5  its.  Recommended option - best
   47024             :                       convergence and stability/quality.
   47025             :                     * LSQRCnt<0 means that instead of LSQR  we  use  iterative
   47026             :                       refinement on normal equations. Again, 2..5 its is enough.
   47027             :     Basis1      -   basis spline, expected to be non-zero only at [-2,+2]
   47028             :     Z           -   possibly preallocated buffer for solution
   47029             :     Residuals   -   possibly preallocated buffer for residuals at dataset points
   47030             :     Rep         -   report structure; fields which are not set by this function
   47031             :                     are left intact
   47032             :     TSS         -   total sum of squares; used to calculate R2
   47033             :     
   47034             : 
   47035             : OUTPUT PARAMETERS:
   47036             :     XY          -   destroyed in process
   47037             :     Z           -   array[KX*KY*D], filled by solution; KX*KY coefficients
   47038             :                     corresponding to each of D dimensions are stored contiguously.
   47039             :     Rep         -   following fields are set:
   47040             :                     * Rep.RMSError
   47041             :                     * Rep.AvgError
   47042             :                     * Rep.MaxError
   47043             :                     * Rep.R2
   47044             : 
   47045             :   -- ALGLIB --
   47046             :      Copyright 05.02.2018 by Bochkanov Sergey
   47047             : *************************************************************************/
   47048           0 : static void spline2d_fastddmfit(/* Real    */ ae_vector* xy,
   47049             :      ae_int_t npoints,
   47050             :      ae_int_t d,
   47051             :      ae_int_t kx,
   47052             :      ae_int_t ky,
   47053             :      ae_int_t basecasex,
   47054             :      ae_int_t basecasey,
   47055             :      ae_int_t maxcoresize,
   47056             :      ae_int_t interfacesize,
   47057             :      ae_int_t nlayers,
   47058             :      double smoothing,
   47059             :      ae_int_t lsqrcnt,
   47060             :      spline1dinterpolant* basis1,
   47061             :      spline2dinterpolant* spline,
   47062             :      spline2dfitreport* rep,
   47063             :      double tss,
   47064             :      ae_state *_state)
   47065             : {
   47066             :     ae_frame _frame_block;
   47067             :     ae_int_t i;
   47068             :     ae_int_t j;
   47069             :     ae_int_t nzwidth;
   47070             :     ae_int_t xew;
   47071             :     ae_int_t ntotallayers;
   47072             :     ae_int_t scaleidx;
   47073             :     ae_int_t scalexy;
   47074             :     double invscalexy;
   47075             :     ae_int_t kxcur;
   47076             :     ae_int_t kycur;
   47077             :     ae_int_t tilescount0;
   47078             :     ae_int_t tilescount1;
   47079             :     double v;
   47080             :     double rss;
   47081             :     ae_vector yraw;
   47082             :     ae_vector xyindex;
   47083             :     ae_vector tmp0;
   47084             :     ae_vector bufi;
   47085             :     spline2dfastddmbuf seed;
   47086             :     ae_shared_pool pool;
   47087             :     spline2dxdesignmatrix xdesignmatrix;
   47088             :     spline2dblockllsbuf blockllsbuf;
   47089             :     spline2dfitreport dummyrep;
   47090             : 
   47091           0 :     ae_frame_make(_state, &_frame_block);
   47092           0 :     memset(&yraw, 0, sizeof(yraw));
   47093           0 :     memset(&xyindex, 0, sizeof(xyindex));
   47094           0 :     memset(&tmp0, 0, sizeof(tmp0));
   47095           0 :     memset(&bufi, 0, sizeof(bufi));
   47096           0 :     memset(&seed, 0, sizeof(seed));
   47097           0 :     memset(&pool, 0, sizeof(pool));
   47098           0 :     memset(&xdesignmatrix, 0, sizeof(xdesignmatrix));
   47099           0 :     memset(&blockllsbuf, 0, sizeof(blockllsbuf));
   47100           0 :     memset(&dummyrep, 0, sizeof(dummyrep));
   47101           0 :     ae_vector_init(&yraw, 0, DT_REAL, _state, ae_true);
   47102           0 :     ae_vector_init(&xyindex, 0, DT_INT, _state, ae_true);
   47103           0 :     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
   47104           0 :     ae_vector_init(&bufi, 0, DT_INT, _state, ae_true);
   47105           0 :     _spline2dfastddmbuf_init(&seed, _state, ae_true);
   47106           0 :     ae_shared_pool_init(&pool, _state, ae_true);
   47107           0 :     _spline2dxdesignmatrix_init(&xdesignmatrix, _state, ae_true);
   47108           0 :     _spline2dblockllsbuf_init(&blockllsbuf, _state, ae_true);
   47109           0 :     _spline2dfitreport_init(&dummyrep, _state, ae_true);
   47110             : 
   47111             :     
   47112             :     /*
   47113             :      * Dataset metrics and integrity checks
   47114             :      */
   47115           0 :     nzwidth = 4;
   47116           0 :     xew = 2+d;
   47117           0 :     ae_assert(maxcoresize>=2, "Spline2DFit: integrity check failed", _state);
   47118           0 :     ae_assert(interfacesize>=1, "Spline2DFit: integrity check failed", _state);
   47119           0 :     ae_assert(kx>=nzwidth, "Spline2DFit: integrity check failed", _state);
   47120           0 :     ae_assert(ky>=nzwidth, "Spline2DFit: integrity check failed", _state);
   47121             :     
   47122             :     /*
   47123             :      * Verify consistency of the grid size (KX,KY) with basecase sizes.
   47124             :      * Determine full number of layers.
   47125             :      */
   47126           0 :     ae_assert(basecasex<=maxcoresize, "Spline2DFit: integrity error", _state);
   47127           0 :     ae_assert(basecasey<=maxcoresize, "Spline2DFit: integrity error", _state);
   47128           0 :     ntotallayers = 1;
   47129           0 :     scalexy = 1;
   47130           0 :     kxcur = kx;
   47131           0 :     kycur = ky;
   47132           0 :     while(kxcur>basecasex+1&&kycur>basecasey+1)
   47133             :     {
   47134           0 :         ae_assert(kxcur%2==1, "Spline2DFit: integrity error", _state);
   47135           0 :         ae_assert(kycur%2==1, "Spline2DFit: integrity error", _state);
   47136           0 :         kxcur = (kxcur-1)/2+1;
   47137           0 :         kycur = (kycur-1)/2+1;
   47138           0 :         scalexy = scalexy*2;
   47139           0 :         inc(&ntotallayers, _state);
   47140             :     }
   47141           0 :     invscalexy = (double)1/(double)scalexy;
   47142           0 :     ae_assert((kxcur<=maxcoresize+1&&kxcur==basecasex+1)||kxcur%basecasex==1, "Spline2DFit: integrity error", _state);
   47143           0 :     ae_assert((kycur<=maxcoresize+1&&kycur==basecasey+1)||kycur%basecasey==1, "Spline2DFit: integrity error", _state);
   47144           0 :     ae_assert(kxcur==basecasex+1||kycur==basecasey+1, "Spline2DFit: integrity error", _state);
   47145             :     
   47146             :     /*
   47147             :      * Initial scaling of dataset.
   47148             :      * Store original target values to YRaw.
   47149             :      */
   47150           0 :     rvectorsetlengthatleast(&yraw, npoints*d, _state);
   47151           0 :     for(i=0; i<=npoints-1; i++)
   47152             :     {
   47153           0 :         xy->ptr.p_double[xew*i+0] = xy->ptr.p_double[xew*i+0]*invscalexy;
   47154           0 :         xy->ptr.p_double[xew*i+1] = xy->ptr.p_double[xew*i+1]*invscalexy;
   47155           0 :         for(j=0; j<=d-1; j++)
   47156             :         {
   47157           0 :             yraw.ptr.p_double[i*d+j] = xy->ptr.p_double[xew*i+2+j];
   47158             :         }
   47159             :     }
   47160           0 :     kxcur = (kx-1)/scalexy+1;
   47161           0 :     kycur = (ky-1)/scalexy+1;
   47162             :     
   47163             :     /*
   47164             :      * Build initial dataset index; area is divided into (KXCur-1)*(KYCur-1)
   47165             :      * cells, with contiguous storage of points in the same cell.
   47166             :      * Iterate over different scales
   47167             :      */
   47168           0 :     ae_shared_pool_set_seed(&pool, &seed, sizeof(seed), _spline2dfastddmbuf_init, _spline2dfastddmbuf_init_copy, _spline2dfastddmbuf_destroy, _state);
   47169           0 :     spline2d_reorderdatasetandbuildindex(xy, npoints, d, &yraw, d, kxcur, kycur, &xyindex, &bufi, _state);
   47170           0 :     for(scaleidx=ntotallayers-1; scaleidx>=0; scaleidx--)
   47171             :     {
   47172           0 :         if( (nlayers>0&&scaleidx<nlayers)||(nlayers<=0&&scaleidx<imax2(ntotallayers+nlayers, 1, _state)) )
   47173             :         {
   47174             :             
   47175             :             /*
   47176             :              * Fit current layer
   47177             :              */
   47178           0 :             ae_assert(kxcur%basecasex==1, "Spline2DFit: integrity error", _state);
   47179           0 :             ae_assert(kycur%basecasey==1, "Spline2DFit: integrity error", _state);
   47180           0 :             tilescount0 = kxcur/basecasex;
   47181           0 :             tilescount1 = kycur/basecasey;
   47182           0 :             spline2d_fastddmfitlayer(xy, d, scalexy, &xyindex, basecasex, 0, tilescount0, tilescount0, basecasey, 0, tilescount1, tilescount1, maxcoresize, interfacesize, lsqrcnt, spline2d_lambdaregfastddm+smoothing*ae_pow(spline2d_lambdadecay, (double)(scaleidx), _state), basis1, &pool, spline, _state);
   47183             :             
   47184             :             /*
   47185             :              * Compute residuals and update XY
   47186             :              */
   47187           0 :             spline2d_computeresidualsfromscratch(xy, &yraw, npoints, d, scalexy, spline, _state);
   47188             :         }
   47189             :         
   47190             :         /*
   47191             :          * Move to the next level
   47192             :          */
   47193           0 :         if( scaleidx!=0 )
   47194             :         {
   47195             :             
   47196             :             /*
   47197             :              * Transform dataset (multply everything by 2.0) and refine grid.
   47198             :              */
   47199           0 :             kxcur = 2*kxcur-1;
   47200           0 :             kycur = 2*kycur-1;
   47201           0 :             scalexy = scalexy/2;
   47202           0 :             invscalexy = (double)1/(double)scalexy;
   47203           0 :             spline2d_rescaledatasetandrefineindex(xy, npoints, d, &yraw, d, kxcur, kycur, &xyindex, &bufi, _state);
   47204             :             
   47205             :             /*
   47206             :              * Clear temporaries from previous round.
   47207             :              *
   47208             :              * We have to do it because upper layer of the multilevel spline
   47209             :              * needs more memory then subsequent layers, and we want to free
   47210             :              * this memory as soon as possible.
   47211             :              */
   47212           0 :             ae_shared_pool_clear_recycled(&pool, _state);
   47213             :         }
   47214             :     }
   47215             :     
   47216             :     /*
   47217             :      * Post-check
   47218             :      */
   47219           0 :     ae_assert(kxcur==kx, "Spline2DFit: integrity check failed", _state);
   47220           0 :     ae_assert(kycur==ky, "Spline2DFit: integrity check failed", _state);
   47221           0 :     ae_assert(scalexy==1, "Spline2DFit: integrity check failed", _state);
   47222             :     
   47223             :     /*
   47224             :      * Report
   47225             :      */
   47226           0 :     rep->rmserror = (double)(0);
   47227           0 :     rep->avgerror = (double)(0);
   47228           0 :     rep->maxerror = (double)(0);
   47229           0 :     rss = 0.0;
   47230           0 :     for(i=0; i<=npoints-1; i++)
   47231             :     {
   47232           0 :         for(j=0; j<=d-1; j++)
   47233             :         {
   47234           0 :             v = xy->ptr.p_double[i*xew+2+j];
   47235           0 :             rss = rss+v*v;
   47236           0 :             rep->rmserror = rep->rmserror+ae_sqr(v, _state);
   47237           0 :             rep->avgerror = rep->avgerror+ae_fabs(v, _state);
   47238           0 :             rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
   47239             :         }
   47240             :     }
   47241           0 :     rep->rmserror = ae_sqrt(rep->rmserror/coalesce((double)(npoints*d), 1.0, _state), _state);
   47242           0 :     rep->avgerror = rep->avgerror/coalesce((double)(npoints*d), 1.0, _state);
   47243           0 :     rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state);
   47244           0 :     ae_frame_leave(_state);
   47245           0 : }
   47246             : 
   47247             : 
   47248             : /*************************************************************************
   47249             : Recursive fitting function for FastDDM algorithm.
   47250             : 
   47251             : Works with KX*KY grid, with KX=BasecaseX*TilesCountX+1 and KY=BasecaseY*TilesCountY+1,
   47252             : which is partitioned into TilesCountX*TilesCountY tiles, each having size
   47253             : BasecaseX*BasecaseY.
   47254             : 
   47255             : This function processes tiles in range [TileX0,TileX1)x[TileY0,TileY1) and
   47256             : recursively divides this range until we move down to single tile, which
   47257             : is processed with BlockLLS solver.
   47258             : 
   47259             :   -- ALGLIB --
   47260             :      Copyright 05.02.2018 by Bochkanov Sergey
   47261             : *************************************************************************/
   47262           0 : static void spline2d_fastddmfitlayer(/* Real    */ ae_vector* xy,
   47263             :      ae_int_t d,
   47264             :      ae_int_t scalexy,
   47265             :      /* Integer */ ae_vector* xyindex,
   47266             :      ae_int_t basecasex,
   47267             :      ae_int_t tilex0,
   47268             :      ae_int_t tilex1,
   47269             :      ae_int_t tilescountx,
   47270             :      ae_int_t basecasey,
   47271             :      ae_int_t tiley0,
   47272             :      ae_int_t tiley1,
   47273             :      ae_int_t tilescounty,
   47274             :      ae_int_t maxcoresize,
   47275             :      ae_int_t interfacesize,
   47276             :      ae_int_t lsqrcnt,
   47277             :      double lambdareg,
   47278             :      spline1dinterpolant* basis1,
   47279             :      ae_shared_pool* pool,
   47280             :      spline2dinterpolant* spline,
   47281             :      ae_state *_state)
   47282             : {
   47283             :     ae_frame _frame_block;
   47284             :     ae_int_t kx;
   47285             :     ae_int_t ky;
   47286             :     ae_int_t i;
   47287             :     ae_int_t j;
   47288             :     ae_int_t j0;
   47289             :     ae_int_t j1;
   47290             :     ae_int_t bfrad;
   47291             :     ae_int_t xa;
   47292             :     ae_int_t xb;
   47293             :     ae_int_t ya;
   47294             :     ae_int_t yb;
   47295             :     ae_int_t tile0;
   47296             :     ae_int_t tile1;
   47297             :     ae_int_t tilesize0;
   47298             :     ae_int_t tilesize1;
   47299             :     ae_int_t sfx;
   47300             :     ae_int_t sfy;
   47301             :     ae_int_t sfxy;
   47302             :     double dummytss;
   47303             :     double invscalexy;
   47304             :     ae_int_t cnt0;
   47305             :     ae_int_t cnt1;
   47306             :     ae_int_t offs;
   47307             :     double vs;
   47308             :     double vsx;
   47309             :     double vsy;
   47310             :     double vsxy;
   47311             :     spline2dfastddmbuf *buf;
   47312             :     ae_smart_ptr _buf;
   47313             : 
   47314           0 :     ae_frame_make(_state, &_frame_block);
   47315           0 :     memset(&_buf, 0, sizeof(_buf));
   47316           0 :     ae_smart_ptr_init(&_buf, (void**)&buf, _state, ae_true);
   47317             : 
   47318             :     
   47319             :     /*
   47320             :      * Dataset metrics and fast integrity checks;
   47321             :      * no code with side effects is allowed before parallel split.
   47322             :      */
   47323           0 :     bfrad = 2;
   47324           0 :     invscalexy = (double)1/(double)scalexy;
   47325           0 :     kx = basecasex*tilescountx+1;
   47326           0 :     ky = basecasey*tilescounty+1;
   47327             :     
   47328             :     /*
   47329             :      * Parallelism; because this function is intended for
   47330             :      * large-scale problems, we always try to:
   47331             :      * * invoke parallel execution mode
   47332             :      * * activate spawn support
   47333             :      */
   47334           0 :     if( _trypexec_spline2d_fastddmfitlayer(xy,d,scalexy,xyindex,basecasex,tilex0,tilex1,tilescountx,basecasey,tiley0,tiley1,tilescounty,maxcoresize,interfacesize,lsqrcnt,lambdareg,basis1,pool,spline, _state) )
   47335             :     {
   47336           0 :         ae_frame_leave(_state);
   47337           0 :         return;
   47338             :     }
   47339           0 :     if( imax2(tiley1-tiley0, tilex1-tilex0, _state)>=2 )
   47340             :     {
   47341           0 :         if( tiley1-tiley0>tilex1-tilex0 )
   47342             :         {
   47343             :             
   47344             :             /*
   47345             :              * Split problem in Y dimension
   47346             :              *
   47347             :              * NOTE: recursive calls to FastDDMFitLayer() compute
   47348             :              *       residuals in the inner cells defined by XYIndex[],
   47349             :              *       but we still have to compute residuals for cells
   47350             :              *       BETWEEN two recursive subdivisions of the task.
   47351             :              */
   47352           0 :             tiledsplit(tiley1-tiley0, 1, &j0, &j1, _state);
   47353           0 :             spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0, tilex1, tilescountx, basecasey, tiley0, tiley0+j0, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state);
   47354           0 :             spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0, tilex1, tilescountx, basecasey, tiley0+j0, tiley1, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state);
   47355             :         }
   47356             :         else
   47357             :         {
   47358             :             
   47359             :             /*
   47360             :              * Split problem in X dimension
   47361             :              *
   47362             :              * NOTE: recursive calls to FastDDMFitLayer() compute
   47363             :              *       residuals in the inner cells defined by XYIndex[],
   47364             :              *       but we still have to compute residuals for cells
   47365             :              *       BETWEEN two recursive subdivisions of the task.
   47366             :              */
   47367           0 :             tiledsplit(tilex1-tilex0, 1, &j0, &j1, _state);
   47368           0 :             spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0, tilex0+j0, tilescountx, basecasey, tiley0, tiley1, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state);
   47369           0 :             spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0+j0, tilex1, tilescountx, basecasey, tiley0, tiley1, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state);
   47370             :         }
   47371           0 :         ae_frame_leave(_state);
   47372           0 :         return;
   47373             :     }
   47374           0 :     ae_assert(tiley0==tiley1-1, "Spline2DFit.FastDDMFitLayer: integrity check failed", _state);
   47375           0 :     ae_assert(tilex0==tilex1-1, "Spline2DFit.FastDDMFitLayer: integrity check failed", _state);
   47376           0 :     tile1 = tiley0;
   47377           0 :     tile0 = tilex0;
   47378             :     
   47379             :     /*
   47380             :      * Retrieve temporaries
   47381             :      */
   47382           0 :     ae_shared_pool_retrieve(pool, &_buf, _state);
   47383             :     
   47384             :     /*
   47385             :      * Analyze dataset
   47386             :      */
   47387           0 :     xa = iboundval(tile0*basecasex-interfacesize, 0, kx, _state);
   47388           0 :     xb = iboundval((tile0+1)*basecasex+interfacesize, 0, kx, _state);
   47389           0 :     ya = iboundval(tile1*basecasey-interfacesize, 0, ky, _state);
   47390           0 :     yb = iboundval((tile1+1)*basecasey+interfacesize, 0, ky, _state);
   47391           0 :     tilesize0 = xb-xa;
   47392           0 :     tilesize1 = yb-ya;
   47393             :     
   47394             :     /*
   47395             :      * Solve current chunk with BlockLLS
   47396             :      */
   47397           0 :     dummytss = 1.0;
   47398           0 :     spline2d_xdesigngenerate(xy, xyindex, xa, xb, kx, ya, yb, ky, d, lambdareg, 0.0, basis1, &buf->xdesignmatrix, _state);
   47399           0 :     spline2d_blockllsfit(&buf->xdesignmatrix, lsqrcnt, &buf->tmpz, &buf->dummyrep, dummytss, &buf->blockllsbuf, _state);
   47400           0 :     buf->localmodel.d = d;
   47401           0 :     buf->localmodel.m = tilesize1;
   47402           0 :     buf->localmodel.n = tilesize0;
   47403           0 :     buf->localmodel.stype = -3;
   47404           0 :     rvectorsetlengthatleast(&buf->localmodel.x, tilesize0, _state);
   47405           0 :     rvectorsetlengthatleast(&buf->localmodel.y, tilesize1, _state);
   47406           0 :     rvectorsetlengthatleast(&buf->localmodel.f, tilesize0*tilesize1*d*4, _state);
   47407           0 :     for(i=0; i<=tilesize0-1; i++)
   47408             :     {
   47409           0 :         buf->localmodel.x.ptr.p_double[i] = (double)(xa+i);
   47410             :     }
   47411           0 :     for(i=0; i<=tilesize1-1; i++)
   47412             :     {
   47413           0 :         buf->localmodel.y.ptr.p_double[i] = (double)(ya+i);
   47414             :     }
   47415           0 :     for(i=0; i<=tilesize0*tilesize1*d*4-1; i++)
   47416             :     {
   47417           0 :         buf->localmodel.f.ptr.p_double[i] = 0.0;
   47418             :     }
   47419           0 :     spline2d_updatesplinetable(&buf->tmpz, tilesize0, tilesize1, d, basis1, bfrad, &buf->localmodel.f, tilesize1, tilesize0, 1, _state);
   47420             :     
   47421             :     /*
   47422             :      * Transform local spline to original coordinates
   47423             :      */
   47424           0 :     sfx = buf->localmodel.n*buf->localmodel.m*d;
   47425           0 :     sfy = 2*buf->localmodel.n*buf->localmodel.m*d;
   47426           0 :     sfxy = 3*buf->localmodel.n*buf->localmodel.m*d;
   47427           0 :     for(i=0; i<=tilesize0-1; i++)
   47428             :     {
   47429           0 :         buf->localmodel.x.ptr.p_double[i] = buf->localmodel.x.ptr.p_double[i]*scalexy;
   47430             :     }
   47431           0 :     for(i=0; i<=tilesize1-1; i++)
   47432             :     {
   47433           0 :         buf->localmodel.y.ptr.p_double[i] = buf->localmodel.y.ptr.p_double[i]*scalexy;
   47434             :     }
   47435           0 :     for(i=0; i<=tilesize0*tilesize1*d-1; i++)
   47436             :     {
   47437           0 :         buf->localmodel.f.ptr.p_double[sfx+i] = buf->localmodel.f.ptr.p_double[sfx+i]*invscalexy;
   47438           0 :         buf->localmodel.f.ptr.p_double[sfy+i] = buf->localmodel.f.ptr.p_double[sfy+i]*invscalexy;
   47439           0 :         buf->localmodel.f.ptr.p_double[sfxy+i] = buf->localmodel.f.ptr.p_double[sfxy+i]*(invscalexy*invscalexy);
   47440             :     }
   47441             :     
   47442             :     /*
   47443             :      * Output results; for inner and topmost/leftmost tiles we output only BasecaseX*BasecaseY
   47444             :      * inner elements; for rightmost/bottom ones we also output one column/row of the interface
   47445             :      * part.
   47446             :      *
   47447             :      * Such complexity is explained by the fact that area size (by design) is not evenly divisible
   47448             :      * by the tile size; it is divisible with remainder=1, and we expect that interface size is
   47449             :      * at least 1, so we can fill the missing rightmost/bottom elements of Z by the interface
   47450             :      * values.
   47451             :      */
   47452           0 :     ae_assert(interfacesize>=1, "Spline2DFit: integrity check failed", _state);
   47453           0 :     sfx = spline->n*spline->m*d;
   47454           0 :     sfy = 2*spline->n*spline->m*d;
   47455           0 :     sfxy = 3*spline->n*spline->m*d;
   47456           0 :     cnt0 = basecasex*scalexy;
   47457           0 :     cnt1 = basecasey*scalexy;
   47458           0 :     if( tile0==tilescountx-1 )
   47459             :     {
   47460           0 :         inc(&cnt0, _state);
   47461             :     }
   47462           0 :     if( tile1==tilescounty-1 )
   47463             :     {
   47464           0 :         inc(&cnt1, _state);
   47465             :     }
   47466           0 :     offs = d*(spline->n*tile1*basecasey*scalexy+tile0*basecasex*scalexy);
   47467           0 :     for(j1=0; j1<=cnt1-1; j1++)
   47468             :     {
   47469           0 :         for(j0=0; j0<=cnt0-1; j0++)
   47470             :         {
   47471           0 :             for(j=0; j<=d-1; j++)
   47472             :             {
   47473           0 :                 spline2ddiffvi(&buf->localmodel, (double)(tile0*basecasex*scalexy+j0), (double)(tile1*basecasey*scalexy+j1), j, &vs, &vsx, &vsy, &vsxy, _state);
   47474           0 :                 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;
   47475           0 :                 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;
   47476           0 :                 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;
   47477           0 :                 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;
   47478             :             }
   47479             :         }
   47480             :     }
   47481             :     
   47482             :     /*
   47483             :      * Recycle temporaries
   47484             :      */
   47485           0 :     ae_shared_pool_recycle(pool, &_buf, _state);
   47486           0 :     ae_frame_leave(_state);
   47487             : }
   47488             : 
   47489             : 
   47490             : /*************************************************************************
   47491             : Serial stub for GPL edition.
   47492             : *************************************************************************/
   47493           0 : ae_bool _trypexec_spline2d_fastddmfitlayer(/* Real    */ ae_vector* xy,
   47494             :     ae_int_t d,
   47495             :     ae_int_t scalexy,
   47496             :     /* Integer */ ae_vector* xyindex,
   47497             :     ae_int_t basecasex,
   47498             :     ae_int_t tilex0,
   47499             :     ae_int_t tilex1,
   47500             :     ae_int_t tilescountx,
   47501             :     ae_int_t basecasey,
   47502             :     ae_int_t tiley0,
   47503             :     ae_int_t tiley1,
   47504             :     ae_int_t tilescounty,
   47505             :     ae_int_t maxcoresize,
   47506             :     ae_int_t interfacesize,
   47507             :     ae_int_t lsqrcnt,
   47508             :     double lambdareg,
   47509             :     spline1dinterpolant* basis1,
   47510             :     ae_shared_pool* pool,
   47511             :     spline2dinterpolant* spline,
   47512             :     ae_state *_state)
   47513             : {
   47514           0 :     return ae_false;
   47515             : }
   47516             : 
   47517             : 
   47518             : /*************************************************************************
   47519             : This function performs fitting with  BlockLLS solver.  Internal  function,
   47520             : never use it directly.
   47521             : 
   47522             : IMPORTANT: performance  and  memory  requirements  of  this  function  are
   47523             :            asymmetric w.r.t. KX and KY: it has
   47524             :            * O(KY*KX^2) memory requirements
   47525             :            * O(KY*KX^3) running time
   47526             :            Thus, if you have large KY and small KX,  simple  transposition
   47527             :            of your dataset may give you great speedup.
   47528             : 
   47529             : INPUT PARAMETERS:
   47530             :     AV      -   sparse matrix, [ARows,KX*KY] in size.  "Vertical"  version
   47531             :                 of design matrix, rows [0,NPoints) contain values of basis
   47532             :                 functions at dataset  points.  Other  rows  are  used  for
   47533             :                 nonlinearity penalty and other stuff like that.
   47534             :     AH      -   transpose(AV), "horizontal" version of AV
   47535             :     ARows   -   rows count
   47536             :     XY      -   array[NPoints*(2+D)], dataset
   47537             :     KX, KY  -   grid size
   47538             :     NPoints -   points count
   47539             :     D       -   number of components in vector-valued spline, D>=1
   47540             :     LSQRCnt -   number of iterations, non-zero:
   47541             :                 * LSQRCnt>0 means that specified amount of  preconditioned
   47542             :                   LSQR  iterations  will  be  performed  to solve problem;
   47543             :                   usually  we  need  2..5  its.  Recommended option - best
   47544             :                   convergence and stability/quality.
   47545             :                 * LSQRCnt<0 means that instead of LSQR  we  use  iterative
   47546             :                   refinement on normal equations. Again, 2..5 its is enough.
   47547             :     Z       -   possibly preallocated buffer for solution
   47548             :     Rep     -   report structure; fields which are not set by this function
   47549             :                 are left intact
   47550             :     TSS     -   total sum of squares; used to calculate R2
   47551             :     
   47552             : 
   47553             : OUTPUT PARAMETERS:
   47554             :     XY      -   destroyed in process
   47555             :     Z       -   array[KX*KY*D], filled by solution; KX*KY coefficients
   47556             :                 corresponding to each of D dimensions are stored contiguously.
   47557             :     Rep         -   following fields are set:
   47558             :                     * Rep.RMSError
   47559             :                     * Rep.AvgError
   47560             :                     * Rep.MaxError
   47561             :                     * Rep.R2
   47562             : 
   47563             :   -- ALGLIB --
   47564             :      Copyright 05.02.2018 by Bochkanov Sergey
   47565             : *************************************************************************/
   47566           0 : static void spline2d_blockllsfit(spline2dxdesignmatrix* xdesign,
   47567             :      ae_int_t lsqrcnt,
   47568             :      /* Real    */ ae_vector* z,
   47569             :      spline2dfitreport* rep,
   47570             :      double tss,
   47571             :      spline2dblockllsbuf* buf,
   47572             :      ae_state *_state)
   47573             : {
   47574             :     ae_frame _frame_block;
   47575             :     ae_int_t blockbandwidth;
   47576             :     ae_int_t d;
   47577             :     ae_int_t i;
   47578             :     ae_int_t j;
   47579             :     double lambdachol;
   47580             :     sreal mxata;
   47581             :     double v;
   47582             :     ae_int_t celloffset;
   47583             :     ae_int_t i0;
   47584             :     ae_int_t i1;
   47585             :     double rss;
   47586             :     ae_int_t arows;
   47587             :     ae_int_t bw2;
   47588             :     ae_int_t kx;
   47589             :     ae_int_t ky;
   47590             : 
   47591           0 :     ae_frame_make(_state, &_frame_block);
   47592           0 :     memset(&mxata, 0, sizeof(mxata));
   47593           0 :     _sreal_init(&mxata, _state, ae_true);
   47594             : 
   47595           0 :     ae_assert(xdesign->blockwidth==4, "Spline2DFit: integrity check failed", _state);
   47596           0 :     blockbandwidth = 3;
   47597           0 :     d = xdesign->d;
   47598           0 :     arows = xdesign->nrows;
   47599           0 :     kx = xdesign->kx;
   47600           0 :     ky = xdesign->ky;
   47601           0 :     bw2 = xdesign->blockwidth*xdesign->blockwidth;
   47602             :     
   47603             :     /*
   47604             :      * Initial values for Z/Residuals
   47605             :      */
   47606           0 :     rvectorsetlengthatleast(z, kx*ky*d, _state);
   47607           0 :     for(i=0; i<=kx*ky*d-1; i++)
   47608             :     {
   47609           0 :         z->ptr.p_double[i] = (double)(0);
   47610             :     }
   47611             :     
   47612             :     /*
   47613             :      * Create and factorize design matrix. Add regularizer if
   47614             :      * factorization failed (happens sometimes with zero
   47615             :      * smoothing and sparsely populated datasets).
   47616             :      *
   47617             :      * The algorithm below is refactoring of NaiveLLS algorithm,
   47618             :      * which uses sparsity properties and compressed block storage.
   47619             :      *
   47620             :      * Problem sparsity pattern results in block-band-diagonal
   47621             :      * matrix (block matrix with limited bandwidth, equal to 3
   47622             :      * for bicubic splines). Thus, we have KY*KY blocks, each
   47623             :      * of them is KX*KX in size. Design matrix is stored in
   47624             :      * large NROWS*KX matrix, with NROWS=(BlockBandwidth+1)*KY*KX.
   47625             :      *
   47626             :      * We use adaptation of block skyline storage format, with
   47627             :      * TOWERSIZE*KX skyline bands (towers) stored sequentially;
   47628             :      * here TOWERSIZE=(BlockBandwidth+1)*KX. So, we have KY
   47629             :      * "towers", stored one below other, in BlockATA matrix.
   47630             :      * Every "tower" is a sequence of BlockBandwidth+1 cells,
   47631             :      * each of them being KX*KX in size.
   47632             :      */
   47633           0 :     lambdachol = spline2d_cholreg;
   47634           0 :     rmatrixsetlengthatleast(&buf->blockata, (blockbandwidth+1)*ky*kx, kx, _state);
   47635             :     for(;;)
   47636             :     {
   47637             :         
   47638             :         /*
   47639             :          * Parallel generation of squared design matrix.
   47640             :          */
   47641           0 :         spline2d_xdesignblockata(xdesign, &buf->blockata, &mxata.val, _state);
   47642             :         
   47643             :         /*
   47644             :          * Regularization
   47645             :          */
   47646           0 :         v = coalesce(mxata.val, 1.0, _state)*lambdachol;
   47647           0 :         for(i1=0; i1<=ky-1; i1++)
   47648             :         {
   47649           0 :             celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i1, _state);
   47650           0 :             for(i0=0; i0<=kx-1; i0++)
   47651             :             {
   47652           0 :                 buf->blockata.ptr.pp_double[celloffset+i0][i0] = buf->blockata.ptr.pp_double[celloffset+i0][i0]+v;
   47653             :             }
   47654             :         }
   47655             :         
   47656             :         /*
   47657             :          * Try Cholesky factorization.
   47658             :          */
   47659           0 :         if( !spline2d_blockllscholesky(&buf->blockata, kx, ky, &buf->trsmbuf2, &buf->cholbuf2, &buf->cholbuf1, _state) )
   47660             :         {
   47661             :             
   47662             :             /*
   47663             :              * Factorization failed, increase regularizer and repeat
   47664             :              */
   47665           0 :             lambdachol = coalesce(10*lambdachol, 1.0E-12, _state);
   47666           0 :             continue;
   47667             :         }
   47668           0 :         break;
   47669             :     }
   47670             :     
   47671             :     /*
   47672             :      * Solve
   47673             :      */
   47674           0 :     rss = 0.0;
   47675           0 :     rep->rmserror = (double)(0);
   47676           0 :     rep->avgerror = (double)(0);
   47677           0 :     rep->maxerror = (double)(0);
   47678           0 :     ae_assert(lsqrcnt>0, "Spline2DFit: integrity failure", _state);
   47679           0 :     rvectorsetlengthatleast(&buf->tmp0, arows, _state);
   47680           0 :     rvectorsetlengthatleast(&buf->tmp1, kx*ky, _state);
   47681           0 :     linlsqrcreatebuf(arows, kx*ky, &buf->solver, _state);
   47682           0 :     for(j=0; j<=d-1; j++)
   47683             :     {
   47684             :         
   47685             :         /*
   47686             :          * Preconditioned LSQR:
   47687             :          *
   47688             :          * use Cholesky factor U of squared design matrix A'*A to
   47689             :          * transform min|A*x-b| to min|[A*inv(U)]*y-b| with y=U*x.
   47690             :          *
   47691             :          * Preconditioned problem is solved with LSQR solver, which
   47692             :          * gives superior results than normal equations.
   47693             :          */
   47694           0 :         for(i=0; i<=arows-1; i++)
   47695             :         {
   47696           0 :             if( i<xdesign->npoints )
   47697             :             {
   47698           0 :                 buf->tmp0.ptr.p_double[i] = xdesign->vals.ptr.pp_double[i][bw2+j];
   47699             :             }
   47700             :             else
   47701             :             {
   47702           0 :                 buf->tmp0.ptr.p_double[i] = 0.0;
   47703             :             }
   47704             :         }
   47705           0 :         linlsqrrestart(&buf->solver, _state);
   47706           0 :         linlsqrsetb(&buf->solver, &buf->tmp0, _state);
   47707           0 :         linlsqrsetcond(&buf->solver, 1.0E-14, 1.0E-14, lsqrcnt, _state);
   47708           0 :         while(linlsqriteration(&buf->solver, _state))
   47709             :         {
   47710           0 :             if( buf->solver.needmv )
   47711             :             {
   47712             :                 
   47713             :                 /*
   47714             :                  * Use Cholesky factorization of the system matrix
   47715             :                  * as preconditioner: solve TRSV(U,Solver.X)
   47716             :                  */
   47717           0 :                 for(i=0; i<=kx*ky-1; i++)
   47718             :                 {
   47719           0 :                     buf->tmp1.ptr.p_double[i] = buf->solver.x.ptr.p_double[i];
   47720             :                 }
   47721           0 :                 spline2d_blockllstrsv(&buf->blockata, kx, ky, ae_false, &buf->tmp1, _state);
   47722             :                 
   47723             :                 /*
   47724             :                  * After preconditioning is done, multiply by A
   47725             :                  */
   47726           0 :                 spline2d_xdesignmv(xdesign, &buf->tmp1, &buf->solver.mv, _state);
   47727             :             }
   47728           0 :             if( buf->solver.needmtv )
   47729             :             {
   47730             :                 
   47731             :                 /*
   47732             :                  * Multiply by design matrix A
   47733             :                  */
   47734           0 :                 spline2d_xdesignmtv(xdesign, &buf->solver.x, &buf->solver.mtv, _state);
   47735             :                 
   47736             :                 /*
   47737             :                  * Multiply by preconditioner: solve TRSV(U',A*Solver.X)
   47738             :                  */
   47739           0 :                 spline2d_blockllstrsv(&buf->blockata, kx, ky, ae_true, &buf->solver.mtv, _state);
   47740             :             }
   47741             :         }
   47742             :         
   47743             :         /*
   47744             :          * Get results and post-multiply by preconditioner to get
   47745             :          * original variables.
   47746             :          */
   47747           0 :         linlsqrresults(&buf->solver, &buf->tmp1, &buf->solverrep, _state);
   47748           0 :         spline2d_blockllstrsv(&buf->blockata, kx, ky, ae_false, &buf->tmp1, _state);
   47749           0 :         for(i=0; i<=kx*ky-1; i++)
   47750             :         {
   47751           0 :             z->ptr.p_double[kx*ky*j+i] = buf->tmp1.ptr.p_double[i];
   47752             :         }
   47753             :         
   47754             :         /*
   47755             :          * Calculate model values
   47756             :          */
   47757           0 :         spline2d_xdesignmv(xdesign, &buf->tmp1, &buf->tmp0, _state);
   47758           0 :         for(i=0; i<=xdesign->npoints-1; i++)
   47759             :         {
   47760           0 :             v = xdesign->vals.ptr.pp_double[i][bw2+j]-buf->tmp0.ptr.p_double[i];
   47761           0 :             rss = rss+v*v;
   47762           0 :             rep->rmserror = rep->rmserror+ae_sqr(v, _state);
   47763           0 :             rep->avgerror = rep->avgerror+ae_fabs(v, _state);
   47764           0 :             rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
   47765             :         }
   47766             :     }
   47767           0 :     rep->rmserror = ae_sqrt(rep->rmserror/coalesce((double)(xdesign->npoints*d), 1.0, _state), _state);
   47768           0 :     rep->avgerror = rep->avgerror/coalesce((double)(xdesign->npoints*d), 1.0, _state);
   47769           0 :     rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state);
   47770           0 :     ae_frame_leave(_state);
   47771           0 : }
   47772             : 
   47773             : 
   47774             : /*************************************************************************
   47775             : This function performs fitting with  NaiveLLS solver.  Internal  function,
   47776             : never use it directly.
   47777             : 
   47778             : INPUT PARAMETERS:
   47779             :     AV      -   sparse matrix, [ARows,KX*KY] in size.  "Vertical"  version
   47780             :                 of design matrix, rows [0,NPoints] contain values of basis
   47781             :                 functions at dataset  points.  Other  rows  are  used  for
   47782             :                 nonlinearity penalty and other stuff like that.
   47783             :     AH      -   transpose(AV), "horizontal" version of AV
   47784             :     ARows   -   rows count
   47785             :     XY      -   array[NPoints*(2+D)], dataset
   47786             :     KX, KY  -   grid size
   47787             :     NPoints -   points count
   47788             :     D       -   number of components in vector-valued spline, D>=1
   47789             :     LSQRCnt -   number of iterations, non-zero:
   47790             :                 * LSQRCnt>0 means that specified amount of  preconditioned
   47791             :                   LSQR  iterations  will  be  performed  to solve problem;
   47792             :                   usually  we  need  2..5  its.  Recommended option - best
   47793             :                   convergence and stability/quality.
   47794             :                 * LSQRCnt<0 means that instead of LSQR  we  use  iterative
   47795             :                   refinement on normal equations. Again, 2..5 its is enough.
   47796             :     Z       -   possibly preallocated buffer for solution
   47797             :     Rep     -   report structure; fields which are not set by this function
   47798             :                 are left intact
   47799             :     TSS     -   total sum of squares; used to calculate R2
   47800             :     
   47801             : 
   47802             : OUTPUT PARAMETERS:
   47803             :     XY      -   destroyed in process
   47804             :     Z       -   array[KX*KY*D], filled by solution; KX*KY coefficients
   47805             :                 corresponding to each of D dimensions are stored contiguously.
   47806             :     Rep     -   following fields are set:
   47807             :                     * Rep.RMSError
   47808             :                     * Rep.AvgError
   47809             :                     * Rep.MaxError
   47810             :                     * Rep.R2
   47811             : 
   47812             :   -- ALGLIB --
   47813             :      Copyright 05.02.2018 by Bochkanov Sergey
   47814             : *************************************************************************/
   47815           0 : static void spline2d_naivellsfit(sparsematrix* av,
   47816             :      sparsematrix* ah,
   47817             :      ae_int_t arows,
   47818             :      /* Real    */ ae_vector* xy,
   47819             :      ae_int_t kx,
   47820             :      ae_int_t ky,
   47821             :      ae_int_t npoints,
   47822             :      ae_int_t d,
   47823             :      ae_int_t lsqrcnt,
   47824             :      /* Real    */ ae_vector* z,
   47825             :      spline2dfitreport* rep,
   47826             :      double tss,
   47827             :      ae_state *_state)
   47828             : {
   47829             :     ae_frame _frame_block;
   47830             :     ae_int_t ew;
   47831             :     ae_int_t i;
   47832             :     ae_int_t j;
   47833             :     ae_int_t i0;
   47834             :     ae_int_t i1;
   47835             :     ae_int_t j0;
   47836             :     ae_int_t j1;
   47837             :     double v;
   47838             :     ae_int_t blockbandwidth;
   47839             :     double lambdareg;
   47840             :     ae_int_t srci;
   47841             :     ae_int_t srcj;
   47842             :     ae_int_t idxi;
   47843             :     ae_int_t idxj;
   47844             :     ae_int_t endi;
   47845             :     ae_int_t endj;
   47846             :     ae_int_t rfsidx;
   47847             :     ae_matrix ata;
   47848             :     ae_vector tmp0;
   47849             :     ae_vector tmp1;
   47850             :     double mxata;
   47851             :     linlsqrstate solver;
   47852             :     linlsqrreport solverrep;
   47853             :     double rss;
   47854             : 
   47855           0 :     ae_frame_make(_state, &_frame_block);
   47856           0 :     memset(&ata, 0, sizeof(ata));
   47857           0 :     memset(&tmp0, 0, sizeof(tmp0));
   47858           0 :     memset(&tmp1, 0, sizeof(tmp1));
   47859           0 :     memset(&solver, 0, sizeof(solver));
   47860           0 :     memset(&solverrep, 0, sizeof(solverrep));
   47861           0 :     ae_matrix_init(&ata, 0, 0, DT_REAL, _state, ae_true);
   47862           0 :     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
   47863           0 :     ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true);
   47864           0 :     _linlsqrstate_init(&solver, _state, ae_true);
   47865           0 :     _linlsqrreport_init(&solverrep, _state, ae_true);
   47866             : 
   47867           0 :     blockbandwidth = 3;
   47868           0 :     ew = 2+d;
   47869             :     
   47870             :     /*
   47871             :      * Initial values for Z/Residuals
   47872             :      */
   47873           0 :     rvectorsetlengthatleast(z, kx*ky*d, _state);
   47874           0 :     for(i=0; i<=kx*ky*d-1; i++)
   47875             :     {
   47876           0 :         z->ptr.p_double[i] = (double)(0);
   47877             :     }
   47878             :     
   47879             :     /*
   47880             :      * Create and factorize design matrix.
   47881             :      *
   47882             :      * Add regularizer if factorization failed (happens sometimes
   47883             :      * with zero smoothing and sparsely populated datasets).
   47884             :      */
   47885           0 :     lambdareg = spline2d_cholreg;
   47886           0 :     rmatrixsetlengthatleast(&ata, kx*ky, kx*ky, _state);
   47887             :     for(;;)
   47888             :     {
   47889           0 :         mxata = 0.0;
   47890           0 :         for(i=0; i<=kx*ky-1; i++)
   47891             :         {
   47892           0 :             for(j=i; j<=kx*ky-1; j++)
   47893             :             {
   47894             :                 
   47895             :                 /*
   47896             :                  * Initialize by zero
   47897             :                  */
   47898           0 :                 ata.ptr.pp_double[i][j] = (double)(0);
   47899             :                 
   47900             :                 /*
   47901             :                  * Determine grid nodes corresponding to I and J;
   47902             :                  * skip if too far away
   47903             :                  */
   47904           0 :                 i0 = i%kx;
   47905           0 :                 i1 = i/kx;
   47906           0 :                 j0 = j%kx;
   47907           0 :                 j1 = j/kx;
   47908           0 :                 if( ae_iabs(i0-j0, _state)>blockbandwidth||ae_iabs(i1-j1, _state)>blockbandwidth )
   47909             :                 {
   47910           0 :                     continue;
   47911             :                 }
   47912             :                 
   47913             :                 /*
   47914             :                  * Nodes are close enough, calculate product of columns I and J of A.
   47915             :                  */
   47916           0 :                 v = (double)(0);
   47917           0 :                 srci = ah->ridx.ptr.p_int[i];
   47918           0 :                 srcj = ah->ridx.ptr.p_int[j];
   47919           0 :                 endi = ah->ridx.ptr.p_int[i+1];
   47920           0 :                 endj = ah->ridx.ptr.p_int[j+1];
   47921             :                 for(;;)
   47922             :                 {
   47923           0 :                     if( srci>=endi||srcj>=endj )
   47924             :                     {
   47925             :                         break;
   47926             :                     }
   47927           0 :                     idxi = ah->idx.ptr.p_int[srci];
   47928           0 :                     idxj = ah->idx.ptr.p_int[srcj];
   47929           0 :                     if( idxi==idxj )
   47930             :                     {
   47931           0 :                         v = v+ah->vals.ptr.p_double[srci]*ah->vals.ptr.p_double[srcj];
   47932           0 :                         srci = srci+1;
   47933           0 :                         srcj = srcj+1;
   47934           0 :                         continue;
   47935             :                     }
   47936           0 :                     if( idxi<idxj )
   47937             :                     {
   47938           0 :                         srci = srci+1;
   47939             :                     }
   47940             :                     else
   47941             :                     {
   47942           0 :                         srcj = srcj+1;
   47943             :                     }
   47944             :                 }
   47945           0 :                 ata.ptr.pp_double[i][j] = v;
   47946           0 :                 mxata = ae_maxreal(mxata, ae_fabs(v, _state), _state);
   47947             :             }
   47948             :         }
   47949           0 :         v = coalesce(mxata, 1.0, _state)*lambdareg;
   47950           0 :         for(i=0; i<=kx*ky-1; i++)
   47951             :         {
   47952           0 :             ata.ptr.pp_double[i][i] = ata.ptr.pp_double[i][i]+v;
   47953             :         }
   47954           0 :         if( spdmatrixcholesky(&ata, kx*ky, ae_true, _state) )
   47955             :         {
   47956             :             
   47957             :             /*
   47958             :              * Success!
   47959             :              */
   47960           0 :             break;
   47961             :         }
   47962             :         
   47963             :         /*
   47964             :          * Factorization failed, increase regularizer and repeat
   47965             :          */
   47966           0 :         lambdareg = coalesce(10*lambdareg, 1.0E-12, _state);
   47967             :     }
   47968             :     
   47969             :     /*
   47970             :      * Solve
   47971             :      *
   47972             :      * NOTE: we expect that Z is zero-filled, and we treat it
   47973             :      *       like initial approximation to solution.
   47974             :      */
   47975           0 :     rvectorsetlengthatleast(&tmp0, arows, _state);
   47976           0 :     rvectorsetlengthatleast(&tmp1, kx*ky, _state);
   47977           0 :     if( lsqrcnt>0 )
   47978             :     {
   47979           0 :         linlsqrcreate(arows, kx*ky, &solver, _state);
   47980             :     }
   47981           0 :     for(j=0; j<=d-1; j++)
   47982             :     {
   47983           0 :         ae_assert(lsqrcnt!=0, "Spline2DFit: integrity failure", _state);
   47984           0 :         if( lsqrcnt>0 )
   47985             :         {
   47986             :             
   47987             :             /*
   47988             :              * Preconditioned LSQR:
   47989             :              *
   47990             :              * use Cholesky factor U of squared design matrix A'*A to
   47991             :              * transform min|A*x-b| to min|[A*inv(U)]*y-b| with y=U*x.
   47992             :              *
   47993             :              * Preconditioned problem is solved with LSQR solver, which
   47994             :              * gives superior results than normal equations.
   47995             :              */
   47996           0 :             linlsqrcreate(arows, kx*ky, &solver, _state);
   47997           0 :             for(i=0; i<=arows-1; i++)
   47998             :             {
   47999           0 :                 if( i<npoints )
   48000             :                 {
   48001           0 :                     tmp0.ptr.p_double[i] = xy->ptr.p_double[i*ew+2+j];
   48002             :                 }
   48003             :                 else
   48004             :                 {
   48005           0 :                     tmp0.ptr.p_double[i] = 0.0;
   48006             :                 }
   48007             :             }
   48008           0 :             linlsqrsetb(&solver, &tmp0, _state);
   48009           0 :             linlsqrsetcond(&solver, 1.0E-14, 1.0E-14, lsqrcnt, _state);
   48010           0 :             while(linlsqriteration(&solver, _state))
   48011             :             {
   48012           0 :                 if( solver.needmv )
   48013             :                 {
   48014             :                     
   48015             :                     /*
   48016             :                      * Use Cholesky factorization of the system matrix
   48017             :                      * as preconditioner: solve TRSV(U,Solver.X)
   48018             :                      */
   48019           0 :                     for(i=0; i<=kx*ky-1; i++)
   48020             :                     {
   48021           0 :                         tmp1.ptr.p_double[i] = solver.x.ptr.p_double[i];
   48022             :                     }
   48023           0 :                     rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 0, &tmp1, 0, _state);
   48024             :                     
   48025             :                     /*
   48026             :                      * After preconditioning is done, multiply by A
   48027             :                      */
   48028           0 :                     sparsemv(av, &tmp1, &solver.mv, _state);
   48029             :                 }
   48030           0 :                 if( solver.needmtv )
   48031             :                 {
   48032             :                     
   48033             :                     /*
   48034             :                      * Multiply by design matrix A
   48035             :                      */
   48036           0 :                     sparsemv(ah, &solver.x, &solver.mtv, _state);
   48037             :                     
   48038             :                     /*
   48039             :                      * Multiply by preconditioner: solve TRSV(U',A*Solver.X)
   48040             :                      */
   48041           0 :                     rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 1, &solver.mtv, 0, _state);
   48042             :                 }
   48043             :             }
   48044           0 :             linlsqrresults(&solver, &tmp1, &solverrep, _state);
   48045           0 :             rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 0, &tmp1, 0, _state);
   48046           0 :             for(i=0; i<=kx*ky-1; i++)
   48047             :             {
   48048           0 :                 z->ptr.p_double[kx*ky*j+i] = tmp1.ptr.p_double[i];
   48049             :             }
   48050             :             
   48051             :             /*
   48052             :              * Calculate model values
   48053             :              */
   48054           0 :             sparsemv(av, &tmp1, &tmp0, _state);
   48055           0 :             for(i=0; i<=npoints-1; i++)
   48056             :             {
   48057           0 :                 xy->ptr.p_double[i*ew+2+j] = xy->ptr.p_double[i*ew+2+j]-tmp0.ptr.p_double[i];
   48058             :             }
   48059             :         }
   48060             :         else
   48061             :         {
   48062             :             
   48063             :             /*
   48064             :              * Iterative refinement, inferior to LSQR
   48065             :              *
   48066             :              * For each dimension D:
   48067             :              * * fetch current estimate for solution from Z to Tmp1
   48068             :              * * calculate residual r for current estimate, store in Tmp0
   48069             :              * * calculate product of residual and design matrix A'*r, store it in Tmp1
   48070             :              * * Cholesky solver
   48071             :              * * update current estimate
   48072             :              */
   48073           0 :             for(rfsidx=1; rfsidx<=-lsqrcnt; rfsidx++)
   48074             :             {
   48075           0 :                 for(i=0; i<=kx*ky-1; i++)
   48076             :                 {
   48077           0 :                     tmp1.ptr.p_double[i] = z->ptr.p_double[kx*ky*j+i];
   48078             :                 }
   48079           0 :                 sparsemv(av, &tmp1, &tmp0, _state);
   48080           0 :                 for(i=0; i<=arows-1; i++)
   48081             :                 {
   48082           0 :                     if( i<npoints )
   48083             :                     {
   48084           0 :                         v = xy->ptr.p_double[i*ew+2+j];
   48085             :                     }
   48086             :                     else
   48087             :                     {
   48088           0 :                         v = (double)(0);
   48089             :                     }
   48090           0 :                     tmp0.ptr.p_double[i] = v-tmp0.ptr.p_double[i];
   48091             :                 }
   48092           0 :                 sparsemv(ah, &tmp0, &tmp1, _state);
   48093           0 :                 rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 1, &tmp1, 0, _state);
   48094           0 :                 rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 0, &tmp1, 0, _state);
   48095           0 :                 for(i=0; i<=kx*ky-1; i++)
   48096             :                 {
   48097           0 :                     z->ptr.p_double[kx*ky*j+i] = z->ptr.p_double[kx*ky*j+i]+tmp1.ptr.p_double[i];
   48098             :                 }
   48099             :             }
   48100             :             
   48101             :             /*
   48102             :              * Calculate model values
   48103             :              */
   48104           0 :             for(i=0; i<=kx*ky-1; i++)
   48105             :             {
   48106           0 :                 tmp1.ptr.p_double[i] = z->ptr.p_double[kx*ky*j+i];
   48107             :             }
   48108           0 :             sparsemv(av, &tmp1, &tmp0, _state);
   48109           0 :             for(i=0; i<=npoints-1; i++)
   48110             :             {
   48111           0 :                 xy->ptr.p_double[i*ew+2+j] = xy->ptr.p_double[i*ew+2+j]-tmp0.ptr.p_double[i];
   48112             :             }
   48113             :         }
   48114             :     }
   48115             :     
   48116             :     /*
   48117             :      * Generate report
   48118             :      */
   48119           0 :     rep->rmserror = (double)(0);
   48120           0 :     rep->avgerror = (double)(0);
   48121           0 :     rep->maxerror = (double)(0);
   48122           0 :     rss = 0.0;
   48123           0 :     for(i=0; i<=npoints-1; i++)
   48124             :     {
   48125           0 :         for(j=0; j<=d-1; j++)
   48126             :         {
   48127           0 :             v = xy->ptr.p_double[i*ew+2+j];
   48128           0 :             rss = rss+v*v;
   48129           0 :             rep->rmserror = rep->rmserror+ae_sqr(v, _state);
   48130           0 :             rep->avgerror = rep->avgerror+ae_fabs(v, _state);
   48131           0 :             rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
   48132             :         }
   48133             :     }
   48134           0 :     rep->rmserror = ae_sqrt(rep->rmserror/coalesce((double)(npoints*d), 1.0, _state), _state);
   48135           0 :     rep->avgerror = rep->avgerror/coalesce((double)(npoints*d), 1.0, _state);
   48136           0 :     rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state);
   48137           0 :     ae_frame_leave(_state);
   48138           0 : }
   48139             : 
   48140             : 
   48141             : /*************************************************************************
   48142             : This  is  convenience  function  for band block storage format; it returns
   48143             : offset of KX*KX-sized block (I,J) in a compressed 2D array.
   48144             : 
   48145             : For specific offset=OFFSET,
   48146             : block (I,J) will be stored in entries BlockMatrix[OFFSET:OFFSET+KX-1,0:KX-1]
   48147             : 
   48148             :   -- ALGLIB --
   48149             :      Copyright 05.02.2018 by Bochkanov Sergey
   48150             : *************************************************************************/
   48151           0 : static ae_int_t spline2d_getcelloffset(ae_int_t kx,
   48152             :      ae_int_t ky,
   48153             :      ae_int_t blockbandwidth,
   48154             :      ae_int_t i,
   48155             :      ae_int_t j,
   48156             :      ae_state *_state)
   48157             : {
   48158             :     ae_int_t result;
   48159             : 
   48160             : 
   48161           0 :     ae_assert(i>=0&&i<ky, "Spline2DFit: GetCellOffset() integrity error", _state);
   48162           0 :     ae_assert(j>=0&&j<ky, "Spline2DFit: GetCellOffset() integrity error", _state);
   48163           0 :     ae_assert(j>=i&&j<=i+blockbandwidth, "Spline2DFit: GetCellOffset() integrity error", _state);
   48164           0 :     result = j*(blockbandwidth+1)*kx;
   48165           0 :     result = result+(blockbandwidth-(j-i))*kx;
   48166           0 :     return result;
   48167             : }
   48168             : 
   48169             : 
   48170             : /*************************************************************************
   48171             : This  is  convenience  function  for band block storage format; it  copies
   48172             : cell (I,J) from compressed format to uncompressed general matrix, at desired
   48173             : position.
   48174             : 
   48175             :   -- ALGLIB --
   48176             :      Copyright 05.02.2018 by Bochkanov Sergey
   48177             : *************************************************************************/
   48178           0 : static void spline2d_copycellto(ae_int_t kx,
   48179             :      ae_int_t ky,
   48180             :      ae_int_t blockbandwidth,
   48181             :      /* Real    */ ae_matrix* blockata,
   48182             :      ae_int_t i,
   48183             :      ae_int_t j,
   48184             :      /* Real    */ ae_matrix* dst,
   48185             :      ae_int_t dst0,
   48186             :      ae_int_t dst1,
   48187             :      ae_state *_state)
   48188             : {
   48189             :     ae_int_t celloffset;
   48190             :     ae_int_t idx0;
   48191             :     ae_int_t idx1;
   48192             : 
   48193             : 
   48194           0 :     celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i, j, _state);
   48195           0 :     for(idx0=0; idx0<=kx-1; idx0++)
   48196             :     {
   48197           0 :         for(idx1=0; idx1<=kx-1; idx1++)
   48198             :         {
   48199           0 :             dst->ptr.pp_double[dst0+idx0][dst1+idx1] = blockata->ptr.pp_double[celloffset+idx0][idx1];
   48200             :         }
   48201             :     }
   48202           0 : }
   48203             : 
   48204             : 
   48205             : /*************************************************************************
   48206             : This  is  convenience  function  for band block storage format; it
   48207             : truncates all elements of  cell (I,J) which are less than Eps in magnitude.
   48208             : 
   48209             :   -- ALGLIB --
   48210             :      Copyright 05.02.2018 by Bochkanov Sergey
   48211             : *************************************************************************/
   48212           0 : static void spline2d_flushtozerocell(ae_int_t kx,
   48213             :      ae_int_t ky,
   48214             :      ae_int_t blockbandwidth,
   48215             :      /* Real    */ ae_matrix* blockata,
   48216             :      ae_int_t i,
   48217             :      ae_int_t j,
   48218             :      double eps,
   48219             :      ae_state *_state)
   48220             : {
   48221             :     ae_int_t celloffset;
   48222             :     ae_int_t idx0;
   48223             :     ae_int_t idx1;
   48224             :     double eps2;
   48225             :     double v;
   48226             : 
   48227             : 
   48228           0 :     celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i, j, _state);
   48229           0 :     eps2 = eps*eps;
   48230           0 :     for(idx0=0; idx0<=kx-1; idx0++)
   48231             :     {
   48232           0 :         for(idx1=0; idx1<=kx-1; idx1++)
   48233             :         {
   48234           0 :             v = blockata->ptr.pp_double[celloffset+idx0][idx1];
   48235           0 :             if( v*v<eps2 )
   48236             :             {
   48237           0 :                 blockata->ptr.pp_double[celloffset+idx0][idx1] = (double)(0);
   48238             :             }
   48239             :         }
   48240             :     }
   48241           0 : }
   48242             : 
   48243             : 
   48244             : /*************************************************************************
   48245             : This function generates squared design matrix stored in block band format.
   48246             : 
   48247             : We use adaptation of block skyline storage format, with
   48248             : TOWERSIZE*KX skyline bands (towers) stored sequentially;
   48249             : here TOWERSIZE=(BlockBandwidth+1)*KX. So, we have KY
   48250             : "towers", stored one below other, in BlockATA matrix.
   48251             : Every "tower" is a sequence of BlockBandwidth+1 cells,
   48252             : each of them being KX*KX in size.
   48253             : 
   48254             : INPUT PARAMETERS:
   48255             :     AH      -   sparse matrix, [KX*KY,ARows] in size. "Horizontal" version
   48256             :                 of design matrix, cols [0,NPoints] contain values of basis
   48257             :                 functions at dataset  points.  Other  cols  are  used  for
   48258             :                 nonlinearity penalty and other stuff like that.
   48259             :     KY0, KY1-   subset of output matrix bands to process; on entry it MUST
   48260             :                 be set to 0 and KY respectively.
   48261             :     KX, KY  -   grid size
   48262             :     BlockATA-   array[KY*(BlockBandwidth+1)*KX,KX],  preallocated  storage
   48263             :                 for output matrix in compressed block band format
   48264             :     MXATA   -   on entry MUST be zero
   48265             : 
   48266             : OUTPUT PARAMETERS:
   48267             :     BlockATA-   AH*AH', stored in compressed block band format
   48268             : 
   48269             :   -- ALGLIB --
   48270             :      Copyright 05.02.2018 by Bochkanov Sergey
   48271             : *************************************************************************/
   48272           0 : static void spline2d_blockllsgenerateata(sparsematrix* ah,
   48273             :      ae_int_t ky0,
   48274             :      ae_int_t ky1,
   48275             :      ae_int_t kx,
   48276             :      ae_int_t ky,
   48277             :      /* Real    */ ae_matrix* blockata,
   48278             :      sreal* mxata,
   48279             :      ae_state *_state)
   48280             : {
   48281             :     ae_frame _frame_block;
   48282             :     ae_int_t blockbandwidth;
   48283             :     double avgrowlen;
   48284             :     double cellcost;
   48285             :     double totalcost;
   48286             :     sreal tmpmxata;
   48287             :     ae_int_t i;
   48288             :     ae_int_t j;
   48289             :     ae_int_t i0;
   48290             :     ae_int_t i1;
   48291             :     ae_int_t j0;
   48292             :     ae_int_t j1;
   48293             :     ae_int_t celloffset;
   48294             :     double v;
   48295             :     ae_int_t srci;
   48296             :     ae_int_t srcj;
   48297             :     ae_int_t idxi;
   48298             :     ae_int_t idxj;
   48299             :     ae_int_t endi;
   48300             :     ae_int_t endj;
   48301             : 
   48302           0 :     ae_frame_make(_state, &_frame_block);
   48303           0 :     memset(&tmpmxata, 0, sizeof(tmpmxata));
   48304           0 :     _sreal_init(&tmpmxata, _state, ae_true);
   48305             : 
   48306           0 :     ae_assert(ae_fp_greater_eq(mxata->val,(double)(0)), "BlockLLSGenerateATA: integrity check failed", _state);
   48307           0 :     blockbandwidth = 3;
   48308             :     
   48309             :     /*
   48310             :      * Determine problem cost, perform recursive subdivision
   48311             :      * (with optional parallelization)
   48312             :      */
   48313           0 :     avgrowlen = (double)ah->ridx.ptr.p_int[kx*ky]/(double)(kx*ky);
   48314           0 :     cellcost = rmul3((double)(kx), (double)(1+2*blockbandwidth), avgrowlen, _state);
   48315           0 :     totalcost = rmul3((double)(ky1-ky0), (double)(1+2*blockbandwidth), cellcost, _state);
   48316           0 :     if( ky1-ky0>=2&&ae_fp_greater(totalcost,smpactivationlevel(_state)) )
   48317             :     {
   48318           0 :         if( _trypexec_spline2d_blockllsgenerateata(ah,ky0,ky1,kx,ky,blockata,mxata, _state) )
   48319             :         {
   48320           0 :             ae_frame_leave(_state);
   48321           0 :             return;
   48322             :         }
   48323             :     }
   48324           0 :     if( ky1-ky0>=2 )
   48325             :     {
   48326             :         
   48327             :         /*
   48328             :          * Split X: X*A = (X1 X2)^T*A
   48329             :          */
   48330           0 :         j = (ky1-ky0)/2;
   48331           0 :         spline2d_blockllsgenerateata(ah, ky0, ky0+j, kx, ky, blockata, &tmpmxata, _state);
   48332           0 :         spline2d_blockllsgenerateata(ah, ky0+j, ky1, kx, ky, blockata, mxata, _state);
   48333           0 :         mxata->val = ae_maxreal(mxata->val, tmpmxata.val, _state);
   48334           0 :         ae_frame_leave(_state);
   48335           0 :         return;
   48336             :     }
   48337             :     
   48338             :     /*
   48339             :      * Splitting in Y-dimension is done, fill I1-th "tower"
   48340             :      */
   48341           0 :     ae_assert(ky1==ky0+1, "BlockLLSGenerateATA: integrity check failed", _state);
   48342           0 :     i1 = ky0;
   48343           0 :     for(j1=i1; j1<=ae_minint(ky-1, i1+blockbandwidth, _state); j1++)
   48344             :     {
   48345           0 :         celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, j1, _state);
   48346             :         
   48347             :         /*
   48348             :          * Clear cell (I1,J1)
   48349             :          */
   48350           0 :         for(i0=0; i0<=kx-1; i0++)
   48351             :         {
   48352           0 :             for(j0=0; j0<=kx-1; j0++)
   48353             :             {
   48354           0 :                 blockata->ptr.pp_double[celloffset+i0][j0] = 0.0;
   48355             :             }
   48356             :         }
   48357             :         
   48358             :         /*
   48359             :          * Initialize cell internals
   48360             :          */
   48361           0 :         for(i0=0; i0<=kx-1; i0++)
   48362             :         {
   48363           0 :             for(j0=0; j0<=kx-1; j0++)
   48364             :             {
   48365           0 :                 if( ae_iabs(i0-j0, _state)<=blockbandwidth )
   48366             :                 {
   48367             :                     
   48368             :                     /*
   48369             :                      * Nodes are close enough, calculate product of columns I and J of A.
   48370             :                      */
   48371           0 :                     v = (double)(0);
   48372           0 :                     i = i1*kx+i0;
   48373           0 :                     j = j1*kx+j0;
   48374           0 :                     srci = ah->ridx.ptr.p_int[i];
   48375           0 :                     srcj = ah->ridx.ptr.p_int[j];
   48376           0 :                     endi = ah->ridx.ptr.p_int[i+1];
   48377           0 :                     endj = ah->ridx.ptr.p_int[j+1];
   48378             :                     for(;;)
   48379             :                     {
   48380           0 :                         if( srci>=endi||srcj>=endj )
   48381             :                         {
   48382             :                             break;
   48383             :                         }
   48384           0 :                         idxi = ah->idx.ptr.p_int[srci];
   48385           0 :                         idxj = ah->idx.ptr.p_int[srcj];
   48386           0 :                         if( idxi==idxj )
   48387             :                         {
   48388           0 :                             v = v+ah->vals.ptr.p_double[srci]*ah->vals.ptr.p_double[srcj];
   48389           0 :                             srci = srci+1;
   48390           0 :                             srcj = srcj+1;
   48391           0 :                             continue;
   48392             :                         }
   48393           0 :                         if( idxi<idxj )
   48394             :                         {
   48395           0 :                             srci = srci+1;
   48396             :                         }
   48397             :                         else
   48398             :                         {
   48399           0 :                             srcj = srcj+1;
   48400             :                         }
   48401             :                     }
   48402           0 :                     blockata->ptr.pp_double[celloffset+i0][j0] = v;
   48403           0 :                     mxata->val = ae_maxreal(mxata->val, ae_fabs(v, _state), _state);
   48404             :                 }
   48405             :             }
   48406             :         }
   48407             :     }
   48408           0 :     ae_frame_leave(_state);
   48409             : }
   48410             : 
   48411             : 
   48412             : /*************************************************************************
   48413             : Serial stub for GPL edition.
   48414             : *************************************************************************/
   48415           0 : ae_bool _trypexec_spline2d_blockllsgenerateata(sparsematrix* ah,
   48416             :     ae_int_t ky0,
   48417             :     ae_int_t ky1,
   48418             :     ae_int_t kx,
   48419             :     ae_int_t ky,
   48420             :     /* Real    */ ae_matrix* blockata,
   48421             :     sreal* mxata,
   48422             :     ae_state *_state)
   48423             : {
   48424           0 :     return ae_false;
   48425             : }
   48426             : 
   48427             : 
   48428             : /*************************************************************************
   48429             : This function performs Cholesky decomposition of squared design matrix
   48430             : stored in block band format.
   48431             : 
   48432             : INPUT PARAMETERS:
   48433             :     BlockATA        -   array[KY*(BlockBandwidth+1)*KX,KX], matrix in compressed
   48434             :                         block band format
   48435             :     KX, KY          -   grid size
   48436             :     TrsmBuf2,
   48437             :     CholBuf2,
   48438             :     CholBuf1        -   buffers; reused by this function on subsequent calls,
   48439             :                         automatically preallocated on the first call
   48440             : 
   48441             : OUTPUT PARAMETERS:
   48442             :     BlockATA-   Cholesky factor, in compressed block band format
   48443             : 
   48444             : Result:
   48445             :     True on success, False on Cholesky failure
   48446             : 
   48447             :   -- ALGLIB --
   48448             :      Copyright 05.02.2018 by Bochkanov Sergey
   48449             : *************************************************************************/
   48450           0 : static ae_bool spline2d_blockllscholesky(/* Real    */ ae_matrix* blockata,
   48451             :      ae_int_t kx,
   48452             :      ae_int_t ky,
   48453             :      /* Real    */ ae_matrix* trsmbuf2,
   48454             :      /* Real    */ ae_matrix* cholbuf2,
   48455             :      /* Real    */ ae_vector* cholbuf1,
   48456             :      ae_state *_state)
   48457             : {
   48458             :     ae_int_t blockbandwidth;
   48459             :     ae_int_t blockidx;
   48460             :     ae_int_t i;
   48461             :     ae_int_t j;
   48462             :     ae_int_t celloffset;
   48463             :     ae_int_t celloffset1;
   48464             :     ae_bool result;
   48465             : 
   48466             : 
   48467           0 :     blockbandwidth = 3;
   48468           0 :     rmatrixsetlengthatleast(trsmbuf2, (blockbandwidth+1)*kx, (blockbandwidth+1)*kx, _state);
   48469           0 :     rmatrixsetlengthatleast(cholbuf2, kx, kx, _state);
   48470           0 :     rvectorsetlengthatleast(cholbuf1, kx, _state);
   48471           0 :     result = ae_true;
   48472           0 :     for(blockidx=0; blockidx<=ky-1; blockidx++)
   48473             :     {
   48474             :         
   48475             :         /*
   48476             :          * TRSM for TRAIL*TRAIL block matrix before current cell;
   48477             :          * here TRAIL=MinInt(BlockIdx,BlockBandwidth).
   48478             :          */
   48479           0 :         for(i=0; i<=ae_minint(blockidx, blockbandwidth, _state)-1; i++)
   48480             :         {
   48481           0 :             for(j=i; j<=ae_minint(blockidx, blockbandwidth, _state)-1; j++)
   48482             :             {
   48483           0 :                 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);
   48484             :             }
   48485             :         }
   48486           0 :         celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, ae_maxint(blockidx-blockbandwidth, 0, _state), blockidx, _state);
   48487           0 :         rmatrixlefttrsm(ae_minint(blockidx, blockbandwidth, _state)*kx, kx, trsmbuf2, 0, 0, ae_true, ae_false, 1, blockata, celloffset, 0, _state);
   48488             :         
   48489             :         /*
   48490             :          * SYRK for diagonal cell: MaxInt(BlockIdx-BlockBandwidth,0)
   48491             :          * cells above diagonal one are used for update.
   48492             :          */
   48493           0 :         celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, ae_maxint(blockidx-blockbandwidth, 0, _state), blockidx, _state);
   48494           0 :         celloffset1 = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state);
   48495           0 :         rmatrixsyrk(kx, ae_minint(blockidx, blockbandwidth, _state)*kx, -1.0, blockata, celloffset, 0, 1, 1.0, blockata, celloffset1, 0, ae_true, _state);
   48496             :         
   48497             :         /*
   48498             :          * Factorize diagonal cell
   48499             :          */
   48500           0 :         celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state);
   48501           0 :         rmatrixcopy(kx, kx, blockata, celloffset, 0, cholbuf2, 0, 0, _state);
   48502           0 :         if( !spdmatrixcholeskyrec(cholbuf2, 0, kx, ae_true, cholbuf1, _state) )
   48503             :         {
   48504           0 :             result = ae_false;
   48505           0 :             return result;
   48506             :         }
   48507           0 :         rmatrixcopy(kx, kx, cholbuf2, 0, 0, blockata, celloffset, 0, _state);
   48508             :         
   48509             :         /*
   48510             :          * PERFORMANCE TWEAK: drop nearly-denormals from last "tower".
   48511             :          *
   48512             :          * Sparse matrices like these may produce denormal numbers on
   48513             :          * sparse datasets, with significant (10x!) performance penalty
   48514             :          * on Intel chips. In order to avoid it, we manually truncate
   48515             :          * small enough numbers.
   48516             :          *
   48517             :          * We use 1.0E-50 as clipping level (not really denormal, but
   48518             :          * such small numbers are not actually important anyway).
   48519             :          */
   48520           0 :         for(i=ae_maxint(blockidx-blockbandwidth, 0, _state); i<=blockidx; i++)
   48521             :         {
   48522           0 :             spline2d_flushtozerocell(kx, ky, blockbandwidth, blockata, i, blockidx, 1.0E-50, _state);
   48523             :         }
   48524             :     }
   48525           0 :     return result;
   48526             : }
   48527             : 
   48528             : 
   48529             : /*************************************************************************
   48530             : This function performs TRSV on upper triangular Cholesky factor U, solving
   48531             : either U*x=b or U'*x=b.
   48532             : 
   48533             : INPUT PARAMETERS:
   48534             :     BlockATA        -   array[KY*(BlockBandwidth+1)*KX,KX], matrix U
   48535             :                         in compressed block band format
   48536             :     KX, KY          -   grid size
   48537             :     TransU          -   whether to transpose U or not
   48538             :     B               -   array[KX*KY], on entry - stores right part B
   48539             : 
   48540             : OUTPUT PARAMETERS:
   48541             :     B               -   replaced by X
   48542             : 
   48543             :   -- ALGLIB --
   48544             :      Copyright 05.02.2018 by Bochkanov Sergey
   48545             : *************************************************************************/
   48546           0 : static void spline2d_blockllstrsv(/* Real    */ ae_matrix* blockata,
   48547             :      ae_int_t kx,
   48548             :      ae_int_t ky,
   48549             :      ae_bool transu,
   48550             :      /* Real    */ ae_vector* b,
   48551             :      ae_state *_state)
   48552             : {
   48553             :     ae_int_t blockbandwidth;
   48554             :     ae_int_t blockidx;
   48555             :     ae_int_t blockidx1;
   48556             :     ae_int_t celloffset;
   48557             : 
   48558             : 
   48559           0 :     blockbandwidth = 3;
   48560           0 :     if( !transu )
   48561             :     {
   48562             :         
   48563             :         /*
   48564             :          * Solve U*x=b
   48565             :          */
   48566           0 :         for(blockidx=ky-1; blockidx>=0; blockidx--)
   48567             :         {
   48568           0 :             for(blockidx1=1; blockidx1<=ae_minint(ky-(blockidx+1), blockbandwidth, _state); blockidx1++)
   48569             :             {
   48570           0 :                 celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx+blockidx1, _state);
   48571           0 :                 rmatrixgemv(kx, kx, -1.0, blockata, celloffset, 0, 0, b, (blockidx+blockidx1)*kx, 1.0, b, blockidx*kx, _state);
   48572             :             }
   48573           0 :             celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state);
   48574           0 :             rmatrixtrsv(kx, blockata, celloffset, 0, ae_true, ae_false, 0, b, blockidx*kx, _state);
   48575             :         }
   48576             :     }
   48577             :     else
   48578             :     {
   48579             :         
   48580             :         /*
   48581             :          * Solve U'*x=b
   48582             :          */
   48583           0 :         for(blockidx=0; blockidx<=ky-1; blockidx++)
   48584             :         {
   48585           0 :             celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state);
   48586           0 :             rmatrixtrsv(kx, blockata, celloffset, 0, ae_true, ae_false, 1, b, blockidx*kx, _state);
   48587           0 :             for(blockidx1=1; blockidx1<=ae_minint(ky-(blockidx+1), blockbandwidth, _state); blockidx1++)
   48588             :             {
   48589           0 :                 celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx+blockidx1, _state);
   48590           0 :                 rmatrixgemv(kx, kx, -1.0, blockata, celloffset, 0, 1, b, blockidx*kx, 1.0, b, (blockidx+blockidx1)*kx, _state);
   48591             :             }
   48592             :         }
   48593             :     }
   48594           0 : }
   48595             : 
   48596             : 
   48597             : /*************************************************************************
   48598             : This function computes residuals for dataset XY[], using array of original
   48599             : values YRaw[], and loads residuals to XY.
   48600             : 
   48601             : Processing is performed in parallel manner.
   48602             : 
   48603             :   -- ALGLIB --
   48604             :      Copyright 05.02.2018 by Bochkanov Sergey
   48605             : *************************************************************************/
   48606           0 : static void spline2d_computeresidualsfromscratch(/* Real    */ ae_vector* xy,
   48607             :      /* Real    */ ae_vector* yraw,
   48608             :      ae_int_t npoints,
   48609             :      ae_int_t d,
   48610             :      ae_int_t scalexy,
   48611             :      spline2dinterpolant* spline,
   48612             :      ae_state *_state)
   48613             : {
   48614             :     ae_frame _frame_block;
   48615             :     srealarray seed;
   48616             :     ae_shared_pool pool;
   48617             :     ae_int_t chunksize;
   48618             :     double pointcost;
   48619             : 
   48620           0 :     ae_frame_make(_state, &_frame_block);
   48621           0 :     memset(&seed, 0, sizeof(seed));
   48622           0 :     memset(&pool, 0, sizeof(pool));
   48623           0 :     _srealarray_init(&seed, _state, ae_true);
   48624           0 :     ae_shared_pool_init(&pool, _state, ae_true);
   48625             : 
   48626             :     
   48627             :     /*
   48628             :      * Setting up
   48629             :      */
   48630           0 :     chunksize = 1000;
   48631           0 :     pointcost = 100.0;
   48632           0 :     if( ae_fp_greater(npoints*pointcost,smpactivationlevel(_state)) )
   48633             :     {
   48634           0 :         if( _trypexec_spline2d_computeresidualsfromscratch(xy,yraw,npoints,d,scalexy,spline, _state) )
   48635             :         {
   48636           0 :             ae_frame_leave(_state);
   48637           0 :             return;
   48638             :         }
   48639             :     }
   48640           0 :     ae_shared_pool_set_seed(&pool, &seed, sizeof(seed), _srealarray_init, _srealarray_init_copy, _srealarray_destroy, _state);
   48641             :     
   48642             :     /*
   48643             :      * Call compute workhorse
   48644             :      */
   48645           0 :     spline2d_computeresidualsfromscratchrec(xy, yraw, 0, npoints, chunksize, d, scalexy, spline, &pool, _state);
   48646           0 :     ae_frame_leave(_state);
   48647             : }
   48648             : 
   48649             : 
   48650             : /*************************************************************************
   48651             : Serial stub for GPL edition.
   48652             : *************************************************************************/
   48653           0 : ae_bool _trypexec_spline2d_computeresidualsfromscratch(/* Real    */ ae_vector* xy,
   48654             :     /* Real    */ ae_vector* yraw,
   48655             :     ae_int_t npoints,
   48656             :     ae_int_t d,
   48657             :     ae_int_t scalexy,
   48658             :     spline2dinterpolant* spline,
   48659             :     ae_state *_state)
   48660             : {
   48661           0 :     return ae_false;
   48662             : }
   48663             : 
   48664             : 
   48665             : /*************************************************************************
   48666             : Recursive workhorse for ComputeResidualsFromScratch.
   48667             : 
   48668             :   -- ALGLIB --
   48669             :      Copyright 05.02.2018 by Bochkanov Sergey
   48670             : *************************************************************************/
   48671           0 : static void spline2d_computeresidualsfromscratchrec(/* Real    */ ae_vector* xy,
   48672             :      /* Real    */ ae_vector* yraw,
   48673             :      ae_int_t pt0,
   48674             :      ae_int_t pt1,
   48675             :      ae_int_t chunksize,
   48676             :      ae_int_t d,
   48677             :      ae_int_t scalexy,
   48678             :      spline2dinterpolant* spline,
   48679             :      ae_shared_pool* pool,
   48680             :      ae_state *_state)
   48681             : {
   48682             :     ae_frame _frame_block;
   48683             :     ae_int_t i;
   48684             :     ae_int_t j;
   48685             :     srealarray *pbuf;
   48686             :     ae_smart_ptr _pbuf;
   48687             :     ae_int_t xew;
   48688             : 
   48689           0 :     ae_frame_make(_state, &_frame_block);
   48690           0 :     memset(&_pbuf, 0, sizeof(_pbuf));
   48691           0 :     ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state, ae_true);
   48692             : 
   48693           0 :     xew = 2+d;
   48694             :     
   48695             :     /*
   48696             :      * Parallelism
   48697             :      */
   48698           0 :     if( pt1-pt0>chunksize )
   48699             :     {
   48700           0 :         tiledsplit(pt1-pt0, chunksize, &i, &j, _state);
   48701           0 :         spline2d_computeresidualsfromscratchrec(xy, yraw, pt0, pt0+i, chunksize, d, scalexy, spline, pool, _state);
   48702           0 :         spline2d_computeresidualsfromscratchrec(xy, yraw, pt0+i, pt1, chunksize, d, scalexy, spline, pool, _state);
   48703           0 :         ae_frame_leave(_state);
   48704           0 :         return;
   48705             :     }
   48706             :     
   48707             :     /*
   48708             :      * Serial execution
   48709             :      */
   48710           0 :     ae_shared_pool_retrieve(pool, &_pbuf, _state);
   48711           0 :     for(i=pt0; i<=pt1-1; i++)
   48712             :     {
   48713           0 :         spline2dcalcvbuf(spline, xy->ptr.p_double[i*xew+0]*scalexy, xy->ptr.p_double[i*xew+1]*scalexy, &pbuf->val, _state);
   48714           0 :         for(j=0; j<=d-1; j++)
   48715             :         {
   48716           0 :             xy->ptr.p_double[i*xew+2+j] = yraw->ptr.p_double[i*d+j]-pbuf->val.ptr.p_double[j];
   48717             :         }
   48718             :     }
   48719           0 :     ae_shared_pool_recycle(pool, &_pbuf, _state);
   48720           0 :     ae_frame_leave(_state);
   48721             : }
   48722             : 
   48723             : 
   48724             : /*************************************************************************
   48725             : Serial stub for GPL edition.
   48726             : *************************************************************************/
   48727           0 : ae_bool _trypexec_spline2d_computeresidualsfromscratchrec(/* Real    */ ae_vector* xy,
   48728             :     /* Real    */ ae_vector* yraw,
   48729             :     ae_int_t pt0,
   48730             :     ae_int_t pt1,
   48731             :     ae_int_t chunksize,
   48732             :     ae_int_t d,
   48733             :     ae_int_t scalexy,
   48734             :     spline2dinterpolant* spline,
   48735             :     ae_shared_pool* pool,
   48736             :     ae_state *_state)
   48737             : {
   48738           0 :     return ae_false;
   48739             : }
   48740             : 
   48741             : 
   48742             : /*************************************************************************
   48743             : This function reorders dataset and builds index:
   48744             : * it is assumed that all points have X in [0,KX-1], Y in [0,KY-1]
   48745             : * area is divided into (KX-1)*(KY-1) cells
   48746             : * all points are reordered in such way that points in same cell are stored
   48747             :   contiguously
   48748             : * dataset index, array[(KX-1)*(KY-1)+1], is generated. Points of cell I
   48749             :   now have indexes XYIndex[I]..XYIndex[I+1]-1;
   48750             : 
   48751             : INPUT PARAMETERS:
   48752             :     XY              -   array[NPoints*(2+D)], dataset
   48753             :     KX, KY, D       -   grid size and dimensionality of the outputs
   48754             :     Shadow          -   shadow array[NPoints*NS], which is sorted together
   48755             :                         with XY; if NS=0, it is not referenced at all.
   48756             :     NS              -   entry width of shadow array
   48757             :     BufI            -   possibly preallocated temporary buffer; resized if
   48758             :                         needed.
   48759             : 
   48760             : OUTPUT PARAMETERS:
   48761             :     XY              -   reordered
   48762             :     XYIndex         -   array[(KX-1)*(KY-1)+1], dataset index
   48763             : 
   48764             :   -- ALGLIB --
   48765             :      Copyright 05.02.2018 by Bochkanov Sergey
   48766             : *************************************************************************/
   48767           0 : static void spline2d_reorderdatasetandbuildindex(/* Real    */ ae_vector* xy,
   48768             :      ae_int_t npoints,
   48769             :      ae_int_t d,
   48770             :      /* Real    */ ae_vector* shadow,
   48771             :      ae_int_t ns,
   48772             :      ae_int_t kx,
   48773             :      ae_int_t ky,
   48774             :      /* Integer */ ae_vector* xyindex,
   48775             :      /* Integer */ ae_vector* bufi,
   48776             :      ae_state *_state)
   48777             : {
   48778             :     ae_int_t i;
   48779             :     ae_int_t i0;
   48780             :     ae_int_t i1;
   48781             :     ae_int_t entrywidth;
   48782             : 
   48783             : 
   48784             :     
   48785             :     /*
   48786             :      * Set up
   48787             :      */
   48788           0 :     ae_assert(kx>=2, "Spline2DFit.ReorderDatasetAndBuildIndex: integrity check failed", _state);
   48789           0 :     ae_assert(ky>=2, "Spline2DFit.ReorderDatasetAndBuildIndex: integrity check failed", _state);
   48790           0 :     entrywidth = 2+d;
   48791           0 :     ivectorsetlengthatleast(xyindex, (kx-1)*(ky-1)+1, _state);
   48792           0 :     ivectorsetlengthatleast(bufi, npoints, _state);
   48793           0 :     for(i=0; i<=npoints-1; i++)
   48794             :     {
   48795           0 :         i0 = iboundval(ae_ifloor(xy->ptr.p_double[i*entrywidth+0], _state), 0, kx-2, _state);
   48796           0 :         i1 = iboundval(ae_ifloor(xy->ptr.p_double[i*entrywidth+1], _state), 0, ky-2, _state);
   48797           0 :         bufi->ptr.p_int[i] = i1*(kx-1)+i0;
   48798             :     }
   48799             :     
   48800             :     /*
   48801             :      * Reorder
   48802             :      */
   48803           0 :     spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, bufi, 0, npoints, xyindex, 0, (kx-1)*(ky-1), ae_true, _state);
   48804           0 :     xyindex->ptr.p_int[(kx-1)*(ky-1)] = npoints;
   48805           0 : }
   48806             : 
   48807             : 
   48808             : /*************************************************************************
   48809             : This function multiplies all points in dataset by 2.0 and rebuilds  index,
   48810             : given previous index built for KX_prev=(KX-1)/2 and KY_prev=(KY-1)/2
   48811             : 
   48812             : INPUT PARAMETERS:
   48813             :     XY              -   array[NPoints*(2+D)], dataset BEFORE scaling
   48814             :     NPoints, D      -   dataset size and dimensionality of the outputs
   48815             :     Shadow          -   shadow array[NPoints*NS], which is sorted together
   48816             :                         with XY; if NS=0, it is not referenced at all.
   48817             :     NS              -   entry width of shadow array
   48818             :     KX, KY          -   new grid dimensionality
   48819             :     XYIndex         -   index built for previous values of KX and KY
   48820             :     BufI            -   possibly preallocated temporary buffer; resized if
   48821             :                         needed.
   48822             : 
   48823             : OUTPUT PARAMETERS:
   48824             :     XY              -   reordered and multiplied by 2.0
   48825             :     XYIndex         -   array[(KX-1)*(KY-1)+1], dataset index
   48826             : 
   48827             :   -- ALGLIB --
   48828             :      Copyright 05.02.2018 by Bochkanov Sergey
   48829             : *************************************************************************/
   48830           0 : static void spline2d_rescaledatasetandrefineindex(/* Real    */ ae_vector* xy,
   48831             :      ae_int_t npoints,
   48832             :      ae_int_t d,
   48833             :      /* Real    */ ae_vector* shadow,
   48834             :      ae_int_t ns,
   48835             :      ae_int_t kx,
   48836             :      ae_int_t ky,
   48837             :      /* Integer */ ae_vector* xyindex,
   48838             :      /* Integer */ ae_vector* bufi,
   48839             :      ae_state *_state)
   48840             : {
   48841             :     ae_frame _frame_block;
   48842             :     ae_vector xyindexprev;
   48843             : 
   48844           0 :     ae_frame_make(_state, &_frame_block);
   48845           0 :     memset(&xyindexprev, 0, sizeof(xyindexprev));
   48846           0 :     ae_vector_init(&xyindexprev, 0, DT_INT, _state, ae_true);
   48847             : 
   48848             :     
   48849             :     /*
   48850             :      * Set up
   48851             :      */
   48852           0 :     ae_assert(kx>=2, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state);
   48853           0 :     ae_assert(ky>=2, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state);
   48854           0 :     ae_assert((kx-1)%2==0, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state);
   48855           0 :     ae_assert((ky-1)%2==0, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state);
   48856           0 :     ae_swap_vectors(xyindex, &xyindexprev);
   48857           0 :     ivectorsetlengthatleast(xyindex, (kx-1)*(ky-1)+1, _state);
   48858           0 :     ivectorsetlengthatleast(bufi, npoints, _state);
   48859             :     
   48860             :     /*
   48861             :      * Refine
   48862             :      */
   48863           0 :     spline2d_expandindexrows(xy, d, shadow, ns, bufi, 0, npoints, &xyindexprev, 0, (ky+1)/2-1, xyindex, kx, ky, ae_true, _state);
   48864           0 :     xyindex->ptr.p_int[(kx-1)*(ky-1)] = npoints;
   48865             :     
   48866             :     /*
   48867             :      * Integrity check
   48868             :      */
   48869           0 :     ae_frame_leave(_state);
   48870           0 : }
   48871             : 
   48872             : 
   48873             : /*************************************************************************
   48874             : Recurrent divide-and-conquer indexing function
   48875             : 
   48876             :   -- ALGLIB --
   48877             :      Copyright 05.02.2018 by Bochkanov Sergey
   48878             : *************************************************************************/
   48879           0 : static void spline2d_expandindexrows(/* Real    */ ae_vector* xy,
   48880             :      ae_int_t d,
   48881             :      /* Real    */ ae_vector* shadow,
   48882             :      ae_int_t ns,
   48883             :      /* Integer */ ae_vector* cidx,
   48884             :      ae_int_t pt0,
   48885             :      ae_int_t pt1,
   48886             :      /* Integer */ ae_vector* xyindexprev,
   48887             :      ae_int_t row0,
   48888             :      ae_int_t row1,
   48889             :      /* Integer */ ae_vector* xyindexnew,
   48890             :      ae_int_t kxnew,
   48891             :      ae_int_t kynew,
   48892             :      ae_bool rootcall,
   48893             :      ae_state *_state)
   48894             : {
   48895             :     ae_int_t i;
   48896             :     ae_int_t entrywidth;
   48897             :     ae_int_t kxprev;
   48898             :     double v;
   48899             :     ae_int_t i0;
   48900             :     ae_int_t i1;
   48901             :     double efficiency;
   48902             :     double cost;
   48903             :     ae_int_t rowmid;
   48904             : 
   48905             : 
   48906           0 :     kxprev = (kxnew+1)/2;
   48907           0 :     entrywidth = 2+d;
   48908           0 :     efficiency = 0.1;
   48909           0 :     cost = d*(pt1-pt0+1)*(ae_log((double)(kxnew), _state)/ae_log((double)(2), _state))/efficiency;
   48910           0 :     ae_assert(xyindexprev->ptr.p_int[row0*(kxprev-1)+0]==pt0, "Spline2DFit.ExpandIndexRows: integrity check failed", _state);
   48911           0 :     ae_assert(xyindexprev->ptr.p_int[row1*(kxprev-1)+0]==pt1, "Spline2DFit.ExpandIndexRows: integrity check failed", _state);
   48912             :     
   48913             :     /*
   48914             :      * Parallelism
   48915             :      */
   48916           0 :     if( ((rootcall&&pt1-pt0>10000)&&row1-row0>=2)&&ae_fp_greater(cost,smpactivationlevel(_state)) )
   48917             :     {
   48918           0 :         if( _trypexec_spline2d_expandindexrows(xy,d,shadow,ns,cidx,pt0,pt1,xyindexprev,row0,row1,xyindexnew,kxnew,kynew,rootcall, _state) )
   48919             :         {
   48920           0 :             return;
   48921             :         }
   48922             :     }
   48923             :     
   48924             :     /*
   48925             :      * Partition
   48926             :      */
   48927           0 :     if( row1-row0>=2 )
   48928             :     {
   48929           0 :         tiledsplit(row1-row0, 1, &i0, &i1, _state);
   48930           0 :         rowmid = row0+i0;
   48931           0 :         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);
   48932           0 :         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);
   48933           0 :         return;
   48934             :     }
   48935             :     
   48936             :     /*
   48937             :      * Serial execution
   48938             :      */
   48939           0 :     for(i=pt0; i<=pt1-1; i++)
   48940             :     {
   48941           0 :         v = 2*xy->ptr.p_double[i*entrywidth+0];
   48942           0 :         xy->ptr.p_double[i*entrywidth+0] = v;
   48943           0 :         i0 = iboundval(ae_ifloor(v, _state), 0, kxnew-2, _state);
   48944           0 :         v = 2*xy->ptr.p_double[i*entrywidth+1];
   48945           0 :         xy->ptr.p_double[i*entrywidth+1] = v;
   48946           0 :         i1 = iboundval(ae_ifloor(v, _state), 0, kynew-2, _state);
   48947           0 :         cidx->ptr.p_int[i] = i1*(kxnew-1)+i0;
   48948             :     }
   48949           0 :     spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, cidx, pt0, pt1, xyindexnew, 2*row0*(kxnew-1)+0, 2*row1*(kxnew-1)+0, ae_false, _state);
   48950             : }
   48951             : 
   48952             : 
   48953             : /*************************************************************************
   48954             : Serial stub for GPL edition.
   48955             : *************************************************************************/
   48956           0 : ae_bool _trypexec_spline2d_expandindexrows(/* Real    */ ae_vector* xy,
   48957             :     ae_int_t d,
   48958             :     /* Real    */ ae_vector* shadow,
   48959             :     ae_int_t ns,
   48960             :     /* Integer */ ae_vector* cidx,
   48961             :     ae_int_t pt0,
   48962             :     ae_int_t pt1,
   48963             :     /* Integer */ ae_vector* xyindexprev,
   48964             :     ae_int_t row0,
   48965             :     ae_int_t row1,
   48966             :     /* Integer */ ae_vector* xyindexnew,
   48967             :     ae_int_t kxnew,
   48968             :     ae_int_t kynew,
   48969             :     ae_bool rootcall,
   48970             :     ae_state *_state)
   48971             : {
   48972           0 :     return ae_false;
   48973             : }
   48974             : 
   48975             : 
   48976             : /*************************************************************************
   48977             : Recurrent divide-and-conquer indexing function
   48978             : 
   48979             :   -- ALGLIB --
   48980             :      Copyright 05.02.2018 by Bochkanov Sergey
   48981             : *************************************************************************/
   48982           0 : static void spline2d_reorderdatasetandbuildindexrec(/* Real    */ ae_vector* xy,
   48983             :      ae_int_t d,
   48984             :      /* Real    */ ae_vector* shadow,
   48985             :      ae_int_t ns,
   48986             :      /* Integer */ ae_vector* cidx,
   48987             :      ae_int_t pt0,
   48988             :      ae_int_t pt1,
   48989             :      /* Integer */ ae_vector* xyindex,
   48990             :      ae_int_t idx0,
   48991             :      ae_int_t idx1,
   48992             :      ae_bool rootcall,
   48993             :      ae_state *_state)
   48994             : {
   48995             :     ae_int_t entrywidth;
   48996             :     ae_int_t idxmid;
   48997             :     ae_int_t wrk0;
   48998             :     ae_int_t wrk1;
   48999             :     double efficiency;
   49000             :     double cost;
   49001             : 
   49002             : 
   49003             :     
   49004             :     /*
   49005             :      * Efficiency - performance of the code when compared with that
   49006             :      * of linear algebra code.
   49007             :      */
   49008           0 :     entrywidth = 2+d;
   49009           0 :     efficiency = 0.1;
   49010           0 :     cost = d*(pt1-pt0+1)*ae_log((double)(idx1-idx0+1), _state)/ae_log((double)(2), _state)/efficiency;
   49011             :     
   49012             :     /*
   49013             :      * Parallelism
   49014             :      */
   49015           0 :     if( ((rootcall&&pt1-pt0>10000)&&idx1-idx0>=2)&&ae_fp_greater(cost,smpactivationlevel(_state)) )
   49016             :     {
   49017           0 :         if( _trypexec_spline2d_reorderdatasetandbuildindexrec(xy,d,shadow,ns,cidx,pt0,pt1,xyindex,idx0,idx1,rootcall, _state) )
   49018             :         {
   49019           0 :             return;
   49020             :         }
   49021             :     }
   49022             :     
   49023             :     /*
   49024             :      * Store left bound to XYIndex
   49025             :      */
   49026           0 :     xyindex->ptr.p_int[idx0] = pt0;
   49027             :     
   49028             :     /*
   49029             :      * Quick exit strategies
   49030             :      */
   49031           0 :     if( idx1<=idx0+1 )
   49032             :     {
   49033           0 :         return;
   49034             :     }
   49035           0 :     if( pt0==pt1 )
   49036             :     {
   49037           0 :         for(idxmid=idx0+1; idxmid<=idx1-1; idxmid++)
   49038             :         {
   49039           0 :             xyindex->ptr.p_int[idxmid] = pt1;
   49040             :         }
   49041           0 :         return;
   49042             :     }
   49043             :     
   49044             :     /*
   49045             :      * Select middle element
   49046             :      */
   49047           0 :     idxmid = idx0+(idx1-idx0)/2;
   49048           0 :     ae_assert(idx0<idxmid&&idxmid<idx1, "Spline2D: integrity check failed", _state);
   49049           0 :     wrk0 = pt0;
   49050           0 :     wrk1 = pt1-1;
   49051             :     for(;;)
   49052             :     {
   49053           0 :         while(wrk0<pt1&&cidx->ptr.p_int[wrk0]<idxmid)
   49054             :         {
   49055           0 :             wrk0 = wrk0+1;
   49056             :         }
   49057           0 :         while(wrk1>=pt0&&cidx->ptr.p_int[wrk1]>=idxmid)
   49058             :         {
   49059           0 :             wrk1 = wrk1-1;
   49060             :         }
   49061           0 :         if( wrk1<=wrk0 )
   49062             :         {
   49063           0 :             break;
   49064             :         }
   49065           0 :         swapentries(xy, wrk0, wrk1, entrywidth, _state);
   49066           0 :         if( ns>0 )
   49067             :         {
   49068           0 :             swapentries(shadow, wrk0, wrk1, ns, _state);
   49069             :         }
   49070           0 :         swapelementsi(cidx, wrk0, wrk1, _state);
   49071             :     }
   49072           0 :     spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, cidx, pt0, wrk0, xyindex, idx0, idxmid, ae_false, _state);
   49073           0 :     spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, cidx, wrk0, pt1, xyindex, idxmid, idx1, ae_false, _state);
   49074             : }
   49075             : 
   49076             : 
   49077             : /*************************************************************************
   49078             : Serial stub for GPL edition.
   49079             : *************************************************************************/
   49080           0 : ae_bool _trypexec_spline2d_reorderdatasetandbuildindexrec(/* Real    */ ae_vector* xy,
   49081             :     ae_int_t d,
   49082             :     /* Real    */ ae_vector* shadow,
   49083             :     ae_int_t ns,
   49084             :     /* Integer */ ae_vector* cidx,
   49085             :     ae_int_t pt0,
   49086             :     ae_int_t pt1,
   49087             :     /* Integer */ ae_vector* xyindex,
   49088             :     ae_int_t idx0,
   49089             :     ae_int_t idx1,
   49090             :     ae_bool rootcall,
   49091             :     ae_state *_state)
   49092             : {
   49093           0 :     return ae_false;
   49094             : }
   49095             : 
   49096             : 
   49097             : /*************************************************************************
   49098             : This function performs fitting with  BlockLLS solver.  Internal  function,
   49099             : never use it directly.
   49100             : 
   49101             : INPUT PARAMETERS:
   49102             :     XY      -   dataset, array[NPoints,2+D]
   49103             :     XYIndex -   dataset index, see ReorderDatasetAndBuildIndex() for more info
   49104             :     KX0, KX1-   X-indices of basis functions to select and fit;
   49105             :                 range [KX0,KX1) is processed
   49106             :     KXTotal -   total number of indexes in the entire grid
   49107             :     KY0, KY1-   Y-indices of basis functions to select and fit;
   49108             :                 range [KY0,KY1) is processed
   49109             :     KYTotal -   total number of indexes in the entire grid
   49110             :     D       -   number of components in vector-valued spline, D>=1
   49111             :     LambdaReg-  regularization coefficient
   49112             :     LambdaNS-   nonlinearity penalty, exactly zero value is specially handled
   49113             :                 (entire set of rows is not added to the matrix)
   49114             :     Basis1  -   single-dimensional B-spline
   49115             :     
   49116             : 
   49117             : OUTPUT PARAMETERS:
   49118             :     A       -   design matrix
   49119             : 
   49120             :   -- ALGLIB --
   49121             :      Copyright 05.02.2018 by Bochkanov Sergey
   49122             : *************************************************************************/
   49123           0 : static void spline2d_xdesigngenerate(/* Real    */ ae_vector* xy,
   49124             :      /* Integer */ ae_vector* xyindex,
   49125             :      ae_int_t kx0,
   49126             :      ae_int_t kx1,
   49127             :      ae_int_t kxtotal,
   49128             :      ae_int_t ky0,
   49129             :      ae_int_t ky1,
   49130             :      ae_int_t kytotal,
   49131             :      ae_int_t d,
   49132             :      double lambdareg,
   49133             :      double lambdans,
   49134             :      spline1dinterpolant* basis1,
   49135             :      spline2dxdesignmatrix* a,
   49136             :      ae_state *_state)
   49137             : {
   49138             :     ae_frame _frame_block;
   49139             :     ae_int_t entrywidth;
   49140             :     ae_int_t i;
   49141             :     ae_int_t j;
   49142             :     ae_int_t j0;
   49143             :     ae_int_t j1;
   49144             :     ae_int_t k0;
   49145             :     ae_int_t k1;
   49146             :     ae_int_t kx;
   49147             :     ae_int_t ky;
   49148             :     ae_int_t rowsdone;
   49149             :     ae_int_t batchesdone;
   49150             :     ae_int_t pt0;
   49151             :     ae_int_t pt1;
   49152             :     ae_int_t base0;
   49153             :     ae_int_t base1;
   49154             :     ae_int_t baseidx;
   49155             :     ae_int_t nzshift;
   49156             :     ae_int_t nzwidth;
   49157             :     ae_matrix d2x;
   49158             :     ae_matrix d2y;
   49159             :     ae_matrix dxy;
   49160             :     double v;
   49161             :     double v0;
   49162             :     double v1;
   49163             :     double v2;
   49164             :     double w0;
   49165             :     double w1;
   49166             :     double w2;
   49167             : 
   49168           0 :     ae_frame_make(_state, &_frame_block);
   49169           0 :     memset(&d2x, 0, sizeof(d2x));
   49170           0 :     memset(&d2y, 0, sizeof(d2y));
   49171           0 :     memset(&dxy, 0, sizeof(dxy));
   49172           0 :     ae_matrix_init(&d2x, 0, 0, DT_REAL, _state, ae_true);
   49173           0 :     ae_matrix_init(&d2y, 0, 0, DT_REAL, _state, ae_true);
   49174           0 :     ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true);
   49175             : 
   49176           0 :     nzshift = 1;
   49177           0 :     nzwidth = 4;
   49178           0 :     entrywidth = 2+d;
   49179           0 :     kx = kx1-kx0;
   49180           0 :     ky = ky1-ky0;
   49181           0 :     a->lambdareg = lambdareg;
   49182           0 :     a->blockwidth = 4;
   49183           0 :     a->kx = kx;
   49184           0 :     a->ky = ky;
   49185           0 :     a->d = d;
   49186           0 :     a->npoints = 0;
   49187           0 :     a->ndenserows = 0;
   49188           0 :     a->ndensebatches = 0;
   49189           0 :     a->maxbatch = 0;
   49190           0 :     for(j1=ky0; j1<=ky1-2; j1++)
   49191             :     {
   49192           0 :         for(j0=kx0; j0<=kx1-2; j0++)
   49193             :         {
   49194           0 :             i = xyindex->ptr.p_int[j1*(kxtotal-1)+j0+1]-xyindex->ptr.p_int[j1*(kxtotal-1)+j0];
   49195           0 :             a->npoints = a->npoints+i;
   49196           0 :             a->ndenserows = a->ndenserows+i;
   49197           0 :             a->ndensebatches = a->ndensebatches+1;
   49198           0 :             a->maxbatch = ae_maxint(a->maxbatch, i, _state);
   49199             :         }
   49200             :     }
   49201           0 :     if( ae_fp_neq(lambdans,(double)(0)) )
   49202             :     {
   49203           0 :         ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline2DFit: integrity check failed", _state);
   49204           0 :         a->ndenserows = a->ndenserows+3*(kx-2)*(ky-2);
   49205           0 :         a->ndensebatches = a->ndensebatches+(kx-2)*(ky-2);
   49206           0 :         a->maxbatch = ae_maxint(a->maxbatch, 3, _state);
   49207             :     }
   49208           0 :     a->nrows = a->ndenserows+kx*ky;
   49209           0 :     rmatrixsetlengthatleast(&a->vals, a->ndenserows, a->blockwidth*a->blockwidth+d, _state);
   49210           0 :     ivectorsetlengthatleast(&a->batches, a->ndensebatches+1, _state);
   49211           0 :     ivectorsetlengthatleast(&a->batchbases, a->ndensebatches, _state);
   49212             :     
   49213             :     /*
   49214             :      * Setup output counters
   49215             :      */
   49216           0 :     batchesdone = 0;
   49217           0 :     rowsdone = 0;
   49218             :     
   49219             :     /*
   49220             :      * Generate rows corresponding to dataset points
   49221             :      */
   49222           0 :     ae_assert(kx>=nzwidth, "Spline2DFit: integrity check failed", _state);
   49223           0 :     ae_assert(ky>=nzwidth, "Spline2DFit: integrity check failed", _state);
   49224           0 :     rvectorsetlengthatleast(&a->tmp0, nzwidth, _state);
   49225           0 :     rvectorsetlengthatleast(&a->tmp1, nzwidth, _state);
   49226           0 :     a->batches.ptr.p_int[batchesdone] = 0;
   49227           0 :     for(j1=ky0; j1<=ky1-2; j1++)
   49228             :     {
   49229           0 :         for(j0=kx0; j0<=kx1-2; j0++)
   49230             :         {
   49231           0 :             pt0 = xyindex->ptr.p_int[j1*(kxtotal-1)+j0];
   49232           0 :             pt1 = xyindex->ptr.p_int[j1*(kxtotal-1)+j0+1];
   49233           0 :             base0 = iboundval(j0-kx0-nzshift, 0, kx-nzwidth, _state);
   49234           0 :             base1 = iboundval(j1-ky0-nzshift, 0, ky-nzwidth, _state);
   49235           0 :             baseidx = base1*kx+base0;
   49236           0 :             a->batchbases.ptr.p_int[batchesdone] = baseidx;
   49237           0 :             for(i=pt0; i<=pt1-1; i++)
   49238             :             {
   49239           0 :                 for(k0=0; k0<=nzwidth-1; k0++)
   49240             :                 {
   49241           0 :                     a->tmp0.ptr.p_double[k0] = spline1dcalc(basis1, xy->ptr.p_double[i*entrywidth+0]-(base0+kx0+k0), _state);
   49242             :                 }
   49243           0 :                 for(k1=0; k1<=nzwidth-1; k1++)
   49244             :                 {
   49245           0 :                     a->tmp1.ptr.p_double[k1] = spline1dcalc(basis1, xy->ptr.p_double[i*entrywidth+1]-(base1+ky0+k1), _state);
   49246             :                 }
   49247           0 :                 for(k1=0; k1<=nzwidth-1; k1++)
   49248             :                 {
   49249           0 :                     for(k0=0; k0<=nzwidth-1; k0++)
   49250             :                     {
   49251           0 :                         a->vals.ptr.pp_double[rowsdone][k1*nzwidth+k0] = a->tmp0.ptr.p_double[k0]*a->tmp1.ptr.p_double[k1];
   49252             :                     }
   49253             :                 }
   49254           0 :                 for(j=0; j<=d-1; j++)
   49255             :                 {
   49256           0 :                     a->vals.ptr.pp_double[rowsdone][nzwidth*nzwidth+j] = xy->ptr.p_double[i*entrywidth+2+j];
   49257             :                 }
   49258           0 :                 rowsdone = rowsdone+1;
   49259             :             }
   49260           0 :             batchesdone = batchesdone+1;
   49261           0 :             a->batches.ptr.p_int[batchesdone] = rowsdone;
   49262             :         }
   49263             :     }
   49264             :     
   49265             :     /*
   49266             :      * Generate rows corresponding to nonlinearity penalty
   49267             :      */
   49268           0 :     if( ae_fp_greater(lambdans,(double)(0)) )
   49269             :     {
   49270             :         
   49271             :         /*
   49272             :          * Smoothing is applied. Because all grid nodes are same,
   49273             :          * we apply same smoothing kernel, which is calculated only
   49274             :          * once at the beginning of design matrix generation.
   49275             :          */
   49276           0 :         ae_matrix_set_length(&d2x, 3, 3, _state);
   49277           0 :         ae_matrix_set_length(&d2y, 3, 3, _state);
   49278           0 :         ae_matrix_set_length(&dxy, 3, 3, _state);
   49279           0 :         for(j1=0; j1<=2; j1++)
   49280             :         {
   49281           0 :             for(j0=0; j0<=2; j0++)
   49282             :             {
   49283           0 :                 d2x.ptr.pp_double[j0][j1] = 0.0;
   49284           0 :                 d2y.ptr.pp_double[j0][j1] = 0.0;
   49285           0 :                 dxy.ptr.pp_double[j0][j1] = 0.0;
   49286             :             }
   49287             :         }
   49288           0 :         for(k1=0; k1<=2; k1++)
   49289             :         {
   49290           0 :             for(k0=0; k0<=2; k0++)
   49291             :             {
   49292           0 :                 spline1ddiff(basis1, (double)(-(k0-1)), &v0, &v1, &v2, _state);
   49293           0 :                 spline1ddiff(basis1, (double)(-(k1-1)), &w0, &w1, &w2, _state);
   49294           0 :                 d2x.ptr.pp_double[k0][k1] = d2x.ptr.pp_double[k0][k1]+v2*w0;
   49295           0 :                 d2y.ptr.pp_double[k0][k1] = d2y.ptr.pp_double[k0][k1]+w2*v0;
   49296           0 :                 dxy.ptr.pp_double[k0][k1] = dxy.ptr.pp_double[k0][k1]+v1*w1;
   49297             :             }
   49298             :         }
   49299             :         
   49300             :         /*
   49301             :          * Now, kernel is ready - apply it to all inner nodes of the grid.
   49302             :          */
   49303           0 :         for(j1=1; j1<=ky-2; j1++)
   49304             :         {
   49305           0 :             for(j0=1; j0<=kx-2; j0++)
   49306             :             {
   49307           0 :                 base0 = imax2(j0-2, 0, _state);
   49308           0 :                 base1 = imax2(j1-2, 0, _state);
   49309           0 :                 baseidx = base1*kx+base0;
   49310           0 :                 a->batchbases.ptr.p_int[batchesdone] = baseidx;
   49311             :                 
   49312             :                 /*
   49313             :                  * d2F/dx2 term
   49314             :                  */
   49315           0 :                 v = lambdans;
   49316           0 :                 for(j=0; j<=nzwidth*nzwidth+d-1; j++)
   49317             :                 {
   49318           0 :                     a->vals.ptr.pp_double[rowsdone][j] = (double)(0);
   49319             :                 }
   49320           0 :                 for(k1=j1-1; k1<=j1+1; k1++)
   49321             :                 {
   49322           0 :                     for(k0=j0-1; k0<=j0+1; k0++)
   49323             :                     {
   49324           0 :                         a->vals.ptr.pp_double[rowsdone][nzwidth*(k1-base1)+(k0-base0)] = v*d2x.ptr.pp_double[1+(k0-j0)][1+(k1-j1)];
   49325             :                     }
   49326             :                 }
   49327           0 :                 rowsdone = rowsdone+1;
   49328             :                 
   49329             :                 /*
   49330             :                  * d2F/dy2 term
   49331             :                  */
   49332           0 :                 v = lambdans;
   49333           0 :                 for(j=0; j<=nzwidth*nzwidth+d-1; j++)
   49334             :                 {
   49335           0 :                     a->vals.ptr.pp_double[rowsdone][j] = (double)(0);
   49336             :                 }
   49337           0 :                 for(k1=j1-1; k1<=j1+1; k1++)
   49338             :                 {
   49339           0 :                     for(k0=j0-1; k0<=j0+1; k0++)
   49340             :                     {
   49341           0 :                         a->vals.ptr.pp_double[rowsdone][nzwidth*(k1-base1)+(k0-base0)] = v*d2y.ptr.pp_double[1+(k0-j0)][1+(k1-j1)];
   49342             :                     }
   49343             :                 }
   49344           0 :                 rowsdone = rowsdone+1;
   49345             :                 
   49346             :                 /*
   49347             :                  * 2*d2F/dxdy term
   49348             :                  */
   49349           0 :                 v = ae_sqrt((double)(2), _state)*lambdans;
   49350           0 :                 for(j=0; j<=nzwidth*nzwidth+d-1; j++)
   49351             :                 {
   49352           0 :                     a->vals.ptr.pp_double[rowsdone][j] = (double)(0);
   49353             :                 }
   49354           0 :                 for(k1=j1-1; k1<=j1+1; k1++)
   49355             :                 {
   49356           0 :                     for(k0=j0-1; k0<=j0+1; k0++)
   49357             :                     {
   49358           0 :                         a->vals.ptr.pp_double[rowsdone][nzwidth*(k1-base1)+(k0-base0)] = v*dxy.ptr.pp_double[1+(k0-j0)][1+(k1-j1)];
   49359             :                     }
   49360             :                 }
   49361           0 :                 rowsdone = rowsdone+1;
   49362           0 :                 batchesdone = batchesdone+1;
   49363           0 :                 a->batches.ptr.p_int[batchesdone] = rowsdone;
   49364             :             }
   49365             :         }
   49366             :     }
   49367             :     
   49368             :     /*
   49369             :      * Integrity post-check
   49370             :      */
   49371           0 :     ae_assert(batchesdone==a->ndensebatches, "Spline2DFit: integrity check failed", _state);
   49372           0 :     ae_assert(rowsdone==a->ndenserows, "Spline2DFit: integrity check failed", _state);
   49373           0 :     ae_frame_leave(_state);
   49374           0 : }
   49375             : 
   49376             : 
   49377             : /*************************************************************************
   49378             : This function performs matrix-vector product of design matrix and dense
   49379             : vector.
   49380             : 
   49381             : INPUT PARAMETERS:
   49382             :     A       -   design matrix, (a.nrows) X (a.kx*a.ky);
   49383             :                 some fields of A are used for temporaries,
   49384             :                 so it is non-constant.
   49385             :     X       -   array[A.KX*A.KY]
   49386             :     
   49387             : 
   49388             : OUTPUT PARAMETERS:
   49389             :     Y       -   product, array[A.NRows], automatically allocated
   49390             : 
   49391             :   -- ALGLIB --
   49392             :      Copyright 05.02.2018 by Bochkanov Sergey
   49393             : *************************************************************************/
   49394           0 : static void spline2d_xdesignmv(spline2dxdesignmatrix* a,
   49395             :      /* Real    */ ae_vector* x,
   49396             :      /* Real    */ ae_vector* y,
   49397             :      ae_state *_state)
   49398             : {
   49399             :     ae_int_t bidx;
   49400             :     ae_int_t i;
   49401             :     ae_int_t cnt;
   49402             :     double v;
   49403             :     ae_int_t baseidx;
   49404             :     ae_int_t outidx;
   49405             :     ae_int_t batchsize;
   49406             :     ae_int_t kx;
   49407             :     ae_int_t k0;
   49408             :     ae_int_t k1;
   49409             :     ae_int_t nzwidth;
   49410             : 
   49411             : 
   49412           0 :     nzwidth = 4;
   49413           0 :     ae_assert(a->blockwidth==nzwidth, "Spline2DFit: integrity check failed", _state);
   49414           0 :     ae_assert(x->cnt>=a->kx*a->ky, "Spline2DFit: integrity check failed", _state);
   49415             :     
   49416             :     /*
   49417             :      * Prepare
   49418             :      */
   49419           0 :     rvectorsetlengthatleast(y, a->nrows, _state);
   49420           0 :     rvectorsetlengthatleast(&a->tmp0, nzwidth*nzwidth, _state);
   49421           0 :     rvectorsetlengthatleast(&a->tmp1, a->maxbatch, _state);
   49422           0 :     kx = a->kx;
   49423           0 :     outidx = 0;
   49424             :     
   49425             :     /*
   49426             :      * Process dense part
   49427             :      */
   49428           0 :     for(bidx=0; bidx<=a->ndensebatches-1; bidx++)
   49429             :     {
   49430           0 :         if( a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]>0 )
   49431             :         {
   49432           0 :             batchsize = a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx];
   49433           0 :             baseidx = a->batchbases.ptr.p_int[bidx];
   49434           0 :             for(k1=0; k1<=nzwidth-1; k1++)
   49435             :             {
   49436           0 :                 for(k0=0; k0<=nzwidth-1; k0++)
   49437             :                 {
   49438           0 :                     a->tmp0.ptr.p_double[k1*nzwidth+k0] = x->ptr.p_double[baseidx+k1*kx+k0];
   49439             :                 }
   49440             :             }
   49441           0 :             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);
   49442           0 :             for(i=0; i<=batchsize-1; i++)
   49443             :             {
   49444           0 :                 y->ptr.p_double[outidx+i] = a->tmp1.ptr.p_double[i];
   49445             :             }
   49446           0 :             outidx = outidx+batchsize;
   49447             :         }
   49448             :     }
   49449           0 :     ae_assert(outidx==a->ndenserows, "Spline2DFit: integrity check failed", _state);
   49450             :     
   49451             :     /*
   49452             :      * Process regularizer 
   49453             :      */
   49454           0 :     v = a->lambdareg;
   49455           0 :     cnt = a->kx*a->ky;
   49456           0 :     for(i=0; i<=cnt-1; i++)
   49457             :     {
   49458           0 :         y->ptr.p_double[outidx+i] = v*x->ptr.p_double[i];
   49459             :     }
   49460           0 :     outidx = outidx+cnt;
   49461             :     
   49462             :     /*
   49463             :      * Post-check
   49464             :      */
   49465           0 :     ae_assert(outidx==a->nrows, "Spline2DFit: integrity check failed", _state);
   49466           0 : }
   49467             : 
   49468             : 
   49469             : /*************************************************************************
   49470             : This function performs matrix-vector product of transposed design matrix and dense
   49471             : vector.
   49472             : 
   49473             : INPUT PARAMETERS:
   49474             :     A       -   design matrix, (a.nrows) X (a.kx*a.ky);
   49475             :                 some fields of A are used for temporaries,
   49476             :                 so it is non-constant.
   49477             :     X       -   array[A.NRows]
   49478             :     
   49479             : 
   49480             : OUTPUT PARAMETERS:
   49481             :     Y       -   product, array[A.KX*A.KY], automatically allocated
   49482             : 
   49483             :   -- ALGLIB --
   49484             :      Copyright 05.02.2018 by Bochkanov Sergey
   49485             : *************************************************************************/
   49486           0 : static void spline2d_xdesignmtv(spline2dxdesignmatrix* a,
   49487             :      /* Real    */ ae_vector* x,
   49488             :      /* Real    */ ae_vector* y,
   49489             :      ae_state *_state)
   49490             : {
   49491             :     ae_int_t bidx;
   49492             :     ae_int_t i;
   49493             :     ae_int_t cnt;
   49494             :     double v;
   49495             :     ae_int_t baseidx;
   49496             :     ae_int_t inidx;
   49497             :     ae_int_t batchsize;
   49498             :     ae_int_t kx;
   49499             :     ae_int_t k0;
   49500             :     ae_int_t k1;
   49501             :     ae_int_t nzwidth;
   49502             : 
   49503             : 
   49504           0 :     nzwidth = 4;
   49505           0 :     ae_assert(a->blockwidth==nzwidth, "Spline2DFit: integrity check failed", _state);
   49506           0 :     ae_assert(x->cnt>=a->nrows, "Spline2DFit: integrity check failed", _state);
   49507             :     
   49508             :     /*
   49509             :      * Prepare
   49510             :      */
   49511           0 :     rvectorsetlengthatleast(y, a->kx*a->ky, _state);
   49512           0 :     rvectorsetlengthatleast(&a->tmp0, nzwidth*nzwidth, _state);
   49513           0 :     rvectorsetlengthatleast(&a->tmp1, a->maxbatch, _state);
   49514           0 :     kx = a->kx;
   49515           0 :     inidx = 0;
   49516           0 :     cnt = a->kx*a->ky;
   49517           0 :     for(i=0; i<=cnt-1; i++)
   49518             :     {
   49519           0 :         y->ptr.p_double[i] = (double)(0);
   49520             :     }
   49521             :     
   49522             :     /*
   49523             :      * Process dense part
   49524             :      */
   49525           0 :     for(bidx=0; bidx<=a->ndensebatches-1; bidx++)
   49526             :     {
   49527           0 :         if( a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]>0 )
   49528             :         {
   49529           0 :             batchsize = a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx];
   49530           0 :             baseidx = a->batchbases.ptr.p_int[bidx];
   49531           0 :             for(i=0; i<=batchsize-1; i++)
   49532             :             {
   49533           0 :                 a->tmp1.ptr.p_double[i] = x->ptr.p_double[inidx+i];
   49534             :             }
   49535           0 :             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);
   49536           0 :             for(k1=0; k1<=nzwidth-1; k1++)
   49537             :             {
   49538           0 :                 for(k0=0; k0<=nzwidth-1; k0++)
   49539             :                 {
   49540           0 :                     y->ptr.p_double[baseidx+k1*kx+k0] = y->ptr.p_double[baseidx+k1*kx+k0]+a->tmp0.ptr.p_double[k1*nzwidth+k0];
   49541             :                 }
   49542             :             }
   49543           0 :             inidx = inidx+batchsize;
   49544             :         }
   49545             :     }
   49546           0 :     ae_assert(inidx==a->ndenserows, "Spline2DFit: integrity check failed", _state);
   49547             :     
   49548             :     /*
   49549             :      * Process regularizer 
   49550             :      */
   49551           0 :     v = a->lambdareg;
   49552           0 :     cnt = a->kx*a->ky;
   49553           0 :     for(i=0; i<=cnt-1; i++)
   49554             :     {
   49555           0 :         y->ptr.p_double[i] = y->ptr.p_double[i]+v*x->ptr.p_double[inidx+i];
   49556             :     }
   49557           0 :     inidx = inidx+cnt;
   49558             :     
   49559             :     /*
   49560             :      * Post-check
   49561             :      */
   49562           0 :     ae_assert(inidx==a->nrows, "Spline2DFit: integrity check failed", _state);
   49563           0 : }
   49564             : 
   49565             : 
   49566             : /*************************************************************************
   49567             : This function generates squared design matrix stored in block band format.
   49568             : 
   49569             : We  use  an   adaptation   of   block   skyline   storage   format,   with
   49570             : TOWERSIZE*KX   skyline    bands   (towers)   stored   sequentially;   here
   49571             : TOWERSIZE=(BlockBandwidth+1)*KX. So, we have KY "towers", stored one below
   49572             : other, in BlockATA matrix. Every "tower" is a sequence of BlockBandwidth+1
   49573             : cells, each of them being KX*KX in size.
   49574             : 
   49575             : INPUT PARAMETERS:
   49576             :     A       -   design matrix; some of its fields are used for temporaries
   49577             :     BlockATA-   array[KY*(BlockBandwidth+1)*KX,KX],  preallocated  storage
   49578             :                 for output matrix in compressed block band format
   49579             : 
   49580             : OUTPUT PARAMETERS:
   49581             :     BlockATA-   AH*AH', stored in compressed block band format
   49582             :     MXATA   -   max(|AH*AH'|), elementwise
   49583             : 
   49584             :   -- ALGLIB --
   49585             :      Copyright 05.02.2018 by Bochkanov Sergey
   49586             : *************************************************************************/
   49587           0 : static void spline2d_xdesignblockata(spline2dxdesignmatrix* a,
   49588             :      /* Real    */ ae_matrix* blockata,
   49589             :      double* mxata,
   49590             :      ae_state *_state)
   49591             : {
   49592             :     ae_int_t blockbandwidth;
   49593             :     ae_int_t nzwidth;
   49594             :     ae_int_t kx;
   49595             :     ae_int_t ky;
   49596             :     ae_int_t i0;
   49597             :     ae_int_t i1;
   49598             :     ae_int_t j0;
   49599             :     ae_int_t j1;
   49600             :     ae_int_t celloffset;
   49601             :     ae_int_t bidx;
   49602             :     ae_int_t baseidx;
   49603             :     ae_int_t batchsize;
   49604             :     ae_int_t offs0;
   49605             :     ae_int_t offs1;
   49606             :     double v;
   49607             : 
   49608             : 
   49609           0 :     blockbandwidth = 3;
   49610           0 :     nzwidth = 4;
   49611           0 :     kx = a->kx;
   49612           0 :     ky = a->ky;
   49613           0 :     ae_assert(a->blockwidth==nzwidth, "Spline2DFit: integrity check failed", _state);
   49614           0 :     rmatrixsetlengthatleast(&a->tmp2, nzwidth*nzwidth, nzwidth*nzwidth, _state);
   49615             :     
   49616             :     /*
   49617             :      * Initial zero-fill:
   49618             :      * * zero-fill ALL elements of BlockATA
   49619             :      * * zero-fill ALL elements of Tmp2
   49620             :      *
   49621             :      * Filling ALL elements, including unused ones, is essential for the
   49622             :      * purposes of calculating max(BlockATA).
   49623             :      */
   49624           0 :     for(i1=0; i1<=ky-1; i1++)
   49625             :     {
   49626           0 :         for(i0=i1; i0<=ae_minint(ky-1, i1+blockbandwidth, _state); i0++)
   49627             :         {
   49628           0 :             celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i0, _state);
   49629           0 :             for(j1=0; j1<=kx-1; j1++)
   49630             :             {
   49631           0 :                 for(j0=0; j0<=kx-1; j0++)
   49632             :                 {
   49633           0 :                     blockata->ptr.pp_double[celloffset+j1][j0] = 0.0;
   49634             :                 }
   49635             :             }
   49636             :         }
   49637             :     }
   49638           0 :     for(j1=0; j1<=nzwidth*nzwidth-1; j1++)
   49639             :     {
   49640           0 :         for(j0=0; j0<=nzwidth*nzwidth-1; j0++)
   49641             :         {
   49642           0 :             a->tmp2.ptr.pp_double[j1][j0] = 0.0;
   49643             :         }
   49644             :     }
   49645             :     
   49646             :     /*
   49647             :      * Process dense part of A
   49648             :      */
   49649           0 :     for(bidx=0; bidx<=a->ndensebatches-1; bidx++)
   49650             :     {
   49651           0 :         if( a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]>0 )
   49652             :         {
   49653             :             
   49654             :             /*
   49655             :              * Generate 16x16 U = BATCH'*BATCH and add it to ATA.
   49656             :              *
   49657             :              * NOTE: it is essential that lower triangle of Tmp2 is
   49658             :              *       filled by zeros.
   49659             :              */
   49660           0 :             batchsize = a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx];
   49661           0 :             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);
   49662           0 :             baseidx = a->batchbases.ptr.p_int[bidx];
   49663           0 :             for(i1=0; i1<=nzwidth-1; i1++)
   49664             :             {
   49665           0 :                 for(j1=i1; j1<=nzwidth-1; j1++)
   49666             :                 {
   49667           0 :                     celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, baseidx/kx+i1, baseidx/kx+j1, _state);
   49668           0 :                     offs0 = baseidx%kx;
   49669           0 :                     offs1 = baseidx%kx;
   49670           0 :                     for(i0=0; i0<=nzwidth-1; i0++)
   49671             :                     {
   49672           0 :                         for(j0=0; j0<=nzwidth-1; j0++)
   49673             :                         {
   49674           0 :                             v = a->tmp2.ptr.pp_double[i1*nzwidth+i0][j1*nzwidth+j0];
   49675           0 :                             blockata->ptr.pp_double[celloffset+offs1+i0][offs0+j0] = blockata->ptr.pp_double[celloffset+offs1+i0][offs0+j0]+v;
   49676             :                         }
   49677             :                     }
   49678             :                 }
   49679             :             }
   49680             :         }
   49681             :     }
   49682             :     
   49683             :     /*
   49684             :      * Process regularizer term
   49685             :      */
   49686           0 :     for(i1=0; i1<=ky-1; i1++)
   49687             :     {
   49688           0 :         celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i1, _state);
   49689           0 :         for(j1=0; j1<=kx-1; j1++)
   49690             :         {
   49691           0 :             blockata->ptr.pp_double[celloffset+j1][j1] = blockata->ptr.pp_double[celloffset+j1][j1]+ae_sqr(a->lambdareg, _state);
   49692             :         }
   49693             :     }
   49694             :     
   49695             :     /*
   49696             :      * Calculate max(ATA)
   49697             :      *
   49698             :      * NOTE: here we rely on zero initialization of unused parts of
   49699             :      *       BlockATA and Tmp2.
   49700             :      */
   49701           0 :     *mxata = 0.0;
   49702           0 :     for(i1=0; i1<=ky-1; i1++)
   49703             :     {
   49704           0 :         for(i0=i1; i0<=ae_minint(ky-1, i1+blockbandwidth, _state); i0++)
   49705             :         {
   49706           0 :             celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i0, _state);
   49707           0 :             for(j1=0; j1<=kx-1; j1++)
   49708             :             {
   49709           0 :                 for(j0=0; j0<=kx-1; j0++)
   49710             :                 {
   49711           0 :                     *mxata = ae_maxreal(*mxata, ae_fabs(blockata->ptr.pp_double[celloffset+j1][j0], _state), _state);
   49712             :                 }
   49713             :             }
   49714             :         }
   49715             :     }
   49716           0 : }
   49717             : 
   49718             : 
   49719           0 : void _spline2dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
   49720             : {
   49721           0 :     spline2dinterpolant *p = (spline2dinterpolant*)_p;
   49722           0 :     ae_touch_ptr((void*)p);
   49723           0 :     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
   49724           0 :     ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic);
   49725           0 :     ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic);
   49726           0 : }
   49727             : 
   49728             : 
   49729           0 : void _spline2dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   49730             : {
   49731           0 :     spline2dinterpolant *dst = (spline2dinterpolant*)_dst;
   49732           0 :     spline2dinterpolant *src = (spline2dinterpolant*)_src;
   49733           0 :     dst->stype = src->stype;
   49734           0 :     dst->n = src->n;
   49735           0 :     dst->m = src->m;
   49736           0 :     dst->d = src->d;
   49737           0 :     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
   49738           0 :     ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic);
   49739           0 :     ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic);
   49740           0 : }
   49741             : 
   49742             : 
   49743           0 : void _spline2dinterpolant_clear(void* _p)
   49744             : {
   49745           0 :     spline2dinterpolant *p = (spline2dinterpolant*)_p;
   49746           0 :     ae_touch_ptr((void*)p);
   49747           0 :     ae_vector_clear(&p->x);
   49748           0 :     ae_vector_clear(&p->y);
   49749           0 :     ae_vector_clear(&p->f);
   49750           0 : }
   49751             : 
   49752             : 
   49753           0 : void _spline2dinterpolant_destroy(void* _p)
   49754             : {
   49755           0 :     spline2dinterpolant *p = (spline2dinterpolant*)_p;
   49756           0 :     ae_touch_ptr((void*)p);
   49757           0 :     ae_vector_destroy(&p->x);
   49758           0 :     ae_vector_destroy(&p->y);
   49759           0 :     ae_vector_destroy(&p->f);
   49760           0 : }
   49761             : 
   49762             : 
   49763           0 : void _spline2dbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic)
   49764             : {
   49765           0 :     spline2dbuilder *p = (spline2dbuilder*)_p;
   49766           0 :     ae_touch_ptr((void*)p);
   49767           0 :     ae_vector_init(&p->xy, 0, DT_REAL, _state, make_automatic);
   49768           0 : }
   49769             : 
   49770             : 
   49771           0 : void _spline2dbuilder_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   49772             : {
   49773           0 :     spline2dbuilder *dst = (spline2dbuilder*)_dst;
   49774           0 :     spline2dbuilder *src = (spline2dbuilder*)_src;
   49775           0 :     dst->priorterm = src->priorterm;
   49776           0 :     dst->priortermval = src->priortermval;
   49777           0 :     dst->areatype = src->areatype;
   49778           0 :     dst->xa = src->xa;
   49779           0 :     dst->xb = src->xb;
   49780           0 :     dst->ya = src->ya;
   49781           0 :     dst->yb = src->yb;
   49782           0 :     dst->gridtype = src->gridtype;
   49783           0 :     dst->kx = src->kx;
   49784           0 :     dst->ky = src->ky;
   49785           0 :     dst->smoothing = src->smoothing;
   49786           0 :     dst->nlayers = src->nlayers;
   49787           0 :     dst->solvertype = src->solvertype;
   49788           0 :     dst->lambdabase = src->lambdabase;
   49789           0 :     ae_vector_init_copy(&dst->xy, &src->xy, _state, make_automatic);
   49790           0 :     dst->npoints = src->npoints;
   49791           0 :     dst->d = src->d;
   49792           0 :     dst->sx = src->sx;
   49793           0 :     dst->sy = src->sy;
   49794           0 :     dst->adddegreeoffreedom = src->adddegreeoffreedom;
   49795           0 :     dst->interfacesize = src->interfacesize;
   49796           0 :     dst->lsqrcnt = src->lsqrcnt;
   49797           0 :     dst->maxcoresize = src->maxcoresize;
   49798           0 : }
   49799             : 
   49800             : 
   49801           0 : void _spline2dbuilder_clear(void* _p)
   49802             : {
   49803           0 :     spline2dbuilder *p = (spline2dbuilder*)_p;
   49804           0 :     ae_touch_ptr((void*)p);
   49805           0 :     ae_vector_clear(&p->xy);
   49806           0 : }
   49807             : 
   49808             : 
   49809           0 : void _spline2dbuilder_destroy(void* _p)
   49810             : {
   49811           0 :     spline2dbuilder *p = (spline2dbuilder*)_p;
   49812           0 :     ae_touch_ptr((void*)p);
   49813           0 :     ae_vector_destroy(&p->xy);
   49814           0 : }
   49815             : 
   49816             : 
   49817           0 : void _spline2dfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
   49818             : {
   49819           0 :     spline2dfitreport *p = (spline2dfitreport*)_p;
   49820           0 :     ae_touch_ptr((void*)p);
   49821           0 : }
   49822             : 
   49823             : 
   49824           0 : void _spline2dfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   49825             : {
   49826           0 :     spline2dfitreport *dst = (spline2dfitreport*)_dst;
   49827           0 :     spline2dfitreport *src = (spline2dfitreport*)_src;
   49828           0 :     dst->rmserror = src->rmserror;
   49829           0 :     dst->avgerror = src->avgerror;
   49830           0 :     dst->maxerror = src->maxerror;
   49831           0 :     dst->r2 = src->r2;
   49832           0 : }
   49833             : 
   49834             : 
   49835           0 : void _spline2dfitreport_clear(void* _p)
   49836             : {
   49837           0 :     spline2dfitreport *p = (spline2dfitreport*)_p;
   49838           0 :     ae_touch_ptr((void*)p);
   49839           0 : }
   49840             : 
   49841             : 
   49842           0 : void _spline2dfitreport_destroy(void* _p)
   49843             : {
   49844           0 :     spline2dfitreport *p = (spline2dfitreport*)_p;
   49845           0 :     ae_touch_ptr((void*)p);
   49846           0 : }
   49847             : 
   49848             : 
   49849           0 : void _spline2dxdesignmatrix_init(void* _p, ae_state *_state, ae_bool make_automatic)
   49850             : {
   49851           0 :     spline2dxdesignmatrix *p = (spline2dxdesignmatrix*)_p;
   49852           0 :     ae_touch_ptr((void*)p);
   49853           0 :     ae_matrix_init(&p->vals, 0, 0, DT_REAL, _state, make_automatic);
   49854           0 :     ae_vector_init(&p->batches, 0, DT_INT, _state, make_automatic);
   49855           0 :     ae_vector_init(&p->batchbases, 0, DT_INT, _state, make_automatic);
   49856           0 :     ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic);
   49857           0 :     ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic);
   49858           0 :     ae_matrix_init(&p->tmp2, 0, 0, DT_REAL, _state, make_automatic);
   49859           0 : }
   49860             : 
   49861             : 
   49862           0 : void _spline2dxdesignmatrix_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   49863             : {
   49864           0 :     spline2dxdesignmatrix *dst = (spline2dxdesignmatrix*)_dst;
   49865           0 :     spline2dxdesignmatrix *src = (spline2dxdesignmatrix*)_src;
   49866           0 :     dst->blockwidth = src->blockwidth;
   49867           0 :     dst->kx = src->kx;
   49868           0 :     dst->ky = src->ky;
   49869           0 :     dst->npoints = src->npoints;
   49870           0 :     dst->nrows = src->nrows;
   49871           0 :     dst->ndenserows = src->ndenserows;
   49872           0 :     dst->ndensebatches = src->ndensebatches;
   49873           0 :     dst->d = src->d;
   49874           0 :     dst->maxbatch = src->maxbatch;
   49875           0 :     ae_matrix_init_copy(&dst->vals, &src->vals, _state, make_automatic);
   49876           0 :     ae_vector_init_copy(&dst->batches, &src->batches, _state, make_automatic);
   49877           0 :     ae_vector_init_copy(&dst->batchbases, &src->batchbases, _state, make_automatic);
   49878           0 :     dst->lambdareg = src->lambdareg;
   49879           0 :     ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic);
   49880           0 :     ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic);
   49881           0 :     ae_matrix_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic);
   49882           0 : }
   49883             : 
   49884             : 
   49885           0 : void _spline2dxdesignmatrix_clear(void* _p)
   49886             : {
   49887           0 :     spline2dxdesignmatrix *p = (spline2dxdesignmatrix*)_p;
   49888           0 :     ae_touch_ptr((void*)p);
   49889           0 :     ae_matrix_clear(&p->vals);
   49890           0 :     ae_vector_clear(&p->batches);
   49891           0 :     ae_vector_clear(&p->batchbases);
   49892           0 :     ae_vector_clear(&p->tmp0);
   49893           0 :     ae_vector_clear(&p->tmp1);
   49894           0 :     ae_matrix_clear(&p->tmp2);
   49895           0 : }
   49896             : 
   49897             : 
   49898           0 : void _spline2dxdesignmatrix_destroy(void* _p)
   49899             : {
   49900           0 :     spline2dxdesignmatrix *p = (spline2dxdesignmatrix*)_p;
   49901           0 :     ae_touch_ptr((void*)p);
   49902           0 :     ae_matrix_destroy(&p->vals);
   49903           0 :     ae_vector_destroy(&p->batches);
   49904           0 :     ae_vector_destroy(&p->batchbases);
   49905           0 :     ae_vector_destroy(&p->tmp0);
   49906           0 :     ae_vector_destroy(&p->tmp1);
   49907           0 :     ae_matrix_destroy(&p->tmp2);
   49908           0 : }
   49909             : 
   49910             : 
   49911           0 : void _spline2dblockllsbuf_init(void* _p, ae_state *_state, ae_bool make_automatic)
   49912             : {
   49913           0 :     spline2dblockllsbuf *p = (spline2dblockllsbuf*)_p;
   49914           0 :     ae_touch_ptr((void*)p);
   49915           0 :     _linlsqrstate_init(&p->solver, _state, make_automatic);
   49916           0 :     _linlsqrreport_init(&p->solverrep, _state, make_automatic);
   49917           0 :     ae_matrix_init(&p->blockata, 0, 0, DT_REAL, _state, make_automatic);
   49918           0 :     ae_matrix_init(&p->trsmbuf2, 0, 0, DT_REAL, _state, make_automatic);
   49919           0 :     ae_matrix_init(&p->cholbuf2, 0, 0, DT_REAL, _state, make_automatic);
   49920           0 :     ae_vector_init(&p->cholbuf1, 0, DT_REAL, _state, make_automatic);
   49921           0 :     ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic);
   49922           0 :     ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic);
   49923           0 : }
   49924             : 
   49925             : 
   49926           0 : void _spline2dblockllsbuf_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   49927             : {
   49928           0 :     spline2dblockllsbuf *dst = (spline2dblockllsbuf*)_dst;
   49929           0 :     spline2dblockllsbuf *src = (spline2dblockllsbuf*)_src;
   49930           0 :     _linlsqrstate_init_copy(&dst->solver, &src->solver, _state, make_automatic);
   49931           0 :     _linlsqrreport_init_copy(&dst->solverrep, &src->solverrep, _state, make_automatic);
   49932           0 :     ae_matrix_init_copy(&dst->blockata, &src->blockata, _state, make_automatic);
   49933           0 :     ae_matrix_init_copy(&dst->trsmbuf2, &src->trsmbuf2, _state, make_automatic);
   49934           0 :     ae_matrix_init_copy(&dst->cholbuf2, &src->cholbuf2, _state, make_automatic);
   49935           0 :     ae_vector_init_copy(&dst->cholbuf1, &src->cholbuf1, _state, make_automatic);
   49936           0 :     ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic);
   49937           0 :     ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic);
   49938           0 : }
   49939             : 
   49940             : 
   49941           0 : void _spline2dblockllsbuf_clear(void* _p)
   49942             : {
   49943           0 :     spline2dblockllsbuf *p = (spline2dblockllsbuf*)_p;
   49944           0 :     ae_touch_ptr((void*)p);
   49945           0 :     _linlsqrstate_clear(&p->solver);
   49946           0 :     _linlsqrreport_clear(&p->solverrep);
   49947           0 :     ae_matrix_clear(&p->blockata);
   49948           0 :     ae_matrix_clear(&p->trsmbuf2);
   49949           0 :     ae_matrix_clear(&p->cholbuf2);
   49950           0 :     ae_vector_clear(&p->cholbuf1);
   49951           0 :     ae_vector_clear(&p->tmp0);
   49952           0 :     ae_vector_clear(&p->tmp1);
   49953           0 : }
   49954             : 
   49955             : 
   49956           0 : void _spline2dblockllsbuf_destroy(void* _p)
   49957             : {
   49958           0 :     spline2dblockllsbuf *p = (spline2dblockllsbuf*)_p;
   49959           0 :     ae_touch_ptr((void*)p);
   49960           0 :     _linlsqrstate_destroy(&p->solver);
   49961           0 :     _linlsqrreport_destroy(&p->solverrep);
   49962           0 :     ae_matrix_destroy(&p->blockata);
   49963           0 :     ae_matrix_destroy(&p->trsmbuf2);
   49964           0 :     ae_matrix_destroy(&p->cholbuf2);
   49965           0 :     ae_vector_destroy(&p->cholbuf1);
   49966           0 :     ae_vector_destroy(&p->tmp0);
   49967           0 :     ae_vector_destroy(&p->tmp1);
   49968           0 : }
   49969             : 
   49970             : 
   49971           0 : void _spline2dfastddmbuf_init(void* _p, ae_state *_state, ae_bool make_automatic)
   49972             : {
   49973           0 :     spline2dfastddmbuf *p = (spline2dfastddmbuf*)_p;
   49974           0 :     ae_touch_ptr((void*)p);
   49975           0 :     _spline2dxdesignmatrix_init(&p->xdesignmatrix, _state, make_automatic);
   49976           0 :     ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic);
   49977           0 :     ae_vector_init(&p->tmpz, 0, DT_REAL, _state, make_automatic);
   49978           0 :     _spline2dfitreport_init(&p->dummyrep, _state, make_automatic);
   49979           0 :     _spline2dinterpolant_init(&p->localmodel, _state, make_automatic);
   49980           0 :     _spline2dblockllsbuf_init(&p->blockllsbuf, _state, make_automatic);
   49981           0 : }
   49982             : 
   49983             : 
   49984           0 : void _spline2dfastddmbuf_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   49985             : {
   49986           0 :     spline2dfastddmbuf *dst = (spline2dfastddmbuf*)_dst;
   49987           0 :     spline2dfastddmbuf *src = (spline2dfastddmbuf*)_src;
   49988           0 :     _spline2dxdesignmatrix_init_copy(&dst->xdesignmatrix, &src->xdesignmatrix, _state, make_automatic);
   49989           0 :     ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic);
   49990           0 :     ae_vector_init_copy(&dst->tmpz, &src->tmpz, _state, make_automatic);
   49991           0 :     _spline2dfitreport_init_copy(&dst->dummyrep, &src->dummyrep, _state, make_automatic);
   49992           0 :     _spline2dinterpolant_init_copy(&dst->localmodel, &src->localmodel, _state, make_automatic);
   49993           0 :     _spline2dblockllsbuf_init_copy(&dst->blockllsbuf, &src->blockllsbuf, _state, make_automatic);
   49994           0 : }
   49995             : 
   49996             : 
   49997           0 : void _spline2dfastddmbuf_clear(void* _p)
   49998             : {
   49999           0 :     spline2dfastddmbuf *p = (spline2dfastddmbuf*)_p;
   50000           0 :     ae_touch_ptr((void*)p);
   50001           0 :     _spline2dxdesignmatrix_clear(&p->xdesignmatrix);
   50002           0 :     ae_vector_clear(&p->tmp0);
   50003           0 :     ae_vector_clear(&p->tmpz);
   50004           0 :     _spline2dfitreport_clear(&p->dummyrep);
   50005           0 :     _spline2dinterpolant_clear(&p->localmodel);
   50006           0 :     _spline2dblockllsbuf_clear(&p->blockllsbuf);
   50007           0 : }
   50008             : 
   50009             : 
   50010           0 : void _spline2dfastddmbuf_destroy(void* _p)
   50011             : {
   50012           0 :     spline2dfastddmbuf *p = (spline2dfastddmbuf*)_p;
   50013           0 :     ae_touch_ptr((void*)p);
   50014           0 :     _spline2dxdesignmatrix_destroy(&p->xdesignmatrix);
   50015           0 :     ae_vector_destroy(&p->tmp0);
   50016           0 :     ae_vector_destroy(&p->tmpz);
   50017           0 :     _spline2dfitreport_destroy(&p->dummyrep);
   50018           0 :     _spline2dinterpolant_destroy(&p->localmodel);
   50019           0 :     _spline2dblockllsbuf_destroy(&p->blockllsbuf);
   50020           0 : }
   50021             : 
   50022             : 
   50023             : #endif
   50024             : #if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD)
   50025             : 
   50026             : 
   50027             : /*************************************************************************
   50028             : This function creates RBF  model  for  a  scalar (NY=1)  or  vector (NY>1)
   50029             : function in a NX-dimensional space (NX=2 or NX=3).
   50030             : 
   50031             : INPUT PARAMETERS:
   50032             :     NX      -   dimension of the space, NX=2 or NX=3
   50033             :     NY      -   function dimension, NY>=1
   50034             : 
   50035             : OUTPUT PARAMETERS:
   50036             :     S       -   RBF model (initially equals to zero)
   50037             : 
   50038             :   -- ALGLIB --
   50039             :      Copyright 13.12.2011 by Bochkanov Sergey
   50040             : *************************************************************************/
   50041           0 : void rbfv1create(ae_int_t nx,
   50042             :      ae_int_t ny,
   50043             :      rbfv1model* s,
   50044             :      ae_state *_state)
   50045             : {
   50046             :     ae_int_t i;
   50047             :     ae_int_t j;
   50048             : 
   50049           0 :     _rbfv1model_clear(s);
   50050             : 
   50051           0 :     ae_assert(nx==2||nx==3, "RBFCreate: NX<>2 and NX<>3", _state);
   50052           0 :     ae_assert(ny>=1, "RBFCreate: NY<1", _state);
   50053           0 :     s->nx = nx;
   50054           0 :     s->ny = ny;
   50055           0 :     s->nl = 0;
   50056           0 :     s->nc = 0;
   50057           0 :     ae_matrix_set_length(&s->v, ny, rbfv1_mxnx+1, _state);
   50058           0 :     for(i=0; i<=ny-1; i++)
   50059             :     {
   50060           0 :         for(j=0; j<=rbfv1_mxnx; j++)
   50061             :         {
   50062           0 :             s->v.ptr.pp_double[i][j] = (double)(0);
   50063             :         }
   50064             :     }
   50065           0 :     s->rmax = (double)(0);
   50066           0 : }
   50067             : 
   50068             : 
   50069             : /*************************************************************************
   50070             : This function creates buffer  structure  which  can  be  used  to  perform
   50071             : parallel  RBF  model  evaluations  (with  one  RBF  model  instance  being
   50072             : used from multiple threads, as long as  different  threads  use  different
   50073             : instances of buffer).
   50074             : 
   50075             : This buffer object can be used with  rbftscalcbuf()  function  (here  "ts"
   50076             : stands for "thread-safe", "buf" is a suffix which denotes  function  which
   50077             : reuses previously allocated output space).
   50078             : 
   50079             : How to use it:
   50080             : * create RBF model structure with rbfcreate()
   50081             : * load data, tune parameters
   50082             : * call rbfbuildmodel()
   50083             : * call rbfcreatecalcbuffer(), once per thread working with RBF model  (you
   50084             :   should call this function only AFTER call to rbfbuildmodel(), see  below
   50085             :   for more information)
   50086             : * call rbftscalcbuf() from different threads,  with  each  thread  working
   50087             :   with its own copy of buffer object.
   50088             : 
   50089             : INPUT PARAMETERS
   50090             :     S           -   RBF model
   50091             : 
   50092             : OUTPUT PARAMETERS
   50093             :     Buf         -   external buffer.
   50094             :     
   50095             :     
   50096             : IMPORTANT: buffer object should be used only with  RBF model object  which
   50097             :            was used to initialize buffer. Any attempt to use buffer   with
   50098             :            different object is dangerous - you may  get  memory  violation
   50099             :            error because sizes of internal arrays do not fit to dimensions
   50100             :            of RBF structure.
   50101             :            
   50102             : IMPORTANT: you  should  call  this function only for model which was built
   50103             :            with rbfbuildmodel() function, after successful  invocation  of
   50104             :            rbfbuildmodel().  Sizes   of   some   internal  structures  are
   50105             :            determined only after model is built, so buffer object  created
   50106             :            before model  construction  stage  will  be  useless  (and  any
   50107             :            attempt to use it will result in exception).
   50108             : 
   50109             :   -- ALGLIB --
   50110             :      Copyright 02.04.2016 by Sergey Bochkanov
   50111             : *************************************************************************/
   50112           0 : void rbfv1createcalcbuffer(rbfv1model* s,
   50113             :      rbfv1calcbuffer* buf,
   50114             :      ae_state *_state)
   50115             : {
   50116             : 
   50117           0 :     _rbfv1calcbuffer_clear(buf);
   50118             : 
   50119           0 :     kdtreecreaterequestbuffer(&s->tree, &buf->requestbuffer, _state);
   50120           0 : }
   50121             : 
   50122             : 
   50123             : /*************************************************************************
   50124             : This   function  builds  RBF  model  and  returns  report  (contains  some 
   50125             : information which can be used for evaluation of the algorithm properties).
   50126             : 
   50127             : Call to this function modifies RBF model by calculating its centers/radii/
   50128             : weights  and  saving  them  into  RBFModel  structure.  Initially RBFModel 
   50129             : contain zero coefficients, but after call to this function  we  will  have
   50130             : coefficients which were calculated in order to fit our dataset.
   50131             : 
   50132             : After you called this function you can call RBFCalc(),  RBFGridCalc()  and
   50133             : other model calculation functions.
   50134             : 
   50135             : INPUT PARAMETERS:
   50136             :     S       -   RBF model, initialized by RBFCreate() call
   50137             :     Rep     -   report:
   50138             :                 * Rep.TerminationType:
   50139             :                   * -5 - non-distinct basis function centers were detected,
   50140             :                          interpolation aborted
   50141             :                   * -4 - nonconvergence of the internal SVD solver
   50142             :                   *  1 - successful termination
   50143             :                 Fields are used for debugging purposes:
   50144             :                 * Rep.IterationsCount - iterations count of the LSQR solver
   50145             :                 * Rep.NMV - number of matrix-vector products
   50146             :                 * Rep.ARows - rows count for the system matrix
   50147             :                 * Rep.ACols - columns count for the system matrix
   50148             :                 * Rep.ANNZ - number of significantly non-zero elements
   50149             :                   (elements above some algorithm-determined threshold)
   50150             : 
   50151             : NOTE:  failure  to  build  model will leave current state of the structure
   50152             : unchanged.
   50153             : 
   50154             :   -- ALGLIB --
   50155             :      Copyright 13.12.2011 by Bochkanov Sergey
   50156             : *************************************************************************/
   50157           0 : void rbfv1buildmodel(/* Real    */ ae_matrix* x,
   50158             :      /* Real    */ ae_matrix* y,
   50159             :      ae_int_t n,
   50160             :      ae_int_t aterm,
   50161             :      ae_int_t algorithmtype,
   50162             :      ae_int_t nlayers,
   50163             :      double radvalue,
   50164             :      double radzvalue,
   50165             :      double lambdav,
   50166             :      double epsort,
   50167             :      double epserr,
   50168             :      ae_int_t maxits,
   50169             :      rbfv1model* s,
   50170             :      rbfv1report* rep,
   50171             :      ae_state *_state)
   50172             : {
   50173             :     ae_frame _frame_block;
   50174             :     kdtree tree;
   50175             :     kdtree ctree;
   50176             :     ae_vector dist;
   50177             :     ae_vector xcx;
   50178             :     ae_matrix a;
   50179             :     ae_matrix v;
   50180             :     ae_matrix omega;
   50181             :     ae_matrix residualy;
   50182             :     ae_vector radius;
   50183             :     ae_matrix xc;
   50184             :     ae_int_t nc;
   50185             :     double rmax;
   50186             :     ae_vector tags;
   50187             :     ae_vector ctags;
   50188             :     ae_int_t i;
   50189             :     ae_int_t j;
   50190             :     ae_int_t k;
   50191             :     ae_int_t snnz;
   50192             :     ae_vector tmp0;
   50193             :     ae_vector tmp1;
   50194             :     ae_int_t layerscnt;
   50195             :     ae_bool modelstatus;
   50196             : 
   50197           0 :     ae_frame_make(_state, &_frame_block);
   50198           0 :     memset(&tree, 0, sizeof(tree));
   50199           0 :     memset(&ctree, 0, sizeof(ctree));
   50200           0 :     memset(&dist, 0, sizeof(dist));
   50201           0 :     memset(&xcx, 0, sizeof(xcx));
   50202           0 :     memset(&a, 0, sizeof(a));
   50203           0 :     memset(&v, 0, sizeof(v));
   50204           0 :     memset(&omega, 0, sizeof(omega));
   50205           0 :     memset(&residualy, 0, sizeof(residualy));
   50206           0 :     memset(&radius, 0, sizeof(radius));
   50207           0 :     memset(&xc, 0, sizeof(xc));
   50208           0 :     memset(&tags, 0, sizeof(tags));
   50209           0 :     memset(&ctags, 0, sizeof(ctags));
   50210           0 :     memset(&tmp0, 0, sizeof(tmp0));
   50211           0 :     memset(&tmp1, 0, sizeof(tmp1));
   50212           0 :     _rbfv1report_clear(rep);
   50213           0 :     _kdtree_init(&tree, _state, ae_true);
   50214           0 :     _kdtree_init(&ctree, _state, ae_true);
   50215           0 :     ae_vector_init(&dist, 0, DT_REAL, _state, ae_true);
   50216           0 :     ae_vector_init(&xcx, 0, DT_REAL, _state, ae_true);
   50217           0 :     ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true);
   50218           0 :     ae_matrix_init(&v, 0, 0, DT_REAL, _state, ae_true);
   50219           0 :     ae_matrix_init(&omega, 0, 0, DT_REAL, _state, ae_true);
   50220           0 :     ae_matrix_init(&residualy, 0, 0, DT_REAL, _state, ae_true);
   50221           0 :     ae_vector_init(&radius, 0, DT_REAL, _state, ae_true);
   50222           0 :     ae_matrix_init(&xc, 0, 0, DT_REAL, _state, ae_true);
   50223           0 :     ae_vector_init(&tags, 0, DT_INT, _state, ae_true);
   50224           0 :     ae_vector_init(&ctags, 0, DT_INT, _state, ae_true);
   50225           0 :     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
   50226           0 :     ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true);
   50227             : 
   50228           0 :     ae_assert(s->nx==2||s->nx==3, "RBFBuildModel: S.NX<>2 or S.NX<>3!", _state);
   50229             :     
   50230             :     /*
   50231             :      * Quick exit when we have no points
   50232             :      */
   50233           0 :     if( n==0 )
   50234             :     {
   50235           0 :         rep->terminationtype = 1;
   50236           0 :         rep->iterationscount = 0;
   50237           0 :         rep->nmv = 0;
   50238           0 :         rep->arows = 0;
   50239           0 :         rep->acols = 0;
   50240           0 :         kdtreebuildtagged(&s->xc, &tags, 0, rbfv1_mxnx, 0, 2, &s->tree, _state);
   50241           0 :         ae_matrix_set_length(&s->xc, 0, 0, _state);
   50242           0 :         ae_matrix_set_length(&s->wr, 0, 0, _state);
   50243           0 :         s->nc = 0;
   50244           0 :         s->rmax = (double)(0);
   50245           0 :         ae_matrix_set_length(&s->v, s->ny, rbfv1_mxnx+1, _state);
   50246           0 :         for(i=0; i<=s->ny-1; i++)
   50247             :         {
   50248           0 :             for(j=0; j<=rbfv1_mxnx; j++)
   50249             :             {
   50250           0 :                 s->v.ptr.pp_double[i][j] = (double)(0);
   50251             :             }
   50252             :         }
   50253           0 :         ae_frame_leave(_state);
   50254           0 :         return;
   50255             :     }
   50256             :     
   50257             :     /*
   50258             :      * General case, N>0
   50259             :      */
   50260           0 :     rep->annz = 0;
   50261           0 :     rep->iterationscount = 0;
   50262           0 :     rep->nmv = 0;
   50263           0 :     ae_vector_set_length(&xcx, rbfv1_mxnx, _state);
   50264             :     
   50265             :     /*
   50266             :      * First model in a sequence - linear model.
   50267             :      * Residuals from linear regression are stored in the ResidualY variable
   50268             :      * (used later to build RBF models).
   50269             :      */
   50270           0 :     ae_matrix_set_length(&residualy, n, s->ny, _state);
   50271           0 :     for(i=0; i<=n-1; i++)
   50272             :     {
   50273           0 :         for(j=0; j<=s->ny-1; j++)
   50274             :         {
   50275           0 :             residualy.ptr.pp_double[i][j] = y->ptr.pp_double[i][j];
   50276             :         }
   50277             :     }
   50278           0 :     if( !rbfv1_rbfv1buildlinearmodel(x, &residualy, n, s->ny, aterm, &v, _state) )
   50279             :     {
   50280           0 :         rep->terminationtype = -5;
   50281           0 :         ae_frame_leave(_state);
   50282           0 :         return;
   50283             :     }
   50284             :     
   50285             :     /*
   50286             :      * Handle special case: multilayer model with NLayers=0.
   50287             :      * Quick exit.
   50288             :      */
   50289           0 :     if( algorithmtype==2&&nlayers==0 )
   50290             :     {
   50291           0 :         rep->terminationtype = 1;
   50292           0 :         rep->iterationscount = 0;
   50293           0 :         rep->nmv = 0;
   50294           0 :         rep->arows = 0;
   50295           0 :         rep->acols = 0;
   50296           0 :         kdtreebuildtagged(&s->xc, &tags, 0, rbfv1_mxnx, 0, 2, &s->tree, _state);
   50297           0 :         ae_matrix_set_length(&s->xc, 0, 0, _state);
   50298           0 :         ae_matrix_set_length(&s->wr, 0, 0, _state);
   50299           0 :         s->nc = 0;
   50300           0 :         s->rmax = (double)(0);
   50301           0 :         ae_matrix_set_length(&s->v, s->ny, rbfv1_mxnx+1, _state);
   50302           0 :         for(i=0; i<=s->ny-1; i++)
   50303             :         {
   50304           0 :             for(j=0; j<=rbfv1_mxnx; j++)
   50305             :             {
   50306           0 :                 s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j];
   50307             :             }
   50308             :         }
   50309           0 :         ae_frame_leave(_state);
   50310           0 :         return;
   50311             :     }
   50312             :     
   50313             :     /*
   50314             :      * Second model in a sequence - RBF term.
   50315             :      *
   50316             :      * NOTE: assignments below are not necessary, but without them
   50317             :      *       MSVC complains about unitialized variables.
   50318             :      */
   50319           0 :     nc = 0;
   50320           0 :     rmax = (double)(0);
   50321           0 :     layerscnt = 0;
   50322           0 :     modelstatus = ae_false;
   50323           0 :     if( algorithmtype==1 )
   50324             :     {
   50325             :         
   50326             :         /*
   50327             :          * Add RBF model.
   50328             :          * This model uses local KD-trees to speed-up nearest neighbor searches.
   50329             :          */
   50330           0 :         nc = n;
   50331           0 :         ae_matrix_set_length(&xc, nc, rbfv1_mxnx, _state);
   50332           0 :         for(i=0; i<=nc-1; i++)
   50333             :         {
   50334           0 :             for(j=0; j<=rbfv1_mxnx-1; j++)
   50335             :             {
   50336           0 :                 xc.ptr.pp_double[i][j] = x->ptr.pp_double[i][j];
   50337             :             }
   50338             :         }
   50339           0 :         rmax = (double)(0);
   50340           0 :         ae_vector_set_length(&radius, nc, _state);
   50341           0 :         ae_vector_set_length(&ctags, nc, _state);
   50342           0 :         for(i=0; i<=nc-1; i++)
   50343             :         {
   50344           0 :             ctags.ptr.p_int[i] = i;
   50345             :         }
   50346           0 :         kdtreebuildtagged(&xc, &ctags, nc, rbfv1_mxnx, 0, 2, &ctree, _state);
   50347           0 :         if( nc==0 )
   50348             :         {
   50349           0 :             rmax = (double)(1);
   50350             :         }
   50351             :         else
   50352             :         {
   50353           0 :             if( nc==1 )
   50354             :             {
   50355           0 :                 radius.ptr.p_double[0] = radvalue;
   50356           0 :                 rmax = radius.ptr.p_double[0];
   50357             :             }
   50358             :             else
   50359             :             {
   50360             :                 
   50361             :                 /*
   50362             :                  * NC>1, calculate radii using distances to nearest neigbors
   50363             :                  */
   50364           0 :                 for(i=0; i<=nc-1; i++)
   50365             :                 {
   50366           0 :                     for(j=0; j<=rbfv1_mxnx-1; j++)
   50367             :                     {
   50368           0 :                         xcx.ptr.p_double[j] = xc.ptr.pp_double[i][j];
   50369             :                     }
   50370           0 :                     if( kdtreequeryknn(&ctree, &xcx, 1, ae_false, _state)>0 )
   50371             :                     {
   50372           0 :                         kdtreequeryresultsdistances(&ctree, &dist, _state);
   50373           0 :                         radius.ptr.p_double[i] = radvalue*dist.ptr.p_double[0];
   50374             :                     }
   50375             :                     else
   50376             :                     {
   50377             :                         
   50378             :                         /*
   50379             :                          * No neighbors found (it will happen when we have only one center).
   50380             :                          * Initialize radius with default value.
   50381             :                          */
   50382           0 :                         radius.ptr.p_double[i] = 1.0;
   50383             :                     }
   50384             :                 }
   50385             :                 
   50386             :                 /*
   50387             :                  * Apply filtering
   50388             :                  */
   50389           0 :                 rvectorsetlengthatleast(&tmp0, nc, _state);
   50390           0 :                 for(i=0; i<=nc-1; i++)
   50391             :                 {
   50392           0 :                     tmp0.ptr.p_double[i] = radius.ptr.p_double[i];
   50393             :                 }
   50394           0 :                 tagsortfast(&tmp0, &tmp1, nc, _state);
   50395           0 :                 for(i=0; i<=nc-1; i++)
   50396             :                 {
   50397           0 :                     radius.ptr.p_double[i] = ae_minreal(radius.ptr.p_double[i], radzvalue*tmp0.ptr.p_double[nc/2], _state);
   50398             :                 }
   50399             :                 
   50400             :                 /*
   50401             :                  * Calculate RMax, check that all radii are non-zero
   50402             :                  */
   50403           0 :                 for(i=0; i<=nc-1; i++)
   50404             :                 {
   50405           0 :                     rmax = ae_maxreal(rmax, radius.ptr.p_double[i], _state);
   50406             :                 }
   50407           0 :                 for(i=0; i<=nc-1; i++)
   50408             :                 {
   50409           0 :                     if( ae_fp_eq(radius.ptr.p_double[i],(double)(0)) )
   50410             :                     {
   50411           0 :                         rep->terminationtype = -5;
   50412           0 :                         ae_frame_leave(_state);
   50413           0 :                         return;
   50414             :                     }
   50415             :                 }
   50416             :             }
   50417             :         }
   50418           0 :         ivectorsetlengthatleast(&tags, n, _state);
   50419           0 :         for(i=0; i<=n-1; i++)
   50420             :         {
   50421           0 :             tags.ptr.p_int[i] = i;
   50422             :         }
   50423           0 :         kdtreebuildtagged(x, &tags, n, rbfv1_mxnx, 0, 2, &tree, _state);
   50424           0 :         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);
   50425           0 :         layerscnt = 1;
   50426           0 :         modelstatus = ae_true;
   50427             :     }
   50428           0 :     if( algorithmtype==2 )
   50429             :     {
   50430           0 :         rmax = radvalue;
   50431           0 :         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);
   50432           0 :         layerscnt = nlayers;
   50433           0 :         modelstatus = ae_true;
   50434             :     }
   50435           0 :     ae_assert(modelstatus, "RBFBuildModel: integrity error", _state);
   50436           0 :     if( rep->terminationtype<=0 )
   50437             :     {
   50438           0 :         ae_frame_leave(_state);
   50439           0 :         return;
   50440             :     }
   50441             :     
   50442             :     /*
   50443             :      * Model is built
   50444             :      */
   50445           0 :     s->nc = nc/layerscnt;
   50446           0 :     s->rmax = rmax;
   50447           0 :     s->nl = layerscnt;
   50448           0 :     ae_matrix_set_length(&s->xc, s->nc, rbfv1_mxnx, _state);
   50449           0 :     ae_matrix_set_length(&s->wr, s->nc, 1+s->nl*s->ny, _state);
   50450           0 :     ae_matrix_set_length(&s->v, s->ny, rbfv1_mxnx+1, _state);
   50451           0 :     for(i=0; i<=s->nc-1; i++)
   50452             :     {
   50453           0 :         for(j=0; j<=rbfv1_mxnx-1; j++)
   50454             :         {
   50455           0 :             s->xc.ptr.pp_double[i][j] = xc.ptr.pp_double[i][j];
   50456             :         }
   50457             :     }
   50458           0 :     ivectorsetlengthatleast(&tags, s->nc, _state);
   50459           0 :     for(i=0; i<=s->nc-1; i++)
   50460             :     {
   50461           0 :         tags.ptr.p_int[i] = i;
   50462             :     }
   50463           0 :     kdtreebuildtagged(&s->xc, &tags, s->nc, rbfv1_mxnx, 0, 2, &s->tree, _state);
   50464           0 :     for(i=0; i<=s->nc-1; i++)
   50465             :     {
   50466           0 :         s->wr.ptr.pp_double[i][0] = radius.ptr.p_double[i];
   50467           0 :         for(k=0; k<=layerscnt-1; k++)
   50468             :         {
   50469           0 :             for(j=0; j<=s->ny-1; j++)
   50470             :             {
   50471           0 :                 s->wr.ptr.pp_double[i][1+k*s->ny+j] = omega.ptr.pp_double[k*s->nc+i][j];
   50472             :             }
   50473             :         }
   50474             :     }
   50475           0 :     for(i=0; i<=s->ny-1; i++)
   50476             :     {
   50477           0 :         for(j=0; j<=rbfv1_mxnx; j++)
   50478             :         {
   50479           0 :             s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j];
   50480             :         }
   50481             :     }
   50482           0 :     rep->terminationtype = 1;
   50483           0 :     rep->arows = n;
   50484           0 :     rep->acols = s->nc;
   50485           0 :     ae_frame_leave(_state);
   50486             : }
   50487             : 
   50488             : 
   50489             : /*************************************************************************
   50490             : Serializer: allocation
   50491             : 
   50492             :   -- ALGLIB --
   50493             :      Copyright 02.02.2012 by Bochkanov Sergey
   50494             : *************************************************************************/
   50495           0 : void rbfv1alloc(ae_serializer* s, rbfv1model* model, ae_state *_state)
   50496             : {
   50497             : 
   50498             : 
   50499             :     
   50500             :     /*
   50501             :      * Data
   50502             :      */
   50503           0 :     ae_serializer_alloc_entry(s);
   50504           0 :     ae_serializer_alloc_entry(s);
   50505           0 :     ae_serializer_alloc_entry(s);
   50506           0 :     ae_serializer_alloc_entry(s);
   50507           0 :     kdtreealloc(s, &model->tree, _state);
   50508           0 :     allocrealmatrix(s, &model->xc, -1, -1, _state);
   50509           0 :     allocrealmatrix(s, &model->wr, -1, -1, _state);
   50510           0 :     ae_serializer_alloc_entry(s);
   50511           0 :     allocrealmatrix(s, &model->v, -1, -1, _state);
   50512           0 : }
   50513             : 
   50514             : 
   50515             : /*************************************************************************
   50516             : Serializer: serialization
   50517             : 
   50518             :   -- ALGLIB --
   50519             :      Copyright 02.02.2012 by Bochkanov Sergey
   50520             : *************************************************************************/
   50521           0 : void rbfv1serialize(ae_serializer* s, rbfv1model* model, ae_state *_state)
   50522             : {
   50523             : 
   50524             : 
   50525             :     
   50526             :     /*
   50527             :      * Data
   50528             :      */
   50529           0 :     ae_serializer_serialize_int(s, model->nx, _state);
   50530           0 :     ae_serializer_serialize_int(s, model->ny, _state);
   50531           0 :     ae_serializer_serialize_int(s, model->nc, _state);
   50532           0 :     ae_serializer_serialize_int(s, model->nl, _state);
   50533           0 :     kdtreeserialize(s, &model->tree, _state);
   50534           0 :     serializerealmatrix(s, &model->xc, -1, -1, _state);
   50535           0 :     serializerealmatrix(s, &model->wr, -1, -1, _state);
   50536           0 :     ae_serializer_serialize_double(s, model->rmax, _state);
   50537           0 :     serializerealmatrix(s, &model->v, -1, -1, _state);
   50538           0 : }
   50539             : 
   50540             : 
   50541             : /*************************************************************************
   50542             : Serializer: unserialization
   50543             : 
   50544             :   -- ALGLIB --
   50545             :      Copyright 02.02.2012 by Bochkanov Sergey
   50546             : *************************************************************************/
   50547           0 : void rbfv1unserialize(ae_serializer* s,
   50548             :      rbfv1model* model,
   50549             :      ae_state *_state)
   50550             : {
   50551             :     ae_int_t nx;
   50552             :     ae_int_t ny;
   50553             : 
   50554           0 :     _rbfv1model_clear(model);
   50555             : 
   50556             :     
   50557             :     /*
   50558             :      * Unserialize primary model parameters, initialize model.
   50559             :      *
   50560             :      * It is necessary to call RBFCreate() because some internal fields
   50561             :      * which are NOT unserialized will need initialization.
   50562             :      */
   50563           0 :     ae_serializer_unserialize_int(s, &nx, _state);
   50564           0 :     ae_serializer_unserialize_int(s, &ny, _state);
   50565           0 :     rbfv1create(nx, ny, model, _state);
   50566           0 :     ae_serializer_unserialize_int(s, &model->nc, _state);
   50567           0 :     ae_serializer_unserialize_int(s, &model->nl, _state);
   50568           0 :     kdtreeunserialize(s, &model->tree, _state);
   50569           0 :     unserializerealmatrix(s, &model->xc, _state);
   50570           0 :     unserializerealmatrix(s, &model->wr, _state);
   50571           0 :     ae_serializer_unserialize_double(s, &model->rmax, _state);
   50572           0 :     unserializerealmatrix(s, &model->v, _state);
   50573           0 : }
   50574             : 
   50575             : 
   50576             : /*************************************************************************
   50577             : This function calculates values of the RBF model in the given point.
   50578             : 
   50579             : This function should be used when we have NY=1 (scalar function) and  NX=2
   50580             : (2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If
   50581             : you have general situation (NX-dimensional space, NY-dimensional function)
   50582             : you should use general, less efficient implementation RBFCalc().
   50583             : 
   50584             : If  you  want  to  calculate  function  values  many times, consider using 
   50585             : RBFGridCalc2(), which is far more efficient than many subsequent calls  to
   50586             : RBFCalc2().
   50587             : 
   50588             : This function returns 0.0 when:
   50589             : * model is not initialized
   50590             : * NX<>2
   50591             :  *NY<>1
   50592             : 
   50593             : INPUT PARAMETERS:
   50594             :     S       -   RBF model
   50595             :     X0      -   first coordinate, finite number
   50596             :     X1      -   second coordinate, finite number
   50597             : 
   50598             : RESULT:
   50599             :     value of the model or 0.0 (as defined above)
   50600             : 
   50601             :   -- ALGLIB --
   50602             :      Copyright 13.12.2011 by Bochkanov Sergey
   50603             : *************************************************************************/
   50604           0 : double rbfv1calc2(rbfv1model* s, double x0, double x1, ae_state *_state)
   50605             : {
   50606             :     ae_int_t i;
   50607             :     ae_int_t j;
   50608             :     ae_int_t lx;
   50609             :     ae_int_t tg;
   50610             :     double d2;
   50611             :     double t;
   50612             :     double bfcur;
   50613             :     double rcur;
   50614             :     double result;
   50615             : 
   50616             : 
   50617           0 :     ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state);
   50618           0 :     ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state);
   50619           0 :     if( s->ny!=1||s->nx!=2 )
   50620             :     {
   50621           0 :         result = (double)(0);
   50622           0 :         return result;
   50623             :     }
   50624           0 :     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];
   50625           0 :     if( s->nc==0 )
   50626             :     {
   50627           0 :         return result;
   50628             :     }
   50629           0 :     rvectorsetlengthatleast(&s->calcbufxcx, rbfv1_mxnx, _state);
   50630           0 :     for(i=0; i<=rbfv1_mxnx-1; i++)
   50631             :     {
   50632           0 :         s->calcbufxcx.ptr.p_double[i] = 0.0;
   50633             :     }
   50634           0 :     s->calcbufxcx.ptr.p_double[0] = x0;
   50635           0 :     s->calcbufxcx.ptr.p_double[1] = x1;
   50636           0 :     lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state);
   50637           0 :     kdtreequeryresultsx(&s->tree, &s->calcbufx, _state);
   50638           0 :     kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state);
   50639           0 :     for(i=0; i<=lx-1; i++)
   50640             :     {
   50641           0 :         tg = s->calcbuftags.ptr.p_int[i];
   50642           0 :         d2 = ae_sqr(x0-s->calcbufx.ptr.pp_double[i][0], _state)+ae_sqr(x1-s->calcbufx.ptr.pp_double[i][1], _state);
   50643           0 :         rcur = s->wr.ptr.pp_double[tg][0];
   50644           0 :         bfcur = ae_exp(-d2/(rcur*rcur), _state);
   50645           0 :         for(j=0; j<=s->nl-1; j++)
   50646             :         {
   50647           0 :             result = result+bfcur*s->wr.ptr.pp_double[tg][1+j];
   50648           0 :             rcur = 0.5*rcur;
   50649           0 :             t = bfcur*bfcur;
   50650           0 :             bfcur = t*t;
   50651             :         }
   50652             :     }
   50653           0 :     return result;
   50654             : }
   50655             : 
   50656             : 
   50657             : /*************************************************************************
   50658             : This function calculates values of the RBF model in the given point.
   50659             : 
   50660             : This function should be used when we have NY=1 (scalar function) and  NX=3
   50661             : (3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If
   50662             : you have general situation (NX-dimensional space, NY-dimensional function)
   50663             : you should use general, less efficient implementation RBFCalc().
   50664             : 
   50665             : This function returns 0.0 when:
   50666             : * model is not initialized
   50667             : * NX<>3
   50668             :  *NY<>1
   50669             : 
   50670             : INPUT PARAMETERS:
   50671             :     S       -   RBF model
   50672             :     X0      -   first coordinate, finite number
   50673             :     X1      -   second coordinate, finite number
   50674             :     X2      -   third coordinate, finite number
   50675             : 
   50676             : RESULT:
   50677             :     value of the model or 0.0 (as defined above)
   50678             : 
   50679             :   -- ALGLIB --
   50680             :      Copyright 13.12.2011 by Bochkanov Sergey
   50681             : *************************************************************************/
   50682           0 : double rbfv1calc3(rbfv1model* s,
   50683             :      double x0,
   50684             :      double x1,
   50685             :      double x2,
   50686             :      ae_state *_state)
   50687             : {
   50688             :     ae_int_t i;
   50689             :     ae_int_t j;
   50690             :     ae_int_t lx;
   50691             :     ae_int_t tg;
   50692             :     double t;
   50693             :     double rcur;
   50694             :     double bf;
   50695             :     double result;
   50696             : 
   50697             : 
   50698           0 :     ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state);
   50699           0 :     ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state);
   50700           0 :     ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state);
   50701           0 :     if( s->ny!=1||s->nx!=3 )
   50702             :     {
   50703           0 :         result = (double)(0);
   50704           0 :         return result;
   50705             :     }
   50706           0 :     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];
   50707           0 :     if( s->nc==0 )
   50708             :     {
   50709           0 :         return result;
   50710             :     }
   50711             :     
   50712             :     /*
   50713             :      * calculating value for F(X)
   50714             :      */
   50715           0 :     rvectorsetlengthatleast(&s->calcbufxcx, rbfv1_mxnx, _state);
   50716           0 :     for(i=0; i<=rbfv1_mxnx-1; i++)
   50717             :     {
   50718           0 :         s->calcbufxcx.ptr.p_double[i] = 0.0;
   50719             :     }
   50720           0 :     s->calcbufxcx.ptr.p_double[0] = x0;
   50721           0 :     s->calcbufxcx.ptr.p_double[1] = x1;
   50722           0 :     s->calcbufxcx.ptr.p_double[2] = x2;
   50723           0 :     lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state);
   50724           0 :     kdtreequeryresultsx(&s->tree, &s->calcbufx, _state);
   50725           0 :     kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state);
   50726           0 :     for(i=0; i<=lx-1; i++)
   50727             :     {
   50728           0 :         tg = s->calcbuftags.ptr.p_int[i];
   50729           0 :         rcur = s->wr.ptr.pp_double[tg][0];
   50730           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);
   50731           0 :         for(j=0; j<=s->nl-1; j++)
   50732             :         {
   50733           0 :             result = result+bf*s->wr.ptr.pp_double[tg][1+j];
   50734           0 :             t = bf*bf;
   50735           0 :             bf = t*t;
   50736             :         }
   50737             :     }
   50738           0 :     return result;
   50739             : }
   50740             : 
   50741             : 
   50742             : /*************************************************************************
   50743             : This function calculates values of the RBF model at the given point.
   50744             : 
   50745             : Same as RBFCalc(), but does not reallocate Y when in is large enough to 
   50746             : store function values.
   50747             : 
   50748             : INPUT PARAMETERS:
   50749             :     S       -   RBF model
   50750             :     X       -   coordinates, array[NX].
   50751             :                 X may have more than NX elements, in this case only 
   50752             :                 leading NX will be used.
   50753             :     Y       -   possibly preallocated array
   50754             : 
   50755             : OUTPUT PARAMETERS:
   50756             :     Y       -   function value, array[NY]. Y is not reallocated when it
   50757             :                 is larger than NY.
   50758             : 
   50759             :   -- ALGLIB --
   50760             :      Copyright 13.12.2011 by Bochkanov Sergey
   50761             : *************************************************************************/
   50762           0 : void rbfv1calcbuf(rbfv1model* s,
   50763             :      /* Real    */ ae_vector* x,
   50764             :      /* Real    */ ae_vector* y,
   50765             :      ae_state *_state)
   50766             : {
   50767             :     ae_int_t i;
   50768             :     ae_int_t j;
   50769             :     ae_int_t k;
   50770             :     ae_int_t lx;
   50771             :     ae_int_t tg;
   50772             :     double t;
   50773             :     double rcur;
   50774             :     double bf;
   50775             : 
   50776             : 
   50777           0 :     ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)<NX", _state);
   50778           0 :     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state);
   50779           0 :     if( y->cnt<s->ny )
   50780             :     {
   50781           0 :         ae_vector_set_length(y, s->ny, _state);
   50782             :     }
   50783           0 :     for(i=0; i<=s->ny-1; i++)
   50784             :     {
   50785           0 :         y->ptr.p_double[i] = s->v.ptr.pp_double[i][rbfv1_mxnx];
   50786           0 :         for(j=0; j<=s->nx-1; j++)
   50787             :         {
   50788           0 :             y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j];
   50789             :         }
   50790             :     }
   50791           0 :     if( s->nc==0 )
   50792             :     {
   50793           0 :         return;
   50794             :     }
   50795           0 :     rvectorsetlengthatleast(&s->calcbufxcx, rbfv1_mxnx, _state);
   50796           0 :     for(i=0; i<=rbfv1_mxnx-1; i++)
   50797             :     {
   50798           0 :         s->calcbufxcx.ptr.p_double[i] = 0.0;
   50799             :     }
   50800           0 :     for(i=0; i<=s->nx-1; i++)
   50801             :     {
   50802           0 :         s->calcbufxcx.ptr.p_double[i] = x->ptr.p_double[i];
   50803             :     }
   50804           0 :     lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state);
   50805           0 :     kdtreequeryresultsx(&s->tree, &s->calcbufx, _state);
   50806           0 :     kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state);
   50807           0 :     for(i=0; i<=s->ny-1; i++)
   50808             :     {
   50809           0 :         for(j=0; j<=lx-1; j++)
   50810             :         {
   50811           0 :             tg = s->calcbuftags.ptr.p_int[j];
   50812           0 :             rcur = s->wr.ptr.pp_double[tg][0];
   50813           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);
   50814           0 :             for(k=0; k<=s->nl-1; k++)
   50815             :             {
   50816           0 :                 y->ptr.p_double[i] = y->ptr.p_double[i]+bf*s->wr.ptr.pp_double[tg][1+k*s->ny+i];
   50817           0 :                 t = bf*bf;
   50818           0 :                 bf = t*t;
   50819             :             }
   50820             :         }
   50821             :     }
   50822             : }
   50823             : 
   50824             : 
   50825             : /*************************************************************************
   50826             : This function calculates values of the RBF model at the given point, using
   50827             : external  buffer  object  (internal  temporaries  of  RBF  model  are  not
   50828             : modified).
   50829             : 
   50830             : This function allows to use same RBF model object  in  different  threads,
   50831             : assuming  that  different   threads  use  different  instances  of  buffer
   50832             : structure.
   50833             : 
   50834             : INPUT PARAMETERS:
   50835             :     S       -   RBF model, may be shared between different threads
   50836             :     Buf     -   buffer object created for this particular instance of  RBF
   50837             :                 model with rbfcreatecalcbuffer().
   50838             :     X       -   coordinates, array[NX].
   50839             :                 X may have more than NX elements, in this case only 
   50840             :                 leading NX will be used.
   50841             :     Y       -   possibly preallocated array
   50842             : 
   50843             : OUTPUT PARAMETERS:
   50844             :     Y       -   function value, array[NY]. Y is not reallocated when it
   50845             :                 is larger than NY.
   50846             : 
   50847             :   -- ALGLIB --
   50848             :      Copyright 13.12.2011 by Bochkanov Sergey
   50849             : *************************************************************************/
   50850           0 : void rbfv1tscalcbuf(rbfv1model* s,
   50851             :      rbfv1calcbuffer* buf,
   50852             :      /* Real    */ ae_vector* x,
   50853             :      /* Real    */ ae_vector* y,
   50854             :      ae_state *_state)
   50855             : {
   50856             :     ae_int_t i;
   50857             :     ae_int_t j;
   50858             :     ae_int_t k;
   50859             :     ae_int_t lx;
   50860             :     ae_int_t tg;
   50861             :     double t;
   50862             :     double rcur;
   50863             :     double bf;
   50864             : 
   50865             : 
   50866           0 :     ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)<NX", _state);
   50867           0 :     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state);
   50868           0 :     if( y->cnt<s->ny )
   50869             :     {
   50870           0 :         ae_vector_set_length(y, s->ny, _state);
   50871             :     }
   50872           0 :     for(i=0; i<=s->ny-1; i++)
   50873             :     {
   50874           0 :         y->ptr.p_double[i] = s->v.ptr.pp_double[i][rbfv1_mxnx];
   50875           0 :         for(j=0; j<=s->nx-1; j++)
   50876             :         {
   50877           0 :             y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j];
   50878             :         }
   50879             :     }
   50880           0 :     if( s->nc==0 )
   50881             :     {
   50882           0 :         return;
   50883             :     }
   50884           0 :     rvectorsetlengthatleast(&buf->calcbufxcx, rbfv1_mxnx, _state);
   50885           0 :     for(i=0; i<=rbfv1_mxnx-1; i++)
   50886             :     {
   50887           0 :         buf->calcbufxcx.ptr.p_double[i] = 0.0;
   50888             :     }
   50889           0 :     for(i=0; i<=s->nx-1; i++)
   50890             :     {
   50891           0 :         buf->calcbufxcx.ptr.p_double[i] = x->ptr.p_double[i];
   50892             :     }
   50893           0 :     lx = kdtreetsqueryrnn(&s->tree, &buf->requestbuffer, &buf->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state);
   50894           0 :     kdtreetsqueryresultsx(&s->tree, &buf->requestbuffer, &buf->calcbufx, _state);
   50895           0 :     kdtreetsqueryresultstags(&s->tree, &buf->requestbuffer, &buf->calcbuftags, _state);
   50896           0 :     for(i=0; i<=s->ny-1; i++)
   50897             :     {
   50898           0 :         for(j=0; j<=lx-1; j++)
   50899             :         {
   50900           0 :             tg = buf->calcbuftags.ptr.p_int[j];
   50901           0 :             rcur = s->wr.ptr.pp_double[tg][0];
   50902           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);
   50903           0 :             for(k=0; k<=s->nl-1; k++)
   50904             :             {
   50905           0 :                 y->ptr.p_double[i] = y->ptr.p_double[i]+bf*s->wr.ptr.pp_double[tg][1+k*s->ny+i];
   50906           0 :                 t = bf*bf;
   50907           0 :                 bf = t*t;
   50908             :             }
   50909             :         }
   50910             :     }
   50911             : }
   50912             : 
   50913             : 
   50914             : /*************************************************************************
   50915             : This function calculates values of the RBF model at the regular grid.
   50916             : 
   50917             : Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J])
   50918             : 
   50919             : This function returns 0.0 when:
   50920             : * model is not initialized
   50921             : * NX<>2
   50922             :  *NY<>1
   50923             : 
   50924             : INPUT PARAMETERS:
   50925             :     S       -   RBF model
   50926             :     X0      -   array of grid nodes, first coordinates, array[N0]
   50927             :     N0      -   grid size (number of nodes) in the first dimension
   50928             :     X1      -   array of grid nodes, second coordinates, array[N1]
   50929             :     N1      -   grid size (number of nodes) in the second dimension
   50930             : 
   50931             : OUTPUT PARAMETERS:
   50932             :     Y       -   function values, array[N0,N1]. Y is out-variable and 
   50933             :                 is reallocated by this function.
   50934             :                 
   50935             : NOTE: as a special exception, this function supports unordered  arrays  X0
   50936             :       and X1. However, future versions may be  more  efficient  for  X0/X1
   50937             :       ordered by ascending.
   50938             : 
   50939             :   -- ALGLIB --
   50940             :      Copyright 13.12.2011 by Bochkanov Sergey
   50941             : *************************************************************************/
   50942           0 : void rbfv1gridcalc2(rbfv1model* s,
   50943             :      /* Real    */ ae_vector* x0,
   50944             :      ae_int_t n0,
   50945             :      /* Real    */ ae_vector* x1,
   50946             :      ae_int_t n1,
   50947             :      /* Real    */ ae_matrix* y,
   50948             :      ae_state *_state)
   50949             : {
   50950             :     ae_frame _frame_block;
   50951             :     ae_vector cpx0;
   50952             :     ae_vector cpx1;
   50953             :     ae_vector p01;
   50954             :     ae_vector p11;
   50955             :     ae_vector p2;
   50956             :     double rlimit;
   50957             :     double xcnorm2;
   50958             :     ae_int_t hp01;
   50959             :     double hcpx0;
   50960             :     double xc0;
   50961             :     double xc1;
   50962             :     double omega;
   50963             :     double radius;
   50964             :     ae_int_t i;
   50965             :     ae_int_t j;
   50966             :     ae_int_t k;
   50967             :     ae_int_t d;
   50968             :     ae_int_t i00;
   50969             :     ae_int_t i01;
   50970             :     ae_int_t i10;
   50971             :     ae_int_t i11;
   50972             : 
   50973           0 :     ae_frame_make(_state, &_frame_block);
   50974           0 :     memset(&cpx0, 0, sizeof(cpx0));
   50975           0 :     memset(&cpx1, 0, sizeof(cpx1));
   50976           0 :     memset(&p01, 0, sizeof(p01));
   50977           0 :     memset(&p11, 0, sizeof(p11));
   50978           0 :     memset(&p2, 0, sizeof(p2));
   50979           0 :     ae_matrix_clear(y);
   50980           0 :     ae_vector_init(&cpx0, 0, DT_REAL, _state, ae_true);
   50981           0 :     ae_vector_init(&cpx1, 0, DT_REAL, _state, ae_true);
   50982           0 :     ae_vector_init(&p01, 0, DT_INT, _state, ae_true);
   50983           0 :     ae_vector_init(&p11, 0, DT_INT, _state, ae_true);
   50984           0 :     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
   50985             : 
   50986           0 :     ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state);
   50987           0 :     ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state);
   50988           0 :     ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)<N0", _state);
   50989           0 :     ae_assert(x1->cnt>=n1, "RBFGridCalc2: Length(X1)<N1", _state);
   50990           0 :     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2: X0 contains infinite or NaN values!", _state);
   50991           0 :     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2: X1 contains infinite or NaN values!", _state);
   50992           0 :     ae_matrix_set_length(y, n0, n1, _state);
   50993           0 :     for(i=0; i<=n0-1; i++)
   50994             :     {
   50995           0 :         for(j=0; j<=n1-1; j++)
   50996             :         {
   50997           0 :             y->ptr.pp_double[i][j] = (double)(0);
   50998             :         }
   50999             :     }
   51000           0 :     if( (s->ny!=1||s->nx!=2)||s->nc==0 )
   51001             :     {
   51002           0 :         ae_frame_leave(_state);
   51003           0 :         return;
   51004             :     }
   51005             :     
   51006             :     /*
   51007             :      *create and sort arrays
   51008             :      */
   51009           0 :     ae_vector_set_length(&cpx0, n0, _state);
   51010           0 :     for(i=0; i<=n0-1; i++)
   51011             :     {
   51012           0 :         cpx0.ptr.p_double[i] = x0->ptr.p_double[i];
   51013             :     }
   51014           0 :     tagsort(&cpx0, n0, &p01, &p2, _state);
   51015           0 :     ae_vector_set_length(&cpx1, n1, _state);
   51016           0 :     for(i=0; i<=n1-1; i++)
   51017             :     {
   51018           0 :         cpx1.ptr.p_double[i] = x1->ptr.p_double[i];
   51019             :     }
   51020           0 :     tagsort(&cpx1, n1, &p11, &p2, _state);
   51021             :     
   51022             :     /*
   51023             :      *calculate function's value
   51024             :      */
   51025           0 :     for(i=0; i<=s->nc-1; i++)
   51026             :     {
   51027           0 :         radius = s->wr.ptr.pp_double[i][0];
   51028           0 :         for(d=0; d<=s->nl-1; d++)
   51029             :         {
   51030           0 :             omega = s->wr.ptr.pp_double[i][1+d];
   51031           0 :             rlimit = radius*rbfv1_rbffarradius;
   51032             :             
   51033             :             /*
   51034             :              *search lower and upper indexes
   51035             :              */
   51036           0 :             i00 = lowerbound(&cpx0, n0, s->xc.ptr.pp_double[i][0]-rlimit, _state);
   51037           0 :             i01 = upperbound(&cpx0, n0, s->xc.ptr.pp_double[i][0]+rlimit, _state);
   51038           0 :             i10 = lowerbound(&cpx1, n1, s->xc.ptr.pp_double[i][1]-rlimit, _state);
   51039           0 :             i11 = upperbound(&cpx1, n1, s->xc.ptr.pp_double[i][1]+rlimit, _state);
   51040           0 :             xc0 = s->xc.ptr.pp_double[i][0];
   51041           0 :             xc1 = s->xc.ptr.pp_double[i][1];
   51042           0 :             for(j=i00; j<=i01-1; j++)
   51043             :             {
   51044           0 :                 hcpx0 = cpx0.ptr.p_double[j];
   51045           0 :                 hp01 = p01.ptr.p_int[j];
   51046           0 :                 for(k=i10; k<=i11-1; k++)
   51047             :                 {
   51048           0 :                     xcnorm2 = ae_sqr(hcpx0-xc0, _state)+ae_sqr(cpx1.ptr.p_double[k]-xc1, _state);
   51049           0 :                     if( ae_fp_less_eq(xcnorm2,rlimit*rlimit) )
   51050             :                     {
   51051           0 :                         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;
   51052             :                     }
   51053             :                 }
   51054             :             }
   51055           0 :             radius = 0.5*radius;
   51056             :         }
   51057             :     }
   51058             :     
   51059             :     /*
   51060             :      *add linear term
   51061             :      */
   51062           0 :     for(i=0; i<=n0-1; i++)
   51063             :     {
   51064           0 :         for(j=0; j<=n1-1; j++)
   51065             :         {
   51066           0 :             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];
   51067             :         }
   51068             :     }
   51069           0 :     ae_frame_leave(_state);
   51070             : }
   51071             : 
   51072             : 
   51073           0 : void rbfv1gridcalc3vrec(rbfv1model* s,
   51074             :      /* Real    */ ae_vector* x0,
   51075             :      ae_int_t n0,
   51076             :      /* Real    */ ae_vector* x1,
   51077             :      ae_int_t n1,
   51078             :      /* Real    */ ae_vector* x2,
   51079             :      ae_int_t n2,
   51080             :      /* Integer */ ae_vector* blocks0,
   51081             :      ae_int_t block0a,
   51082             :      ae_int_t block0b,
   51083             :      /* Integer */ ae_vector* blocks1,
   51084             :      ae_int_t block1a,
   51085             :      ae_int_t block1b,
   51086             :      /* Integer */ ae_vector* blocks2,
   51087             :      ae_int_t block2a,
   51088             :      ae_int_t block2b,
   51089             :      /* Boolean */ ae_vector* flagy,
   51090             :      ae_bool sparsey,
   51091             :      double searchradius,
   51092             :      double avgfuncpernode,
   51093             :      ae_shared_pool* bufpool,
   51094             :      /* Real    */ ae_vector* y,
   51095             :      ae_state *_state)
   51096             : {
   51097             :     ae_frame _frame_block;
   51098             :     ae_int_t i;
   51099             :     ae_int_t j;
   51100             :     ae_int_t k;
   51101             :     ae_int_t t;
   51102             :     ae_int_t l;
   51103             :     ae_int_t i0;
   51104             :     ae_int_t i1;
   51105             :     ae_int_t i2;
   51106             :     ae_int_t ic;
   51107             :     gridcalc3v1buf *pbuf;
   51108             :     ae_smart_ptr _pbuf;
   51109             :     ae_int_t flag12dim1;
   51110             :     ae_int_t flag12dim2;
   51111             :     double problemcost;
   51112             :     ae_int_t maxbs;
   51113             :     ae_int_t nx;
   51114             :     ae_int_t ny;
   51115             :     double v;
   51116             :     ae_int_t kc;
   51117             :     ae_int_t tg;
   51118             :     double rcur;
   51119             :     double rcur2;
   51120             :     double basisfuncval;
   51121             :     ae_int_t dstoffs;
   51122             :     ae_int_t srcoffs;
   51123             :     ae_int_t ubnd;
   51124             :     double w0;
   51125             :     double w1;
   51126             :     double w2;
   51127             :     ae_bool allnodes;
   51128             :     ae_bool somenodes;
   51129             : 
   51130           0 :     ae_frame_make(_state, &_frame_block);
   51131           0 :     memset(&_pbuf, 0, sizeof(_pbuf));
   51132           0 :     ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state, ae_true);
   51133             : 
   51134           0 :     nx = s->nx;
   51135           0 :     ny = s->ny;
   51136             :     
   51137             :     /*
   51138             :      * Try to split large problem
   51139             :      */
   51140           0 :     problemcost = (s->nl+1)*s->ny*2*(avgfuncpernode+1);
   51141           0 :     problemcost = problemcost*(blocks0->ptr.p_int[block0b]-blocks0->ptr.p_int[block0a]);
   51142           0 :     problemcost = problemcost*(blocks1->ptr.p_int[block1b]-blocks1->ptr.p_int[block1a]);
   51143           0 :     problemcost = problemcost*(blocks2->ptr.p_int[block2b]-blocks2->ptr.p_int[block2a]);
   51144           0 :     maxbs = 0;
   51145           0 :     maxbs = ae_maxint(maxbs, block0b-block0a, _state);
   51146           0 :     maxbs = ae_maxint(maxbs, block1b-block1a, _state);
   51147           0 :     maxbs = ae_maxint(maxbs, block2b-block2a, _state);
   51148           0 :     if( ae_fp_greater_eq(problemcost,rbfv1_minbasecasecost)&&maxbs>=2 )
   51149             :     {
   51150           0 :         if( block0b-block0a==maxbs )
   51151             :         {
   51152           0 :             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);
   51153           0 :             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);
   51154           0 :             ae_frame_leave(_state);
   51155           0 :             return;
   51156             :         }
   51157           0 :         if( block1b-block1a==maxbs )
   51158             :         {
   51159           0 :             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);
   51160           0 :             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);
   51161           0 :             ae_frame_leave(_state);
   51162           0 :             return;
   51163             :         }
   51164           0 :         if( block2b-block2a==maxbs )
   51165             :         {
   51166           0 :             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);
   51167           0 :             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);
   51168           0 :             ae_frame_leave(_state);
   51169           0 :             return;
   51170             :         }
   51171             :     }
   51172             :     
   51173             :     /*
   51174             :      * Retrieve buffer object from pool (it will be returned later)
   51175             :      */
   51176           0 :     ae_shared_pool_retrieve(bufpool, &_pbuf, _state);
   51177             :     
   51178             :     /*
   51179             :      * Calculate RBF model
   51180             :      */
   51181           0 :     for(i2=block2a; i2<=block2b-1; i2++)
   51182             :     {
   51183           0 :         for(i1=block1a; i1<=block1b-1; i1++)
   51184             :         {
   51185           0 :             for(i0=block0a; i0<=block0b-1; i0++)
   51186             :             {
   51187             :                 
   51188             :                 /*
   51189             :                  * Analyze block - determine what elements are needed and what are not.
   51190             :                  *
   51191             :                  * After this block is done, two flag variables can be used:
   51192             :                  * * SomeNodes, which is True when there are at least one node which have
   51193             :                  *   to be calculated
   51194             :                  * * AllNodes, which is True when all nodes are required
   51195             :                  */
   51196           0 :                 somenodes = ae_true;
   51197           0 :                 allnodes = ae_true;
   51198           0 :                 flag12dim1 = blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1];
   51199           0 :                 flag12dim2 = blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2];
   51200           0 :                 if( sparsey )
   51201             :                 {
   51202             :                     
   51203             :                     /*
   51204             :                      * Use FlagY to determine what is required.
   51205             :                      */
   51206           0 :                     bvectorsetlengthatleast(&pbuf->flag0, n0, _state);
   51207           0 :                     bvectorsetlengthatleast(&pbuf->flag1, n1, _state);
   51208           0 :                     bvectorsetlengthatleast(&pbuf->flag2, n2, _state);
   51209           0 :                     bvectorsetlengthatleast(&pbuf->flag12, flag12dim1*flag12dim2, _state);
   51210           0 :                     for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++)
   51211             :                     {
   51212           0 :                         pbuf->flag0.ptr.p_bool[i] = ae_false;
   51213             :                     }
   51214           0 :                     for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++)
   51215             :                     {
   51216           0 :                         pbuf->flag1.ptr.p_bool[j] = ae_false;
   51217             :                     }
   51218           0 :                     for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++)
   51219             :                     {
   51220           0 :                         pbuf->flag2.ptr.p_bool[k] = ae_false;
   51221             :                     }
   51222           0 :                     for(i=0; i<=flag12dim1*flag12dim2-1; i++)
   51223             :                     {
   51224           0 :                         pbuf->flag12.ptr.p_bool[i] = ae_false;
   51225             :                     }
   51226           0 :                     somenodes = ae_false;
   51227           0 :                     allnodes = ae_true;
   51228           0 :                     for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++)
   51229             :                     {
   51230           0 :                         for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++)
   51231             :                         {
   51232           0 :                             dstoffs = j-blocks1->ptr.p_int[i1]+flag12dim1*(k-blocks2->ptr.p_int[i2]);
   51233           0 :                             srcoffs = j*n0+k*n0*n1;
   51234           0 :                             for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++)
   51235             :                             {
   51236           0 :                                 if( flagy->ptr.p_bool[srcoffs+i] )
   51237             :                                 {
   51238           0 :                                     pbuf->flag0.ptr.p_bool[i] = ae_true;
   51239           0 :                                     pbuf->flag1.ptr.p_bool[j] = ae_true;
   51240           0 :                                     pbuf->flag2.ptr.p_bool[k] = ae_true;
   51241           0 :                                     pbuf->flag12.ptr.p_bool[dstoffs] = ae_true;
   51242           0 :                                     somenodes = ae_true;
   51243             :                                 }
   51244             :                                 else
   51245             :                                 {
   51246           0 :                                     allnodes = ae_false;
   51247             :                                 }
   51248             :                             }
   51249             :                         }
   51250             :                     }
   51251             :                 }
   51252             :                 
   51253             :                 /*
   51254             :                  * Skip block if it is completely empty.
   51255             :                  */
   51256           0 :                 if( !somenodes )
   51257             :                 {
   51258           0 :                     continue;
   51259             :                 }
   51260             :                 
   51261             :                 /*
   51262             :                  * compute linear term for block (I0,I1,I2)
   51263             :                  */
   51264           0 :                 for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++)
   51265             :                 {
   51266           0 :                     for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++)
   51267             :                     {
   51268             :                         
   51269             :                         /*
   51270             :                          * do we need this micro-row?
   51271             :                          */
   51272           0 :                         if( !allnodes&&!pbuf->flag12.ptr.p_bool[j-blocks1->ptr.p_int[i1]+flag12dim1*(k-blocks2->ptr.p_int[i2])] )
   51273             :                         {
   51274           0 :                             continue;
   51275             :                         }
   51276             :                         
   51277             :                         /*
   51278             :                          * Compute linear term
   51279             :                          */
   51280           0 :                         for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++)
   51281             :                         {
   51282           0 :                             pbuf->tx.ptr.p_double[0] = x0->ptr.p_double[i];
   51283           0 :                             pbuf->tx.ptr.p_double[1] = x1->ptr.p_double[j];
   51284           0 :                             pbuf->tx.ptr.p_double[2] = x2->ptr.p_double[k];
   51285           0 :                             for(l=0; l<=s->ny-1; l++)
   51286             :                             {
   51287           0 :                                 v = s->v.ptr.pp_double[l][rbfv1_mxnx];
   51288           0 :                                 for(t=0; t<=nx-1; t++)
   51289             :                                 {
   51290           0 :                                     v = v+s->v.ptr.pp_double[l][t]*pbuf->tx.ptr.p_double[t];
   51291             :                                 }
   51292           0 :                                 y->ptr.p_double[l+ny*(i+j*n0+k*n0*n1)] = v;
   51293             :                             }
   51294             :                         }
   51295             :                     }
   51296             :                 }
   51297             :                 
   51298             :                 /*
   51299             :                  * compute RBF term for block (I0,I1,I2)
   51300             :                  */
   51301           0 :                 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]);
   51302           0 :                 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]);
   51303           0 :                 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]);
   51304           0 :                 kc = kdtreetsqueryrnn(&s->tree, &pbuf->requestbuf, &pbuf->tx, searchradius, ae_true, _state);
   51305           0 :                 kdtreetsqueryresultsx(&s->tree, &pbuf->requestbuf, &pbuf->calcbufx, _state);
   51306           0 :                 kdtreetsqueryresultstags(&s->tree, &pbuf->requestbuf, &pbuf->calcbuftags, _state);
   51307           0 :                 for(ic=0; ic<=kc-1; ic++)
   51308             :                 {
   51309           0 :                     pbuf->cx.ptr.p_double[0] = pbuf->calcbufx.ptr.pp_double[ic][0];
   51310           0 :                     pbuf->cx.ptr.p_double[1] = pbuf->calcbufx.ptr.pp_double[ic][1];
   51311           0 :                     pbuf->cx.ptr.p_double[2] = pbuf->calcbufx.ptr.pp_double[ic][2];
   51312           0 :                     tg = pbuf->calcbuftags.ptr.p_int[ic];
   51313           0 :                     rcur = s->wr.ptr.pp_double[tg][0];
   51314           0 :                     rcur2 = rcur*rcur;
   51315           0 :                     for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++)
   51316             :                     {
   51317           0 :                         if( allnodes||pbuf->flag0.ptr.p_bool[i] )
   51318             :                         {
   51319           0 :                             pbuf->expbuf0.ptr.p_double[i] = ae_exp(-ae_sqr(x0->ptr.p_double[i]-pbuf->cx.ptr.p_double[0], _state)/rcur2, _state);
   51320             :                         }
   51321             :                         else
   51322             :                         {
   51323           0 :                             pbuf->expbuf0.ptr.p_double[i] = 0.0;
   51324             :                         }
   51325             :                     }
   51326           0 :                     for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++)
   51327             :                     {
   51328           0 :                         if( allnodes||pbuf->flag1.ptr.p_bool[j] )
   51329             :                         {
   51330           0 :                             pbuf->expbuf1.ptr.p_double[j] = ae_exp(-ae_sqr(x1->ptr.p_double[j]-pbuf->cx.ptr.p_double[1], _state)/rcur2, _state);
   51331             :                         }
   51332             :                         else
   51333             :                         {
   51334           0 :                             pbuf->expbuf1.ptr.p_double[j] = 0.0;
   51335             :                         }
   51336             :                     }
   51337           0 :                     for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++)
   51338             :                     {
   51339           0 :                         if( allnodes||pbuf->flag2.ptr.p_bool[k] )
   51340             :                         {
   51341           0 :                             pbuf->expbuf2.ptr.p_double[k] = ae_exp(-ae_sqr(x2->ptr.p_double[k]-pbuf->cx.ptr.p_double[2], _state)/rcur2, _state);
   51342             :                         }
   51343             :                         else
   51344             :                         {
   51345           0 :                             pbuf->expbuf2.ptr.p_double[k] = 0.0;
   51346             :                         }
   51347             :                     }
   51348           0 :                     for(t=0; t<=s->nl-1; t++)
   51349             :                     {
   51350             :                         
   51351             :                         /*
   51352             :                          * Calculate
   51353             :                          */
   51354           0 :                         for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++)
   51355             :                         {
   51356           0 :                             for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++)
   51357             :                             {
   51358             :                                 
   51359             :                                 /*
   51360             :                                  * do we need this micro-row?
   51361             :                                  */
   51362           0 :                                 if( !allnodes&&!pbuf->flag12.ptr.p_bool[j-blocks1->ptr.p_int[i1]+flag12dim1*(k-blocks2->ptr.p_int[i2])] )
   51363             :                                 {
   51364           0 :                                     continue;
   51365             :                                 }
   51366             :                                 
   51367             :                                 /*
   51368             :                                  * Prepare local variables
   51369             :                                  */
   51370           0 :                                 dstoffs = ny*(blocks0->ptr.p_int[i0]+j*n0+k*n0*n1);
   51371           0 :                                 v = pbuf->expbuf1.ptr.p_double[j]*pbuf->expbuf2.ptr.p_double[k];
   51372             :                                 
   51373             :                                 /*
   51374             :                                  * Optimized for NY=1
   51375             :                                  */
   51376           0 :                                 if( s->ny==1 )
   51377             :                                 {
   51378           0 :                                     w0 = s->wr.ptr.pp_double[tg][1+t*s->ny+0];
   51379           0 :                                     ubnd = blocks0->ptr.p_int[i0+1]-1;
   51380           0 :                                     for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++)
   51381             :                                     {
   51382           0 :                                         basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v;
   51383           0 :                                         y->ptr.p_double[dstoffs] = y->ptr.p_double[dstoffs]+basisfuncval*w0;
   51384           0 :                                         dstoffs = dstoffs+1;
   51385             :                                     }
   51386           0 :                                     continue;
   51387             :                                 }
   51388             :                                 
   51389             :                                 /*
   51390             :                                  * Optimized for NY=2
   51391             :                                  */
   51392           0 :                                 if( s->ny==2 )
   51393             :                                 {
   51394           0 :                                     w0 = s->wr.ptr.pp_double[tg][1+t*s->ny+0];
   51395           0 :                                     w1 = s->wr.ptr.pp_double[tg][1+t*s->ny+1];
   51396           0 :                                     ubnd = blocks0->ptr.p_int[i0+1]-1;
   51397           0 :                                     for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++)
   51398             :                                     {
   51399           0 :                                         basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v;
   51400           0 :                                         y->ptr.p_double[dstoffs+0] = y->ptr.p_double[dstoffs+0]+basisfuncval*w0;
   51401           0 :                                         y->ptr.p_double[dstoffs+1] = y->ptr.p_double[dstoffs+1]+basisfuncval*w1;
   51402           0 :                                         dstoffs = dstoffs+2;
   51403             :                                     }
   51404           0 :                                     continue;
   51405             :                                 }
   51406             :                                 
   51407             :                                 /*
   51408             :                                  * Optimized for NY=3
   51409             :                                  */
   51410           0 :                                 if( s->ny==3 )
   51411             :                                 {
   51412           0 :                                     w0 = s->wr.ptr.pp_double[tg][1+t*s->ny+0];
   51413           0 :                                     w1 = s->wr.ptr.pp_double[tg][1+t*s->ny+1];
   51414           0 :                                     w2 = s->wr.ptr.pp_double[tg][1+t*s->ny+2];
   51415           0 :                                     ubnd = blocks0->ptr.p_int[i0+1]-1;
   51416           0 :                                     for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++)
   51417             :                                     {
   51418           0 :                                         basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v;
   51419           0 :                                         y->ptr.p_double[dstoffs+0] = y->ptr.p_double[dstoffs+0]+basisfuncval*w0;
   51420           0 :                                         y->ptr.p_double[dstoffs+1] = y->ptr.p_double[dstoffs+1]+basisfuncval*w1;
   51421           0 :                                         y->ptr.p_double[dstoffs+2] = y->ptr.p_double[dstoffs+2]+basisfuncval*w2;
   51422           0 :                                         dstoffs = dstoffs+3;
   51423             :                                     }
   51424           0 :                                     continue;
   51425             :                                 }
   51426             :                                 
   51427             :                                 /*
   51428             :                                  * General case
   51429             :                                  */
   51430           0 :                                 for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++)
   51431             :                                 {
   51432           0 :                                     basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v;
   51433           0 :                                     for(l=0; l<=s->ny-1; l++)
   51434             :                                     {
   51435           0 :                                         y->ptr.p_double[l+dstoffs] = y->ptr.p_double[l+dstoffs]+basisfuncval*s->wr.ptr.pp_double[tg][1+t*s->ny+l];
   51436             :                                     }
   51437           0 :                                     dstoffs = dstoffs+ny;
   51438             :                                 }
   51439             :                             }
   51440             :                         }
   51441             :                         
   51442             :                         /*
   51443             :                          * Update basis functions
   51444             :                          */
   51445           0 :                         if( t!=s->nl-1 )
   51446             :                         {
   51447           0 :                             ubnd = blocks0->ptr.p_int[i0+1]-1;
   51448           0 :                             for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++)
   51449             :                             {
   51450           0 :                                 if( allnodes||pbuf->flag0.ptr.p_bool[i] )
   51451             :                                 {
   51452           0 :                                     v = pbuf->expbuf0.ptr.p_double[i]*pbuf->expbuf0.ptr.p_double[i];
   51453           0 :                                     pbuf->expbuf0.ptr.p_double[i] = v*v;
   51454             :                                 }
   51455             :                             }
   51456           0 :                             ubnd = blocks1->ptr.p_int[i1+1]-1;
   51457           0 :                             for(j=blocks1->ptr.p_int[i1]; j<=ubnd; j++)
   51458             :                             {
   51459           0 :                                 if( allnodes||pbuf->flag1.ptr.p_bool[j] )
   51460             :                                 {
   51461           0 :                                     v = pbuf->expbuf1.ptr.p_double[j]*pbuf->expbuf1.ptr.p_double[j];
   51462           0 :                                     pbuf->expbuf1.ptr.p_double[j] = v*v;
   51463             :                                 }
   51464             :                             }
   51465           0 :                             ubnd = blocks2->ptr.p_int[i2+1]-1;
   51466           0 :                             for(k=blocks2->ptr.p_int[i2]; k<=ubnd; k++)
   51467             :                             {
   51468           0 :                                 if( allnodes||pbuf->flag2.ptr.p_bool[k] )
   51469             :                                 {
   51470           0 :                                     v = pbuf->expbuf2.ptr.p_double[k]*pbuf->expbuf2.ptr.p_double[k];
   51471           0 :                                     pbuf->expbuf2.ptr.p_double[k] = v*v;
   51472             :                                 }
   51473             :                             }
   51474             :                         }
   51475             :                     }
   51476             :                 }
   51477             :             }
   51478             :         }
   51479             :     }
   51480             :     
   51481             :     /*
   51482             :      * Recycle buffer object back to pool
   51483             :      */
   51484           0 :     ae_shared_pool_recycle(bufpool, &_pbuf, _state);
   51485           0 :     ae_frame_leave(_state);
   51486             : }
   51487             : 
   51488             : 
   51489             : /*************************************************************************
   51490             : Serial stub for GPL edition.
   51491             : *************************************************************************/
   51492           0 : ae_bool _trypexec_rbfv1gridcalc3vrec(rbfv1model* s,
   51493             :     /* Real    */ ae_vector* x0,
   51494             :     ae_int_t n0,
   51495             :     /* Real    */ ae_vector* x1,
   51496             :     ae_int_t n1,
   51497             :     /* Real    */ ae_vector* x2,
   51498             :     ae_int_t n2,
   51499             :     /* Integer */ ae_vector* blocks0,
   51500             :     ae_int_t block0a,
   51501             :     ae_int_t block0b,
   51502             :     /* Integer */ ae_vector* blocks1,
   51503             :     ae_int_t block1a,
   51504             :     ae_int_t block1b,
   51505             :     /* Integer */ ae_vector* blocks2,
   51506             :     ae_int_t block2a,
   51507             :     ae_int_t block2b,
   51508             :     /* Boolean */ ae_vector* flagy,
   51509             :     ae_bool sparsey,
   51510             :     double searchradius,
   51511             :     double avgfuncpernode,
   51512             :     ae_shared_pool* bufpool,
   51513             :     /* Real    */ ae_vector* y,
   51514             :     ae_state *_state)
   51515             : {
   51516           0 :     return ae_false;
   51517             : }
   51518             : 
   51519             : 
   51520             : /*************************************************************************
   51521             : This function "unpacks" RBF model by extracting its coefficients.
   51522             : 
   51523             : INPUT PARAMETERS:
   51524             :     S       -   RBF model
   51525             : 
   51526             : OUTPUT PARAMETERS:
   51527             :     NX      -   dimensionality of argument
   51528             :     NY      -   dimensionality of the target function
   51529             :     XWR     -   model information, array[NC,NX+NY+1].
   51530             :                 One row of the array corresponds to one basis function:
   51531             :                 * first NX columns  - coordinates of the center 
   51532             :                 * next NY columns   - weights, one per dimension of the 
   51533             :                                       function being modelled
   51534             :                 * last column       - radius, same for all dimensions of
   51535             :                                       the function being modelled
   51536             :     NC      -   number of the centers
   51537             :     V       -   polynomial  term , array[NY,NX+1]. One row per one 
   51538             :                 dimension of the function being modelled. First NX 
   51539             :                 elements are linear coefficients, V[NX] is equal to the 
   51540             :                 constant part.
   51541             : 
   51542             :   -- ALGLIB --
   51543             :      Copyright 13.12.2011 by Bochkanov Sergey
   51544             : *************************************************************************/
   51545           0 : void rbfv1unpack(rbfv1model* s,
   51546             :      ae_int_t* nx,
   51547             :      ae_int_t* ny,
   51548             :      /* Real    */ ae_matrix* xwr,
   51549             :      ae_int_t* nc,
   51550             :      /* Real    */ ae_matrix* v,
   51551             :      ae_state *_state)
   51552             : {
   51553             :     ae_int_t i;
   51554             :     ae_int_t j;
   51555             :     double rcur;
   51556             : 
   51557           0 :     *nx = 0;
   51558           0 :     *ny = 0;
   51559           0 :     ae_matrix_clear(xwr);
   51560           0 :     *nc = 0;
   51561           0 :     ae_matrix_clear(v);
   51562             : 
   51563           0 :     *nx = s->nx;
   51564           0 :     *ny = s->ny;
   51565           0 :     *nc = s->nc;
   51566             :     
   51567             :     /*
   51568             :      * Fill V
   51569             :      */
   51570           0 :     ae_matrix_set_length(v, s->ny, s->nx+1, _state);
   51571           0 :     for(i=0; i<=s->ny-1; i++)
   51572             :     {
   51573           0 :         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));
   51574           0 :         v->ptr.pp_double[i][s->nx] = s->v.ptr.pp_double[i][rbfv1_mxnx];
   51575             :     }
   51576             :     
   51577             :     /*
   51578             :      * Fill XWR and V
   51579             :      */
   51580           0 :     if( *nc*s->nl>0 )
   51581             :     {
   51582           0 :         ae_matrix_set_length(xwr, s->nc*s->nl, s->nx+s->ny+1, _state);
   51583           0 :         for(i=0; i<=s->nc-1; i++)
   51584             :         {
   51585           0 :             rcur = s->wr.ptr.pp_double[i][0];
   51586           0 :             for(j=0; j<=s->nl-1; j++)
   51587             :             {
   51588           0 :                 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));
   51589           0 :                 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));
   51590           0 :                 xwr->ptr.pp_double[i*s->nl+j][s->nx+s->ny] = rcur;
   51591           0 :                 rcur = 0.5*rcur;
   51592             :             }
   51593             :         }
   51594             :     }
   51595           0 : }
   51596             : 
   51597             : 
   51598           0 : static ae_bool rbfv1_rbfv1buildlinearmodel(/* Real    */ ae_matrix* x,
   51599             :      /* Real    */ ae_matrix* y,
   51600             :      ae_int_t n,
   51601             :      ae_int_t ny,
   51602             :      ae_int_t modeltype,
   51603             :      /* Real    */ ae_matrix* v,
   51604             :      ae_state *_state)
   51605             : {
   51606             :     ae_frame _frame_block;
   51607             :     ae_vector tmpy;
   51608             :     ae_matrix a;
   51609             :     double scaling;
   51610             :     ae_vector shifting;
   51611             :     double mn;
   51612             :     double mx;
   51613             :     ae_vector c;
   51614             :     lsfitreport rep;
   51615             :     ae_int_t i;
   51616             :     ae_int_t j;
   51617             :     ae_int_t k;
   51618             :     ae_int_t info;
   51619             :     ae_bool result;
   51620             : 
   51621           0 :     ae_frame_make(_state, &_frame_block);
   51622           0 :     memset(&tmpy, 0, sizeof(tmpy));
   51623           0 :     memset(&a, 0, sizeof(a));
   51624           0 :     memset(&shifting, 0, sizeof(shifting));
   51625           0 :     memset(&c, 0, sizeof(c));
   51626           0 :     memset(&rep, 0, sizeof(rep));
   51627           0 :     ae_matrix_clear(v);
   51628           0 :     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
   51629           0 :     ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true);
   51630           0 :     ae_vector_init(&shifting, 0, DT_REAL, _state, ae_true);
   51631           0 :     ae_vector_init(&c, 0, DT_REAL, _state, ae_true);
   51632           0 :     _lsfitreport_init(&rep, _state, ae_true);
   51633             : 
   51634           0 :     ae_assert(n>=0, "BuildLinearModel: N<0", _state);
   51635           0 :     ae_assert(ny>0, "BuildLinearModel: NY<=0", _state);
   51636             :     
   51637             :     /*
   51638             :      * Handle degenerate case (N=0)
   51639             :      */
   51640           0 :     result = ae_true;
   51641           0 :     ae_matrix_set_length(v, ny, rbfv1_mxnx+1, _state);
   51642           0 :     if( n==0 )
   51643             :     {
   51644           0 :         for(j=0; j<=rbfv1_mxnx; j++)
   51645             :         {
   51646           0 :             for(i=0; i<=ny-1; i++)
   51647             :             {
   51648           0 :                 v->ptr.pp_double[i][j] = (double)(0);
   51649             :             }
   51650             :         }
   51651           0 :         ae_frame_leave(_state);
   51652           0 :         return result;
   51653             :     }
   51654             :     
   51655             :     /*
   51656             :      * Allocate temporaries
   51657             :      */
   51658           0 :     ae_vector_set_length(&tmpy, n, _state);
   51659             :     
   51660             :     /*
   51661             :      * General linear model.
   51662             :      */
   51663           0 :     if( modeltype==1 )
   51664             :     {
   51665             :         
   51666             :         /*
   51667             :          * Calculate scaling/shifting, transform variables, prepare LLS problem
   51668             :          */
   51669           0 :         ae_matrix_set_length(&a, n, rbfv1_mxnx+1, _state);
   51670           0 :         ae_vector_set_length(&shifting, rbfv1_mxnx, _state);
   51671           0 :         scaling = (double)(0);
   51672           0 :         for(i=0; i<=rbfv1_mxnx-1; i++)
   51673             :         {
   51674           0 :             mn = x->ptr.pp_double[0][i];
   51675           0 :             mx = mn;
   51676           0 :             for(j=1; j<=n-1; j++)
   51677             :             {
   51678           0 :                 if( ae_fp_greater(mn,x->ptr.pp_double[j][i]) )
   51679             :                 {
   51680           0 :                     mn = x->ptr.pp_double[j][i];
   51681             :                 }
   51682           0 :                 if( ae_fp_less(mx,x->ptr.pp_double[j][i]) )
   51683             :                 {
   51684           0 :                     mx = x->ptr.pp_double[j][i];
   51685             :                 }
   51686             :             }
   51687           0 :             scaling = ae_maxreal(scaling, mx-mn, _state);
   51688           0 :             shifting.ptr.p_double[i] = 0.5*(mx+mn);
   51689             :         }
   51690           0 :         if( ae_fp_eq(scaling,(double)(0)) )
   51691             :         {
   51692           0 :             scaling = (double)(1);
   51693             :         }
   51694             :         else
   51695             :         {
   51696           0 :             scaling = 0.5*scaling;
   51697             :         }
   51698           0 :         for(i=0; i<=n-1; i++)
   51699             :         {
   51700           0 :             for(j=0; j<=rbfv1_mxnx-1; j++)
   51701             :             {
   51702           0 :                 a.ptr.pp_double[i][j] = (x->ptr.pp_double[i][j]-shifting.ptr.p_double[j])/scaling;
   51703             :             }
   51704             :         }
   51705           0 :         for(i=0; i<=n-1; i++)
   51706             :         {
   51707           0 :             a.ptr.pp_double[i][rbfv1_mxnx] = (double)(1);
   51708             :         }
   51709             :         
   51710             :         /*
   51711             :          * Solve linear system in transformed variables, make backward 
   51712             :          */
   51713           0 :         for(i=0; i<=ny-1; i++)
   51714             :         {
   51715           0 :             for(j=0; j<=n-1; j++)
   51716             :             {
   51717           0 :                 tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i];
   51718             :             }
   51719           0 :             lsfitlinear(&tmpy, &a, n, rbfv1_mxnx+1, &info, &c, &rep, _state);
   51720           0 :             if( info<=0 )
   51721             :             {
   51722           0 :                 result = ae_false;
   51723           0 :                 ae_frame_leave(_state);
   51724           0 :                 return result;
   51725             :             }
   51726           0 :             for(j=0; j<=rbfv1_mxnx-1; j++)
   51727             :             {
   51728           0 :                 v->ptr.pp_double[i][j] = c.ptr.p_double[j]/scaling;
   51729             :             }
   51730           0 :             v->ptr.pp_double[i][rbfv1_mxnx] = c.ptr.p_double[rbfv1_mxnx];
   51731           0 :             for(j=0; j<=rbfv1_mxnx-1; j++)
   51732             :             {
   51733           0 :                 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];
   51734             :             }
   51735           0 :             for(j=0; j<=n-1; j++)
   51736             :             {
   51737           0 :                 for(k=0; k<=rbfv1_mxnx-1; k++)
   51738             :                 {
   51739           0 :                     y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-x->ptr.pp_double[j][k]*v->ptr.pp_double[i][k];
   51740             :                 }
   51741           0 :                 y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][rbfv1_mxnx];
   51742             :             }
   51743             :         }
   51744           0 :         ae_frame_leave(_state);
   51745           0 :         return result;
   51746             :     }
   51747             :     
   51748             :     /*
   51749             :      * Constant model, very simple
   51750             :      */
   51751           0 :     if( modeltype==2 )
   51752             :     {
   51753           0 :         for(i=0; i<=ny-1; i++)
   51754             :         {
   51755           0 :             for(j=0; j<=rbfv1_mxnx; j++)
   51756             :             {
   51757           0 :                 v->ptr.pp_double[i][j] = (double)(0);
   51758             :             }
   51759           0 :             for(j=0; j<=n-1; j++)
   51760             :             {
   51761           0 :                 v->ptr.pp_double[i][rbfv1_mxnx] = v->ptr.pp_double[i][rbfv1_mxnx]+y->ptr.pp_double[j][i];
   51762             :             }
   51763           0 :             if( n>0 )
   51764             :             {
   51765           0 :                 v->ptr.pp_double[i][rbfv1_mxnx] = v->ptr.pp_double[i][rbfv1_mxnx]/n;
   51766             :             }
   51767           0 :             for(j=0; j<=n-1; j++)
   51768             :             {
   51769           0 :                 y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][rbfv1_mxnx];
   51770             :             }
   51771             :         }
   51772           0 :         ae_frame_leave(_state);
   51773           0 :         return result;
   51774             :     }
   51775             :     
   51776             :     /*
   51777             :      * Zero model
   51778             :      */
   51779           0 :     ae_assert(modeltype==3, "BuildLinearModel: unknown model type", _state);
   51780           0 :     for(i=0; i<=ny-1; i++)
   51781             :     {
   51782           0 :         for(j=0; j<=rbfv1_mxnx; j++)
   51783             :         {
   51784           0 :             v->ptr.pp_double[i][j] = (double)(0);
   51785             :         }
   51786             :     }
   51787           0 :     ae_frame_leave(_state);
   51788           0 :     return result;
   51789             : }
   51790             : 
   51791             : 
   51792           0 : static void rbfv1_buildrbfmodellsqr(/* Real    */ ae_matrix* x,
   51793             :      /* Real    */ ae_matrix* y,
   51794             :      /* Real    */ ae_matrix* xc,
   51795             :      /* Real    */ ae_vector* r,
   51796             :      ae_int_t n,
   51797             :      ae_int_t nc,
   51798             :      ae_int_t ny,
   51799             :      kdtree* pointstree,
   51800             :      kdtree* centerstree,
   51801             :      double epsort,
   51802             :      double epserr,
   51803             :      ae_int_t maxits,
   51804             :      ae_int_t* gnnz,
   51805             :      ae_int_t* snnz,
   51806             :      /* Real    */ ae_matrix* w,
   51807             :      ae_int_t* info,
   51808             :      ae_int_t* iterationscount,
   51809             :      ae_int_t* nmv,
   51810             :      ae_state *_state)
   51811             : {
   51812             :     ae_frame _frame_block;
   51813             :     linlsqrstate state;
   51814             :     linlsqrreport lsqrrep;
   51815             :     sparsematrix spg;
   51816             :     sparsematrix sps;
   51817             :     ae_vector nearcenterscnt;
   51818             :     ae_vector nearpointscnt;
   51819             :     ae_vector skipnearpointscnt;
   51820             :     ae_vector farpointscnt;
   51821             :     ae_int_t maxnearcenterscnt;
   51822             :     ae_int_t maxnearpointscnt;
   51823             :     ae_int_t maxfarpointscnt;
   51824             :     ae_int_t sumnearcenterscnt;
   51825             :     ae_int_t sumnearpointscnt;
   51826             :     ae_int_t sumfarpointscnt;
   51827             :     double maxrad;
   51828             :     ae_vector pointstags;
   51829             :     ae_vector centerstags;
   51830             :     ae_matrix nearpoints;
   51831             :     ae_matrix nearcenters;
   51832             :     ae_matrix farpoints;
   51833             :     ae_int_t tmpi;
   51834             :     ae_int_t pointscnt;
   51835             :     ae_int_t centerscnt;
   51836             :     ae_vector xcx;
   51837             :     ae_vector tmpy;
   51838             :     ae_vector tc;
   51839             :     ae_vector g;
   51840             :     ae_vector c;
   51841             :     ae_int_t i;
   51842             :     ae_int_t j;
   51843             :     ae_int_t k;
   51844             :     ae_int_t sind;
   51845             :     ae_matrix a;
   51846             :     double vv;
   51847             :     double vx;
   51848             :     double vy;
   51849             :     double vz;
   51850             :     double vr;
   51851             :     double gnorm2;
   51852             :     ae_vector tmp0;
   51853             :     ae_vector tmp1;
   51854             :     ae_vector tmp2;
   51855             :     double fx;
   51856             :     ae_matrix xx;
   51857             :     ae_matrix cx;
   51858             :     double mrad;
   51859             : 
   51860           0 :     ae_frame_make(_state, &_frame_block);
   51861           0 :     memset(&state, 0, sizeof(state));
   51862           0 :     memset(&lsqrrep, 0, sizeof(lsqrrep));
   51863           0 :     memset(&spg, 0, sizeof(spg));
   51864           0 :     memset(&sps, 0, sizeof(sps));
   51865           0 :     memset(&nearcenterscnt, 0, sizeof(nearcenterscnt));
   51866           0 :     memset(&nearpointscnt, 0, sizeof(nearpointscnt));
   51867           0 :     memset(&skipnearpointscnt, 0, sizeof(skipnearpointscnt));
   51868           0 :     memset(&farpointscnt, 0, sizeof(farpointscnt));
   51869           0 :     memset(&pointstags, 0, sizeof(pointstags));
   51870           0 :     memset(&centerstags, 0, sizeof(centerstags));
   51871           0 :     memset(&nearpoints, 0, sizeof(nearpoints));
   51872           0 :     memset(&nearcenters, 0, sizeof(nearcenters));
   51873           0 :     memset(&farpoints, 0, sizeof(farpoints));
   51874           0 :     memset(&xcx, 0, sizeof(xcx));
   51875           0 :     memset(&tmpy, 0, sizeof(tmpy));
   51876           0 :     memset(&tc, 0, sizeof(tc));
   51877           0 :     memset(&g, 0, sizeof(g));
   51878           0 :     memset(&c, 0, sizeof(c));
   51879           0 :     memset(&a, 0, sizeof(a));
   51880           0 :     memset(&tmp0, 0, sizeof(tmp0));
   51881           0 :     memset(&tmp1, 0, sizeof(tmp1));
   51882           0 :     memset(&tmp2, 0, sizeof(tmp2));
   51883           0 :     memset(&xx, 0, sizeof(xx));
   51884           0 :     memset(&cx, 0, sizeof(cx));
   51885           0 :     *gnnz = 0;
   51886           0 :     *snnz = 0;
   51887           0 :     ae_matrix_clear(w);
   51888           0 :     *info = 0;
   51889           0 :     *iterationscount = 0;
   51890           0 :     *nmv = 0;
   51891           0 :     _linlsqrstate_init(&state, _state, ae_true);
   51892           0 :     _linlsqrreport_init(&lsqrrep, _state, ae_true);
   51893           0 :     _sparsematrix_init(&spg, _state, ae_true);
   51894           0 :     _sparsematrix_init(&sps, _state, ae_true);
   51895           0 :     ae_vector_init(&nearcenterscnt, 0, DT_INT, _state, ae_true);
   51896           0 :     ae_vector_init(&nearpointscnt, 0, DT_INT, _state, ae_true);
   51897           0 :     ae_vector_init(&skipnearpointscnt, 0, DT_INT, _state, ae_true);
   51898           0 :     ae_vector_init(&farpointscnt, 0, DT_INT, _state, ae_true);
   51899           0 :     ae_vector_init(&pointstags, 0, DT_INT, _state, ae_true);
   51900           0 :     ae_vector_init(&centerstags, 0, DT_INT, _state, ae_true);
   51901           0 :     ae_matrix_init(&nearpoints, 0, 0, DT_REAL, _state, ae_true);
   51902           0 :     ae_matrix_init(&nearcenters, 0, 0, DT_REAL, _state, ae_true);
   51903           0 :     ae_matrix_init(&farpoints, 0, 0, DT_REAL, _state, ae_true);
   51904           0 :     ae_vector_init(&xcx, 0, DT_REAL, _state, ae_true);
   51905           0 :     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
   51906           0 :     ae_vector_init(&tc, 0, DT_REAL, _state, ae_true);
   51907           0 :     ae_vector_init(&g, 0, DT_REAL, _state, ae_true);
   51908           0 :     ae_vector_init(&c, 0, DT_REAL, _state, ae_true);
   51909           0 :     ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true);
   51910           0 :     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
   51911           0 :     ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true);
   51912           0 :     ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true);
   51913           0 :     ae_matrix_init(&xx, 0, 0, DT_REAL, _state, ae_true);
   51914           0 :     ae_matrix_init(&cx, 0, 0, DT_REAL, _state, ae_true);
   51915             : 
   51916             :     
   51917             :     /*
   51918             :      * Handle special cases: NC=0
   51919             :      */
   51920           0 :     if( nc==0 )
   51921             :     {
   51922           0 :         *info = 1;
   51923           0 :         *iterationscount = 0;
   51924           0 :         *nmv = 0;
   51925           0 :         ae_frame_leave(_state);
   51926           0 :         return;
   51927             :     }
   51928             :     
   51929             :     /*
   51930             :      * Prepare for general case, NC>0
   51931             :      */
   51932           0 :     ae_vector_set_length(&xcx, rbfv1_mxnx, _state);
   51933           0 :     ae_vector_set_length(&pointstags, n, _state);
   51934           0 :     ae_vector_set_length(&centerstags, nc, _state);
   51935           0 :     *info = -1;
   51936           0 :     *iterationscount = 0;
   51937           0 :     *nmv = 0;
   51938             :     
   51939             :     /*
   51940             :      * This block prepares quantities used to compute approximate cardinal basis functions (ACBFs):
   51941             :      * * NearCentersCnt[]   -   array[NC], whose elements store number of near centers used to build ACBF
   51942             :      * * NearPointsCnt[]    -   array[NC], number of near points used to build ACBF
   51943             :      * * FarPointsCnt[]     -   array[NC], number of far points (ones where ACBF is nonzero)
   51944             :      * * MaxNearCentersCnt  -   max(NearCentersCnt)
   51945             :      * * MaxNearPointsCnt   -   max(NearPointsCnt)
   51946             :      * * SumNearCentersCnt  -   sum(NearCentersCnt)
   51947             :      * * SumNearPointsCnt   -   sum(NearPointsCnt)
   51948             :      * * SumFarPointsCnt    -   sum(FarPointsCnt)
   51949             :      */
   51950           0 :     ae_vector_set_length(&nearcenterscnt, nc, _state);
   51951           0 :     ae_vector_set_length(&nearpointscnt, nc, _state);
   51952           0 :     ae_vector_set_length(&skipnearpointscnt, nc, _state);
   51953           0 :     ae_vector_set_length(&farpointscnt, nc, _state);
   51954           0 :     maxnearcenterscnt = 0;
   51955           0 :     maxnearpointscnt = 0;
   51956           0 :     maxfarpointscnt = 0;
   51957           0 :     sumnearcenterscnt = 0;
   51958           0 :     sumnearpointscnt = 0;
   51959           0 :     sumfarpointscnt = 0;
   51960           0 :     for(i=0; i<=nc-1; i++)
   51961             :     {
   51962           0 :         for(j=0; j<=rbfv1_mxnx-1; j++)
   51963             :         {
   51964           0 :             xcx.ptr.p_double[j] = xc->ptr.pp_double[i][j];
   51965             :         }
   51966             :         
   51967             :         /*
   51968             :          * Determine number of near centers and maximum radius of near centers
   51969             :          */
   51970           0 :         nearcenterscnt.ptr.p_int[i] = kdtreequeryrnn(centerstree, &xcx, r->ptr.p_double[i]*rbfv1_rbfnearradius, ae_true, _state);
   51971           0 :         kdtreequeryresultstags(centerstree, &centerstags, _state);
   51972           0 :         maxrad = (double)(0);
   51973           0 :         for(j=0; j<=nearcenterscnt.ptr.p_int[i]-1; j++)
   51974             :         {
   51975           0 :             maxrad = ae_maxreal(maxrad, ae_fabs(r->ptr.p_double[centerstags.ptr.p_int[j]], _state), _state);
   51976             :         }
   51977             :         
   51978             :         /*
   51979             :          * Determine number of near points (ones which used to build ACBF)
   51980             :          * and skipped points (the most near points which are NOT used to build ACBF
   51981             :          * and are NOT included in the near points count
   51982             :          */
   51983           0 :         skipnearpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, 0.1*r->ptr.p_double[i], ae_true, _state);
   51984           0 :         nearpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, (r->ptr.p_double[i]+maxrad)*rbfv1_rbfnearradius, ae_true, _state)-skipnearpointscnt.ptr.p_int[i];
   51985           0 :         ae_assert(nearpointscnt.ptr.p_int[i]>=0, "BuildRBFModelLSQR: internal error", _state);
   51986             :         
   51987             :         /*
   51988             :          * Determine number of far points
   51989             :          */
   51990           0 :         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);
   51991             :         
   51992             :         /*
   51993             :          * calculate sum and max, make some basic checks
   51994             :          */
   51995           0 :         ae_assert(nearcenterscnt.ptr.p_int[i]>0, "BuildRBFModelLSQR: internal error", _state);
   51996           0 :         maxnearcenterscnt = ae_maxint(maxnearcenterscnt, nearcenterscnt.ptr.p_int[i], _state);
   51997           0 :         maxnearpointscnt = ae_maxint(maxnearpointscnt, nearpointscnt.ptr.p_int[i], _state);
   51998           0 :         maxfarpointscnt = ae_maxint(maxfarpointscnt, farpointscnt.ptr.p_int[i], _state);
   51999           0 :         sumnearcenterscnt = sumnearcenterscnt+nearcenterscnt.ptr.p_int[i];
   52000           0 :         sumnearpointscnt = sumnearpointscnt+nearpointscnt.ptr.p_int[i];
   52001           0 :         sumfarpointscnt = sumfarpointscnt+farpointscnt.ptr.p_int[i];
   52002             :     }
   52003           0 :     *snnz = sumnearcenterscnt;
   52004           0 :     *gnnz = sumfarpointscnt;
   52005           0 :     ae_assert(maxnearcenterscnt>0, "BuildRBFModelLSQR: internal error", _state);
   52006             :     
   52007             :     /*
   52008             :      * Allocate temporaries.
   52009             :      *
   52010             :      * NOTE: we want to avoid allocation of zero-size arrays, so we
   52011             :      *       use max(desired_size,1) instead of desired_size when performing
   52012             :      *       memory allocation.
   52013             :      */
   52014           0 :     ae_matrix_set_length(&a, maxnearpointscnt+maxnearcenterscnt, maxnearcenterscnt, _state);
   52015           0 :     ae_vector_set_length(&tmpy, maxnearpointscnt+maxnearcenterscnt, _state);
   52016           0 :     ae_vector_set_length(&g, maxnearcenterscnt, _state);
   52017           0 :     ae_vector_set_length(&c, maxnearcenterscnt, _state);
   52018           0 :     ae_matrix_set_length(&nearcenters, maxnearcenterscnt, rbfv1_mxnx, _state);
   52019           0 :     ae_matrix_set_length(&nearpoints, ae_maxint(maxnearpointscnt, 1, _state), rbfv1_mxnx, _state);
   52020           0 :     ae_matrix_set_length(&farpoints, ae_maxint(maxfarpointscnt, 1, _state), rbfv1_mxnx, _state);
   52021             :     
   52022             :     /*
   52023             :      * fill matrix SpG
   52024             :      */
   52025           0 :     sparsecreate(n, nc, *gnnz, &spg, _state);
   52026           0 :     sparsecreate(nc, nc, *snnz, &sps, _state);
   52027           0 :     for(i=0; i<=nc-1; i++)
   52028             :     {
   52029           0 :         centerscnt = nearcenterscnt.ptr.p_int[i];
   52030             :         
   52031             :         /*
   52032             :          * main center
   52033             :          */
   52034           0 :         for(j=0; j<=rbfv1_mxnx-1; j++)
   52035             :         {
   52036           0 :             xcx.ptr.p_double[j] = xc->ptr.pp_double[i][j];
   52037             :         }
   52038             :         
   52039             :         /*
   52040             :          * center's tree
   52041             :          */
   52042           0 :         tmpi = kdtreequeryknn(centerstree, &xcx, centerscnt, ae_true, _state);
   52043           0 :         ae_assert(tmpi==centerscnt, "BuildRBFModelLSQR: internal error", _state);
   52044           0 :         kdtreequeryresultsx(centerstree, &cx, _state);
   52045           0 :         kdtreequeryresultstags(centerstree, &centerstags, _state);
   52046             :         
   52047             :         /*
   52048             :          * point's tree
   52049             :          */
   52050           0 :         mrad = (double)(0);
   52051           0 :         for(j=0; j<=centerscnt-1; j++)
   52052             :         {
   52053           0 :             mrad = ae_maxreal(mrad, r->ptr.p_double[centerstags.ptr.p_int[j]], _state);
   52054             :         }
   52055             :         
   52056             :         /*
   52057             :          * we need to be sure that 'CTree' contains
   52058             :          * at least one side center
   52059             :          */
   52060           0 :         sparseset(&sps, i, i, (double)(1), _state);
   52061           0 :         c.ptr.p_double[0] = 1.0;
   52062           0 :         for(j=1; j<=centerscnt-1; j++)
   52063             :         {
   52064           0 :             c.ptr.p_double[j] = 0.0;
   52065             :         }
   52066           0 :         if( centerscnt>1&&nearpointscnt.ptr.p_int[i]>0 )
   52067             :         {
   52068             :             
   52069             :             /*
   52070             :              * first KDTree request for points
   52071             :              */
   52072           0 :             pointscnt = nearpointscnt.ptr.p_int[i];
   52073           0 :             tmpi = kdtreequeryknn(pointstree, &xcx, skipnearpointscnt.ptr.p_int[i]+nearpointscnt.ptr.p_int[i], ae_true, _state);
   52074           0 :             ae_assert(tmpi==skipnearpointscnt.ptr.p_int[i]+nearpointscnt.ptr.p_int[i], "BuildRBFModelLSQR: internal error", _state);
   52075           0 :             kdtreequeryresultsx(pointstree, &xx, _state);
   52076           0 :             sind = skipnearpointscnt.ptr.p_int[i];
   52077           0 :             for(j=0; j<=pointscnt-1; j++)
   52078             :             {
   52079           0 :                 vx = xx.ptr.pp_double[sind+j][0];
   52080           0 :                 vy = xx.ptr.pp_double[sind+j][1];
   52081           0 :                 vz = xx.ptr.pp_double[sind+j][2];
   52082           0 :                 for(k=0; k<=centerscnt-1; k++)
   52083             :                 {
   52084           0 :                     vr = 0.0;
   52085           0 :                     vv = vx-cx.ptr.pp_double[k][0];
   52086           0 :                     vr = vr+vv*vv;
   52087           0 :                     vv = vy-cx.ptr.pp_double[k][1];
   52088           0 :                     vr = vr+vv*vv;
   52089           0 :                     vv = vz-cx.ptr.pp_double[k][2];
   52090           0 :                     vr = vr+vv*vv;
   52091           0 :                     vv = r->ptr.p_double[centerstags.ptr.p_int[k]];
   52092           0 :                     a.ptr.pp_double[j][k] = ae_exp(-vr/(vv*vv), _state);
   52093             :                 }
   52094             :             }
   52095           0 :             for(j=0; j<=centerscnt-1; j++)
   52096             :             {
   52097           0 :                 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);
   52098             :             }
   52099             :             
   52100             :             /*
   52101             :              * calculate the problem
   52102             :              */
   52103           0 :             gnorm2 = ae_v_dotproduct(&g.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1));
   52104           0 :             for(j=0; j<=pointscnt-1; j++)
   52105             :             {
   52106           0 :                 vv = ae_v_dotproduct(&a.ptr.pp_double[j][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1));
   52107           0 :                 vv = vv/gnorm2;
   52108           0 :                 tmpy.ptr.p_double[j] = -vv;
   52109           0 :                 ae_v_subd(&a.ptr.pp_double[j][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv);
   52110             :             }
   52111           0 :             for(j=pointscnt; j<=pointscnt+centerscnt-1; j++)
   52112             :             {
   52113           0 :                 for(k=0; k<=centerscnt-1; k++)
   52114             :                 {
   52115           0 :                     a.ptr.pp_double[j][k] = 0.0;
   52116             :                 }
   52117           0 :                 a.ptr.pp_double[j][j-pointscnt] = 1.0E-6;
   52118           0 :                 tmpy.ptr.p_double[j] = 0.0;
   52119             :             }
   52120           0 :             fblssolvels(&a, &tmpy, pointscnt+centerscnt, centerscnt, &tmp0, &tmp1, &tmp2, _state);
   52121           0 :             ae_v_move(&c.ptr.p_double[0], 1, &tmpy.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1));
   52122           0 :             vv = ae_v_dotproduct(&g.ptr.p_double[0], 1, &c.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1));
   52123           0 :             vv = vv/gnorm2;
   52124           0 :             ae_v_subd(&c.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv);
   52125           0 :             vv = 1/gnorm2;
   52126           0 :             ae_v_addd(&c.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv);
   52127           0 :             for(j=0; j<=centerscnt-1; j++)
   52128             :             {
   52129           0 :                 sparseset(&sps, i, centerstags.ptr.p_int[j], c.ptr.p_double[j], _state);
   52130             :             }
   52131             :         }
   52132             :         
   52133             :         /*
   52134             :          * second KDTree request for points
   52135             :          */
   52136           0 :         pointscnt = farpointscnt.ptr.p_int[i];
   52137           0 :         tmpi = kdtreequeryknn(pointstree, &xcx, pointscnt, ae_true, _state);
   52138           0 :         ae_assert(tmpi==pointscnt, "BuildRBFModelLSQR: internal error", _state);
   52139           0 :         kdtreequeryresultsx(pointstree, &xx, _state);
   52140           0 :         kdtreequeryresultstags(pointstree, &pointstags, _state);
   52141             :         
   52142             :         /*
   52143             :          *fill SpG matrix
   52144             :          */
   52145           0 :         for(j=0; j<=pointscnt-1; j++)
   52146             :         {
   52147           0 :             fx = (double)(0);
   52148           0 :             vx = xx.ptr.pp_double[j][0];
   52149           0 :             vy = xx.ptr.pp_double[j][1];
   52150           0 :             vz = xx.ptr.pp_double[j][2];
   52151           0 :             for(k=0; k<=centerscnt-1; k++)
   52152             :             {
   52153           0 :                 vr = 0.0;
   52154           0 :                 vv = vx-cx.ptr.pp_double[k][0];
   52155           0 :                 vr = vr+vv*vv;
   52156           0 :                 vv = vy-cx.ptr.pp_double[k][1];
   52157           0 :                 vr = vr+vv*vv;
   52158           0 :                 vv = vz-cx.ptr.pp_double[k][2];
   52159           0 :                 vr = vr+vv*vv;
   52160           0 :                 vv = r->ptr.p_double[centerstags.ptr.p_int[k]];
   52161           0 :                 vv = vv*vv;
   52162           0 :                 fx = fx+c.ptr.p_double[k]*ae_exp(-vr/vv, _state);
   52163             :             }
   52164           0 :             sparseset(&spg, pointstags.ptr.p_int[j], i, fx, _state);
   52165             :         }
   52166             :     }
   52167           0 :     sparseconverttocrs(&spg, _state);
   52168           0 :     sparseconverttocrs(&sps, _state);
   52169             :     
   52170             :     /*
   52171             :      * solve by LSQR method
   52172             :      */
   52173           0 :     ae_vector_set_length(&tmpy, n, _state);
   52174           0 :     ae_vector_set_length(&tc, nc, _state);
   52175           0 :     ae_matrix_set_length(w, nc, ny, _state);
   52176           0 :     linlsqrcreate(n, nc, &state, _state);
   52177           0 :     linlsqrsetcond(&state, epsort, epserr, maxits, _state);
   52178           0 :     for(i=0; i<=ny-1; i++)
   52179             :     {
   52180           0 :         for(j=0; j<=n-1; j++)
   52181             :         {
   52182           0 :             tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i];
   52183             :         }
   52184           0 :         linlsqrsolvesparse(&state, &spg, &tmpy, _state);
   52185           0 :         linlsqrresults(&state, &c, &lsqrrep, _state);
   52186           0 :         if( lsqrrep.terminationtype<=0 )
   52187             :         {
   52188           0 :             *info = -4;
   52189           0 :             ae_frame_leave(_state);
   52190           0 :             return;
   52191             :         }
   52192           0 :         sparsemtv(&sps, &c, &tc, _state);
   52193           0 :         for(j=0; j<=nc-1; j++)
   52194             :         {
   52195           0 :             w->ptr.pp_double[j][i] = tc.ptr.p_double[j];
   52196             :         }
   52197           0 :         *iterationscount = *iterationscount+lsqrrep.iterationscount;
   52198           0 :         *nmv = *nmv+lsqrrep.nmv;
   52199             :     }
   52200           0 :     *info = 1;
   52201           0 :     ae_frame_leave(_state);
   52202             : }
   52203             : 
   52204             : 
   52205           0 : static void rbfv1_buildrbfmlayersmodellsqr(/* Real    */ ae_matrix* x,
   52206             :      /* Real    */ ae_matrix* y,
   52207             :      /* Real    */ ae_matrix* xc,
   52208             :      double rval,
   52209             :      /* Real    */ ae_vector* r,
   52210             :      ae_int_t n,
   52211             :      ae_int_t* nc,
   52212             :      ae_int_t ny,
   52213             :      ae_int_t nlayers,
   52214             :      kdtree* centerstree,
   52215             :      double epsort,
   52216             :      double epserr,
   52217             :      ae_int_t maxits,
   52218             :      double lambdav,
   52219             :      ae_int_t* annz,
   52220             :      /* Real    */ ae_matrix* w,
   52221             :      ae_int_t* info,
   52222             :      ae_int_t* iterationscount,
   52223             :      ae_int_t* nmv,
   52224             :      ae_state *_state)
   52225             : {
   52226             :     ae_frame _frame_block;
   52227             :     linlsqrstate state;
   52228             :     linlsqrreport lsqrrep;
   52229             :     sparsematrix spa;
   52230             :     double anorm;
   52231             :     ae_vector omega;
   52232             :     ae_vector xx;
   52233             :     ae_vector tmpy;
   52234             :     ae_matrix cx;
   52235             :     double yval;
   52236             :     ae_int_t nec;
   52237             :     ae_vector centerstags;
   52238             :     ae_int_t layer;
   52239             :     ae_int_t i;
   52240             :     ae_int_t j;
   52241             :     ae_int_t k;
   52242             :     double v;
   52243             :     double rmaxbefore;
   52244             :     double rmaxafter;
   52245             : 
   52246           0 :     ae_frame_make(_state, &_frame_block);
   52247           0 :     memset(&state, 0, sizeof(state));
   52248           0 :     memset(&lsqrrep, 0, sizeof(lsqrrep));
   52249           0 :     memset(&spa, 0, sizeof(spa));
   52250           0 :     memset(&omega, 0, sizeof(omega));
   52251           0 :     memset(&xx, 0, sizeof(xx));
   52252           0 :     memset(&tmpy, 0, sizeof(tmpy));
   52253           0 :     memset(&cx, 0, sizeof(cx));
   52254           0 :     memset(&centerstags, 0, sizeof(centerstags));
   52255           0 :     ae_matrix_clear(xc);
   52256           0 :     ae_vector_clear(r);
   52257           0 :     *nc = 0;
   52258           0 :     *annz = 0;
   52259           0 :     ae_matrix_clear(w);
   52260           0 :     *info = 0;
   52261           0 :     *iterationscount = 0;
   52262           0 :     *nmv = 0;
   52263           0 :     _linlsqrstate_init(&state, _state, ae_true);
   52264           0 :     _linlsqrreport_init(&lsqrrep, _state, ae_true);
   52265           0 :     _sparsematrix_init(&spa, _state, ae_true);
   52266           0 :     ae_vector_init(&omega, 0, DT_REAL, _state, ae_true);
   52267           0 :     ae_vector_init(&xx, 0, DT_REAL, _state, ae_true);
   52268           0 :     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
   52269           0 :     ae_matrix_init(&cx, 0, 0, DT_REAL, _state, ae_true);
   52270           0 :     ae_vector_init(&centerstags, 0, DT_INT, _state, ae_true);
   52271             : 
   52272           0 :     ae_assert(nlayers>=0, "BuildRBFMLayersModelLSQR: invalid argument(NLayers<0)", _state);
   52273           0 :     ae_assert(n>=0, "BuildRBFMLayersModelLSQR: invalid argument(N<0)", _state);
   52274           0 :     ae_assert(rbfv1_mxnx>0&&rbfv1_mxnx<=3, "BuildRBFMLayersModelLSQR: internal error(invalid global const MxNX: either MxNX<=0 or MxNX>3)", _state);
   52275           0 :     *annz = 0;
   52276           0 :     if( n==0||nlayers==0 )
   52277             :     {
   52278           0 :         *info = 1;
   52279           0 :         *iterationscount = 0;
   52280           0 :         *nmv = 0;
   52281           0 :         ae_frame_leave(_state);
   52282           0 :         return;
   52283             :     }
   52284           0 :     *nc = n*nlayers;
   52285           0 :     ae_vector_set_length(&xx, rbfv1_mxnx, _state);
   52286           0 :     ae_vector_set_length(&centerstags, n, _state);
   52287           0 :     ae_matrix_set_length(xc, *nc, rbfv1_mxnx, _state);
   52288           0 :     ae_vector_set_length(r, *nc, _state);
   52289           0 :     for(i=0; i<=*nc-1; i++)
   52290             :     {
   52291           0 :         for(j=0; j<=rbfv1_mxnx-1; j++)
   52292             :         {
   52293           0 :             xc->ptr.pp_double[i][j] = x->ptr.pp_double[i%n][j];
   52294             :         }
   52295             :     }
   52296           0 :     for(i=0; i<=*nc-1; i++)
   52297             :     {
   52298           0 :         r->ptr.p_double[i] = rval/ae_pow((double)(2), (double)(i/n), _state);
   52299             :     }
   52300           0 :     for(i=0; i<=n-1; i++)
   52301             :     {
   52302           0 :         centerstags.ptr.p_int[i] = i;
   52303             :     }
   52304           0 :     kdtreebuildtagged(xc, &centerstags, n, rbfv1_mxnx, 0, 2, centerstree, _state);
   52305           0 :     ae_vector_set_length(&omega, n, _state);
   52306           0 :     ae_vector_set_length(&tmpy, n, _state);
   52307           0 :     ae_matrix_set_length(w, *nc, ny, _state);
   52308           0 :     *info = -1;
   52309           0 :     *iterationscount = 0;
   52310           0 :     *nmv = 0;
   52311           0 :     linlsqrcreate(n, n, &state, _state);
   52312           0 :     linlsqrsetcond(&state, epsort, epserr, maxits, _state);
   52313           0 :     linlsqrsetlambdai(&state, 1.0E-6, _state);
   52314             :     
   52315             :     /*
   52316             :      * calculate number of non-zero elements for sparse matrix
   52317             :      */
   52318           0 :     for(i=0; i<=n-1; i++)
   52319             :     {
   52320           0 :         for(j=0; j<=rbfv1_mxnx-1; j++)
   52321             :         {
   52322           0 :             xx.ptr.p_double[j] = x->ptr.pp_double[i][j];
   52323             :         }
   52324           0 :         *annz = *annz+kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[0]*rbfv1_rbfmlradius, ae_true, _state);
   52325             :     }
   52326           0 :     for(layer=0; layer<=nlayers-1; layer++)
   52327             :     {
   52328             :         
   52329             :         /*
   52330             :          * Fill sparse matrix, calculate norm(A)
   52331             :          */
   52332           0 :         anorm = 0.0;
   52333           0 :         sparsecreate(n, n, *annz, &spa, _state);
   52334           0 :         for(i=0; i<=n-1; i++)
   52335             :         {
   52336           0 :             for(j=0; j<=rbfv1_mxnx-1; j++)
   52337             :             {
   52338           0 :                 xx.ptr.p_double[j] = x->ptr.pp_double[i][j];
   52339             :             }
   52340           0 :             nec = kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[layer*n]*rbfv1_rbfmlradius, ae_true, _state);
   52341           0 :             kdtreequeryresultsx(centerstree, &cx, _state);
   52342           0 :             kdtreequeryresultstags(centerstree, &centerstags, _state);
   52343           0 :             for(j=0; j<=nec-1; j++)
   52344             :             {
   52345           0 :                 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);
   52346           0 :                 sparseset(&spa, i, centerstags.ptr.p_int[j], v, _state);
   52347           0 :                 anorm = anorm+ae_sqr(v, _state);
   52348             :             }
   52349             :         }
   52350           0 :         anorm = ae_sqrt(anorm, _state);
   52351           0 :         sparseconverttocrs(&spa, _state);
   52352             :         
   52353             :         /*
   52354             :          * Calculate maximum residual before adding new layer.
   52355             :          * This value is not used by algorithm, the only purpose is to make debugging easier.
   52356             :          */
   52357           0 :         rmaxbefore = 0.0;
   52358           0 :         for(j=0; j<=n-1; j++)
   52359             :         {
   52360           0 :             for(i=0; i<=ny-1; i++)
   52361             :             {
   52362           0 :                 rmaxbefore = ae_maxreal(rmaxbefore, ae_fabs(y->ptr.pp_double[j][i], _state), _state);
   52363             :             }
   52364             :         }
   52365             :         
   52366             :         /*
   52367             :          * Process NY dimensions of the target function
   52368             :          */
   52369           0 :         for(i=0; i<=ny-1; i++)
   52370             :         {
   52371           0 :             for(j=0; j<=n-1; j++)
   52372             :             {
   52373           0 :                 tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i];
   52374             :             }
   52375             :             
   52376             :             /*
   52377             :              * calculate Omega for current layer
   52378             :              */
   52379           0 :             linlsqrsetlambdai(&state, lambdav*anorm/n, _state);
   52380           0 :             linlsqrsolvesparse(&state, &spa, &tmpy, _state);
   52381           0 :             linlsqrresults(&state, &omega, &lsqrrep, _state);
   52382           0 :             if( lsqrrep.terminationtype<=0 )
   52383             :             {
   52384           0 :                 *info = -4;
   52385           0 :                 ae_frame_leave(_state);
   52386           0 :                 return;
   52387             :             }
   52388             :             
   52389             :             /*
   52390             :              * calculate error for current layer
   52391             :              */
   52392           0 :             for(j=0; j<=n-1; j++)
   52393             :             {
   52394           0 :                 yval = (double)(0);
   52395           0 :                 for(k=0; k<=rbfv1_mxnx-1; k++)
   52396             :                 {
   52397           0 :                     xx.ptr.p_double[k] = x->ptr.pp_double[j][k];
   52398             :                 }
   52399           0 :                 nec = kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[layer*n]*rbfv1_rbffarradius, ae_true, _state);
   52400           0 :                 kdtreequeryresultsx(centerstree, &cx, _state);
   52401           0 :                 kdtreequeryresultstags(centerstree, &centerstags, _state);
   52402           0 :                 for(k=0; k<=nec-1; k++)
   52403             :                 {
   52404           0 :                     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);
   52405             :                 }
   52406           0 :                 y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-yval;
   52407             :             }
   52408             :             
   52409             :             /*
   52410             :              * write Omega in out parameter W
   52411             :              */
   52412           0 :             for(j=0; j<=n-1; j++)
   52413             :             {
   52414           0 :                 w->ptr.pp_double[layer*n+j][i] = omega.ptr.p_double[j];
   52415             :             }
   52416           0 :             *iterationscount = *iterationscount+lsqrrep.iterationscount;
   52417           0 :             *nmv = *nmv+lsqrrep.nmv;
   52418             :         }
   52419             :         
   52420             :         /*
   52421             :          * Calculate maximum residual before adding new layer.
   52422             :          * This value is not used by algorithm, the only purpose is to make debugging easier.
   52423             :          */
   52424           0 :         rmaxafter = 0.0;
   52425           0 :         for(j=0; j<=n-1; j++)
   52426             :         {
   52427           0 :             for(i=0; i<=ny-1; i++)
   52428             :             {
   52429           0 :                 rmaxafter = ae_maxreal(rmaxafter, ae_fabs(y->ptr.pp_double[j][i], _state), _state);
   52430             :             }
   52431             :         }
   52432             :     }
   52433           0 :     *info = 1;
   52434           0 :     ae_frame_leave(_state);
   52435             : }
   52436             : 
   52437             : 
   52438           0 : void _rbfv1calcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic)
   52439             : {
   52440           0 :     rbfv1calcbuffer *p = (rbfv1calcbuffer*)_p;
   52441           0 :     ae_touch_ptr((void*)p);
   52442           0 :     ae_vector_init(&p->calcbufxcx, 0, DT_REAL, _state, make_automatic);
   52443           0 :     ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state, make_automatic);
   52444           0 :     ae_vector_init(&p->calcbuftags, 0, DT_INT, _state, make_automatic);
   52445           0 :     _kdtreerequestbuffer_init(&p->requestbuffer, _state, make_automatic);
   52446           0 : }
   52447             : 
   52448             : 
   52449           0 : void _rbfv1calcbuffer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   52450             : {
   52451           0 :     rbfv1calcbuffer *dst = (rbfv1calcbuffer*)_dst;
   52452           0 :     rbfv1calcbuffer *src = (rbfv1calcbuffer*)_src;
   52453           0 :     ae_vector_init_copy(&dst->calcbufxcx, &src->calcbufxcx, _state, make_automatic);
   52454           0 :     ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state, make_automatic);
   52455           0 :     ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state, make_automatic);
   52456           0 :     _kdtreerequestbuffer_init_copy(&dst->requestbuffer, &src->requestbuffer, _state, make_automatic);
   52457           0 : }
   52458             : 
   52459             : 
   52460           0 : void _rbfv1calcbuffer_clear(void* _p)
   52461             : {
   52462           0 :     rbfv1calcbuffer *p = (rbfv1calcbuffer*)_p;
   52463           0 :     ae_touch_ptr((void*)p);
   52464           0 :     ae_vector_clear(&p->calcbufxcx);
   52465           0 :     ae_matrix_clear(&p->calcbufx);
   52466           0 :     ae_vector_clear(&p->calcbuftags);
   52467           0 :     _kdtreerequestbuffer_clear(&p->requestbuffer);
   52468           0 : }
   52469             : 
   52470             : 
   52471           0 : void _rbfv1calcbuffer_destroy(void* _p)
   52472             : {
   52473           0 :     rbfv1calcbuffer *p = (rbfv1calcbuffer*)_p;
   52474           0 :     ae_touch_ptr((void*)p);
   52475           0 :     ae_vector_destroy(&p->calcbufxcx);
   52476           0 :     ae_matrix_destroy(&p->calcbufx);
   52477           0 :     ae_vector_destroy(&p->calcbuftags);
   52478           0 :     _kdtreerequestbuffer_destroy(&p->requestbuffer);
   52479           0 : }
   52480             : 
   52481             : 
   52482           0 : void _rbfv1model_init(void* _p, ae_state *_state, ae_bool make_automatic)
   52483             : {
   52484           0 :     rbfv1model *p = (rbfv1model*)_p;
   52485           0 :     ae_touch_ptr((void*)p);
   52486           0 :     _kdtree_init(&p->tree, _state, make_automatic);
   52487           0 :     ae_matrix_init(&p->xc, 0, 0, DT_REAL, _state, make_automatic);
   52488           0 :     ae_matrix_init(&p->wr, 0, 0, DT_REAL, _state, make_automatic);
   52489           0 :     ae_matrix_init(&p->v, 0, 0, DT_REAL, _state, make_automatic);
   52490           0 :     ae_vector_init(&p->calcbufxcx, 0, DT_REAL, _state, make_automatic);
   52491           0 :     ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state, make_automatic);
   52492           0 :     ae_vector_init(&p->calcbuftags, 0, DT_INT, _state, make_automatic);
   52493           0 : }
   52494             : 
   52495             : 
   52496           0 : void _rbfv1model_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   52497             : {
   52498           0 :     rbfv1model *dst = (rbfv1model*)_dst;
   52499           0 :     rbfv1model *src = (rbfv1model*)_src;
   52500           0 :     dst->ny = src->ny;
   52501           0 :     dst->nx = src->nx;
   52502           0 :     dst->nc = src->nc;
   52503           0 :     dst->nl = src->nl;
   52504           0 :     _kdtree_init_copy(&dst->tree, &src->tree, _state, make_automatic);
   52505           0 :     ae_matrix_init_copy(&dst->xc, &src->xc, _state, make_automatic);
   52506           0 :     ae_matrix_init_copy(&dst->wr, &src->wr, _state, make_automatic);
   52507           0 :     dst->rmax = src->rmax;
   52508           0 :     ae_matrix_init_copy(&dst->v, &src->v, _state, make_automatic);
   52509           0 :     ae_vector_init_copy(&dst->calcbufxcx, &src->calcbufxcx, _state, make_automatic);
   52510           0 :     ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state, make_automatic);
   52511           0 :     ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state, make_automatic);
   52512           0 : }
   52513             : 
   52514             : 
   52515           0 : void _rbfv1model_clear(void* _p)
   52516             : {
   52517           0 :     rbfv1model *p = (rbfv1model*)_p;
   52518           0 :     ae_touch_ptr((void*)p);
   52519           0 :     _kdtree_clear(&p->tree);
   52520           0 :     ae_matrix_clear(&p->xc);
   52521           0 :     ae_matrix_clear(&p->wr);
   52522           0 :     ae_matrix_clear(&p->v);
   52523           0 :     ae_vector_clear(&p->calcbufxcx);
   52524           0 :     ae_matrix_clear(&p->calcbufx);
   52525           0 :     ae_vector_clear(&p->calcbuftags);
   52526           0 : }
   52527             : 
   52528             : 
   52529           0 : void _rbfv1model_destroy(void* _p)
   52530             : {
   52531           0 :     rbfv1model *p = (rbfv1model*)_p;
   52532           0 :     ae_touch_ptr((void*)p);
   52533           0 :     _kdtree_destroy(&p->tree);
   52534           0 :     ae_matrix_destroy(&p->xc);
   52535           0 :     ae_matrix_destroy(&p->wr);
   52536           0 :     ae_matrix_destroy(&p->v);
   52537           0 :     ae_vector_destroy(&p->calcbufxcx);
   52538           0 :     ae_matrix_destroy(&p->calcbufx);
   52539           0 :     ae_vector_destroy(&p->calcbuftags);
   52540           0 : }
   52541             : 
   52542             : 
   52543           0 : void _gridcalc3v1buf_init(void* _p, ae_state *_state, ae_bool make_automatic)
   52544             : {
   52545           0 :     gridcalc3v1buf *p = (gridcalc3v1buf*)_p;
   52546           0 :     ae_touch_ptr((void*)p);
   52547           0 :     ae_vector_init(&p->tx, 0, DT_REAL, _state, make_automatic);
   52548           0 :     ae_vector_init(&p->cx, 0, DT_REAL, _state, make_automatic);
   52549           0 :     ae_vector_init(&p->ty, 0, DT_REAL, _state, make_automatic);
   52550           0 :     ae_vector_init(&p->flag0, 0, DT_BOOL, _state, make_automatic);
   52551           0 :     ae_vector_init(&p->flag1, 0, DT_BOOL, _state, make_automatic);
   52552           0 :     ae_vector_init(&p->flag2, 0, DT_BOOL, _state, make_automatic);
   52553           0 :     ae_vector_init(&p->flag12, 0, DT_BOOL, _state, make_automatic);
   52554           0 :     ae_vector_init(&p->expbuf0, 0, DT_REAL, _state, make_automatic);
   52555           0 :     ae_vector_init(&p->expbuf1, 0, DT_REAL, _state, make_automatic);
   52556           0 :     ae_vector_init(&p->expbuf2, 0, DT_REAL, _state, make_automatic);
   52557           0 :     _kdtreerequestbuffer_init(&p->requestbuf, _state, make_automatic);
   52558           0 :     ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state, make_automatic);
   52559           0 :     ae_vector_init(&p->calcbuftags, 0, DT_INT, _state, make_automatic);
   52560           0 : }
   52561             : 
   52562             : 
   52563           0 : void _gridcalc3v1buf_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   52564             : {
   52565           0 :     gridcalc3v1buf *dst = (gridcalc3v1buf*)_dst;
   52566           0 :     gridcalc3v1buf *src = (gridcalc3v1buf*)_src;
   52567           0 :     ae_vector_init_copy(&dst->tx, &src->tx, _state, make_automatic);
   52568           0 :     ae_vector_init_copy(&dst->cx, &src->cx, _state, make_automatic);
   52569           0 :     ae_vector_init_copy(&dst->ty, &src->ty, _state, make_automatic);
   52570           0 :     ae_vector_init_copy(&dst->flag0, &src->flag0, _state, make_automatic);
   52571           0 :     ae_vector_init_copy(&dst->flag1, &src->flag1, _state, make_automatic);
   52572           0 :     ae_vector_init_copy(&dst->flag2, &src->flag2, _state, make_automatic);
   52573           0 :     ae_vector_init_copy(&dst->flag12, &src->flag12, _state, make_automatic);
   52574           0 :     ae_vector_init_copy(&dst->expbuf0, &src->expbuf0, _state, make_automatic);
   52575           0 :     ae_vector_init_copy(&dst->expbuf1, &src->expbuf1, _state, make_automatic);
   52576           0 :     ae_vector_init_copy(&dst->expbuf2, &src->expbuf2, _state, make_automatic);
   52577           0 :     _kdtreerequestbuffer_init_copy(&dst->requestbuf, &src->requestbuf, _state, make_automatic);
   52578           0 :     ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state, make_automatic);
   52579           0 :     ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state, make_automatic);
   52580           0 : }
   52581             : 
   52582             : 
   52583           0 : void _gridcalc3v1buf_clear(void* _p)
   52584             : {
   52585           0 :     gridcalc3v1buf *p = (gridcalc3v1buf*)_p;
   52586           0 :     ae_touch_ptr((void*)p);
   52587           0 :     ae_vector_clear(&p->tx);
   52588           0 :     ae_vector_clear(&p->cx);
   52589           0 :     ae_vector_clear(&p->ty);
   52590           0 :     ae_vector_clear(&p->flag0);
   52591           0 :     ae_vector_clear(&p->flag1);
   52592           0 :     ae_vector_clear(&p->flag2);
   52593           0 :     ae_vector_clear(&p->flag12);
   52594           0 :     ae_vector_clear(&p->expbuf0);
   52595           0 :     ae_vector_clear(&p->expbuf1);
   52596           0 :     ae_vector_clear(&p->expbuf2);
   52597           0 :     _kdtreerequestbuffer_clear(&p->requestbuf);
   52598           0 :     ae_matrix_clear(&p->calcbufx);
   52599           0 :     ae_vector_clear(&p->calcbuftags);
   52600           0 : }
   52601             : 
   52602             : 
   52603           0 : void _gridcalc3v1buf_destroy(void* _p)
   52604             : {
   52605           0 :     gridcalc3v1buf *p = (gridcalc3v1buf*)_p;
   52606           0 :     ae_touch_ptr((void*)p);
   52607           0 :     ae_vector_destroy(&p->tx);
   52608           0 :     ae_vector_destroy(&p->cx);
   52609           0 :     ae_vector_destroy(&p->ty);
   52610           0 :     ae_vector_destroy(&p->flag0);
   52611           0 :     ae_vector_destroy(&p->flag1);
   52612           0 :     ae_vector_destroy(&p->flag2);
   52613           0 :     ae_vector_destroy(&p->flag12);
   52614           0 :     ae_vector_destroy(&p->expbuf0);
   52615           0 :     ae_vector_destroy(&p->expbuf1);
   52616           0 :     ae_vector_destroy(&p->expbuf2);
   52617           0 :     _kdtreerequestbuffer_destroy(&p->requestbuf);
   52618           0 :     ae_matrix_destroy(&p->calcbufx);
   52619           0 :     ae_vector_destroy(&p->calcbuftags);
   52620           0 : }
   52621             : 
   52622             : 
   52623           0 : void _rbfv1report_init(void* _p, ae_state *_state, ae_bool make_automatic)
   52624             : {
   52625           0 :     rbfv1report *p = (rbfv1report*)_p;
   52626           0 :     ae_touch_ptr((void*)p);
   52627           0 : }
   52628             : 
   52629             : 
   52630           0 : void _rbfv1report_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   52631             : {
   52632           0 :     rbfv1report *dst = (rbfv1report*)_dst;
   52633           0 :     rbfv1report *src = (rbfv1report*)_src;
   52634           0 :     dst->arows = src->arows;
   52635           0 :     dst->acols = src->acols;
   52636           0 :     dst->annz = src->annz;
   52637           0 :     dst->iterationscount = src->iterationscount;
   52638           0 :     dst->nmv = src->nmv;
   52639           0 :     dst->terminationtype = src->terminationtype;
   52640           0 : }
   52641             : 
   52642             : 
   52643           0 : void _rbfv1report_clear(void* _p)
   52644             : {
   52645           0 :     rbfv1report *p = (rbfv1report*)_p;
   52646           0 :     ae_touch_ptr((void*)p);
   52647           0 : }
   52648             : 
   52649             : 
   52650           0 : void _rbfv1report_destroy(void* _p)
   52651             : {
   52652           0 :     rbfv1report *p = (rbfv1report*)_p;
   52653           0 :     ae_touch_ptr((void*)p);
   52654           0 : }
   52655             : 
   52656             : 
   52657             : #endif
   52658             : #if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD)
   52659             : 
   52660             : 
   52661             : /*************************************************************************
   52662             : This function creates RBF  model  for  a  scalar (NY=1)  or  vector (NY>1)
   52663             : function in a NX-dimensional space (NX>=1).
   52664             : 
   52665             : Newly created model is empty. It can be used for interpolation right after
   52666             : creation, but it just returns zeros. You have to add points to the  model,
   52667             : tune interpolation settings, and then  call  model  construction  function
   52668             : rbfbuildmodel() which will update model according to your specification.
   52669             : 
   52670             : USAGE:
   52671             : 1. User creates model with rbfcreate()
   52672             : 2. User adds dataset with rbfsetpoints() (points do NOT have to  be  on  a
   52673             :    regular grid) or rbfsetpointsandscales().
   52674             : 3. (OPTIONAL) User chooses polynomial term by calling:
   52675             :    * rbflinterm() to set linear term
   52676             :    * rbfconstterm() to set constant term
   52677             :    * rbfzeroterm() to set zero term
   52678             :    By default, linear term is used.
   52679             : 4. User tweaks algorithm properties with  rbfsetalgohierarchical()  method
   52680             :    (or chooses one of the legacy algorithms - QNN  (rbfsetalgoqnn)  or  ML
   52681             :    (rbfsetalgomultilayer)).
   52682             : 5. User calls rbfbuildmodel() function which rebuilds model  according  to
   52683             :    the specification
   52684             : 6. User may call rbfcalc() to calculate model value at the specified point,
   52685             :    rbfgridcalc() to  calculate   model  values at the points of the regular
   52686             :    grid. User may extract model coefficients with rbfunpack() call.
   52687             :    
   52688             : IMPORTANT: we recommend you to use latest model construction  algorithm  -
   52689             :            hierarchical RBFs, which is activated by rbfsetalgohierarchical()
   52690             :            function. This algorithm is the fastest one, and  most  memory-
   52691             :            efficient.
   52692             :            However,  it  is  incompatible  with older versions  of  ALGLIB
   52693             :            (pre-3.11). So, if you serialize hierarchical model,  you  will
   52694             :            be unable to load it in pre-3.11 ALGLIB. Other model types (QNN
   52695             :            and RBF-ML) are still backward-compatible.
   52696             :    
   52697             : INPUT PARAMETERS:
   52698             :     NX      -   dimension of the space, NX>=1
   52699             :     NY      -   function dimension, NY>=1
   52700             : 
   52701             : OUTPUT PARAMETERS:
   52702             :     S       -   RBF model (initially equals to zero)
   52703             : 
   52704             : NOTE 1: memory requirements. RBF models require amount of memory  which is
   52705             :         proportional  to the number of data points. Some additional memory
   52706             :         is allocated during model construction, but most of this memory is
   52707             :         freed after model coefficients  are  calculated.  Amount  of  this
   52708             :         additional memory depends on model  construction  algorithm  being
   52709             :         used.
   52710             :         
   52711             : NOTE 2: prior to ALGLIB version 3.11, RBF models supported  only  NX=2  or
   52712             :         NX=3. Any  attempt  to  create  single-dimensional  or  more  than
   52713             :         3-dimensional RBF model resulted in exception.
   52714             :         
   52715             :         ALGLIB 3.11 supports any NX>0, but models created with  NX!=2  and
   52716             :         NX!=3 are incompatible with (a) older versions of ALGLIB, (b)  old
   52717             :         model construction algorithms (QNN or RBF-ML).
   52718             :         
   52719             :         So, if you create a model with NX=2 or NX=3,  then,  depending  on
   52720             :         specific  model construction algorithm being chosen, you will (QNN
   52721             :         and RBF-ML) or will not (HierarchicalRBF) get backward compatibility
   52722             :         with older versions of ALGLIB. You have a choice here.
   52723             :         
   52724             :         However, if you create a model with NX neither 2 nor 3,  you  have
   52725             :         no backward compatibility from the start, and you  are  forced  to
   52726             :         use hierarchical RBFs and ALGLIB 3.11 or later.
   52727             : 
   52728             :   -- ALGLIB --
   52729             :      Copyright 13.12.2011, 20.06.2016 by Bochkanov Sergey
   52730             : *************************************************************************/
   52731           0 : void rbfcreate(ae_int_t nx, ae_int_t ny, rbfmodel* s, ae_state *_state)
   52732             : {
   52733             : 
   52734           0 :     _rbfmodel_clear(s);
   52735             : 
   52736           0 :     ae_assert(nx>=1, "RBFCreate: NX<1", _state);
   52737           0 :     ae_assert(ny>=1, "RBFCreate: NY<1", _state);
   52738           0 :     s->nx = nx;
   52739           0 :     s->ny = ny;
   52740           0 :     rbf_rbfpreparenonserializablefields(s, _state);
   52741             :     
   52742             :     /*
   52743             :      * Select default model version according to NX.
   52744             :      *
   52745             :      * The idea is that when we call this function with NX=2 or NX=3, backward
   52746             :      * compatible dummy (zero) V1 model is created, so serialization produces
   52747             :      * model which are compatible with pre-3.11 ALGLIB.
   52748             :      */
   52749           0 :     rbf_initializev1(nx, ny, &s->model1, _state);
   52750           0 :     rbf_initializev2(nx, ny, &s->model2, _state);
   52751           0 :     if( nx==2||nx==3 )
   52752             :     {
   52753           0 :         s->modelversion = 1;
   52754             :     }
   52755             :     else
   52756             :     {
   52757           0 :         s->modelversion = 2;
   52758             :     }
   52759             :     
   52760             :     /*
   52761             :      * Report fields
   52762             :      */
   52763           0 :     s->progress10000 = 0;
   52764           0 :     s->terminationrequest = ae_false;
   52765           0 : }
   52766             : 
   52767             : 
   52768             : /*************************************************************************
   52769             : This function creates buffer  structure  which  can  be  used  to  perform
   52770             : parallel  RBF  model  evaluations  (with  one  RBF  model  instance  being
   52771             : used from multiple threads, as long as  different  threads  use  different
   52772             : instances of buffer).
   52773             : 
   52774             : This buffer object can be used with  rbftscalcbuf()  function  (here  "ts"
   52775             : stands for "thread-safe", "buf" is a suffix which denotes  function  which
   52776             : reuses previously allocated output space).
   52777             : 
   52778             : How to use it:
   52779             : * create RBF model structure with rbfcreate()
   52780             : * load data, tune parameters
   52781             : * call rbfbuildmodel()
   52782             : * call rbfcreatecalcbuffer(), once per thread working with RBF model  (you
   52783             :   should call this function only AFTER call to rbfbuildmodel(), see  below
   52784             :   for more information)
   52785             : * call rbftscalcbuf() from different threads,  with  each  thread  working
   52786             :   with its own copy of buffer object.
   52787             : 
   52788             : INPUT PARAMETERS
   52789             :     S           -   RBF model
   52790             : 
   52791             : OUTPUT PARAMETERS
   52792             :     Buf         -   external buffer.
   52793             :     
   52794             :     
   52795             : IMPORTANT: buffer object should be used only with  RBF model object  which
   52796             :            was used to initialize buffer. Any attempt to use buffer   with
   52797             :            different object is dangerous - you may  get  memory  violation
   52798             :            error because sizes of internal arrays do not fit to dimensions
   52799             :            of RBF structure.
   52800             :            
   52801             : IMPORTANT: you  should  call  this function only for model which was built
   52802             :            with rbfbuildmodel() function, after successful  invocation  of
   52803             :            rbfbuildmodel().  Sizes   of   some   internal  structures  are
   52804             :            determined only after model is built, so buffer object  created
   52805             :            before model  construction  stage  will  be  useless  (and  any
   52806             :            attempt to use it will result in exception).
   52807             : 
   52808             :   -- ALGLIB --
   52809             :      Copyright 02.04.2016 by Sergey Bochkanov
   52810             : *************************************************************************/
   52811           0 : void rbfcreatecalcbuffer(rbfmodel* s,
   52812             :      rbfcalcbuffer* buf,
   52813             :      ae_state *_state)
   52814             : {
   52815             : 
   52816           0 :     _rbfcalcbuffer_clear(buf);
   52817             : 
   52818           0 :     if( s->modelversion==1 )
   52819             :     {
   52820           0 :         buf->modelversion = 1;
   52821           0 :         rbfv1createcalcbuffer(&s->model1, &buf->bufv1, _state);
   52822           0 :         return;
   52823             :     }
   52824           0 :     if( s->modelversion==2 )
   52825             :     {
   52826           0 :         buf->modelversion = 2;
   52827           0 :         rbfv2createcalcbuffer(&s->model2, &buf->bufv2, _state);
   52828           0 :         return;
   52829             :     }
   52830           0 :     ae_assert(ae_false, "RBFCreateCalcBuffer: integrity check failed", _state);
   52831             : }
   52832             : 
   52833             : 
   52834             : /*************************************************************************
   52835             : This function adds dataset.
   52836             : 
   52837             : This function overrides results of the previous calls, i.e. multiple calls
   52838             : of this function will result in only the last set being added.
   52839             : 
   52840             : IMPORTANT: ALGLIB version 3.11 and later allows you to specify  a  set  of
   52841             :            per-dimension scales. Interpolation radii are multiplied by the
   52842             :            scale vector. It may be useful if you have mixed spatio-temporal
   52843             :            data (say, a set of 3D slices recorded at different times).
   52844             :            You should call rbfsetpointsandscales() function  to  use  this
   52845             :            feature.
   52846             : 
   52847             : INPUT PARAMETERS:
   52848             :     S       -   RBF model, initialized by rbfcreate() call.
   52849             :     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
   52850             :                 in the dataset. First NX elements  are  coordinates,  next
   52851             :                 NY elements are function values. Array may  be larger than 
   52852             :                 specified, in  this  case  only leading [N,NX+NY] elements 
   52853             :                 will be used.
   52854             :     N       -   number of points in the dataset
   52855             : 
   52856             : After you've added dataset and (optionally) tuned algorithm  settings  you
   52857             : should call rbfbuildmodel() in order to build a model for you.
   52858             : 
   52859             : NOTE: dataset added by this function is not saved during model serialization.
   52860             :       MODEL ITSELF is serialized, but data used to build it are not.
   52861             :       
   52862             :       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
   52863             :       unserialize it, then you will get an empty RBF model with no dataset
   52864             :       being attached.
   52865             :       
   52866             :       From the other side, if you call rbfbuildmodel() between (1) and (2),
   52867             :       then after (2) you will get your fully constructed RBF model  -  but
   52868             :       again with no dataset attached, so subsequent calls to rbfbuildmodel()
   52869             :       will produce empty model.
   52870             :       
   52871             : 
   52872             :   -- ALGLIB --
   52873             :      Copyright 13.12.2011 by Bochkanov Sergey
   52874             : *************************************************************************/
   52875           0 : void rbfsetpoints(rbfmodel* s,
   52876             :      /* Real    */ ae_matrix* xy,
   52877             :      ae_int_t n,
   52878             :      ae_state *_state)
   52879             : {
   52880             :     ae_int_t i;
   52881             :     ae_int_t j;
   52882             : 
   52883             : 
   52884           0 :     ae_assert(n>0, "RBFSetPoints: N<0", _state);
   52885           0 :     ae_assert(xy->rows>=n, "RBFSetPoints: Rows(XY)<N", _state);
   52886           0 :     ae_assert(xy->cols>=s->nx+s->ny, "RBFSetPoints: Cols(XY)<NX+NY", _state);
   52887           0 :     ae_assert(apservisfinitematrix(xy, n, s->nx+s->ny, _state), "RBFSetPoints: XY contains infinite or NaN values!", _state);
   52888           0 :     s->n = n;
   52889           0 :     s->hasscale = ae_false;
   52890           0 :     ae_matrix_set_length(&s->x, s->n, s->nx, _state);
   52891           0 :     ae_matrix_set_length(&s->y, s->n, s->ny, _state);
   52892           0 :     for(i=0; i<=s->n-1; i++)
   52893             :     {
   52894           0 :         for(j=0; j<=s->nx-1; j++)
   52895             :         {
   52896           0 :             s->x.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j];
   52897             :         }
   52898           0 :         for(j=0; j<=s->ny-1; j++)
   52899             :         {
   52900           0 :             s->y.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j+s->nx];
   52901             :         }
   52902             :     }
   52903           0 : }
   52904             : 
   52905             : 
   52906             : /*************************************************************************
   52907             : This function adds dataset and a vector of per-dimension scales.
   52908             : 
   52909             : It may be useful if you have mixed spatio-temporal data - say, a set of 3D
   52910             : slices recorded at different times. Such data typically require  different
   52911             : RBF radii for spatial and temporal dimensions. ALGLIB solves this  problem
   52912             : by specifying single RBF radius, which is (optionally) multiplied  by  the
   52913             : scale vector.
   52914             : 
   52915             : This function overrides results of the previous calls, i.e. multiple calls
   52916             : of this function will result in only the last set being added.
   52917             : 
   52918             : IMPORTANT: only HierarchicalRBF algorithm can work with scaled points. So,
   52919             :            using this function results in RBF models which can be used  in
   52920             :            ALGLIB 3.11 or later. Previous versions of the library will  be
   52921             :            unable  to unserialize models produced by HierarchicalRBF algo.
   52922             :            
   52923             :            Any attempt to use this function with RBF-ML or QNN  algorithms
   52924             :            will result  in  -3  error  code   being   returned  (incorrect
   52925             :            algorithm).
   52926             : 
   52927             : INPUT PARAMETERS:
   52928             :     R       -   RBF model, initialized by rbfcreate() call.
   52929             :     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
   52930             :                 in the dataset. First NX elements  are  coordinates,  next
   52931             :                 NY elements are function values. Array may  be larger than 
   52932             :                 specified, in  this  case  only leading [N,NX+NY] elements 
   52933             :                 will be used.
   52934             :     N       -   number of points in the dataset
   52935             :     S       -   array[NX], scale vector, S[i]>0.
   52936             : 
   52937             : After you've added dataset and (optionally) tuned algorithm  settings  you
   52938             : should call rbfbuildmodel() in order to build a model for you.
   52939             : 
   52940             : NOTE: dataset added by this function is not saved during model serialization.
   52941             :       MODEL ITSELF is serialized, but data used to build it are not.
   52942             :       
   52943             :       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
   52944             :       unserialize it, then you will get an empty RBF model with no dataset
   52945             :       being attached.
   52946             :       
   52947             :       From the other side, if you call rbfbuildmodel() between (1) and (2),
   52948             :       then after (2) you will get your fully constructed RBF model  -  but
   52949             :       again with no dataset attached, so subsequent calls to rbfbuildmodel()
   52950             :       will produce empty model.
   52951             :       
   52952             : 
   52953             :   -- ALGLIB --
   52954             :      Copyright 20.06.2016 by Bochkanov Sergey
   52955             : *************************************************************************/
   52956           0 : void rbfsetpointsandscales(rbfmodel* r,
   52957             :      /* Real    */ ae_matrix* xy,
   52958             :      ae_int_t n,
   52959             :      /* Real    */ ae_vector* s,
   52960             :      ae_state *_state)
   52961             : {
   52962             :     ae_int_t i;
   52963             :     ae_int_t j;
   52964             : 
   52965             : 
   52966           0 :     ae_assert(n>0, "RBFSetPointsAndScales: N<0", _state);
   52967           0 :     ae_assert(xy->rows>=n, "RBFSetPointsAndScales: Rows(XY)<N", _state);
   52968           0 :     ae_assert(xy->cols>=r->nx+r->ny, "RBFSetPointsAndScales: Cols(XY)<NX+NY", _state);
   52969           0 :     ae_assert(s->cnt>=r->nx, "RBFSetPointsAndScales: Length(S)<NX", _state);
   52970           0 :     r->n = n;
   52971           0 :     r->hasscale = ae_true;
   52972           0 :     ae_matrix_set_length(&r->x, r->n, r->nx, _state);
   52973           0 :     ae_matrix_set_length(&r->y, r->n, r->ny, _state);
   52974           0 :     for(i=0; i<=r->n-1; i++)
   52975             :     {
   52976           0 :         for(j=0; j<=r->nx-1; j++)
   52977             :         {
   52978           0 :             r->x.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j];
   52979             :         }
   52980           0 :         for(j=0; j<=r->ny-1; j++)
   52981             :         {
   52982           0 :             r->y.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j+r->nx];
   52983             :         }
   52984             :     }
   52985           0 :     ae_vector_set_length(&r->s, r->nx, _state);
   52986           0 :     for(i=0; i<=r->nx-1; i++)
   52987             :     {
   52988           0 :         ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "RBFSetPointsAndScales: S[i] is not finite number", _state);
   52989           0 :         ae_assert(ae_fp_greater(s->ptr.p_double[i],(double)(0)), "RBFSetPointsAndScales: S[i]<=0", _state);
   52990           0 :         r->s.ptr.p_double[i] = s->ptr.p_double[i];
   52991             :     }
   52992           0 : }
   52993             : 
   52994             : 
   52995             : /*************************************************************************
   52996             : DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
   52997             :            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
   52998             :            requires less memory than QNN and RBF-ML. It is especially good
   52999             :            for large-scale interpolation problems. So, we recommend you to
   53000             :            consider Hierarchical RBF as default option.
   53001             :            
   53002             : ==========================================================================
   53003             : 
   53004             : This  function  sets  RBF interpolation algorithm. ALGLIB supports several
   53005             : RBF algorithms with different properties.
   53006             : 
   53007             : This algorithm is called RBF-QNN and  it  is  good  for  point  sets  with
   53008             : following properties:
   53009             : a) all points are distinct
   53010             : b) all points are well separated.
   53011             : c) points  distribution  is  approximately  uniform.  There is no "contour
   53012             :    lines", clusters of points, or other small-scale structures.
   53013             : 
   53014             : Algorithm description:
   53015             : 1) interpolation centers are allocated to data points
   53016             : 2) interpolation radii are calculated as distances to the  nearest centers
   53017             :    times Q coefficient (where Q is a value from [0.75,1.50]).
   53018             : 3) after  performing (2) radii are transformed in order to avoid situation
   53019             :    when single outlier has very large radius and  influences  many  points
   53020             :    across all dataset. Transformation has following form:
   53021             :        new_r[i] = min(r[i],Z*median(r[]))
   53022             :    where r[i] is I-th radius, median()  is a median  radius across  entire
   53023             :    dataset, Z is user-specified value which controls amount  of  deviation
   53024             :    from median radius.
   53025             : 
   53026             : When (a) is violated,  we  will  be unable to build RBF model. When (b) or
   53027             : (c) are violated, model will be built, but interpolation quality  will  be
   53028             : low. See http://www.alglib.net/interpolation/ for more information on this
   53029             : subject.
   53030             : 
   53031             : This algorithm is used by default.
   53032             : 
   53033             : Additional Q parameter controls smoothness properties of the RBF basis:
   53034             : * Q<0.75 will give perfectly conditioned basis,  but  terrible  smoothness
   53035             :   properties (RBF interpolant will have sharp peaks around function values)
   53036             : * Q around 1.0 gives good balance between smoothness and condition number
   53037             : * Q>1.5 will lead to badly conditioned systems and slow convergence of the
   53038             :   underlying linear solver (although smoothness will be very good)
   53039             : * Q>2.0 will effectively make optimizer useless because it won't  converge
   53040             :   within reasonable amount of iterations. It is possible to set such large
   53041             :   Q, but it is advised not to do so.
   53042             : 
   53043             : INPUT PARAMETERS:
   53044             :     S       -   RBF model, initialized by RBFCreate() call
   53045             :     Q       -   Q parameter, Q>0, recommended value - 1.0
   53046             :     Z       -   Z parameter, Z>0, recommended value - 5.0
   53047             : 
   53048             : NOTE: this   function  has   some   serialization-related  subtleties.  We
   53049             :       recommend you to study serialization examples from ALGLIB  Reference
   53050             :       Manual if you want to perform serialization of your models.
   53051             : 
   53052             : 
   53053             :   -- ALGLIB --
   53054             :      Copyright 13.12.2011 by Bochkanov Sergey
   53055             : *************************************************************************/
   53056           0 : void rbfsetalgoqnn(rbfmodel* s, double q, double z, ae_state *_state)
   53057             : {
   53058             : 
   53059             : 
   53060           0 :     ae_assert(ae_isfinite(q, _state), "RBFSetAlgoQNN: Q is infinite or NAN", _state);
   53061           0 :     ae_assert(ae_fp_greater(q,(double)(0)), "RBFSetAlgoQNN: Q<=0", _state);
   53062           0 :     ae_assert(ae_isfinite(z, _state), "RBFSetAlgoQNN: Z is infinite or NAN", _state);
   53063           0 :     ae_assert(ae_fp_greater(z,(double)(0)), "RBFSetAlgoQNN: Z<=0", _state);
   53064           0 :     s->radvalue = q;
   53065           0 :     s->radzvalue = z;
   53066           0 :     s->algorithmtype = 1;
   53067           0 : }
   53068             : 
   53069             : 
   53070             : /*************************************************************************
   53071             : DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
   53072             :            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
   53073             :            requires less memory than QNN and RBF-ML. It is especially good
   53074             :            for large-scale interpolation problems. So, we recommend you to
   53075             :            consider Hierarchical RBF as default option.
   53076             :            
   53077             : ==========================================================================
   53078             : 
   53079             : This  function  sets  RBF interpolation algorithm. ALGLIB supports several
   53080             : RBF algorithms with different properties.
   53081             : 
   53082             : This  algorithm is called RBF-ML. It builds  multilayer  RBF  model,  i.e.
   53083             : model with subsequently decreasing  radii,  which  allows  us  to  combine
   53084             : smoothness (due to  large radii of  the first layers) with  exactness (due
   53085             : to small radii of the last layers) and fast convergence.
   53086             : 
   53087             : Internally RBF-ML uses many different  means  of acceleration, from sparse
   53088             : matrices  to  KD-trees,  which  results in algorithm whose working time is
   53089             : roughly proportional to N*log(N)*Density*RBase^2*NLayers,  where  N  is  a
   53090             : number of points, Density is an average density if points per unit of  the
   53091             : interpolation space, RBase is an initial radius, NLayers is  a  number  of
   53092             : layers.
   53093             : 
   53094             : RBF-ML is good for following kinds of interpolation problems:
   53095             : 1. "exact" problems (perfect fit) with well separated points
   53096             : 2. least squares problems with arbitrary distribution of points (algorithm
   53097             :    gives  perfect  fit  where it is possible, and resorts to least squares
   53098             :    fit in the hard areas).
   53099             : 3. noisy problems where  we  want  to  apply  some  controlled  amount  of
   53100             :    smoothing.
   53101             : 
   53102             : INPUT PARAMETERS:
   53103             :     S       -   RBF model, initialized by RBFCreate() call
   53104             :     RBase   -   RBase parameter, RBase>0
   53105             :     NLayers -   NLayers parameter, NLayers>0, recommended value  to  start
   53106             :                 with - about 5.
   53107             :     LambdaV -   regularization value, can be useful when  solving  problem
   53108             :                 in the least squares sense.  Optimal  lambda  is  problem-
   53109             :                 dependent and require trial and error. In our  experience,
   53110             :                 good lambda can be as large as 0.1, and you can use  0.001
   53111             :                 as initial guess.
   53112             :                 Default  value  - 0.01, which is used when LambdaV is  not
   53113             :                 given.  You  can  specify  zero  value,  but  it  is   not
   53114             :                 recommended to do so.
   53115             : 
   53116             : TUNING ALGORITHM
   53117             : 
   53118             : In order to use this algorithm you have to choose three parameters:
   53119             : * initial radius RBase
   53120             : * number of layers in the model NLayers
   53121             : * regularization coefficient LambdaV
   53122             : 
   53123             : Initial radius is easy to choose - you can pick any number  several  times
   53124             : larger  than  the  average  distance between points. Algorithm won't break
   53125             : down if you choose radius which is too large (model construction time will
   53126             : increase, but model will be built correctly).
   53127             : 
   53128             : Choose such number of layers that RLast=RBase/2^(NLayers-1)  (radius  used
   53129             : by  the  last  layer)  will  be  smaller than the typical distance between
   53130             : points.  In  case  model  error  is  too large, you can increase number of
   53131             : layers.  Having  more  layers  will make model construction and evaluation
   53132             : proportionally slower, but it will allow you to have model which precisely
   53133             : fits your data. From the other side, if you want to  suppress  noise,  you
   53134             : can DECREASE number of layers to make your model less flexible.
   53135             : 
   53136             : Regularization coefficient LambdaV controls smoothness of  the  individual
   53137             : models built for each layer. We recommend you to use default value in case
   53138             : you don't want to tune this parameter,  because  having  non-zero  LambdaV
   53139             : accelerates and stabilizes internal iterative algorithm. In case you  want
   53140             : to suppress noise you can use  LambdaV  as  additional  parameter  (larger
   53141             : value = more smoothness) to tune.
   53142             : 
   53143             : TYPICAL ERRORS
   53144             : 
   53145             : 1. Using  initial  radius  which is too large. Memory requirements  of the
   53146             :    RBF-ML are roughly proportional to N*Density*RBase^2 (where Density  is
   53147             :    an average density of points per unit of the interpolation  space).  In
   53148             :    the extreme case of the very large RBase we will need O(N^2)  units  of
   53149             :    memory - and many layers in order to decrease radius to some reasonably
   53150             :    small value.
   53151             : 
   53152             : 2. Using too small number of layers - RBF models with large radius are not
   53153             :    flexible enough to reproduce small variations in the  target  function.
   53154             :    You  need  many  layers  with  different radii, from large to small, in
   53155             :    order to have good model.
   53156             : 
   53157             : 3. Using  initial  radius  which  is  too  small.  You will get model with
   53158             :    "holes" in the areas which are too far away from interpolation centers.
   53159             :    However, algorithm will work correctly (and quickly) in this case.
   53160             : 
   53161             : 4. Using too many layers - you will get too large and too slow model. This
   53162             :    model  will  perfectly  reproduce  your function, but maybe you will be
   53163             :    able to achieve similar results with less layers (and less memory).
   53164             :    
   53165             :   -- ALGLIB --
   53166             :      Copyright 02.03.2012 by Bochkanov Sergey
   53167             : *************************************************************************/
   53168           0 : void rbfsetalgomultilayer(rbfmodel* s,
   53169             :      double rbase,
   53170             :      ae_int_t nlayers,
   53171             :      double lambdav,
   53172             :      ae_state *_state)
   53173             : {
   53174             : 
   53175             : 
   53176           0 :     ae_assert(ae_isfinite(rbase, _state), "RBFSetAlgoMultiLayer: RBase is infinite or NaN", _state);
   53177           0 :     ae_assert(ae_fp_greater(rbase,(double)(0)), "RBFSetAlgoMultiLayer: RBase<=0", _state);
   53178           0 :     ae_assert(nlayers>=0, "RBFSetAlgoMultiLayer: NLayers<0", _state);
   53179           0 :     ae_assert(ae_isfinite(lambdav, _state), "RBFSetAlgoMultiLayer: LambdaV is infinite or NAN", _state);
   53180           0 :     ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "RBFSetAlgoMultiLayer: LambdaV<0", _state);
   53181           0 :     s->radvalue = rbase;
   53182           0 :     s->nlayers = nlayers;
   53183           0 :     s->algorithmtype = 2;
   53184           0 :     s->lambdav = lambdav;
   53185           0 : }
   53186             : 
   53187             : 
   53188             : /*************************************************************************
   53189             : This  function  sets  RBF interpolation algorithm. ALGLIB supports several
   53190             : RBF algorithms with different properties.
   53191             : 
   53192             : This  algorithm is called Hierarchical RBF. It  similar  to  its  previous
   53193             : incarnation, RBF-ML, i.e.  it  also  builds  a  sequence  of  models  with
   53194             : decreasing radii. However, it uses more economical way of  building  upper
   53195             : layers (ones with large radii), which results in faster model construction
   53196             : and evaluation, as well as smaller memory footprint during construction.
   53197             : 
   53198             : This algorithm has following important features:
   53199             : * ability to handle millions of points
   53200             : * controllable smoothing via nonlinearity penalization
   53201             : * support for NX-dimensional models with NX=1 or NX>3 (unlike QNN or RBF-ML)
   53202             : * support for specification of per-dimensional  radii  via  scale  vector,
   53203             :   which is set by means of rbfsetpointsandscales() function. This  feature
   53204             :   is useful if you solve  spatio-temporal  interpolation  problems,  where
   53205             :   different radii are required for spatial and temporal dimensions.
   53206             : 
   53207             : Running times are roughly proportional to:
   53208             : * N*log(N)*NLayers - for model construction
   53209             : * N*NLayers - for model evaluation
   53210             : You may see that running time does not depend on search radius  or  points
   53211             : density, just on number of layers in the hierarchy.
   53212             : 
   53213             : IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.11
   53214             :            and  produces  models  which  are  INCOMPATIBLE  with  previous
   53215             :            versions of ALGLIB. You can  not  unserialize  models  produced
   53216             :            with this function in ALGLIB 3.10 or earlier.
   53217             : 
   53218             : INPUT PARAMETERS:
   53219             :     S       -   RBF model, initialized by rbfcreate() call
   53220             :     RBase   -   RBase parameter, RBase>0
   53221             :     NLayers -   NLayers parameter, NLayers>0, recommended value  to  start
   53222             :                 with - about 5.
   53223             :     LambdaNS-   >=0, nonlinearity penalty coefficient, negative values are
   53224             :                 not allowed. This parameter adds controllable smoothing to
   53225             :                 the problem, which may reduce noise. Specification of non-
   53226             :                 zero lambda means that in addition to fitting error solver
   53227             :                 will  also  minimize   LambdaNS*|S''(x)|^2  (appropriately
   53228             :                 generalized to multiple dimensions.
   53229             :                 
   53230             :                 Specification of exactly zero value means that no  penalty
   53231             :                 is added  (we  do  not  even  evaluate  matrix  of  second
   53232             :                 derivatives which is necessary for smoothing).
   53233             :                 
   53234             :                 Calculation of nonlinearity penalty is costly - it results
   53235             :                 in  several-fold  increase  of  model  construction  time.
   53236             :                 Evaluation time remains the same.
   53237             :                 
   53238             :                 Optimal  lambda  is  problem-dependent and requires  trial
   53239             :                 and  error.  Good  value to  start  from  is  1e-5...1e-6,
   53240             :                 which corresponds to slightly noticeable smoothing  of the
   53241             :                 function.  Value  1e-2  usually  means  that  quite  heavy
   53242             :                 smoothing is applied.
   53243             : 
   53244             : TUNING ALGORITHM
   53245             : 
   53246             : In order to use this algorithm you have to choose three parameters:
   53247             : * initial radius RBase
   53248             : * number of layers in the model NLayers
   53249             : * penalty coefficient LambdaNS
   53250             : 
   53251             : Initial radius is easy to choose - you can pick any number  several  times
   53252             : larger  than  the  average  distance between points. Algorithm won't break
   53253             : down if you choose radius which is too large (model construction time will
   53254             : increase, but model will be built correctly).
   53255             : 
   53256             : Choose such number of layers that RLast=RBase/2^(NLayers-1)  (radius  used
   53257             : by  the  last  layer)  will  be  smaller than the typical distance between
   53258             : points.  In  case  model  error  is  too large, you can increase number of
   53259             : layers.  Having  more  layers  will make model construction and evaluation
   53260             : proportionally slower, but it will allow you to have model which precisely
   53261             : fits your data. From the other side, if you want to  suppress  noise,  you
   53262             : can DECREASE number of layers to make your model less flexible (or specify
   53263             : non-zero LambdaNS).
   53264             : 
   53265             : TYPICAL ERRORS
   53266             : 
   53267             : 1. Using too small number of layers - RBF models with large radius are not
   53268             :    flexible enough to reproduce small variations in the  target  function.
   53269             :    You  need  many  layers  with  different radii, from large to small, in
   53270             :    order to have good model.
   53271             : 
   53272             : 2. Using  initial  radius  which  is  too  small.  You will get model with
   53273             :    "holes" in the areas which are too far away from interpolation centers.
   53274             :    However, algorithm will work correctly (and quickly) in this case.
   53275             : 
   53276             :   -- ALGLIB --
   53277             :      Copyright 20.06.2016 by Bochkanov Sergey
   53278             : *************************************************************************/
   53279           0 : void rbfsetalgohierarchical(rbfmodel* s,
   53280             :      double rbase,
   53281             :      ae_int_t nlayers,
   53282             :      double lambdans,
   53283             :      ae_state *_state)
   53284             : {
   53285             : 
   53286             : 
   53287           0 :     ae_assert(ae_isfinite(rbase, _state), "RBFSetAlgoHierarchical: RBase is infinite or NaN", _state);
   53288           0 :     ae_assert(ae_fp_greater(rbase,(double)(0)), "RBFSetAlgoHierarchical: RBase<=0", _state);
   53289           0 :     ae_assert(nlayers>=0, "RBFSetAlgoHierarchical: NLayers<0", _state);
   53290           0 :     ae_assert(ae_isfinite(lambdans, _state)&&ae_fp_greater_eq(lambdans,(double)(0)), "RBFSetAlgoHierarchical: LambdaNS<0 or infinite", _state);
   53291           0 :     s->radvalue = rbase;
   53292           0 :     s->nlayers = nlayers;
   53293           0 :     s->algorithmtype = 3;
   53294           0 :     s->lambdav = lambdans;
   53295           0 : }
   53296             : 
   53297             : 
   53298             : /*************************************************************************
   53299             : This function sets linear term (model is a sum of radial  basis  functions
   53300             : plus linear polynomial). This function won't have effect until  next  call 
   53301             : to RBFBuildModel().
   53302             : 
   53303             : INPUT PARAMETERS:
   53304             :     S       -   RBF model, initialized by RBFCreate() call
   53305             : 
   53306             : NOTE: this   function  has   some   serialization-related  subtleties.  We
   53307             :       recommend you to study serialization examples from ALGLIB  Reference
   53308             :       Manual if you want to perform serialization of your models.
   53309             : 
   53310             :   -- ALGLIB --
   53311             :      Copyright 13.12.2011 by Bochkanov Sergey
   53312             : *************************************************************************/
   53313           0 : void rbfsetlinterm(rbfmodel* s, ae_state *_state)
   53314             : {
   53315             : 
   53316             : 
   53317           0 :     s->aterm = 1;
   53318           0 : }
   53319             : 
   53320             : 
   53321             : /*************************************************************************
   53322             : This function sets constant term (model is a sum of radial basis functions
   53323             : plus constant).  This  function  won't  have  effect  until  next  call to 
   53324             : RBFBuildModel().
   53325             : 
   53326             : INPUT PARAMETERS:
   53327             :     S       -   RBF model, initialized by RBFCreate() call
   53328             : 
   53329             : NOTE: this   function  has   some   serialization-related  subtleties.  We
   53330             :       recommend you to study serialization examples from ALGLIB  Reference
   53331             :       Manual if you want to perform serialization of your models.
   53332             : 
   53333             :   -- ALGLIB --
   53334             :      Copyright 13.12.2011 by Bochkanov Sergey
   53335             : *************************************************************************/
   53336           0 : void rbfsetconstterm(rbfmodel* s, ae_state *_state)
   53337             : {
   53338             : 
   53339             : 
   53340           0 :     s->aterm = 2;
   53341           0 : }
   53342             : 
   53343             : 
   53344             : /*************************************************************************
   53345             : This  function  sets  zero  term (model is a sum of radial basis functions 
   53346             : without polynomial term). This function won't have effect until next  call
   53347             : to RBFBuildModel().
   53348             : 
   53349             : INPUT PARAMETERS:
   53350             :     S       -   RBF model, initialized by RBFCreate() call
   53351             : 
   53352             : NOTE: this   function  has   some   serialization-related  subtleties.  We
   53353             :       recommend you to study serialization examples from ALGLIB  Reference
   53354             :       Manual if you want to perform serialization of your models.
   53355             : 
   53356             :   -- ALGLIB --
   53357             :      Copyright 13.12.2011 by Bochkanov Sergey
   53358             : *************************************************************************/
   53359           0 : void rbfsetzeroterm(rbfmodel* s, ae_state *_state)
   53360             : {
   53361             : 
   53362             : 
   53363           0 :     s->aterm = 3;
   53364           0 : }
   53365             : 
   53366             : 
   53367             : /*************************************************************************
   53368             : This function sets basis function type, which can be:
   53369             : * 0 for classic Gaussian
   53370             : * 1 for fast and compact bell-like basis function, which  becomes  exactly
   53371             :   zero at distance equal to 3*R (default option).
   53372             : 
   53373             : INPUT PARAMETERS:
   53374             :     S       -   RBF model, initialized by RBFCreate() call
   53375             :     BF      -   basis function type:
   53376             :                 * 0 - classic Gaussian
   53377             :                 * 1 - fast and compact one
   53378             : 
   53379             :   -- ALGLIB --
   53380             :      Copyright 01.02.2017 by Bochkanov Sergey
   53381             : *************************************************************************/
   53382           0 : void rbfsetv2bf(rbfmodel* s, ae_int_t bf, ae_state *_state)
   53383             : {
   53384             : 
   53385             : 
   53386           0 :     ae_assert(bf==0||bf==1, "RBFSetV2Its: BF<>0 and BF<>1", _state);
   53387           0 :     s->model2.basisfunction = bf;
   53388           0 : }
   53389             : 
   53390             : 
   53391             : /*************************************************************************
   53392             : This function sets stopping criteria of the underlying linear  solver  for
   53393             : hierarchical (version 2) RBF constructor.
   53394             : 
   53395             : INPUT PARAMETERS:
   53396             :     S       -   RBF model, initialized by RBFCreate() call
   53397             :     MaxIts  -   this criterion will stop algorithm after MaxIts iterations.
   53398             :                 Typically a few hundreds iterations is required,  with 400
   53399             :                 being a good default value to start experimentation.
   53400             :                 Zero value means that default value will be selected.
   53401             : 
   53402             :   -- ALGLIB --
   53403             :      Copyright 01.02.2017 by Bochkanov Sergey
   53404             : *************************************************************************/
   53405           0 : void rbfsetv2its(rbfmodel* s, ae_int_t maxits, ae_state *_state)
   53406             : {
   53407             : 
   53408             : 
   53409           0 :     ae_assert(maxits>=0, "RBFSetV2Its: MaxIts is negative", _state);
   53410           0 :     s->model2.maxits = maxits;
   53411           0 : }
   53412             : 
   53413             : 
   53414             : /*************************************************************************
   53415             : This function sets support radius parameter  of  hierarchical  (version 2)
   53416             : RBF constructor.
   53417             : 
   53418             : Hierarchical RBF model achieves great speed-up  by removing from the model
   53419             : excessive (too dense) nodes. Say, if you have RBF radius equal to 1 meter,
   53420             : and two nodes are just 1 millimeter apart, you  may  remove  one  of  them
   53421             : without reducing model quality.
   53422             : 
   53423             : Support radius parameter is used to justify which points need removal, and
   53424             : which do not. If two points are less than  SUPPORT_R*CUR_RADIUS  units  of
   53425             : distance apart, one of them is removed from the model. The larger  support
   53426             : radius  is, the faster model  construction  AND  evaluation are.  However,
   53427             : too large values result in "bumpy" models.
   53428             : 
   53429             : INPUT PARAMETERS:
   53430             :     S       -   RBF model, initialized by RBFCreate() call
   53431             :     R       -   support radius coefficient, >=0.
   53432             :                 Recommended values are [0.1,0.4] range, with 0.1 being
   53433             :                 default value.
   53434             : 
   53435             :   -- ALGLIB --
   53436             :      Copyright 01.02.2017 by Bochkanov Sergey
   53437             : *************************************************************************/
   53438           0 : void rbfsetv2supportr(rbfmodel* s, double r, ae_state *_state)
   53439             : {
   53440             : 
   53441             : 
   53442           0 :     ae_assert(ae_isfinite(r, _state), "RBFSetV2SupportR: R is not finite", _state);
   53443           0 :     ae_assert(ae_fp_greater_eq(r,(double)(0)), "RBFSetV2SupportR: R<0", _state);
   53444           0 :     s->model2.supportr = r;
   53445           0 : }
   53446             : 
   53447             : 
   53448             : /*************************************************************************
   53449             : This function sets stopping criteria of the underlying linear solver.
   53450             : 
   53451             : INPUT PARAMETERS:
   53452             :     S       -   RBF model, initialized by RBFCreate() call
   53453             :     EpsOrt  -   orthogonality stopping criterion, EpsOrt>=0. Algorithm will
   53454             :                 stop when ||A'*r||<=EpsOrt where A' is a transpose of  the 
   53455             :                 system matrix, r is a residual vector.
   53456             :                 Recommended value of EpsOrt is equal to 1E-6.
   53457             :                 This criterion will stop algorithm when we have "bad fit"
   53458             :                 situation, i.e. when we should stop in a point with large,
   53459             :                 nonzero residual.
   53460             :     EpsErr  -   residual stopping  criterion.  Algorithm  will  stop  when
   53461             :                 ||r||<=EpsErr*||b||, where r is a residual vector, b is  a
   53462             :                 right part of the system (function values).
   53463             :                 Recommended value of EpsErr is equal to 1E-3 or 1E-6.
   53464             :                 This  criterion  will  stop  algorithm  in  a  "good  fit" 
   53465             :                 situation when we have near-zero residual near the desired
   53466             :                 solution.
   53467             :     MaxIts  -   this criterion will stop algorithm after MaxIts iterations.
   53468             :                 It should be used for debugging purposes only!
   53469             :                 Zero MaxIts means that no limit is placed on the number of
   53470             :                 iterations.
   53471             : 
   53472             : We  recommend  to  set  moderate  non-zero  values   EpsOrt   and   EpsErr 
   53473             : simultaneously. Values equal to 10E-6 are good to start with. In case  you
   53474             : need high performance and do not need high precision ,  you  may  decrease
   53475             : EpsErr down to 0.001. However, we do not recommend decreasing EpsOrt.
   53476             : 
   53477             : As for MaxIts, we recommend to leave it zero unless you know what you do.
   53478             : 
   53479             : NOTE: this   function  has   some   serialization-related  subtleties.  We
   53480             :       recommend you to study serialization examples from ALGLIB  Reference
   53481             :       Manual if you want to perform serialization of your models.
   53482             : 
   53483             :   -- ALGLIB --
   53484             :      Copyright 13.12.2011 by Bochkanov Sergey
   53485             : *************************************************************************/
   53486           0 : void rbfsetcond(rbfmodel* s,
   53487             :      double epsort,
   53488             :      double epserr,
   53489             :      ae_int_t maxits,
   53490             :      ae_state *_state)
   53491             : {
   53492             : 
   53493             : 
   53494           0 :     ae_assert(ae_isfinite(epsort, _state)&&ae_fp_greater_eq(epsort,(double)(0)), "RBFSetCond: EpsOrt is negative, INF or NAN", _state);
   53495           0 :     ae_assert(ae_isfinite(epserr, _state)&&ae_fp_greater_eq(epserr,(double)(0)), "RBFSetCond: EpsB is negative, INF or NAN", _state);
   53496           0 :     ae_assert(maxits>=0, "RBFSetCond: MaxIts is negative", _state);
   53497           0 :     if( (ae_fp_eq(epsort,(double)(0))&&ae_fp_eq(epserr,(double)(0)))&&maxits==0 )
   53498             :     {
   53499           0 :         s->epsort = rbf_eps;
   53500           0 :         s->epserr = rbf_eps;
   53501           0 :         s->maxits = 0;
   53502             :     }
   53503             :     else
   53504             :     {
   53505           0 :         s->epsort = epsort;
   53506           0 :         s->epserr = epserr;
   53507           0 :         s->maxits = maxits;
   53508             :     }
   53509           0 : }
   53510             : 
   53511             : 
   53512             : /*************************************************************************
   53513             : This   function  builds  RBF  model  and  returns  report  (contains  some 
   53514             : information which can be used for evaluation of the algorithm properties).
   53515             : 
   53516             : Call to this function modifies RBF model by calculating its centers/radii/
   53517             : weights  and  saving  them  into  RBFModel  structure.  Initially RBFModel 
   53518             : contain zero coefficients, but after call to this function  we  will  have
   53519             : coefficients which were calculated in order to fit our dataset.
   53520             : 
   53521             : After you called this function you can call RBFCalc(),  RBFGridCalc()  and
   53522             : other model calculation functions.
   53523             : 
   53524             : INPUT PARAMETERS:
   53525             :     S       -   RBF model, initialized by RBFCreate() call
   53526             :     Rep     -   report:
   53527             :                 * Rep.TerminationType:
   53528             :                   * -5 - non-distinct basis function centers were detected,
   53529             :                          interpolation  aborted;  only  QNN  returns  this
   53530             :                          error   code, other  algorithms  can  handle non-
   53531             :                          distinct nodes.
   53532             :                   * -4 - nonconvergence of the internal SVD solver
   53533             :                   * -3   incorrect model construction algorithm was chosen:
   53534             :                          QNN or RBF-ML, combined with one of the incompatible
   53535             :                          features - NX=1 or NX>3; points with per-dimension
   53536             :                          scales.
   53537             :                   *  1 - successful termination
   53538             :                   *  8 - a termination request was submitted via
   53539             :                          rbfrequesttermination() function.
   53540             :                 
   53541             :                 Fields which are set only by modern RBF solvers (hierarchical
   53542             :                 or nonnegative; older solvers like QNN and ML initialize these
   53543             :                 fields by NANs):
   53544             :                 * rep.rmserror - root-mean-square error at nodes
   53545             :                 * rep.maxerror - maximum error at nodes
   53546             :                 
   53547             :                 Fields are used for debugging purposes:
   53548             :                 * Rep.IterationsCount - iterations count of the LSQR solver
   53549             :                 * Rep.NMV - number of matrix-vector products
   53550             :                 * Rep.ARows - rows count for the system matrix
   53551             :                 * Rep.ACols - columns count for the system matrix
   53552             :                 * Rep.ANNZ - number of significantly non-zero elements
   53553             :                   (elements above some algorithm-determined threshold)
   53554             : 
   53555             : NOTE:  failure  to  build  model will leave current state of the structure
   53556             : unchanged.
   53557             : 
   53558             :   -- ALGLIB --
   53559             :      Copyright 13.12.2011 by Bochkanov Sergey
   53560             : *************************************************************************/
   53561           0 : void rbfbuildmodel(rbfmodel* s, rbfreport* rep, ae_state *_state)
   53562             : {
   53563             :     ae_frame _frame_block;
   53564             :     rbfv1report rep1;
   53565             :     rbfv2report rep2;
   53566             :     ae_matrix x3;
   53567             :     ae_vector scalevec;
   53568             :     ae_int_t i;
   53569             :     ae_int_t curalgorithmtype;
   53570             : 
   53571           0 :     ae_frame_make(_state, &_frame_block);
   53572           0 :     memset(&rep1, 0, sizeof(rep1));
   53573           0 :     memset(&rep2, 0, sizeof(rep2));
   53574           0 :     memset(&x3, 0, sizeof(x3));
   53575           0 :     memset(&scalevec, 0, sizeof(scalevec));
   53576           0 :     _rbfreport_clear(rep);
   53577           0 :     _rbfv1report_init(&rep1, _state, ae_true);
   53578           0 :     _rbfv2report_init(&rep2, _state, ae_true);
   53579           0 :     ae_matrix_init(&x3, 0, 0, DT_REAL, _state, ae_true);
   53580           0 :     ae_vector_init(&scalevec, 0, DT_REAL, _state, ae_true);
   53581             : 
   53582             :     
   53583             :     /*
   53584             :      * Clean fields prior to processing
   53585             :      */
   53586           0 :     rbf_clearreportfields(rep, _state);
   53587           0 :     s->progress10000 = 0;
   53588           0 :     s->terminationrequest = ae_false;
   53589             :     
   53590             :     /*
   53591             :      * Autoselect algorithm
   53592             :      */
   53593           0 :     if( s->algorithmtype==0 )
   53594             :     {
   53595           0 :         if( (s->nx<2||s->nx>3)||s->hasscale )
   53596             :         {
   53597           0 :             curalgorithmtype = 3;
   53598             :         }
   53599             :         else
   53600             :         {
   53601           0 :             curalgorithmtype = 1;
   53602             :         }
   53603             :     }
   53604             :     else
   53605             :     {
   53606           0 :         curalgorithmtype = s->algorithmtype;
   53607             :     }
   53608             :     
   53609             :     /*
   53610             :      * Algorithms which generate V1 models
   53611             :      */
   53612           0 :     if( curalgorithmtype==1||curalgorithmtype==2 )
   53613             :     {
   53614             :         
   53615             :         /*
   53616             :          * Perform compatibility checks
   53617             :          */
   53618           0 :         if( (s->nx<2||s->nx>3)||s->hasscale )
   53619             :         {
   53620           0 :             rep->terminationtype = -3;
   53621           0 :             ae_frame_leave(_state);
   53622           0 :             return;
   53623             :         }
   53624             :         
   53625             :         /*
   53626             :          * Try to build model.
   53627             :          *
   53628             :          * NOTE: due to historical reasons RBFV1BuildModel() accepts points
   53629             :          *       cast to 3-dimensional space, even if they are really 2-dimensional.
   53630             :          *       So, for 2D data we have to explicitly convert them to 3D.
   53631             :          */
   53632           0 :         if( s->nx==2 )
   53633             :         {
   53634             :             
   53635             :             /*
   53636             :              * Convert data to 3D
   53637             :              */
   53638           0 :             rmatrixsetlengthatleast(&x3, s->n, 3, _state);
   53639           0 :             for(i=0; i<=s->n-1; i++)
   53640             :             {
   53641           0 :                 x3.ptr.pp_double[i][0] = s->x.ptr.pp_double[i][0];
   53642           0 :                 x3.ptr.pp_double[i][1] = s->x.ptr.pp_double[i][1];
   53643           0 :                 x3.ptr.pp_double[i][2] = (double)(0);
   53644             :             }
   53645           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);
   53646             :         }
   53647             :         else
   53648             :         {
   53649             :             
   53650             :             /*
   53651             :              * Work with raw data
   53652             :              */
   53653           0 :             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);
   53654             :         }
   53655           0 :         s->modelversion = 1;
   53656             :         
   53657             :         /*
   53658             :          * Convert report fields
   53659             :          */
   53660           0 :         rep->arows = rep1.arows;
   53661           0 :         rep->acols = rep1.acols;
   53662           0 :         rep->annz = rep1.annz;
   53663           0 :         rep->iterationscount = rep1.iterationscount;
   53664           0 :         rep->nmv = rep1.nmv;
   53665           0 :         rep->terminationtype = rep1.terminationtype;
   53666             :         
   53667             :         /*
   53668             :          * Done
   53669             :          */
   53670           0 :         ae_frame_leave(_state);
   53671           0 :         return;
   53672             :     }
   53673             :     
   53674             :     /*
   53675             :      * Algorithms which generate V2 models
   53676             :      */
   53677           0 :     if( curalgorithmtype==3 )
   53678             :     {
   53679             :         
   53680             :         /*
   53681             :          * Prepare scale vector - use unit values or user supplied ones
   53682             :          */
   53683           0 :         ae_vector_set_length(&scalevec, s->nx, _state);
   53684           0 :         for(i=0; i<=s->nx-1; i++)
   53685             :         {
   53686           0 :             if( s->hasscale )
   53687             :             {
   53688           0 :                 scalevec.ptr.p_double[i] = s->s.ptr.p_double[i];
   53689             :             }
   53690             :             else
   53691             :             {
   53692           0 :                 scalevec.ptr.p_double[i] = (double)(1);
   53693             :             }
   53694             :         }
   53695             :         
   53696             :         /*
   53697             :          * Build model
   53698             :          */
   53699           0 :         rbfv2buildhierarchical(&s->x, &s->y, s->n, &scalevec, s->aterm, s->nlayers, s->radvalue, s->lambdav, &s->model2, &s->progress10000, &s->terminationrequest, &rep2, _state);
   53700           0 :         s->modelversion = 2;
   53701             :         
   53702             :         /*
   53703             :          * Convert report fields
   53704             :          */
   53705           0 :         rep->terminationtype = rep2.terminationtype;
   53706           0 :         rep->rmserror = rep2.rmserror;
   53707           0 :         rep->maxerror = rep2.maxerror;
   53708             :         
   53709             :         /*
   53710             :          * Done
   53711             :          */
   53712           0 :         ae_frame_leave(_state);
   53713           0 :         return;
   53714             :     }
   53715             :     
   53716             :     /*
   53717             :      * Critical error
   53718             :      */
   53719           0 :     ae_assert(ae_false, "RBFBuildModel: integrity check failure", _state);
   53720           0 :     ae_frame_leave(_state);
   53721             : }
   53722             : 
   53723             : 
   53724             : /*************************************************************************
   53725             : This function calculates values of the RBF model in the given point.
   53726             : 
   53727             : IMPORTANT: this function works only with modern  (hierarchical)  RBFs.  It 
   53728             :            can not be used with legacy (version 1) RBFs because older  RBF
   53729             :            code does not support 1-dimensional models.
   53730             : 
   53731             : This function should be used when we have NY=1 (scalar function) and  NX=1
   53732             : (1-dimensional space). If you have 3-dimensional space, use rbfcalc3(). If
   53733             : you  have  2-dimensional  space,  use  rbfcalc3().  If  you  have  general
   53734             : situation (NX-dimensional space, NY-dimensional function)  you  should use
   53735             : generic rbfcalc().
   53736             : 
   53737             : If you want to perform parallel model evaluation  from  multiple  threads,
   53738             : use rbftscalcbuf() with per-thread buffer object.
   53739             : 
   53740             : This function returns 0.0 when:
   53741             : * model is not initialized
   53742             : * NX<>1
   53743             : * NY<>1
   53744             : 
   53745             : INPUT PARAMETERS:
   53746             :     S       -   RBF model
   53747             :     X0      -   X-coordinate, finite number
   53748             : 
   53749             : RESULT:
   53750             :     value of the model or 0.0 (as defined above)
   53751             : 
   53752             :   -- ALGLIB --
   53753             :      Copyright 13.12.2011 by Bochkanov Sergey
   53754             : *************************************************************************/
   53755           0 : double rbfcalc1(rbfmodel* s, double x0, ae_state *_state)
   53756             : {
   53757             :     double result;
   53758             : 
   53759             : 
   53760           0 :     ae_assert(ae_isfinite(x0, _state), "RBFCalc1: invalid value for X0 (X0 is Inf)!", _state);
   53761           0 :     result = (double)(0);
   53762           0 :     if( s->ny!=1||s->nx!=1 )
   53763             :     {
   53764           0 :         return result;
   53765             :     }
   53766           0 :     if( s->modelversion==1 )
   53767             :     {
   53768           0 :         result = (double)(0);
   53769           0 :         return result;
   53770             :     }
   53771           0 :     if( s->modelversion==2 )
   53772             :     {
   53773           0 :         result = rbfv2calc1(&s->model2, x0, _state);
   53774           0 :         return result;
   53775             :     }
   53776           0 :     ae_assert(ae_false, "RBFCalc1: integrity check failed", _state);
   53777           0 :     return result;
   53778             : }
   53779             : 
   53780             : 
   53781             : /*************************************************************************
   53782             : This function calculates values of the RBF model in the given point.
   53783             : 
   53784             : This function should be used when we have NY=1 (scalar function) and  NX=2
   53785             : (2-dimensional space). If you have 3-dimensional space, use rbfcalc3(). If
   53786             : you have general situation (NX-dimensional space, NY-dimensional function)
   53787             : you should use generic rbfcalc().
   53788             : 
   53789             : If  you  want  to  calculate  function  values  many times, consider using 
   53790             : rbfgridcalc2v(), which is far more efficient than many subsequent calls to
   53791             : rbfcalc2().
   53792             : 
   53793             : If you want to perform parallel model evaluation  from  multiple  threads,
   53794             : use rbftscalcbuf() with per-thread buffer object.
   53795             : 
   53796             : This function returns 0.0 when:
   53797             : * model is not initialized
   53798             : * NX<>2
   53799             :  *NY<>1
   53800             : 
   53801             : INPUT PARAMETERS:
   53802             :     S       -   RBF model
   53803             :     X0      -   first coordinate, finite number
   53804             :     X1      -   second coordinate, finite number
   53805             : 
   53806             : RESULT:
   53807             :     value of the model or 0.0 (as defined above)
   53808             : 
   53809             :   -- ALGLIB --
   53810             :      Copyright 13.12.2011 by Bochkanov Sergey
   53811             : *************************************************************************/
   53812           0 : double rbfcalc2(rbfmodel* s, double x0, double x1, ae_state *_state)
   53813             : {
   53814             :     double result;
   53815             : 
   53816             : 
   53817           0 :     ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state);
   53818           0 :     ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state);
   53819           0 :     result = (double)(0);
   53820           0 :     if( s->ny!=1||s->nx!=2 )
   53821             :     {
   53822           0 :         return result;
   53823             :     }
   53824           0 :     if( s->modelversion==1 )
   53825             :     {
   53826           0 :         result = rbfv1calc2(&s->model1, x0, x1, _state);
   53827           0 :         return result;
   53828             :     }
   53829           0 :     if( s->modelversion==2 )
   53830             :     {
   53831           0 :         result = rbfv2calc2(&s->model2, x0, x1, _state);
   53832           0 :         return result;
   53833             :     }
   53834           0 :     ae_assert(ae_false, "RBFCalc2: integrity check failed", _state);
   53835           0 :     return result;
   53836             : }
   53837             : 
   53838             : 
   53839             : /*************************************************************************
   53840             : This function calculates value of the RBF model in the given point.
   53841             : 
   53842             : This function should be used when we have NY=1 (scalar function) and  NX=3
   53843             : (3-dimensional space). If you have 2-dimensional space, use rbfcalc2(). If
   53844             : you have general situation (NX-dimensional space, NY-dimensional function)
   53845             : you should use generic rbfcalc().
   53846             : 
   53847             : If  you  want  to  calculate  function  values  many times, consider using 
   53848             : rbfgridcalc3v(), which is far more efficient than many subsequent calls to
   53849             : rbfcalc3().
   53850             : 
   53851             : If you want to perform parallel model evaluation  from  multiple  threads,
   53852             : use rbftscalcbuf() with per-thread buffer object.
   53853             : 
   53854             : This function returns 0.0 when:
   53855             : * model is not initialized
   53856             : * NX<>3
   53857             :  *NY<>1
   53858             : 
   53859             : INPUT PARAMETERS:
   53860             :     S       -   RBF model
   53861             :     X0      -   first coordinate, finite number
   53862             :     X1      -   second coordinate, finite number
   53863             :     X2      -   third coordinate, finite number
   53864             : 
   53865             : RESULT:
   53866             :     value of the model or 0.0 (as defined above)
   53867             : 
   53868             :   -- ALGLIB --
   53869             :      Copyright 13.12.2011 by Bochkanov Sergey
   53870             : *************************************************************************/
   53871           0 : double rbfcalc3(rbfmodel* s,
   53872             :      double x0,
   53873             :      double x1,
   53874             :      double x2,
   53875             :      ae_state *_state)
   53876             : {
   53877             :     double result;
   53878             : 
   53879             : 
   53880           0 :     ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state);
   53881           0 :     ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state);
   53882           0 :     ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state);
   53883           0 :     result = (double)(0);
   53884           0 :     if( s->ny!=1||s->nx!=3 )
   53885             :     {
   53886           0 :         return result;
   53887             :     }
   53888           0 :     if( s->modelversion==1 )
   53889             :     {
   53890           0 :         result = rbfv1calc3(&s->model1, x0, x1, x2, _state);
   53891           0 :         return result;
   53892             :     }
   53893           0 :     if( s->modelversion==2 )
   53894             :     {
   53895           0 :         result = rbfv2calc3(&s->model2, x0, x1, x2, _state);
   53896           0 :         return result;
   53897             :     }
   53898           0 :     ae_assert(ae_false, "RBFCalc3: integrity check failed", _state);
   53899           0 :     return result;
   53900             : }
   53901             : 
   53902             : 
   53903             : /*************************************************************************
   53904             : This function calculates values of the RBF model at the given point.
   53905             : 
   53906             : This is general function which can be used for arbitrary NX (dimension  of 
   53907             : the space of arguments) and NY (dimension of the function itself). However
   53908             : when  you  have  NY=1  you  may  find more convenient to use rbfcalc2() or 
   53909             : rbfcalc3().
   53910             : 
   53911             : If you want to perform parallel model evaluation  from  multiple  threads,
   53912             : use rbftscalcbuf() with per-thread buffer object.
   53913             : 
   53914             : This function returns 0.0 when model is not initialized.
   53915             : 
   53916             : INPUT PARAMETERS:
   53917             :     S       -   RBF model
   53918             :     X       -   coordinates, array[NX].
   53919             :                 X may have more than NX elements, in this case only 
   53920             :                 leading NX will be used.
   53921             : 
   53922             : OUTPUT PARAMETERS:
   53923             :     Y       -   function value, array[NY]. Y is out-parameter and 
   53924             :                 reallocated after call to this function. In case you  want
   53925             :                 to reuse previously allocated Y, you may use RBFCalcBuf(),
   53926             :                 which reallocates Y only when it is too small.
   53927             : 
   53928             :   -- ALGLIB --
   53929             :      Copyright 13.12.2011 by Bochkanov Sergey
   53930             : *************************************************************************/
   53931           0 : void rbfcalc(rbfmodel* s,
   53932             :      /* Real    */ ae_vector* x,
   53933             :      /* Real    */ ae_vector* y,
   53934             :      ae_state *_state)
   53935             : {
   53936             : 
   53937           0 :     ae_vector_clear(y);
   53938             : 
   53939           0 :     ae_assert(x->cnt>=s->nx, "RBFCalc: Length(X)<NX", _state);
   53940           0 :     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalc: X contains infinite or NaN values", _state);
   53941           0 :     rbfcalcbuf(s, x, y, _state);
   53942           0 : }
   53943             : 
   53944             : 
   53945             : /*************************************************************************
   53946             : This function calculates values of the RBF model at the given point.
   53947             : 
   53948             : Same as rbfcalc(), but does not reallocate Y when in is large enough to 
   53949             : store function values.
   53950             : 
   53951             : If you want to perform parallel model evaluation  from  multiple  threads,
   53952             : use rbftscalcbuf() with per-thread buffer object.
   53953             : 
   53954             : INPUT PARAMETERS:
   53955             :     S       -   RBF model
   53956             :     X       -   coordinates, array[NX].
   53957             :                 X may have more than NX elements, in this case only 
   53958             :                 leading NX will be used.
   53959             :     Y       -   possibly preallocated array
   53960             : 
   53961             : OUTPUT PARAMETERS:
   53962             :     Y       -   function value, array[NY]. Y is not reallocated when it
   53963             :                 is larger than NY.
   53964             : 
   53965             :   -- ALGLIB --
   53966             :      Copyright 13.12.2011 by Bochkanov Sergey
   53967             : *************************************************************************/
   53968           0 : void rbfcalcbuf(rbfmodel* s,
   53969             :      /* Real    */ ae_vector* x,
   53970             :      /* Real    */ ae_vector* y,
   53971             :      ae_state *_state)
   53972             : {
   53973             :     ae_int_t i;
   53974             : 
   53975             : 
   53976           0 :     ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)<NX", _state);
   53977           0 :     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state);
   53978           0 :     if( y->cnt<s->ny )
   53979             :     {
   53980           0 :         ae_vector_set_length(y, s->ny, _state);
   53981             :     }
   53982           0 :     for(i=0; i<=s->ny-1; i++)
   53983             :     {
   53984           0 :         y->ptr.p_double[i] = (double)(0);
   53985             :     }
   53986           0 :     if( s->modelversion==1 )
   53987             :     {
   53988           0 :         rbfv1calcbuf(&s->model1, x, y, _state);
   53989           0 :         return;
   53990             :     }
   53991           0 :     if( s->modelversion==2 )
   53992             :     {
   53993           0 :         rbfv2calcbuf(&s->model2, x, y, _state);
   53994           0 :         return;
   53995             :     }
   53996           0 :     ae_assert(ae_false, "RBFCalcBuf: integrity check failed", _state);
   53997             : }
   53998             : 
   53999             : 
   54000             : /*************************************************************************
   54001             : This function calculates values of the RBF model at the given point, using
   54002             : external  buffer  object  (internal  temporaries  of  RBF  model  are  not
   54003             : modified).
   54004             : 
   54005             : This function allows to use same RBF model object  in  different  threads,
   54006             : assuming  that  different   threads  use  different  instances  of  buffer
   54007             : structure.
   54008             : 
   54009             : INPUT PARAMETERS:
   54010             :     S       -   RBF model, may be shared between different threads
   54011             :     Buf     -   buffer object created for this particular instance of  RBF
   54012             :                 model with rbfcreatecalcbuffer().
   54013             :     X       -   coordinates, array[NX].
   54014             :                 X may have more than NX elements, in this case only 
   54015             :                 leading NX will be used.
   54016             :     Y       -   possibly preallocated array
   54017             : 
   54018             : OUTPUT PARAMETERS:
   54019             :     Y       -   function value, array[NY]. Y is not reallocated when it
   54020             :                 is larger than NY.
   54021             : 
   54022             :   -- ALGLIB --
   54023             :      Copyright 13.12.2011 by Bochkanov Sergey
   54024             : *************************************************************************/
   54025           0 : void rbftscalcbuf(rbfmodel* s,
   54026             :      rbfcalcbuffer* buf,
   54027             :      /* Real    */ ae_vector* x,
   54028             :      /* Real    */ ae_vector* y,
   54029             :      ae_state *_state)
   54030             : {
   54031             :     ae_int_t i;
   54032             : 
   54033             : 
   54034           0 :     ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)<NX", _state);
   54035           0 :     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state);
   54036           0 :     ae_assert(s->modelversion==buf->modelversion, "RBFCalcBuf: buffer object is not compatible with RBF model", _state);
   54037           0 :     if( y->cnt<s->ny )
   54038             :     {
   54039           0 :         ae_vector_set_length(y, s->ny, _state);
   54040             :     }
   54041           0 :     for(i=0; i<=s->ny-1; i++)
   54042             :     {
   54043           0 :         y->ptr.p_double[i] = (double)(0);
   54044             :     }
   54045           0 :     if( s->modelversion==1 )
   54046             :     {
   54047           0 :         rbfv1tscalcbuf(&s->model1, &buf->bufv1, x, y, _state);
   54048           0 :         return;
   54049             :     }
   54050           0 :     if( s->modelversion==2 )
   54051             :     {
   54052           0 :         rbfv2tscalcbuf(&s->model2, &buf->bufv2, x, y, _state);
   54053           0 :         return;
   54054             :     }
   54055           0 :     ae_assert(ae_false, "RBFTsCalcBuf: integrity check failed", _state);
   54056             : }
   54057             : 
   54058             : 
   54059             : /*************************************************************************
   54060             : This is legacy function for gridded calculation of RBF model.
   54061             : 
   54062             : It is superseded by rbfgridcalc2v() and  rbfgridcalc2vsubset()  functions.
   54063             : 
   54064             :   -- ALGLIB --
   54065             :      Copyright 13.12.2011 by Bochkanov Sergey
   54066             : *************************************************************************/
   54067           0 : void rbfgridcalc2(rbfmodel* s,
   54068             :      /* Real    */ ae_vector* x0,
   54069             :      ae_int_t n0,
   54070             :      /* Real    */ ae_vector* x1,
   54071             :      ae_int_t n1,
   54072             :      /* Real    */ ae_matrix* y,
   54073             :      ae_state *_state)
   54074             : {
   54075             :     ae_frame _frame_block;
   54076             :     ae_vector cpx0;
   54077             :     ae_vector cpx1;
   54078             :     ae_vector p01;
   54079             :     ae_vector p11;
   54080             :     ae_vector p2;
   54081             : 
   54082           0 :     ae_frame_make(_state, &_frame_block);
   54083           0 :     memset(&cpx0, 0, sizeof(cpx0));
   54084           0 :     memset(&cpx1, 0, sizeof(cpx1));
   54085           0 :     memset(&p01, 0, sizeof(p01));
   54086           0 :     memset(&p11, 0, sizeof(p11));
   54087           0 :     memset(&p2, 0, sizeof(p2));
   54088           0 :     ae_matrix_clear(y);
   54089           0 :     ae_vector_init(&cpx0, 0, DT_REAL, _state, ae_true);
   54090           0 :     ae_vector_init(&cpx1, 0, DT_REAL, _state, ae_true);
   54091           0 :     ae_vector_init(&p01, 0, DT_INT, _state, ae_true);
   54092           0 :     ae_vector_init(&p11, 0, DT_INT, _state, ae_true);
   54093           0 :     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
   54094             : 
   54095           0 :     ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state);
   54096           0 :     ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state);
   54097           0 :     ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)<N0", _state);
   54098           0 :     ae_assert(x1->cnt>=n1, "RBFGridCalc2: Length(X1)<N1", _state);
   54099           0 :     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2: X0 contains infinite or NaN values!", _state);
   54100           0 :     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2: X1 contains infinite or NaN values!", _state);
   54101           0 :     if( s->modelversion==1 )
   54102             :     {
   54103           0 :         rbfv1gridcalc2(&s->model1, x0, n0, x1, n1, y, _state);
   54104           0 :         ae_frame_leave(_state);
   54105           0 :         return;
   54106             :     }
   54107           0 :     if( s->modelversion==2 )
   54108             :     {
   54109           0 :         rbfv2gridcalc2(&s->model2, x0, n0, x1, n1, y, _state);
   54110           0 :         ae_frame_leave(_state);
   54111           0 :         return;
   54112             :     }
   54113           0 :     ae_assert(ae_false, "RBFGridCalc2: integrity check failed", _state);
   54114           0 :     ae_frame_leave(_state);
   54115             : }
   54116             : 
   54117             : 
   54118             : /*************************************************************************
   54119             : This function calculates values of the RBF  model  at  the  regular  grid,
   54120             : which  has  N0*N1 points, with Point[I,J] = (X0[I], X1[J]).  Vector-valued
   54121             : RBF models are supported.
   54122             : 
   54123             : This function returns 0.0 when:
   54124             : * model is not initialized
   54125             : * NX<>2
   54126             : 
   54127             :   ! COMMERCIAL EDITION OF ALGLIB:
   54128             :   ! 
   54129             :   ! Commercial Edition of ALGLIB includes following important improvements
   54130             :   ! of this function:
   54131             :   ! * high-performance native backend with same C# interface (C# version)
   54132             :   ! * multithreading support (C++ and C# versions)
   54133             :   ! 
   54134             :   ! We recommend you to read 'Working with commercial version' section  of
   54135             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   54136             :   ! related features provided by commercial edition of ALGLIB.
   54137             : 
   54138             : NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
   54139             :       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
   54140             :       processed serially.
   54141             : 
   54142             : INPUT PARAMETERS:
   54143             :     S       -   RBF model, used in read-only mode, can be  shared  between
   54144             :                 multiple   invocations  of  this  function  from  multiple
   54145             :                 threads.
   54146             :     
   54147             :     X0      -   array of grid nodes, first coordinates, array[N0].
   54148             :                 Must be ordered by ascending. Exception is generated
   54149             :                 if the array is not correctly ordered.
   54150             :     N0      -   grid size (number of nodes) in the first dimension
   54151             :     
   54152             :     X1      -   array of grid nodes, second coordinates, array[N1]
   54153             :                 Must be ordered by ascending. Exception is generated
   54154             :                 if the array is not correctly ordered.
   54155             :     N1      -   grid size (number of nodes) in the second dimension
   54156             : 
   54157             : OUTPUT PARAMETERS:
   54158             :     Y       -   function values, array[NY*N0*N1], where NY is a  number of
   54159             :                 "output" vector values (this  function   supports  vector-
   54160             :                 valued RBF models). Y is out-variable and  is  reallocated
   54161             :                 by this function.
   54162             :                 Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), for:
   54163             :                 *  K=0...NY-1
   54164             :                 * I0=0...N0-1
   54165             :                 * I1=0...N1-1
   54166             : 
   54167             : NOTE: this function supports weakly ordered grid nodes, i.e. you may  have                
   54168             :       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
   54169             :       benefits  due  to   duplication  of  points,  just  convenience  and
   54170             :       flexibility.
   54171             :       
   54172             : NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
   54173             :       structure in multiple threads calling  this function  for  different
   54174             :       grids.
   54175             :       
   54176             : NOTE: if you need function values on some subset  of  regular  grid, which
   54177             :       may be described as "several compact and  dense  islands",  you  may
   54178             :       use rbfgridcalc2vsubset().
   54179             : 
   54180             :   -- ALGLIB --
   54181             :      Copyright 27.01.2017 by Bochkanov Sergey
   54182             : *************************************************************************/
   54183           0 : void rbfgridcalc2v(rbfmodel* s,
   54184             :      /* Real    */ ae_vector* x0,
   54185             :      ae_int_t n0,
   54186             :      /* Real    */ ae_vector* x1,
   54187             :      ae_int_t n1,
   54188             :      /* Real    */ ae_vector* y,
   54189             :      ae_state *_state)
   54190             : {
   54191             :     ae_frame _frame_block;
   54192             :     ae_int_t i;
   54193             :     ae_vector dummy;
   54194             : 
   54195           0 :     ae_frame_make(_state, &_frame_block);
   54196           0 :     memset(&dummy, 0, sizeof(dummy));
   54197           0 :     ae_vector_clear(y);
   54198           0 :     ae_vector_init(&dummy, 0, DT_BOOL, _state, ae_true);
   54199             : 
   54200           0 :     ae_assert(n0>0, "RBFGridCalc2V: invalid value for N0 (N0<=0)!", _state);
   54201           0 :     ae_assert(n1>0, "RBFGridCalc2V: invalid value for N1 (N1<=0)!", _state);
   54202           0 :     ae_assert(x0->cnt>=n0, "RBFGridCalc2V: Length(X0)<N0", _state);
   54203           0 :     ae_assert(x1->cnt>=n1, "RBFGridCalc2V: Length(X1)<N1", _state);
   54204           0 :     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2V: X0 contains infinite or NaN values!", _state);
   54205           0 :     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2V: X1 contains infinite or NaN values!", _state);
   54206           0 :     for(i=0; i<=n0-2; i++)
   54207             :     {
   54208           0 :         ae_assert(ae_fp_less_eq(x0->ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc2V: X0 is not ordered by ascending", _state);
   54209             :     }
   54210           0 :     for(i=0; i<=n1-2; i++)
   54211             :     {
   54212           0 :         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);
   54213             :     }
   54214           0 :     rbfgridcalc2vx(s, x0, n0, x1, n1, &dummy, ae_false, y, _state);
   54215           0 :     ae_frame_leave(_state);
   54216           0 : }
   54217             : 
   54218             : 
   54219             : /*************************************************************************
   54220             : This function calculates values of the RBF model at some subset of regular
   54221             : grid:
   54222             : * grid has N0*N1 points, with Point[I,J] = (X0[I], X1[J])
   54223             : * only values at some subset of this grid are required
   54224             : Vector-valued RBF models are supported.
   54225             : 
   54226             : This function returns 0.0 when:
   54227             : * model is not initialized
   54228             : * NX<>2
   54229             : 
   54230             :   ! COMMERCIAL EDITION OF ALGLIB:
   54231             :   ! 
   54232             :   ! Commercial Edition of ALGLIB includes following important improvements
   54233             :   ! of this function:
   54234             :   ! * high-performance native backend with same C# interface (C# version)
   54235             :   ! * multithreading support (C++ and C# versions)
   54236             :   ! 
   54237             :   ! We recommend you to read 'Working with commercial version' section  of
   54238             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   54239             :   ! related features provided by commercial edition of ALGLIB.
   54240             : 
   54241             : NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
   54242             :       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
   54243             :       processed serially.
   54244             : 
   54245             : INPUT PARAMETERS:
   54246             :     S       -   RBF model, used in read-only mode, can be  shared  between
   54247             :                 multiple   invocations  of  this  function  from  multiple
   54248             :                 threads.
   54249             :     
   54250             :     X0      -   array of grid nodes, first coordinates, array[N0].
   54251             :                 Must be ordered by ascending. Exception is generated
   54252             :                 if the array is not correctly ordered.
   54253             :     N0      -   grid size (number of nodes) in the first dimension
   54254             :     
   54255             :     X1      -   array of grid nodes, second coordinates, array[N1]
   54256             :                 Must be ordered by ascending. Exception is generated
   54257             :                 if the array is not correctly ordered.
   54258             :     N1      -   grid size (number of nodes) in the second dimension
   54259             :     
   54260             :     FlagY   -   array[N0*N1]:
   54261             :                 * Y[I0+I1*N0] corresponds to node (X0[I0],X1[I1])
   54262             :                 * it is a "bitmap" array which contains  False  for  nodes
   54263             :                   which are NOT calculated, and True for nodes  which  are
   54264             :                   required.
   54265             : 
   54266             : OUTPUT PARAMETERS:
   54267             :     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
   54268             :                 of "output" vector values (this function  supports vector-
   54269             :                 valued RBF models):
   54270             :                 * Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]),
   54271             :                   for K=0...NY-1, I0=0...N0-1, I1=0...N1-1.
   54272             :                 * elements of Y[] which correspond  to  FlagY[]=True   are
   54273             :                   loaded by model values (which may be  exactly  zero  for
   54274             :                   some nodes).
   54275             :                 * elements of Y[] which correspond to FlagY[]=False MAY be
   54276             :                   initialized by zeros OR may be calculated. This function
   54277             :                   processes  grid  as  a  hierarchy  of  nested blocks and
   54278             :                   micro-rows. If just one element of micro-row is required,
   54279             :                   entire micro-row (up to 8 nodes in the current  version,
   54280             :                   but no promises) is calculated.
   54281             : 
   54282             : NOTE: this function supports weakly ordered grid nodes, i.e. you may  have                
   54283             :       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
   54284             :       benefits  due  to   duplication  of  points,  just  convenience  and
   54285             :       flexibility.
   54286             :       
   54287             : NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
   54288             :       structure in multiple threads calling  this function  for  different
   54289             :       grids.
   54290             : 
   54291             :   -- ALGLIB --
   54292             :      Copyright 04.03.2016 by Bochkanov Sergey
   54293             : *************************************************************************/
   54294           0 : void rbfgridcalc2vsubset(rbfmodel* s,
   54295             :      /* Real    */ ae_vector* x0,
   54296             :      ae_int_t n0,
   54297             :      /* Real    */ ae_vector* x1,
   54298             :      ae_int_t n1,
   54299             :      /* Boolean */ ae_vector* flagy,
   54300             :      /* Real    */ ae_vector* y,
   54301             :      ae_state *_state)
   54302             : {
   54303             :     ae_int_t i;
   54304             : 
   54305           0 :     ae_vector_clear(y);
   54306             : 
   54307           0 :     ae_assert(n0>0, "RBFGridCalc2VSubset: invalid value for N0 (N0<=0)!", _state);
   54308           0 :     ae_assert(n1>0, "RBFGridCalc2VSubset: invalid value for N1 (N1<=0)!", _state);
   54309           0 :     ae_assert(x0->cnt>=n0, "RBFGridCalc2VSubset: Length(X0)<N0", _state);
   54310           0 :     ae_assert(x1->cnt>=n1, "RBFGridCalc2VSubset: Length(X1)<N1", _state);
   54311           0 :     ae_assert(flagy->cnt>=n0*n1, "RBFGridCalc2VSubset: Length(FlagY)<N0*N1*N2", _state);
   54312           0 :     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2VSubset: X0 contains infinite or NaN values!", _state);
   54313           0 :     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2VSubset: X1 contains infinite or NaN values!", _state);
   54314           0 :     for(i=0; i<=n0-2; i++)
   54315             :     {
   54316           0 :         ae_assert(ae_fp_less_eq(x0->ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc2VSubset: X0 is not ordered by ascending", _state);
   54317             :     }
   54318           0 :     for(i=0; i<=n1-2; i++)
   54319             :     {
   54320           0 :         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);
   54321             :     }
   54322           0 :     rbfgridcalc2vx(s, x0, n0, x1, n1, flagy, ae_true, y, _state);
   54323           0 : }
   54324             : 
   54325             : 
   54326             : /*************************************************************************
   54327             : This function calculates values of the RBF  model  at  the  regular  grid,
   54328             : which  has  N0*N1*N2  points,  with  Point[I,J,K] = (X0[I], X1[J], X2[K]).
   54329             : Vector-valued RBF models are supported.
   54330             : 
   54331             : This function returns 0.0 when:
   54332             : * model is not initialized
   54333             : * NX<>3
   54334             : 
   54335             :   ! COMMERCIAL EDITION OF ALGLIB:
   54336             :   ! 
   54337             :   ! Commercial Edition of ALGLIB includes following important improvements
   54338             :   ! of this function:
   54339             :   ! * high-performance native backend with same C# interface (C# version)
   54340             :   ! * multithreading support (C++ and C# versions)
   54341             :   ! 
   54342             :   ! We recommend you to read 'Working with commercial version' section  of
   54343             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   54344             :   ! related features provided by commercial edition of ALGLIB.
   54345             : 
   54346             : NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
   54347             :       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
   54348             :       processed serially.
   54349             : 
   54350             : INPUT PARAMETERS:
   54351             :     S       -   RBF model, used in read-only mode, can be  shared  between
   54352             :                 multiple   invocations  of  this  function  from  multiple
   54353             :                 threads.
   54354             :     
   54355             :     X0      -   array of grid nodes, first coordinates, array[N0].
   54356             :                 Must be ordered by ascending. Exception is generated
   54357             :                 if the array is not correctly ordered.
   54358             :     N0      -   grid size (number of nodes) in the first dimension
   54359             :     
   54360             :     X1      -   array of grid nodes, second coordinates, array[N1]
   54361             :                 Must be ordered by ascending. Exception is generated
   54362             :                 if the array is not correctly ordered.
   54363             :     N1      -   grid size (number of nodes) in the second dimension
   54364             :     
   54365             :     X2      -   array of grid nodes, third coordinates, array[N2]
   54366             :                 Must be ordered by ascending. Exception is generated
   54367             :                 if the array is not correctly ordered.
   54368             :     N2      -   grid size (number of nodes) in the third dimension
   54369             : 
   54370             : OUTPUT PARAMETERS:
   54371             :     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
   54372             :                 of "output" vector values (this function  supports vector-
   54373             :                 valued RBF models). Y is out-variable and  is  reallocated
   54374             :                 by this function.
   54375             :                 Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]), for:
   54376             :                 *  K=0...NY-1
   54377             :                 * I0=0...N0-1
   54378             :                 * I1=0...N1-1
   54379             :                 * I2=0...N2-1
   54380             : 
   54381             : NOTE: this function supports weakly ordered grid nodes, i.e. you may  have                
   54382             :       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
   54383             :       benefits  due  to   duplication  of  points,  just  convenience  and
   54384             :       flexibility.
   54385             :       
   54386             : NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
   54387             :       structure in multiple threads calling  this function  for  different
   54388             :       grids.
   54389             :       
   54390             : NOTE: if you need function values on some subset  of  regular  grid, which
   54391             :       may be described as "several compact and  dense  islands",  you  may
   54392             :       use rbfgridcalc3vsubset().
   54393             : 
   54394             :   -- ALGLIB --
   54395             :      Copyright 04.03.2016 by Bochkanov Sergey
   54396             : *************************************************************************/
   54397           0 : void rbfgridcalc3v(rbfmodel* s,
   54398             :      /* Real    */ ae_vector* x0,
   54399             :      ae_int_t n0,
   54400             :      /* Real    */ ae_vector* x1,
   54401             :      ae_int_t n1,
   54402             :      /* Real    */ ae_vector* x2,
   54403             :      ae_int_t n2,
   54404             :      /* Real    */ ae_vector* y,
   54405             :      ae_state *_state)
   54406             : {
   54407             :     ae_frame _frame_block;
   54408             :     ae_int_t i;
   54409             :     ae_vector dummy;
   54410             : 
   54411           0 :     ae_frame_make(_state, &_frame_block);
   54412           0 :     memset(&dummy, 0, sizeof(dummy));
   54413           0 :     ae_vector_clear(y);
   54414           0 :     ae_vector_init(&dummy, 0, DT_BOOL, _state, ae_true);
   54415             : 
   54416           0 :     ae_assert(n0>0, "RBFGridCalc3V: invalid value for N0 (N0<=0)!", _state);
   54417           0 :     ae_assert(n1>0, "RBFGridCalc3V: invalid value for N1 (N1<=0)!", _state);
   54418           0 :     ae_assert(n2>0, "RBFGridCalc3V: invalid value for N2 (N2<=0)!", _state);
   54419           0 :     ae_assert(x0->cnt>=n0, "RBFGridCalc3V: Length(X0)<N0", _state);
   54420           0 :     ae_assert(x1->cnt>=n1, "RBFGridCalc3V: Length(X1)<N1", _state);
   54421           0 :     ae_assert(x2->cnt>=n2, "RBFGridCalc3V: Length(X2)<N2", _state);
   54422           0 :     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc3V: X0 contains infinite or NaN values!", _state);
   54423           0 :     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc3V: X1 contains infinite or NaN values!", _state);
   54424           0 :     ae_assert(isfinitevector(x2, n2, _state), "RBFGridCalc3V: X2 contains infinite or NaN values!", _state);
   54425           0 :     for(i=0; i<=n0-2; i++)
   54426             :     {
   54427           0 :         ae_assert(ae_fp_less_eq(x0->ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc3V: X0 is not ordered by ascending", _state);
   54428             :     }
   54429           0 :     for(i=0; i<=n1-2; i++)
   54430             :     {
   54431           0 :         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);
   54432             :     }
   54433           0 :     for(i=0; i<=n2-2; i++)
   54434             :     {
   54435           0 :         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);
   54436             :     }
   54437           0 :     rbfgridcalc3vx(s, x0, n0, x1, n1, x2, n2, &dummy, ae_false, y, _state);
   54438           0 :     ae_frame_leave(_state);
   54439           0 : }
   54440             : 
   54441             : 
   54442             : /*************************************************************************
   54443             : This function calculates values of the RBF model at some subset of regular
   54444             : grid:
   54445             : * grid has N0*N1*N2 points, with Point[I,J,K] = (X0[I], X1[J], X2[K])
   54446             : * only values at some subset of this grid are required
   54447             : Vector-valued RBF models are supported.
   54448             : 
   54449             : This function returns 0.0 when:
   54450             : * model is not initialized
   54451             : * NX<>3
   54452             : 
   54453             :   ! COMMERCIAL EDITION OF ALGLIB:
   54454             :   ! 
   54455             :   ! Commercial Edition of ALGLIB includes following important improvements
   54456             :   ! of this function:
   54457             :   ! * high-performance native backend with same C# interface (C# version)
   54458             :   ! * multithreading support (C++ and C# versions)
   54459             :   ! 
   54460             :   ! We recommend you to read 'Working with commercial version' section  of
   54461             :   ! ALGLIB Reference Manual in order to find out how to  use  performance-
   54462             :   ! related features provided by commercial edition of ALGLIB.
   54463             : 
   54464             : NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
   54465             :       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
   54466             :       processed serially.
   54467             : 
   54468             : INPUT PARAMETERS:
   54469             :     S       -   RBF model, used in read-only mode, can be  shared  between
   54470             :                 multiple   invocations  of  this  function  from  multiple
   54471             :                 threads.
   54472             :     
   54473             :     X0      -   array of grid nodes, first coordinates, array[N0].
   54474             :                 Must be ordered by ascending. Exception is generated
   54475             :                 if the array is not correctly ordered.
   54476             :     N0      -   grid size (number of nodes) in the first dimension
   54477             :     
   54478             :     X1      -   array of grid nodes, second coordinates, array[N1]
   54479             :                 Must be ordered by ascending. Exception is generated
   54480             :                 if the array is not correctly ordered.
   54481             :     N1      -   grid size (number of nodes) in the second dimension
   54482             :     
   54483             :     X2      -   array of grid nodes, third coordinates, array[N2]
   54484             :                 Must be ordered by ascending. Exception is generated
   54485             :                 if the array is not correctly ordered.
   54486             :     N2      -   grid size (number of nodes) in the third dimension
   54487             :     
   54488             :     FlagY   -   array[N0*N1*N2]:
   54489             :                 * Y[I0+I1*N0+I2*N0*N1] corresponds to node (X0[I0],X1[I1],X2[I2])
   54490             :                 * it is a "bitmap" array which contains  False  for  nodes
   54491             :                   which are NOT calculated, and True for nodes  which  are
   54492             :                   required.
   54493             : 
   54494             : OUTPUT PARAMETERS:
   54495             :     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
   54496             :                 of "output" vector values (this function  supports vector-
   54497             :                 valued RBF models):
   54498             :                 * Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]),
   54499             :                   for K=0...NY-1, I0=0...N0-1, I1=0...N1-1, I2=0...N2-1.
   54500             :                 * elements of Y[] which correspond  to  FlagY[]=True   are
   54501             :                   loaded by model values (which may be  exactly  zero  for
   54502             :                   some nodes).
   54503             :                 * elements of Y[] which correspond to FlagY[]=False MAY be
   54504             :                   initialized by zeros OR may be calculated. This function
   54505             :                   processes  grid  as  a  hierarchy  of  nested blocks and
   54506             :                   micro-rows. If just one element of micro-row is required,
   54507             :                   entire micro-row (up to 8 nodes in the current  version,
   54508             :                   but no promises) is calculated.
   54509             : 
   54510             : NOTE: this function supports weakly ordered grid nodes, i.e. you may  have                
   54511             :       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
   54512             :       benefits  due  to   duplication  of  points,  just  convenience  and
   54513             :       flexibility.
   54514             :       
   54515             : NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
   54516             :       structure in multiple threads calling  this function  for  different
   54517             :       grids.
   54518             : 
   54519             :   -- ALGLIB --
   54520             :      Copyright 04.03.2016 by Bochkanov Sergey
   54521             : *************************************************************************/
   54522           0 : void rbfgridcalc3vsubset(rbfmodel* s,
   54523             :      /* Real    */ ae_vector* x0,
   54524             :      ae_int_t n0,
   54525             :      /* Real    */ ae_vector* x1,
   54526             :      ae_int_t n1,
   54527             :      /* Real    */ ae_vector* x2,
   54528             :      ae_int_t n2,
   54529             :      /* Boolean */ ae_vector* flagy,
   54530             :      /* Real    */ ae_vector* y,
   54531             :      ae_state *_state)
   54532             : {
   54533             :     ae_int_t i;
   54534             : 
   54535           0 :     ae_vector_clear(y);
   54536             : 
   54537           0 :     ae_assert(n0>0, "RBFGridCalc3VSubset: invalid value for N0 (N0<=0)!", _state);
   54538           0 :     ae_assert(n1>0, "RBFGridCalc3VSubset: invalid value for N1 (N1<=0)!", _state);
   54539           0 :     ae_assert(n2>0, "RBFGridCalc3VSubset: invalid value for N2 (N2<=0)!", _state);
   54540           0 :     ae_assert(x0->cnt>=n0, "RBFGridCalc3VSubset: Length(X0)<N0", _state);
   54541           0 :     ae_assert(x1->cnt>=n1, "RBFGridCalc3VSubset: Length(X1)<N1", _state);
   54542           0 :     ae_assert(x2->cnt>=n2, "RBFGridCalc3VSubset: Length(X2)<N2", _state);
   54543           0 :     ae_assert(flagy->cnt>=n0*n1*n2, "RBFGridCalc3VSubset: Length(FlagY)<N0*N1*N2", _state);
   54544           0 :     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc3VSubset: X0 contains infinite or NaN values!", _state);
   54545           0 :     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc3VSubset: X1 contains infinite or NaN values!", _state);
   54546           0 :     ae_assert(isfinitevector(x2, n2, _state), "RBFGridCalc3VSubset: X2 contains infinite or NaN values!", _state);
   54547           0 :     for(i=0; i<=n0-2; i++)
   54548             :     {
   54549           0 :         ae_assert(ae_fp_less_eq(x0->ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc3VSubset: X0 is not ordered by ascending", _state);
   54550             :     }
   54551           0 :     for(i=0; i<=n1-2; i++)
   54552             :     {
   54553           0 :         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);
   54554             :     }
   54555           0 :     for(i=0; i<=n2-2; i++)
   54556             :     {
   54557           0 :         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);
   54558             :     }
   54559           0 :     rbfgridcalc3vx(s, x0, n0, x1, n1, x2, n2, flagy, ae_true, y, _state);
   54560           0 : }
   54561             : 
   54562             : 
   54563             : /*************************************************************************
   54564             : This function, depending on SparseY, acts as RBFGridCalc2V (SparseY=False)
   54565             : or RBFGridCalc2VSubset (SparseY=True) function.  See  comments  for  these
   54566             : functions for more information
   54567             : 
   54568             :   -- ALGLIB --
   54569             :      Copyright 04.03.2016 by Bochkanov Sergey
   54570             : *************************************************************************/
   54571           0 : void rbfgridcalc2vx(rbfmodel* s,
   54572             :      /* Real    */ ae_vector* x0,
   54573             :      ae_int_t n0,
   54574             :      /* Real    */ ae_vector* x1,
   54575             :      ae_int_t n1,
   54576             :      /* Boolean */ ae_vector* flagy,
   54577             :      ae_bool sparsey,
   54578             :      /* Real    */ ae_vector* y,
   54579             :      ae_state *_state)
   54580             : {
   54581             :     ae_frame _frame_block;
   54582             :     ae_int_t nx;
   54583             :     ae_int_t ny;
   54584             :     ae_int_t ylen;
   54585             :     hqrndstate rs;
   54586             :     ae_vector dummyx2;
   54587             :     ae_vector dummyx3;
   54588             :     ae_int_t i;
   54589             :     ae_int_t j;
   54590             :     ae_int_t k;
   54591             :     ae_int_t l;
   54592             :     ae_vector tx;
   54593             :     ae_vector ty;
   54594             :     ae_int_t dstoffs;
   54595             :     rbfcalcbuffer calcbuf;
   54596             : 
   54597           0 :     ae_frame_make(_state, &_frame_block);
   54598           0 :     memset(&rs, 0, sizeof(rs));
   54599           0 :     memset(&dummyx2, 0, sizeof(dummyx2));
   54600           0 :     memset(&dummyx3, 0, sizeof(dummyx3));
   54601           0 :     memset(&tx, 0, sizeof(tx));
   54602           0 :     memset(&ty, 0, sizeof(ty));
   54603           0 :     memset(&calcbuf, 0, sizeof(calcbuf));
   54604           0 :     _hqrndstate_init(&rs, _state, ae_true);
   54605           0 :     ae_vector_init(&dummyx2, 0, DT_REAL, _state, ae_true);
   54606           0 :     ae_vector_init(&dummyx3, 0, DT_REAL, _state, ae_true);
   54607           0 :     ae_vector_init(&tx, 0, DT_REAL, _state, ae_true);
   54608           0 :     ae_vector_init(&ty, 0, DT_REAL, _state, ae_true);
   54609           0 :     _rbfcalcbuffer_init(&calcbuf, _state, ae_true);
   54610             : 
   54611           0 :     ae_assert(n0>0, "RBFGridCalc2VX: invalid value for N0 (N0<=0)!", _state);
   54612           0 :     ae_assert(n1>0, "RBFGridCalc2VX: invalid value for N1 (N1<=0)!", _state);
   54613           0 :     ae_assert(x0->cnt>=n0, "RBFGridCalc2VX: Length(X0)<N0", _state);
   54614           0 :     ae_assert(x1->cnt>=n1, "RBFGridCalc2VX: Length(X1)<N1", _state);
   54615           0 :     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2VX: X0 contains infinite or NaN values!", _state);
   54616           0 :     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2VX: X1 contains infinite or NaN values!", _state);
   54617           0 :     for(i=0; i<=n0-2; i++)
   54618             :     {
   54619           0 :         ae_assert(ae_fp_less_eq(x0->ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc2VX: X0 is not ordered by ascending", _state);
   54620             :     }
   54621           0 :     for(i=0; i<=n1-2; i++)
   54622             :     {
   54623           0 :         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);
   54624             :     }
   54625             :     
   54626             :     /*
   54627             :      * Prepare local variables
   54628             :      */
   54629           0 :     nx = s->nx;
   54630           0 :     ny = s->ny;
   54631           0 :     hqrndseed(325, 46345, &rs, _state);
   54632             :     
   54633             :     /*
   54634             :      * Prepare output array
   54635             :      */
   54636           0 :     ylen = ny*n0*n1;
   54637           0 :     ae_vector_set_length(y, ylen, _state);
   54638           0 :     for(i=0; i<=ylen-1; i++)
   54639             :     {
   54640           0 :         y->ptr.p_double[i] = (double)(0);
   54641             :     }
   54642           0 :     if( s->nx!=2 )
   54643             :     {
   54644           0 :         ae_frame_leave(_state);
   54645           0 :         return;
   54646             :     }
   54647             :     
   54648             :     /*
   54649             :      * Process V2 model
   54650             :      */
   54651           0 :     if( s->modelversion==2 )
   54652             :     {
   54653           0 :         ae_vector_set_length(&dummyx2, 1, _state);
   54654           0 :         dummyx2.ptr.p_double[0] = (double)(0);
   54655           0 :         ae_vector_set_length(&dummyx3, 1, _state);
   54656           0 :         dummyx3.ptr.p_double[0] = (double)(0);
   54657           0 :         rbfv2gridcalcvx(&s->model2, x0, n0, x1, n1, &dummyx2, 1, &dummyx3, 1, flagy, sparsey, y, _state);
   54658           0 :         ae_frame_leave(_state);
   54659           0 :         return;
   54660             :     }
   54661             :     
   54662             :     /*
   54663             :      * Reference code for V1 models
   54664             :      */
   54665           0 :     if( s->modelversion==1 )
   54666             :     {
   54667           0 :         ae_vector_set_length(&tx, nx, _state);
   54668           0 :         rbfcreatecalcbuffer(s, &calcbuf, _state);
   54669           0 :         for(i=0; i<=n0-1; i++)
   54670             :         {
   54671           0 :             for(j=0; j<=n1-1; j++)
   54672             :             {
   54673           0 :                 k = i+j*n0;
   54674           0 :                 dstoffs = ny*k;
   54675           0 :                 if( sparsey&&!flagy->ptr.p_bool[k] )
   54676             :                 {
   54677           0 :                     for(l=0; l<=ny-1; l++)
   54678             :                     {
   54679           0 :                         y->ptr.p_double[l+dstoffs] = (double)(0);
   54680             :                     }
   54681           0 :                     continue;
   54682             :                 }
   54683           0 :                 tx.ptr.p_double[0] = x0->ptr.p_double[i];
   54684           0 :                 tx.ptr.p_double[1] = x1->ptr.p_double[j];
   54685           0 :                 rbftscalcbuf(s, &calcbuf, &tx, &ty, _state);
   54686           0 :                 for(l=0; l<=ny-1; l++)
   54687             :                 {
   54688           0 :                     y->ptr.p_double[l+dstoffs] = ty.ptr.p_double[l];
   54689             :                 }
   54690             :             }
   54691             :         }
   54692           0 :         ae_frame_leave(_state);
   54693           0 :         return;
   54694             :     }
   54695             :     
   54696             :     /*
   54697             :      * Unknown model
   54698             :      */
   54699           0 :     ae_assert(ae_false, "RBFGradCalc3VX: integrity check failed", _state);
   54700           0 :     ae_frame_leave(_state);
   54701             : }
   54702             : 
   54703             : 
   54704             : /*************************************************************************
   54705             : This function, depending on SparseY, acts as RBFGridCalc3V (SparseY=False)
   54706             : or RBFGridCalc3VSubset (SparseY=True) function.  See  comments  for  these
   54707             : functions for more information
   54708             : 
   54709             :   -- ALGLIB --
   54710             :      Copyright 04.03.2016 by Bochkanov Sergey
   54711             : *************************************************************************/
   54712           0 : void rbfgridcalc3vx(rbfmodel* s,
   54713             :      /* Real    */ ae_vector* x0,
   54714             :      ae_int_t n0,
   54715             :      /* Real    */ ae_vector* x1,
   54716             :      ae_int_t n1,
   54717             :      /* Real    */ ae_vector* x2,
   54718             :      ae_int_t n2,
   54719             :      /* Boolean */ ae_vector* flagy,
   54720             :      ae_bool sparsey,
   54721             :      /* Real    */ ae_vector* y,
   54722             :      ae_state *_state)
   54723             : {
   54724             :     ae_frame _frame_block;
   54725             :     ae_int_t i;
   54726             :     ae_int_t ylen;
   54727             :     ae_int_t nx;
   54728             :     ae_int_t ny;
   54729             :     double rmax;
   54730             :     ae_vector blocks0;
   54731             :     ae_vector blocks1;
   54732             :     ae_vector blocks2;
   54733             :     ae_int_t blockscnt0;
   54734             :     ae_int_t blockscnt1;
   54735             :     ae_int_t blockscnt2;
   54736             :     double blockwidth;
   54737             :     double searchradius;
   54738             :     double avgfuncpernode;
   54739             :     ae_int_t ntrials;
   54740             :     ae_int_t maxblocksize;
   54741             :     gridcalc3v1buf bufseedv1;
   54742             :     ae_shared_pool bufpool;
   54743             :     hqrndstate rs;
   54744             :     ae_vector dummyx3;
   54745             : 
   54746           0 :     ae_frame_make(_state, &_frame_block);
   54747           0 :     memset(&blocks0, 0, sizeof(blocks0));
   54748           0 :     memset(&blocks1, 0, sizeof(blocks1));
   54749           0 :     memset(&blocks2, 0, sizeof(blocks2));
   54750           0 :     memset(&bufseedv1, 0, sizeof(bufseedv1));
   54751           0 :     memset(&bufpool, 0, sizeof(bufpool));
   54752           0 :     memset(&rs, 0, sizeof(rs));
   54753           0 :     memset(&dummyx3, 0, sizeof(dummyx3));
   54754           0 :     ae_vector_init(&blocks0, 0, DT_INT, _state, ae_true);
   54755           0 :     ae_vector_init(&blocks1, 0, DT_INT, _state, ae_true);
   54756           0 :     ae_vector_init(&blocks2, 0, DT_INT, _state, ae_true);
   54757           0 :     _gridcalc3v1buf_init(&bufseedv1, _state, ae_true);
   54758           0 :     ae_shared_pool_init(&bufpool, _state, ae_true);
   54759           0 :     _hqrndstate_init(&rs, _state, ae_true);
   54760           0 :     ae_vector_init(&dummyx3, 0, DT_REAL, _state, ae_true);
   54761             : 
   54762           0 :     ae_assert(n0>0, "RBFGridCalc3V: invalid value for N0 (N0<=0)!", _state);
   54763           0 :     ae_assert(n1>0, "RBFGridCalc3V: invalid value for N1 (N1<=0)!", _state);
   54764           0 :     ae_assert(n2>0, "RBFGridCalc3V: invalid value for N2 (N2<=0)!", _state);
   54765           0 :     ae_assert(x0->cnt>=n0, "RBFGridCalc3V: Length(X0)<N0", _state);
   54766           0 :     ae_assert(x1->cnt>=n1, "RBFGridCalc3V: Length(X1)<N1", _state);
   54767           0 :     ae_assert(x2->cnt>=n2, "RBFGridCalc3V: Length(X2)<N2", _state);
   54768           0 :     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc3V: X0 contains infinite or NaN values!", _state);
   54769           0 :     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc3V: X1 contains infinite or NaN values!", _state);
   54770           0 :     ae_assert(isfinitevector(x2, n2, _state), "RBFGridCalc3V: X2 contains infinite or NaN values!", _state);
   54771           0 :     for(i=0; i<=n0-2; i++)
   54772             :     {
   54773           0 :         ae_assert(ae_fp_less_eq(x0->ptr.p_double[i],x0->ptr.p_double[i+1]), "RBFGridCalc3V: X0 is not ordered by ascending", _state);
   54774             :     }
   54775           0 :     for(i=0; i<=n1-2; i++)
   54776             :     {
   54777           0 :         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);
   54778             :     }
   54779           0 :     for(i=0; i<=n2-2; i++)
   54780             :     {
   54781           0 :         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);
   54782             :     }
   54783             :     
   54784             :     /*
   54785             :      * Prepare local variables
   54786             :      */
   54787           0 :     nx = s->nx;
   54788           0 :     ny = s->ny;
   54789           0 :     hqrndseed(325, 46345, &rs, _state);
   54790             :     
   54791             :     /*
   54792             :      * Prepare output array
   54793             :      */
   54794           0 :     ylen = ny*n0*n1*n2;
   54795           0 :     ae_vector_set_length(y, ylen, _state);
   54796           0 :     for(i=0; i<=ylen-1; i++)
   54797             :     {
   54798           0 :         y->ptr.p_double[i] = (double)(0);
   54799             :     }
   54800           0 :     if( s->nx!=3 )
   54801             :     {
   54802           0 :         ae_frame_leave(_state);
   54803           0 :         return;
   54804             :     }
   54805             :     
   54806             :     /*
   54807             :      * Process V1 model
   54808             :      */
   54809           0 :     if( s->modelversion==1 )
   54810             :     {
   54811             :         
   54812             :         /*
   54813             :          * Fast exit for models without centers
   54814             :          */
   54815           0 :         if( s->model1.nc==0 )
   54816             :         {
   54817           0 :             ae_frame_leave(_state);
   54818           0 :             return;
   54819             :         }
   54820             :         
   54821             :         /*
   54822             :          * Prepare seed, create shared pool of temporary buffers
   54823             :          */
   54824           0 :         ae_vector_set_length(&bufseedv1.cx, nx, _state);
   54825           0 :         ae_vector_set_length(&bufseedv1.tx, nx, _state);
   54826           0 :         ae_vector_set_length(&bufseedv1.ty, ny, _state);
   54827           0 :         ae_vector_set_length(&bufseedv1.expbuf0, n0, _state);
   54828           0 :         ae_vector_set_length(&bufseedv1.expbuf1, n1, _state);
   54829           0 :         ae_vector_set_length(&bufseedv1.expbuf2, n2, _state);
   54830           0 :         kdtreecreaterequestbuffer(&s->model1.tree, &bufseedv1.requestbuf, _state);
   54831           0 :         ae_shared_pool_set_seed(&bufpool, &bufseedv1, sizeof(bufseedv1), _gridcalc3v1buf_init, _gridcalc3v1buf_init_copy, _gridcalc3v1buf_destroy, _state);
   54832             :         
   54833             :         /*
   54834             :          * Analyze input grid:
   54835             :          * * analyze average number of basis functions per grid node
   54836             :          * * partition grid in into blocks
   54837             :          */
   54838           0 :         rmax = s->model1.rmax;
   54839           0 :         blockwidth = 2*rmax;
   54840           0 :         maxblocksize = 8;
   54841           0 :         searchradius = rmax*rbf_rbffarradius+0.5*ae_sqrt((double)(s->nx), _state)*blockwidth;
   54842           0 :         ntrials = 100;
   54843           0 :         avgfuncpernode = 0.0;
   54844           0 :         for(i=0; i<=ntrials-1; i++)
   54845             :         {
   54846           0 :             bufseedv1.tx.ptr.p_double[0] = x0->ptr.p_double[hqrnduniformi(&rs, n0, _state)];
   54847           0 :             bufseedv1.tx.ptr.p_double[1] = x1->ptr.p_double[hqrnduniformi(&rs, n1, _state)];
   54848           0 :             bufseedv1.tx.ptr.p_double[2] = x2->ptr.p_double[hqrnduniformi(&rs, n2, _state)];
   54849           0 :             avgfuncpernode = avgfuncpernode+(double)kdtreetsqueryrnn(&s->model1.tree, &bufseedv1.requestbuf, &bufseedv1.tx, searchradius, ae_true, _state)/(double)ntrials;
   54850             :         }
   54851           0 :         ae_vector_set_length(&blocks0, n0+1, _state);
   54852           0 :         blockscnt0 = 0;
   54853           0 :         blocks0.ptr.p_int[0] = 0;
   54854           0 :         for(i=1; i<=n0-1; i++)
   54855             :         {
   54856           0 :             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 )
   54857             :             {
   54858           0 :                 inc(&blockscnt0, _state);
   54859           0 :                 blocks0.ptr.p_int[blockscnt0] = i;
   54860             :             }
   54861             :         }
   54862           0 :         inc(&blockscnt0, _state);
   54863           0 :         blocks0.ptr.p_int[blockscnt0] = n0;
   54864           0 :         ae_vector_set_length(&blocks1, n1+1, _state);
   54865           0 :         blockscnt1 = 0;
   54866           0 :         blocks1.ptr.p_int[0] = 0;
   54867           0 :         for(i=1; i<=n1-1; i++)
   54868             :         {
   54869           0 :             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 )
   54870             :             {
   54871           0 :                 inc(&blockscnt1, _state);
   54872           0 :                 blocks1.ptr.p_int[blockscnt1] = i;
   54873             :             }
   54874             :         }
   54875           0 :         inc(&blockscnt1, _state);
   54876           0 :         blocks1.ptr.p_int[blockscnt1] = n1;
   54877           0 :         ae_vector_set_length(&blocks2, n2+1, _state);
   54878           0 :         blockscnt2 = 0;
   54879           0 :         blocks2.ptr.p_int[0] = 0;
   54880           0 :         for(i=1; i<=n2-1; i++)
   54881             :         {
   54882           0 :             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 )
   54883             :             {
   54884           0 :                 inc(&blockscnt2, _state);
   54885           0 :                 blocks2.ptr.p_int[blockscnt2] = i;
   54886             :             }
   54887             :         }
   54888           0 :         inc(&blockscnt2, _state);
   54889           0 :         blocks2.ptr.p_int[blockscnt2] = n2;
   54890             :         
   54891             :         /*
   54892             :          * Perform calculation in multithreaded mode
   54893             :          */
   54894           0 :         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);
   54895             :         
   54896             :         /*
   54897             :          * Done
   54898             :          */
   54899           0 :         ae_frame_leave(_state);
   54900           0 :         return;
   54901             :     }
   54902             :     
   54903             :     /*
   54904             :      * Process V2 model
   54905             :      */
   54906           0 :     if( s->modelversion==2 )
   54907             :     {
   54908           0 :         ae_vector_set_length(&dummyx3, 1, _state);
   54909           0 :         dummyx3.ptr.p_double[0] = (double)(0);
   54910           0 :         rbfv2gridcalcvx(&s->model2, x0, n0, x1, n1, x2, n2, &dummyx3, 1, flagy, sparsey, y, _state);
   54911           0 :         ae_frame_leave(_state);
   54912           0 :         return;
   54913             :     }
   54914             :     
   54915             :     /*
   54916             :      * Unknown model
   54917             :      */
   54918           0 :     ae_assert(ae_false, "RBFGradCalc3VX: integrity check failed", _state);
   54919           0 :     ae_frame_leave(_state);
   54920             : }
   54921             : 
   54922             : 
   54923             : /*************************************************************************
   54924             : This function "unpacks" RBF model by extracting its coefficients.
   54925             : 
   54926             : INPUT PARAMETERS:
   54927             :     S       -   RBF model
   54928             : 
   54929             : OUTPUT PARAMETERS:
   54930             :     NX      -   dimensionality of argument
   54931             :     NY      -   dimensionality of the target function
   54932             :     XWR     -   model information, array[NC,NX+NY+1].
   54933             :                 One row of the array corresponds to one basis function:
   54934             :                 * first NX columns  - coordinates of the center 
   54935             :                 * next NY columns   - weights, one per dimension of the 
   54936             :                                       function being modelled
   54937             :                 For ModelVersion=1:
   54938             :                 * last column       - radius, same for all dimensions of
   54939             :                                       the function being modelled
   54940             :                 For ModelVersion=2:
   54941             :                 * last NX columns   - radii, one per dimension
   54942             :     NC      -   number of the centers
   54943             :     V       -   polynomial  term , array[NY,NX+1]. One row per one 
   54944             :                 dimension of the function being modelled. First NX 
   54945             :                 elements are linear coefficients, V[NX] is equal to the 
   54946             :                 constant part.
   54947             :     ModelVersion-version of the RBF model:
   54948             :                 * 1 - for models created by QNN and RBF-ML algorithms,
   54949             :                   compatible with ALGLIB 3.10 or earlier.
   54950             :                 * 2 - for models created by HierarchicalRBF, requires
   54951             :                   ALGLIB 3.11 or later
   54952             : 
   54953             :   -- ALGLIB --
   54954             :      Copyright 13.12.2011 by Bochkanov Sergey
   54955             : *************************************************************************/
   54956           0 : void rbfunpack(rbfmodel* s,
   54957             :      ae_int_t* nx,
   54958             :      ae_int_t* ny,
   54959             :      /* Real    */ ae_matrix* xwr,
   54960             :      ae_int_t* nc,
   54961             :      /* Real    */ ae_matrix* v,
   54962             :      ae_int_t* modelversion,
   54963             :      ae_state *_state)
   54964             : {
   54965             : 
   54966           0 :     *nx = 0;
   54967           0 :     *ny = 0;
   54968           0 :     ae_matrix_clear(xwr);
   54969           0 :     *nc = 0;
   54970           0 :     ae_matrix_clear(v);
   54971           0 :     *modelversion = 0;
   54972             : 
   54973           0 :     if( s->modelversion==1 )
   54974             :     {
   54975           0 :         *modelversion = 1;
   54976           0 :         rbfv1unpack(&s->model1, nx, ny, xwr, nc, v, _state);
   54977           0 :         return;
   54978             :     }
   54979           0 :     if( s->modelversion==2 )
   54980             :     {
   54981           0 :         *modelversion = 2;
   54982           0 :         rbfv2unpack(&s->model2, nx, ny, xwr, nc, v, _state);
   54983           0 :         return;
   54984             :     }
   54985           0 :     ae_assert(ae_false, "RBFUnpack: integrity check failure", _state);
   54986             : }
   54987             : 
   54988             : 
   54989             : /*************************************************************************
   54990             : This function returns model version.
   54991             : 
   54992             : INPUT PARAMETERS:
   54993             :     S       -   RBF model
   54994             : 
   54995             : RESULT:
   54996             :     * 1 - for models created by QNN and RBF-ML algorithms,
   54997             :       compatible with ALGLIB 3.10 or earlier.
   54998             :     * 2 - for models created by HierarchicalRBF, requires
   54999             :       ALGLIB 3.11 or later
   55000             : 
   55001             :   -- ALGLIB --
   55002             :      Copyright 06.07.2016 by Bochkanov Sergey
   55003             : *************************************************************************/
   55004           0 : ae_int_t rbfgetmodelversion(rbfmodel* s, ae_state *_state)
   55005             : {
   55006             :     ae_int_t result;
   55007             : 
   55008             : 
   55009           0 :     result = s->modelversion;
   55010           0 :     return result;
   55011             : }
   55012             : 
   55013             : 
   55014             : /*************************************************************************
   55015             : This function is used to peek into hierarchical RBF  construction  process
   55016             : from  some  other  thread  and  get current progress indicator. It returns
   55017             : value in [0,1].
   55018             : 
   55019             : IMPORTANT: only HRBFs (hierarchical RBFs) support  peeking  into  progress
   55020             :            indicator. Legacy RBF-ML and RBF-QNN do  not  support  it.  You
   55021             :            will always get 0 value.
   55022             : 
   55023             : INPUT PARAMETERS:
   55024             :     S           -   RBF model object
   55025             : 
   55026             : RESULT:
   55027             :     progress value, in [0,1]
   55028             : 
   55029             :   -- ALGLIB --
   55030             :      Copyright 17.11.2018 by Bochkanov Sergey
   55031             : *************************************************************************/
   55032           0 : double rbfpeekprogress(rbfmodel* s, ae_state *_state)
   55033             : {
   55034             :     double result;
   55035             : 
   55036             : 
   55037           0 :     result = (double)s->progress10000/(double)10000;
   55038           0 :     return result;
   55039             : }
   55040             : 
   55041             : 
   55042             : /*************************************************************************
   55043             : This function  is  used  to  submit  a  request  for  termination  of  the
   55044             : hierarchical RBF construction process from some other thread.  As  result,
   55045             : RBF construction is terminated smoothly (with proper deallocation  of  all
   55046             : necessary resources) and resultant model is filled by zeros.
   55047             : 
   55048             : A rep.terminationtype=8 will be returned upon receiving such request.
   55049             : 
   55050             : IMPORTANT: only  HRBFs  (hierarchical  RBFs) support termination requests.
   55051             :            Legacy RBF-ML and RBF-QNN do not  support  it.  An  attempt  to
   55052             :            terminate their construction will be ignored.
   55053             : 
   55054             : IMPORTANT: termination request flag is cleared when the model construction
   55055             :            starts. Thus, any pre-construction termination requests will be
   55056             :            silently ignored - only ones submitted AFTER  construction  has
   55057             :            actually began will be handled.
   55058             : 
   55059             : INPUT PARAMETERS:
   55060             :     S           -   RBF model object
   55061             : 
   55062             :   -- ALGLIB --
   55063             :      Copyright 17.11.2018 by Bochkanov Sergey
   55064             : *************************************************************************/
   55065           0 : void rbfrequesttermination(rbfmodel* s, ae_state *_state)
   55066             : {
   55067             : 
   55068             : 
   55069           0 :     s->terminationrequest = ae_true;
   55070           0 : }
   55071             : 
   55072             : 
   55073             : /*************************************************************************
   55074             : Serializer: allocation
   55075             : 
   55076             :   -- ALGLIB --
   55077             :      Copyright 02.02.2012 by Bochkanov Sergey
   55078             : *************************************************************************/
   55079           0 : void rbfalloc(ae_serializer* s, rbfmodel* model, ae_state *_state)
   55080             : {
   55081             : 
   55082             : 
   55083             :     
   55084             :     /*
   55085             :      * Header
   55086             :      */
   55087           0 :     ae_serializer_alloc_entry(s);
   55088             :     
   55089             :     /*
   55090             :      * V1 model
   55091             :      */
   55092           0 :     if( model->modelversion==1 )
   55093             :     {
   55094             :         
   55095             :         /*
   55096             :          * Header
   55097             :          */
   55098           0 :         ae_serializer_alloc_entry(s);
   55099           0 :         rbfv1alloc(s, &model->model1, _state);
   55100           0 :         return;
   55101             :     }
   55102             :     
   55103             :     /*
   55104             :      * V2 model
   55105             :      */
   55106           0 :     if( model->modelversion==2 )
   55107             :     {
   55108             :         
   55109             :         /*
   55110             :          * Header
   55111             :          */
   55112           0 :         ae_serializer_alloc_entry(s);
   55113           0 :         rbfv2alloc(s, &model->model2, _state);
   55114           0 :         return;
   55115             :     }
   55116           0 :     ae_assert(ae_false, "Assertion failed", _state);
   55117             : }
   55118             : 
   55119             : 
   55120             : /*************************************************************************
   55121             : Serializer: serialization
   55122             : 
   55123             :   -- ALGLIB --
   55124             :      Copyright 02.02.2012 by Bochkanov Sergey
   55125             : *************************************************************************/
   55126           0 : void rbfserialize(ae_serializer* s, rbfmodel* model, ae_state *_state)
   55127             : {
   55128             : 
   55129             : 
   55130             :     
   55131             :     /*
   55132             :      * Header
   55133             :      */
   55134           0 :     ae_serializer_serialize_int(s, getrbfserializationcode(_state), _state);
   55135             :     
   55136             :     /*
   55137             :      * V1 model
   55138             :      */
   55139           0 :     if( model->modelversion==1 )
   55140             :     {
   55141           0 :         ae_serializer_serialize_int(s, rbf_rbffirstversion, _state);
   55142           0 :         rbfv1serialize(s, &model->model1, _state);
   55143           0 :         return;
   55144             :     }
   55145             :     
   55146             :     /*
   55147             :      * V2 model
   55148             :      */
   55149           0 :     if( model->modelversion==2 )
   55150             :     {
   55151             :         
   55152             :         /*
   55153             :          * Header
   55154             :          */
   55155           0 :         ae_serializer_serialize_int(s, rbf_rbfversion2, _state);
   55156           0 :         rbfv2serialize(s, &model->model2, _state);
   55157           0 :         return;
   55158             :     }
   55159           0 :     ae_assert(ae_false, "Assertion failed", _state);
   55160             : }
   55161             : 
   55162             : 
   55163             : /*************************************************************************
   55164             : Serializer: unserialization
   55165             : 
   55166             :   -- ALGLIB --
   55167             :      Copyright 02.02.2012 by Bochkanov Sergey
   55168             : *************************************************************************/
   55169           0 : void rbfunserialize(ae_serializer* s, rbfmodel* model, ae_state *_state)
   55170             : {
   55171             :     ae_int_t i0;
   55172             :     ae_int_t i1;
   55173             : 
   55174           0 :     _rbfmodel_clear(model);
   55175             : 
   55176           0 :     rbf_rbfpreparenonserializablefields(model, _state);
   55177             :     
   55178             :     /*
   55179             :      * Header
   55180             :      */
   55181           0 :     ae_serializer_unserialize_int(s, &i0, _state);
   55182           0 :     ae_assert(i0==getrbfserializationcode(_state), "RBFUnserialize: stream header corrupted", _state);
   55183           0 :     ae_serializer_unserialize_int(s, &i1, _state);
   55184           0 :     ae_assert(i1==rbf_rbffirstversion||i1==rbf_rbfversion2, "RBFUnserialize: stream header corrupted", _state);
   55185             :     
   55186             :     /*
   55187             :      * V1 model
   55188             :      */
   55189           0 :     if( i1==rbf_rbffirstversion )
   55190             :     {
   55191           0 :         rbfv1unserialize(s, &model->model1, _state);
   55192           0 :         model->modelversion = 1;
   55193           0 :         model->ny = model->model1.ny;
   55194           0 :         model->nx = model->model1.nx;
   55195           0 :         rbf_initializev2(model->nx, model->ny, &model->model2, _state);
   55196           0 :         return;
   55197             :     }
   55198             :     
   55199             :     /*
   55200             :      * V2 model
   55201             :      */
   55202           0 :     if( i1==rbf_rbfversion2 )
   55203             :     {
   55204           0 :         rbfv2unserialize(s, &model->model2, _state);
   55205           0 :         model->modelversion = 2;
   55206           0 :         model->ny = model->model2.ny;
   55207           0 :         model->nx = model->model2.nx;
   55208           0 :         rbf_initializev1(model->nx, model->ny, &model->model1, _state);
   55209           0 :         return;
   55210             :     }
   55211           0 :     ae_assert(ae_false, "Assertion failed", _state);
   55212             : }
   55213             : 
   55214             : 
   55215             : /*************************************************************************
   55216             : Initialize empty model
   55217             : 
   55218             :   -- ALGLIB --
   55219             :      Copyright 12.05.2016 by Bochkanov Sergey
   55220             : *************************************************************************/
   55221           0 : static void rbf_rbfpreparenonserializablefields(rbfmodel* s,
   55222             :      ae_state *_state)
   55223             : {
   55224             : 
   55225             : 
   55226           0 :     s->n = 0;
   55227           0 :     s->hasscale = ae_false;
   55228           0 :     s->radvalue = (double)(1);
   55229           0 :     s->radzvalue = (double)(5);
   55230           0 :     s->nlayers = 0;
   55231           0 :     s->lambdav = (double)(0);
   55232           0 :     s->aterm = 1;
   55233           0 :     s->algorithmtype = 0;
   55234           0 :     s->epsort = rbf_eps;
   55235           0 :     s->epserr = rbf_eps;
   55236           0 :     s->maxits = 0;
   55237           0 :     s->nnmaxits = 100;
   55238           0 : }
   55239             : 
   55240             : 
   55241             : /*************************************************************************
   55242             : Initialize V1 model (skip initialization for NX=1 or NX>3)
   55243             : 
   55244             :   -- ALGLIB --
   55245             :      Copyright 12.05.2016 by Bochkanov Sergey
   55246             : *************************************************************************/
   55247           0 : static void rbf_initializev1(ae_int_t nx,
   55248             :      ae_int_t ny,
   55249             :      rbfv1model* s,
   55250             :      ae_state *_state)
   55251             : {
   55252             : 
   55253           0 :     _rbfv1model_clear(s);
   55254             : 
   55255           0 :     if( nx==2||nx==3 )
   55256             :     {
   55257           0 :         rbfv1create(nx, ny, s, _state);
   55258             :     }
   55259           0 : }
   55260             : 
   55261             : 
   55262             : /*************************************************************************
   55263             : Initialize V2 model
   55264             : 
   55265             :   -- ALGLIB --
   55266             :      Copyright 12.05.2016 by Bochkanov Sergey
   55267             : *************************************************************************/
   55268           0 : static void rbf_initializev2(ae_int_t nx,
   55269             :      ae_int_t ny,
   55270             :      rbfv2model* s,
   55271             :      ae_state *_state)
   55272             : {
   55273             : 
   55274           0 :     _rbfv2model_clear(s);
   55275             : 
   55276           0 :     rbfv2create(nx, ny, s, _state);
   55277           0 : }
   55278             : 
   55279             : 
   55280             : /*************************************************************************
   55281             : Cleans report fields
   55282             : 
   55283             :   -- ALGLIB --
   55284             :      Copyright 16.06.2016 by Bochkanov Sergey
   55285             : *************************************************************************/
   55286           0 : static void rbf_clearreportfields(rbfreport* rep, ae_state *_state)
   55287             : {
   55288             : 
   55289             : 
   55290           0 :     rep->rmserror = _state->v_nan;
   55291           0 :     rep->maxerror = _state->v_nan;
   55292           0 :     rep->arows = 0;
   55293           0 :     rep->acols = 0;
   55294           0 :     rep->annz = 0;
   55295           0 :     rep->iterationscount = 0;
   55296           0 :     rep->nmv = 0;
   55297           0 :     rep->terminationtype = 0;
   55298           0 : }
   55299             : 
   55300             : 
   55301           0 : void _rbfcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic)
   55302             : {
   55303           0 :     rbfcalcbuffer *p = (rbfcalcbuffer*)_p;
   55304           0 :     ae_touch_ptr((void*)p);
   55305           0 :     _rbfv1calcbuffer_init(&p->bufv1, _state, make_automatic);
   55306           0 :     _rbfv2calcbuffer_init(&p->bufv2, _state, make_automatic);
   55307           0 : }
   55308             : 
   55309             : 
   55310           0 : void _rbfcalcbuffer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   55311             : {
   55312           0 :     rbfcalcbuffer *dst = (rbfcalcbuffer*)_dst;
   55313           0 :     rbfcalcbuffer *src = (rbfcalcbuffer*)_src;
   55314           0 :     dst->modelversion = src->modelversion;
   55315           0 :     _rbfv1calcbuffer_init_copy(&dst->bufv1, &src->bufv1, _state, make_automatic);
   55316           0 :     _rbfv2calcbuffer_init_copy(&dst->bufv2, &src->bufv2, _state, make_automatic);
   55317           0 : }
   55318             : 
   55319             : 
   55320           0 : void _rbfcalcbuffer_clear(void* _p)
   55321             : {
   55322           0 :     rbfcalcbuffer *p = (rbfcalcbuffer*)_p;
   55323           0 :     ae_touch_ptr((void*)p);
   55324           0 :     _rbfv1calcbuffer_clear(&p->bufv1);
   55325           0 :     _rbfv2calcbuffer_clear(&p->bufv2);
   55326           0 : }
   55327             : 
   55328             : 
   55329           0 : void _rbfcalcbuffer_destroy(void* _p)
   55330             : {
   55331           0 :     rbfcalcbuffer *p = (rbfcalcbuffer*)_p;
   55332           0 :     ae_touch_ptr((void*)p);
   55333           0 :     _rbfv1calcbuffer_destroy(&p->bufv1);
   55334           0 :     _rbfv2calcbuffer_destroy(&p->bufv2);
   55335           0 : }
   55336             : 
   55337             : 
   55338           0 : void _rbfmodel_init(void* _p, ae_state *_state, ae_bool make_automatic)
   55339             : {
   55340           0 :     rbfmodel *p = (rbfmodel*)_p;
   55341           0 :     ae_touch_ptr((void*)p);
   55342           0 :     _rbfv1model_init(&p->model1, _state, make_automatic);
   55343           0 :     _rbfv2model_init(&p->model2, _state, make_automatic);
   55344           0 :     ae_matrix_init(&p->x, 0, 0, DT_REAL, _state, make_automatic);
   55345           0 :     ae_matrix_init(&p->y, 0, 0, DT_REAL, _state, make_automatic);
   55346           0 :     ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic);
   55347           0 : }
   55348             : 
   55349             : 
   55350           0 : void _rbfmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   55351             : {
   55352           0 :     rbfmodel *dst = (rbfmodel*)_dst;
   55353           0 :     rbfmodel *src = (rbfmodel*)_src;
   55354           0 :     dst->nx = src->nx;
   55355           0 :     dst->ny = src->ny;
   55356           0 :     dst->modelversion = src->modelversion;
   55357           0 :     _rbfv1model_init_copy(&dst->model1, &src->model1, _state, make_automatic);
   55358           0 :     _rbfv2model_init_copy(&dst->model2, &src->model2, _state, make_automatic);
   55359           0 :     dst->lambdav = src->lambdav;
   55360           0 :     dst->radvalue = src->radvalue;
   55361           0 :     dst->radzvalue = src->radzvalue;
   55362           0 :     dst->nlayers = src->nlayers;
   55363           0 :     dst->aterm = src->aterm;
   55364           0 :     dst->algorithmtype = src->algorithmtype;
   55365           0 :     dst->epsort = src->epsort;
   55366           0 :     dst->epserr = src->epserr;
   55367           0 :     dst->maxits = src->maxits;
   55368           0 :     dst->nnmaxits = src->nnmaxits;
   55369           0 :     dst->n = src->n;
   55370           0 :     ae_matrix_init_copy(&dst->x, &src->x, _state, make_automatic);
   55371           0 :     ae_matrix_init_copy(&dst->y, &src->y, _state, make_automatic);
   55372           0 :     dst->hasscale = src->hasscale;
   55373           0 :     ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic);
   55374           0 :     dst->progress10000 = src->progress10000;
   55375           0 :     dst->terminationrequest = src->terminationrequest;
   55376           0 : }
   55377             : 
   55378             : 
   55379           0 : void _rbfmodel_clear(void* _p)
   55380             : {
   55381           0 :     rbfmodel *p = (rbfmodel*)_p;
   55382           0 :     ae_touch_ptr((void*)p);
   55383           0 :     _rbfv1model_clear(&p->model1);
   55384           0 :     _rbfv2model_clear(&p->model2);
   55385           0 :     ae_matrix_clear(&p->x);
   55386           0 :     ae_matrix_clear(&p->y);
   55387           0 :     ae_vector_clear(&p->s);
   55388           0 : }
   55389             : 
   55390             : 
   55391           0 : void _rbfmodel_destroy(void* _p)
   55392             : {
   55393           0 :     rbfmodel *p = (rbfmodel*)_p;
   55394           0 :     ae_touch_ptr((void*)p);
   55395           0 :     _rbfv1model_destroy(&p->model1);
   55396           0 :     _rbfv2model_destroy(&p->model2);
   55397           0 :     ae_matrix_destroy(&p->x);
   55398           0 :     ae_matrix_destroy(&p->y);
   55399           0 :     ae_vector_destroy(&p->s);
   55400           0 : }
   55401             : 
   55402             : 
   55403           0 : void _rbfreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
   55404             : {
   55405           0 :     rbfreport *p = (rbfreport*)_p;
   55406           0 :     ae_touch_ptr((void*)p);
   55407           0 : }
   55408             : 
   55409             : 
   55410           0 : void _rbfreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
   55411             : {
   55412           0 :     rbfreport *dst = (rbfreport*)_dst;
   55413           0 :     rbfreport *src = (rbfreport*)_src;
   55414           0 :     dst->rmserror = src->rmserror;
   55415           0 :     dst->maxerror = src->maxerror;
   55416           0 :     dst->arows = src->arows;
   55417           0 :     dst->acols = src->acols;
   55418           0 :     dst->annz = src->annz;
   55419           0 :     dst->iterationscount = src->iterationscount;
   55420           0 :     dst->nmv = src->nmv;
   55421           0 :     dst->terminationtype = src->terminationtype;
   55422           0 : }
   55423             : 
   55424             : 
   55425           0 : void _rbfreport_clear(void* _p)
   55426             : {
   55427           0 :     rbfreport *p = (rbfreport*)_p;
   55428           0 :     ae_touch_ptr((void*)p);
   55429           0 : }
   55430             : 
   55431             : 
   55432           0 : void _rbfreport_destroy(void* _p)
   55433             : {
   55434           0 :     rbfreport *p = (rbfreport*)_p;
   55435           0 :     ae_touch_ptr((void*)p);
   55436           0 : }
   55437             : 
   55438             : 
   55439             : #endif
   55440             : #if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD)
   55441             : 
   55442             : 
   55443             : /*************************************************************************
   55444             : This function is left for backward compatibility.
   55445             : Use fitspheremc() instead.
   55446             : 
   55447             :                                     
   55448             :   -- ALGLIB --
   55449             :      Copyright 14.04.2017 by Bochkanov Sergey
   55450             : *************************************************************************/
   55451           0 : void nsfitspheremcc(/* Real    */ ae_matrix* xy,
   55452             :      ae_int_t npoints,
   55453             :      ae_int_t nx,
   55454             :      /* Real    */ ae_vector* cx,
   55455             :      double* rhi,
   55456             :      ae_state *_state)
   55457             : {
   55458             :     double dummy;
   55459             : 
   55460           0 :     ae_vector_clear(cx);
   55461           0 :     *rhi = 0;
   55462             : 
   55463           0 :     nsfitspherex(xy, npoints, nx, 1, 0.0, 0, 0.0, cx, &dummy, rhi, _state);
   55464           0 : }
   55465             : 
   55466             : 
   55467             : /*************************************************************************
   55468             : This function is left for backward compatibility.
   55469             : Use fitspheremi() instead.
   55470             :                                     
   55471             :   -- ALGLIB --
   55472             :      Copyright 14.04.2017 by Bochkanov Sergey
   55473             : *************************************************************************/
   55474           0 : void nsfitspheremic(/* Real    */ ae_matrix* xy,
   55475             :      ae_int_t npoints,
   55476             :      ae_int_t nx,
   55477             :      /* Real    */ ae_vector* cx,
   55478             :      double* rlo,
   55479             :      ae_state *_state)
   55480             : {
   55481             :     double dummy;
   55482             : 
   55483           0 :     ae_vector_clear(cx);
   55484           0 :     *rlo = 0;
   55485             : 
   55486           0 :     nsfitspherex(xy, npoints, nx, 2, 0.0, 0, 0.0, cx, rlo, &dummy, _state);
   55487           0 : }
   55488             : 
   55489             : 
   55490             : /*************************************************************************
   55491             : This function is left for backward compatibility.
   55492             : Use fitspheremz() instead.
   55493             :                                     
   55494             :   -- ALGLIB --
   55495             :      Copyright 14.04.2017 by Bochkanov Sergey
   55496             : *************************************************************************/
   55497           0 : void nsfitspheremzc(/* Real    */ ae_matrix* xy,
   55498             :      ae_int_t npoints,
   55499             :      ae_int_t nx,
   55500             :      /* Real    */ ae_vector* cx,
   55501             :      double* rlo,
   55502             :      double* rhi,
   55503             :      ae_state *_state)
   55504             : {
   55505             : 
   55506           0 :     ae_vector_clear(cx);
   55507           0 :     *rlo = 0;
   55508           0 :     *rhi = 0;
   55509             : 
   55510           0 :     nsfitspherex(xy, npoints, nx, 3, 0.0, 0, 0.0, cx, rlo, rhi, _state);
   55511           0 : }
   55512             : 
   55513             : 
   55514             : /*************************************************************************
   55515             : This function is left for backward compatibility.
   55516             : Use fitspherex() instead.
   55517             :                                     
   55518             :   -- ALGLIB --
   55519             :      Copyright 14.04.2017 by Bochkanov Sergey
   55520             : *************************************************************************/
   55521           0 : void nsfitspherex(/* Real    */ ae_matrix* xy,
   55522             :      ae_int_t npoints,
   55523             :      ae_int_t nx,
   55524             :      ae_int_t problemtype,
   55525             :      double epsx,
   55526             :      ae_int_t aulits,
   55527             :      double penalty,
   55528             :      /* Real    */ ae_vector* cx,
   55529             :      double* rlo,
   55530             :      double* rhi,
   55531             :      ae_state *_state)
   55532             : {
   55533             : 
   55534           0 :     ae_vector_clear(cx);
   55535           0 :     *rlo = 0;
   55536           0 :     *rhi = 0;
   55537             : 
   55538           0 :     fitspherex(xy, npoints, nx, problemtype, epsx, aulits, penalty, cx, rlo, rhi, _state);
   55539           0 : }
   55540             : 
   55541             : 
   55542             : /*************************************************************************
   55543             : This function is an obsolete and deprecated version of fitting by
   55544             : penalized cubic spline.
   55545             : 
   55546             : It was superseded by spline1dfit(), which is an orders of magnitude faster
   55547             : and more memory-efficient implementation.
   55548             : 
   55549             : Do NOT use this function in the new code!
   55550             : 
   55551             :   -- ALGLIB PROJECT --
   55552             :      Copyright 18.08.2009 by Bochkanov Sergey
   55553             : *************************************************************************/
   55554           0 : void spline1dfitpenalized(/* Real    */ ae_vector* x,
   55555             :      /* Real    */ ae_vector* y,
   55556             :      ae_int_t n,
   55557             :      ae_int_t m,
   55558             :      double rho,
   55559             :      ae_int_t* info,
   55560             :      spline1dinterpolant* s,
   55561             :      spline1dfitreport* rep,
   55562             :      ae_state *_state)
   55563             : {
   55564             :     ae_frame _frame_block;
   55565             :     ae_vector _x;
   55566             :     ae_vector _y;
   55567             :     ae_vector w;
   55568             :     ae_int_t i;
   55569             : 
   55570           0 :     ae_frame_make(_state, &_frame_block);
   55571           0 :     memset(&_x, 0, sizeof(_x));
   55572           0 :     memset(&_y, 0, sizeof(_y));
   55573           0 :     memset(&w, 0, sizeof(w));
   55574           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   55575           0 :     x = &_x;
   55576           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   55577           0 :     y = &_y;
   55578           0 :     *info = 0;
   55579           0 :     _spline1dinterpolant_clear(s);
   55580           0 :     _spline1dfitreport_clear(rep);
   55581           0 :     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
   55582             : 
   55583           0 :     ae_assert(n>=1, "Spline1DFitPenalized: N<1!", _state);
   55584           0 :     ae_assert(m>=4, "Spline1DFitPenalized: M<4!", _state);
   55585           0 :     ae_assert(x->cnt>=n, "Spline1DFitPenalized: Length(X)<N!", _state);
   55586           0 :     ae_assert(y->cnt>=n, "Spline1DFitPenalized: Length(Y)<N!", _state);
   55587           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DFitPenalized: X contains infinite or NAN values!", _state);
   55588           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DFitPenalized: Y contains infinite or NAN values!", _state);
   55589           0 :     ae_assert(ae_isfinite(rho, _state), "Spline1DFitPenalized: Rho is infinite!", _state);
   55590           0 :     ae_vector_set_length(&w, n, _state);
   55591           0 :     for(i=0; i<=n-1; i++)
   55592             :     {
   55593           0 :         w.ptr.p_double[i] = (double)(1);
   55594             :     }
   55595           0 :     spline1dfitpenalizedw(x, y, &w, n, m, rho, info, s, rep, _state);
   55596           0 :     ae_frame_leave(_state);
   55597           0 : }
   55598             : 
   55599             : 
   55600             : /*************************************************************************
   55601             : This function is an obsolete and deprecated version of fitting by
   55602             : penalized cubic spline.
   55603             : 
   55604             : It was superseded by spline1dfit(), which is an orders of magnitude faster
   55605             : and more memory-efficient implementation.
   55606             : 
   55607             : Do NOT use this function in the new code!
   55608             : 
   55609             :   -- ALGLIB PROJECT --
   55610             :      Copyright 19.10.2010 by Bochkanov Sergey
   55611             : *************************************************************************/
   55612           0 : void spline1dfitpenalizedw(/* Real    */ ae_vector* x,
   55613             :      /* Real    */ ae_vector* y,
   55614             :      /* Real    */ ae_vector* w,
   55615             :      ae_int_t n,
   55616             :      ae_int_t m,
   55617             :      double rho,
   55618             :      ae_int_t* info,
   55619             :      spline1dinterpolant* s,
   55620             :      spline1dfitreport* rep,
   55621             :      ae_state *_state)
   55622             : {
   55623             :     ae_frame _frame_block;
   55624             :     ae_vector _x;
   55625             :     ae_vector _y;
   55626             :     ae_vector _w;
   55627             :     ae_int_t i;
   55628             :     ae_int_t j;
   55629             :     ae_int_t b;
   55630             :     double v;
   55631             :     double relcnt;
   55632             :     double xa;
   55633             :     double xb;
   55634             :     double sa;
   55635             :     double sb;
   55636             :     ae_vector xoriginal;
   55637             :     ae_vector yoriginal;
   55638             :     double pdecay;
   55639             :     double tdecay;
   55640             :     ae_matrix fmatrix;
   55641             :     ae_vector fcolumn;
   55642             :     ae_vector y2;
   55643             :     ae_vector w2;
   55644             :     ae_vector xc;
   55645             :     ae_vector yc;
   55646             :     ae_vector dc;
   55647             :     double fdmax;
   55648             :     double admax;
   55649             :     ae_matrix amatrix;
   55650             :     ae_matrix d2matrix;
   55651             :     double fa;
   55652             :     double ga;
   55653             :     double fb;
   55654             :     double gb;
   55655             :     double lambdav;
   55656             :     ae_vector bx;
   55657             :     ae_vector by;
   55658             :     ae_vector bd1;
   55659             :     ae_vector bd2;
   55660             :     ae_vector tx;
   55661             :     ae_vector ty;
   55662             :     ae_vector td;
   55663             :     spline1dinterpolant bs;
   55664             :     ae_matrix nmatrix;
   55665             :     ae_vector rightpart;
   55666             :     fblslincgstate cgstate;
   55667             :     ae_vector c;
   55668             :     ae_vector tmp0;
   55669             : 
   55670           0 :     ae_frame_make(_state, &_frame_block);
   55671           0 :     memset(&_x, 0, sizeof(_x));
   55672           0 :     memset(&_y, 0, sizeof(_y));
   55673           0 :     memset(&_w, 0, sizeof(_w));
   55674           0 :     memset(&xoriginal, 0, sizeof(xoriginal));
   55675           0 :     memset(&yoriginal, 0, sizeof(yoriginal));
   55676           0 :     memset(&fmatrix, 0, sizeof(fmatrix));
   55677           0 :     memset(&fcolumn, 0, sizeof(fcolumn));
   55678           0 :     memset(&y2, 0, sizeof(y2));
   55679           0 :     memset(&w2, 0, sizeof(w2));
   55680           0 :     memset(&xc, 0, sizeof(xc));
   55681           0 :     memset(&yc, 0, sizeof(yc));
   55682           0 :     memset(&dc, 0, sizeof(dc));
   55683           0 :     memset(&amatrix, 0, sizeof(amatrix));
   55684           0 :     memset(&d2matrix, 0, sizeof(d2matrix));
   55685           0 :     memset(&bx, 0, sizeof(bx));
   55686           0 :     memset(&by, 0, sizeof(by));
   55687           0 :     memset(&bd1, 0, sizeof(bd1));
   55688           0 :     memset(&bd2, 0, sizeof(bd2));
   55689           0 :     memset(&tx, 0, sizeof(tx));
   55690           0 :     memset(&ty, 0, sizeof(ty));
   55691           0 :     memset(&td, 0, sizeof(td));
   55692           0 :     memset(&bs, 0, sizeof(bs));
   55693           0 :     memset(&nmatrix, 0, sizeof(nmatrix));
   55694           0 :     memset(&rightpart, 0, sizeof(rightpart));
   55695           0 :     memset(&cgstate, 0, sizeof(cgstate));
   55696           0 :     memset(&c, 0, sizeof(c));
   55697           0 :     memset(&tmp0, 0, sizeof(tmp0));
   55698           0 :     ae_vector_init_copy(&_x, x, _state, ae_true);
   55699           0 :     x = &_x;
   55700           0 :     ae_vector_init_copy(&_y, y, _state, ae_true);
   55701           0 :     y = &_y;
   55702           0 :     ae_vector_init_copy(&_w, w, _state, ae_true);
   55703           0 :     w = &_w;
   55704           0 :     *info = 0;
   55705           0 :     _spline1dinterpolant_clear(s);
   55706           0 :     _spline1dfitreport_clear(rep);
   55707           0 :     ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true);
   55708           0 :     ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true);
   55709           0 :     ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true);
   55710           0 :     ae_vector_init(&fcolumn, 0, DT_REAL, _state, ae_true);
   55711           0 :     ae_vector_init(&y2, 0, DT_REAL, _state, ae_true);
   55712           0 :     ae_vector_init(&w2, 0, DT_REAL, _state, ae_true);
   55713           0 :     ae_vector_init(&xc, 0, DT_REAL, _state, ae_true);
   55714           0 :     ae_vector_init(&yc, 0, DT_REAL, _state, ae_true);
   55715           0 :     ae_vector_init(&dc, 0, DT_INT, _state, ae_true);
   55716           0 :     ae_matrix_init(&amatrix, 0, 0, DT_REAL, _state, ae_true);
   55717           0 :     ae_matrix_init(&d2matrix, 0, 0, DT_REAL, _state, ae_true);
   55718           0 :     ae_vector_init(&bx, 0, DT_REAL, _state, ae_true);
   55719           0 :     ae_vector_init(&by, 0, DT_REAL, _state, ae_true);
   55720           0 :     ae_vector_init(&bd1, 0, DT_REAL, _state, ae_true);
   55721           0 :     ae_vector_init(&bd2, 0, DT_REAL, _state, ae_true);
   55722           0 :     ae_vector_init(&tx, 0, DT_REAL, _state, ae_true);
   55723           0 :     ae_vector_init(&ty, 0, DT_REAL, _state, ae_true);
   55724           0 :     ae_vector_init(&td, 0, DT_REAL, _state, ae_true);
   55725           0 :     _spline1dinterpolant_init(&bs, _state, ae_true);
   55726           0 :     ae_matrix_init(&nmatrix, 0, 0, DT_REAL, _state, ae_true);
   55727           0 :     ae_vector_init(&rightpart, 0, DT_REAL, _state, ae_true);
   55728           0 :     _fblslincgstate_init(&cgstate, _state, ae_true);
   55729           0 :     ae_vector_init(&c, 0, DT_REAL, _state, ae_true);
   55730           0 :     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
   55731             : 
   55732           0 :     ae_assert(n>=1, "Spline1DFitPenalizedW: N<1!", _state);
   55733           0 :     ae_assert(m>=4, "Spline1DFitPenalizedW: M<4!", _state);
   55734           0 :     ae_assert(x->cnt>=n, "Spline1DFitPenalizedW: Length(X)<N!", _state);
   55735           0 :     ae_assert(y->cnt>=n, "Spline1DFitPenalizedW: Length(Y)<N!", _state);
   55736           0 :     ae_assert(w->cnt>=n, "Spline1DFitPenalizedW: Length(W)<N!", _state);
   55737           0 :     ae_assert(isfinitevector(x, n, _state), "Spline1DFitPenalizedW: X contains infinite or NAN values!", _state);
   55738           0 :     ae_assert(isfinitevector(y, n, _state), "Spline1DFitPenalizedW: Y contains infinite or NAN values!", _state);
   55739           0 :     ae_assert(isfinitevector(w, n, _state), "Spline1DFitPenalizedW: Y contains infinite or NAN values!", _state);
   55740           0 :     ae_assert(ae_isfinite(rho, _state), "Spline1DFitPenalizedW: Rho is infinite!", _state);
   55741             :     
   55742             :     /*
   55743             :      * Prepare LambdaV
   55744             :      */
   55745           0 :     v = -ae_log(ae_machineepsilon, _state)/ae_log((double)(10), _state);
   55746           0 :     if( ae_fp_less(rho,-v) )
   55747             :     {
   55748           0 :         rho = -v;
   55749             :     }
   55750           0 :     if( ae_fp_greater(rho,v) )
   55751             :     {
   55752           0 :         rho = v;
   55753             :     }
   55754           0 :     lambdav = ae_pow((double)(10), rho, _state);
   55755             :     
   55756             :     /*
   55757             :      * Sort X, Y, W
   55758             :      */
   55759           0 :     heapsortdpoints(x, y, w, n, _state);
   55760             :     
   55761             :     /*
   55762             :      * Scale X, Y, XC, YC
   55763             :      */
   55764           0 :     lsfitscalexy(x, y, w, n, &xc, &yc, &dc, 0, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state);
   55765             :     
   55766             :     /*
   55767             :      * Allocate space
   55768             :      */
   55769           0 :     ae_matrix_set_length(&fmatrix, n, m, _state);
   55770           0 :     ae_matrix_set_length(&amatrix, m, m, _state);
   55771           0 :     ae_matrix_set_length(&d2matrix, m, m, _state);
   55772           0 :     ae_vector_set_length(&bx, m, _state);
   55773           0 :     ae_vector_set_length(&by, m, _state);
   55774           0 :     ae_vector_set_length(&fcolumn, n, _state);
   55775           0 :     ae_matrix_set_length(&nmatrix, m, m, _state);
   55776           0 :     ae_vector_set_length(&rightpart, m, _state);
   55777           0 :     ae_vector_set_length(&tmp0, ae_maxint(m, n, _state), _state);
   55778           0 :     ae_vector_set_length(&c, m, _state);
   55779             :     
   55780             :     /*
   55781             :      * Fill:
   55782             :      * * FMatrix by values of basis functions
   55783             :      * * TmpAMatrix by second derivatives of I-th function at J-th point
   55784             :      * * CMatrix by constraints
   55785             :      */
   55786           0 :     fdmax = (double)(0);
   55787           0 :     for(b=0; b<=m-1; b++)
   55788             :     {
   55789             :         
   55790             :         /*
   55791             :          * Prepare I-th basis function
   55792             :          */
   55793           0 :         for(j=0; j<=m-1; j++)
   55794             :         {
   55795           0 :             bx.ptr.p_double[j] = (double)(2*j)/(double)(m-1)-1;
   55796           0 :             by.ptr.p_double[j] = (double)(0);
   55797             :         }
   55798           0 :         by.ptr.p_double[b] = (double)(1);
   55799           0 :         spline1dgriddiff2cubic(&bx, &by, m, 2, 0.0, 2, 0.0, &bd1, &bd2, _state);
   55800           0 :         spline1dbuildcubic(&bx, &by, m, 2, 0.0, 2, 0.0, &bs, _state);
   55801             :         
   55802             :         /*
   55803             :          * Calculate B-th column of FMatrix
   55804             :          * Update FDMax (maximum column norm)
   55805             :          */
   55806           0 :         spline1dconvcubic(&bx, &by, m, 2, 0.0, 2, 0.0, x, n, &fcolumn, _state);
   55807           0 :         ae_v_move(&fmatrix.ptr.pp_double[0][b], fmatrix.stride, &fcolumn.ptr.p_double[0], 1, ae_v_len(0,n-1));
   55808           0 :         v = (double)(0);
   55809           0 :         for(i=0; i<=n-1; i++)
   55810             :         {
   55811           0 :             v = v+ae_sqr(w->ptr.p_double[i]*fcolumn.ptr.p_double[i], _state);
   55812             :         }
   55813           0 :         fdmax = ae_maxreal(fdmax, v, _state);
   55814             :         
   55815             :         /*
   55816             :          * Fill temporary with second derivatives of basis function
   55817             :          */
   55818           0 :         ae_v_move(&d2matrix.ptr.pp_double[b][0], 1, &bd2.ptr.p_double[0], 1, ae_v_len(0,m-1));
   55819             :     }
   55820             :     
   55821             :     /*
   55822             :      * * calculate penalty matrix A
   55823             :      * * calculate max of diagonal elements of A
   55824             :      * * calculate PDecay - coefficient before penalty matrix
   55825             :      */
   55826           0 :     for(i=0; i<=m-1; i++)
   55827             :     {
   55828           0 :         for(j=i; j<=m-1; j++)
   55829             :         {
   55830             :             
   55831             :             /*
   55832             :              * calculate integral(B_i''*B_j'') where B_i and B_j are
   55833             :              * i-th and j-th basis splines.
   55834             :              * B_i and B_j are piecewise linear functions.
   55835             :              */
   55836           0 :             v = (double)(0);
   55837           0 :             for(b=0; b<=m-2; b++)
   55838             :             {
   55839           0 :                 fa = d2matrix.ptr.pp_double[i][b];
   55840           0 :                 fb = d2matrix.ptr.pp_double[i][b+1];
   55841           0 :                 ga = d2matrix.ptr.pp_double[j][b];
   55842           0 :                 gb = d2matrix.ptr.pp_double[j][b+1];
   55843           0 :                 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);
   55844             :             }
   55845           0 :             amatrix.ptr.pp_double[i][j] = v;
   55846           0 :             amatrix.ptr.pp_double[j][i] = v;
   55847             :         }
   55848             :     }
   55849           0 :     admax = (double)(0);
   55850           0 :     for(i=0; i<=m-1; i++)
   55851             :     {
   55852           0 :         admax = ae_maxreal(admax, ae_fabs(amatrix.ptr.pp_double[i][i], _state), _state);
   55853             :     }
   55854           0 :     pdecay = lambdav*fdmax/admax;
   55855             :     
   55856             :     /*
   55857             :      * Calculate TDecay for Tikhonov regularization
   55858             :      */
   55859           0 :     tdecay = fdmax*(1+pdecay)*10*ae_machineepsilon;
   55860             :     
   55861             :     /*
   55862             :      * Prepare system
   55863             :      *
   55864             :      * NOTE: FMatrix is spoiled during this process
   55865             :      */
   55866           0 :     for(i=0; i<=n-1; i++)
   55867             :     {
   55868           0 :         v = w->ptr.p_double[i];
   55869           0 :         ae_v_muld(&fmatrix.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
   55870             :     }
   55871           0 :     rmatrixgemm(m, m, n, 1.0, &fmatrix, 0, 0, 1, &fmatrix, 0, 0, 0, 0.0, &nmatrix, 0, 0, _state);
   55872           0 :     for(i=0; i<=m-1; i++)
   55873             :     {
   55874           0 :         for(j=0; j<=m-1; j++)
   55875             :         {
   55876           0 :             nmatrix.ptr.pp_double[i][j] = nmatrix.ptr.pp_double[i][j]+pdecay*amatrix.ptr.pp_double[i][j];
   55877             :         }
   55878             :     }
   55879           0 :     for(i=0; i<=m-1; i++)
   55880             :     {
   55881           0 :         nmatrix.ptr.pp_double[i][i] = nmatrix.ptr.pp_double[i][i]+tdecay;
   55882             :     }
   55883           0 :     for(i=0; i<=m-1; i++)
   55884             :     {
   55885           0 :         rightpart.ptr.p_double[i] = (double)(0);
   55886             :     }
   55887           0 :     for(i=0; i<=n-1; i++)
   55888             :     {
   55889           0 :         v = y->ptr.p_double[i]*w->ptr.p_double[i];
   55890           0 :         ae_v_addd(&rightpart.ptr.p_double[0], 1, &fmatrix.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
   55891             :     }
   55892             :     
   55893             :     /*
   55894             :      * Solve system
   55895             :      */
   55896           0 :     if( !spdmatrixcholesky(&nmatrix, m, ae_true, _state) )
   55897             :     {
   55898           0 :         *info = -4;
   55899           0 :         ae_frame_leave(_state);
   55900           0 :         return;
   55901             :     }
   55902           0 :     fblscholeskysolve(&nmatrix, 1.0, m, ae_true, &rightpart, &tmp0, _state);
   55903           0 :     ae_v_move(&c.ptr.p_double[0], 1, &rightpart.ptr.p_double[0], 1, ae_v_len(0,m-1));
   55904             :     
   55905             :     /*
   55906             :      * add nodes to force linearity outside of the fitting interval
   55907             :      */
   55908           0 :     spline1dgriddiffcubic(&bx, &c, m, 2, 0.0, 2, 0.0, &bd1, _state);
   55909           0 :     ae_vector_set_length(&tx, m+2, _state);
   55910           0 :     ae_vector_set_length(&ty, m+2, _state);
   55911           0 :     ae_vector_set_length(&td, m+2, _state);
   55912           0 :     ae_v_move(&tx.ptr.p_double[1], 1, &bx.ptr.p_double[0], 1, ae_v_len(1,m));
   55913           0 :     ae_v_move(&ty.ptr.p_double[1], 1, &rightpart.ptr.p_double[0], 1, ae_v_len(1,m));
   55914           0 :     ae_v_move(&td.ptr.p_double[1], 1, &bd1.ptr.p_double[0], 1, ae_v_len(1,m));
   55915           0 :     tx.ptr.p_double[0] = tx.ptr.p_double[1]-(tx.ptr.p_double[2]-tx.ptr.p_double[1]);
   55916           0 :     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]);
   55917           0 :     td.ptr.p_double[0] = td.ptr.p_double[1];
   55918           0 :     tx.ptr.p_double[m+1] = tx.ptr.p_double[m]+(tx.ptr.p_double[m]-tx.ptr.p_double[m-1]);
   55919           0 :     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]);
   55920           0 :     td.ptr.p_double[m+1] = td.ptr.p_double[m];
   55921           0 :     spline1dbuildhermite(&tx, &ty, &td, m+2, s, _state);
   55922           0 :     spline1dlintransx(s, 2/(xb-xa), -(xa+xb)/(xb-xa), _state);
   55923           0 :     spline1dlintransy(s, sb-sa, sa, _state);
   55924           0 :     *info = 1;
   55925             :     
   55926             :     /*
   55927             :      * Fill report
   55928             :      */
   55929           0 :     rep->rmserror = (double)(0);
   55930           0 :     rep->avgerror = (double)(0);
   55931           0 :     rep->avgrelerror = (double)(0);
   55932           0 :     rep->maxerror = (double)(0);
   55933           0 :     relcnt = (double)(0);
   55934           0 :     spline1dconvcubic(&bx, &rightpart, m, 2, 0.0, 2, 0.0, x, n, &fcolumn, _state);
   55935           0 :     for(i=0; i<=n-1; i++)
   55936             :     {
   55937           0 :         v = (sb-sa)*fcolumn.ptr.p_double[i]+sa;
   55938           0 :         rep->rmserror = rep->rmserror+ae_sqr(v-yoriginal.ptr.p_double[i], _state);
   55939           0 :         rep->avgerror = rep->avgerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state);
   55940           0 :         if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) )
   55941             :         {
   55942           0 :             rep->avgrelerror = rep->avgrelerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state);
   55943           0 :             relcnt = relcnt+1;
   55944             :         }
   55945           0 :         rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-yoriginal.ptr.p_double[i], _state), _state);
   55946             :     }
   55947           0 :     rep->rmserror = ae_sqrt(rep->rmserror/n, _state);
   55948           0 :     rep->avgerror = rep->avgerror/n;
   55949           0 :     if( ae_fp_neq(relcnt,(double)(0)) )
   55950             :     {
   55951           0 :         rep->avgrelerror = rep->avgrelerror/relcnt;
   55952             :     }
   55953           0 :     ae_frame_leave(_state);
   55954             : }
   55955             : 
   55956             : 
   55957             : #endif
   55958             : 
   55959             : }
   55960             : 

Generated by: LCOV version 1.16