55961 lines
		
	
	
		
			2.0 MiB
		
	
	
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			55961 lines
		
	
	
		
			2.0 MiB
		
	
	
	
	
		
			Executable File
		
	
	
	
	
| /*************************************************************************
 | |
| ALGLIB 3.16.0 (source code generated 2019-12-19)
 | |
| Copyright (c) Sergey Bochkanov (ALGLIB project).
 | |
| 
 | |
| >>> SOURCE LICENSE >>>
 | |
| This program is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation (www.fsf.org); either version 2 of the 
 | |
| License, or (at your option) any later version.
 | |
| 
 | |
| This program is distributed in the hope that it will be useful,
 | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| GNU General Public License for more details.
 | |
| 
 | |
| A copy of the GNU General Public License is available at
 | |
| http://www.fsf.org/licensing/licenses
 | |
| >>> END OF LICENSE >>>
 | |
| *************************************************************************/
 | |
| #ifdef _MSC_VER
 | |
| #define _CRT_SECURE_NO_WARNINGS
 | |
| #endif
 | |
| #include "stdafx.h"
 | |
| #include "interpolation.h"
 | |
| 
 | |
| // disable some irrelevant warnings
 | |
| #if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS)
 | |
| #pragma warning(disable:4100)
 | |
| #pragma warning(disable:4127)
 | |
| #pragma warning(disable:4611)
 | |
| #pragma warning(disable:4702)
 | |
| #pragma warning(disable:4996)
 | |
| #endif
 | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| // THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE
 | |
| //
 | |
| /////////////////////////////////////////////////////////////////////////
 | |
| namespace alglib
 | |
| {
 | |
| 
 | |
| #if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| Buffer  object  which  is  used  to  perform  evaluation  requests  in  the
 | |
| multithreaded mode (multiple threads working with same IDW object).
 | |
| 
 | |
| This object should be created with idwcreatecalcbuffer().
 | |
| *************************************************************************/
 | |
| _idwcalcbuffer_owner::_idwcalcbuffer_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_idwcalcbuffer_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::idwcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwcalcbuffer), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwcalcbuffer));
 | |
|     alglib_impl::_idwcalcbuffer_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _idwcalcbuffer_owner::_idwcalcbuffer_owner(const _idwcalcbuffer_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_idwcalcbuffer_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwcalcbuffer copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::idwcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwcalcbuffer), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwcalcbuffer));
 | |
|     alglib_impl::_idwcalcbuffer_init_copy(p_struct, const_cast<alglib_impl::idwcalcbuffer*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _idwcalcbuffer_owner& _idwcalcbuffer_owner::operator=(const _idwcalcbuffer_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwcalcbuffer assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwcalcbuffer assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_idwcalcbuffer_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwcalcbuffer));
 | |
|     alglib_impl::_idwcalcbuffer_init_copy(p_struct, const_cast<alglib_impl::idwcalcbuffer*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _idwcalcbuffer_owner::~_idwcalcbuffer_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_idwcalcbuffer_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::idwcalcbuffer* _idwcalcbuffer_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::idwcalcbuffer* _idwcalcbuffer_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::idwcalcbuffer*>(p_struct);
 | |
| }
 | |
| idwcalcbuffer::idwcalcbuffer() : _idwcalcbuffer_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| idwcalcbuffer::idwcalcbuffer(const idwcalcbuffer &rhs):_idwcalcbuffer_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| idwcalcbuffer& idwcalcbuffer::operator=(const idwcalcbuffer &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _idwcalcbuffer_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| idwcalcbuffer::~idwcalcbuffer()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| IDW (Inverse Distance Weighting) model object.
 | |
| *************************************************************************/
 | |
| _idwmodel_owner::_idwmodel_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_idwmodel_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::idwmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwmodel), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwmodel));
 | |
|     alglib_impl::_idwmodel_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _idwmodel_owner::_idwmodel_owner(const _idwmodel_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_idwmodel_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwmodel copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::idwmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwmodel), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwmodel));
 | |
|     alglib_impl::_idwmodel_init_copy(p_struct, const_cast<alglib_impl::idwmodel*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _idwmodel_owner& _idwmodel_owner::operator=(const _idwmodel_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwmodel assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwmodel assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_idwmodel_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwmodel));
 | |
|     alglib_impl::_idwmodel_init_copy(p_struct, const_cast<alglib_impl::idwmodel*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _idwmodel_owner::~_idwmodel_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_idwmodel_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::idwmodel* _idwmodel_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::idwmodel* _idwmodel_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::idwmodel*>(p_struct);
 | |
| }
 | |
| idwmodel::idwmodel() : _idwmodel_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| idwmodel::idwmodel(const idwmodel &rhs):_idwmodel_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| idwmodel& idwmodel::operator=(const idwmodel &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _idwmodel_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| idwmodel::~idwmodel()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Builder object used to generate IDW (Inverse Distance Weighting) model.
 | |
| *************************************************************************/
 | |
| _idwbuilder_owner::_idwbuilder_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_idwbuilder_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::idwbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwbuilder), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwbuilder));
 | |
|     alglib_impl::_idwbuilder_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _idwbuilder_owner::_idwbuilder_owner(const _idwbuilder_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_idwbuilder_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwbuilder copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::idwbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwbuilder), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwbuilder));
 | |
|     alglib_impl::_idwbuilder_init_copy(p_struct, const_cast<alglib_impl::idwbuilder*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _idwbuilder_owner& _idwbuilder_owner::operator=(const _idwbuilder_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwbuilder assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwbuilder assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_idwbuilder_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwbuilder));
 | |
|     alglib_impl::_idwbuilder_init_copy(p_struct, const_cast<alglib_impl::idwbuilder*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _idwbuilder_owner::~_idwbuilder_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_idwbuilder_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::idwbuilder* _idwbuilder_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::idwbuilder* _idwbuilder_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::idwbuilder*>(p_struct);
 | |
| }
 | |
| idwbuilder::idwbuilder() : _idwbuilder_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| idwbuilder::idwbuilder(const idwbuilder &rhs):_idwbuilder_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| idwbuilder& idwbuilder::operator=(const idwbuilder &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _idwbuilder_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| idwbuilder::~idwbuilder()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| IDW fitting report:
 | |
|     rmserror        RMS error
 | |
|     avgerror        average error
 | |
|     maxerror        maximum error
 | |
|     r2              coefficient of determination,  R-squared, 1-RSS/TSS
 | |
| *************************************************************************/
 | |
| _idwreport_owner::_idwreport_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_idwreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::idwreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwreport));
 | |
|     alglib_impl::_idwreport_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _idwreport_owner::_idwreport_owner(const _idwreport_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_idwreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwreport copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::idwreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::idwreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwreport));
 | |
|     alglib_impl::_idwreport_init_copy(p_struct, const_cast<alglib_impl::idwreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _idwreport_owner& _idwreport_owner::operator=(const _idwreport_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: idwreport assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: idwreport assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_idwreport_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::idwreport));
 | |
|     alglib_impl::_idwreport_init_copy(p_struct, const_cast<alglib_impl::idwreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _idwreport_owner::~_idwreport_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_idwreport_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::idwreport* _idwreport_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::idwreport* _idwreport_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::idwreport*>(p_struct);
 | |
| }
 | |
| idwreport::idwreport() : _idwreport_owner() ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2)
 | |
| {
 | |
| }
 | |
| 
 | |
| idwreport::idwreport(const idwreport &rhs):_idwreport_owner(rhs) ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2)
 | |
| {
 | |
| }
 | |
| 
 | |
| idwreport& idwreport::operator=(const idwreport &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _idwreport_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| idwreport::~idwreport()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function serializes data structure to string.
 | |
| 
 | |
| Important properties of s_out:
 | |
| * it contains alphanumeric characters, dots, underscores, minus signs
 | |
| * these symbols are grouped into words, which are separated by spaces
 | |
|   and Windows-style (CR+LF) newlines
 | |
| * although  serializer  uses  spaces and CR+LF as separators, you can 
 | |
|   replace any separator character by arbitrary combination of spaces,
 | |
|   tabs, Windows or Unix newlines. It allows flexible reformatting  of
 | |
|   the  string  in  case you want to include it into text or XML file. 
 | |
|   But you should not insert separators into the middle of the "words"
 | |
|   nor you should change case of letters.
 | |
| * s_out can be freely moved between 32-bit and 64-bit systems, little
 | |
|   and big endian machines, and so on. You can serialize structure  on
 | |
|   32-bit machine and unserialize it on 64-bit one (or vice versa), or
 | |
|   serialize  it  on  SPARC  and  unserialize  on  x86.  You  can also 
 | |
|   serialize  it  in  C++ version of ALGLIB and unserialize in C# one, 
 | |
|   and vice versa.
 | |
| *************************************************************************/
 | |
| void idwserialize(idwmodel &obj, std::string &s_out)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
|     alglib_impl::ae_int_t ssize;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_alloc_start(&serializer);
 | |
|     alglib_impl::idwalloc(&serializer, obj.c_ptr(), &state);
 | |
|     ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer);
 | |
|     s_out.clear();
 | |
|     s_out.reserve((size_t)(ssize+1));
 | |
|     alglib_impl::ae_serializer_sstart_str(&serializer, &s_out);
 | |
|     alglib_impl::idwserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| /*************************************************************************
 | |
| This function unserializes data structure from string.
 | |
| *************************************************************************/
 | |
| void idwunserialize(const std::string &s_in, idwmodel &obj)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_ustart_str(&serializer, &s_in);
 | |
|     alglib_impl::idwunserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function serializes data structure to C++ stream.
 | |
| 
 | |
| Data stream generated by this function is same as  string  representation
 | |
| generated  by  string  version  of  serializer - alphanumeric characters,
 | |
| dots, underscores, minus signs, which are grouped into words separated by
 | |
| spaces and CR+LF.
 | |
| 
 | |
| We recommend you to read comments on string version of serializer to find
 | |
| out more about serialization of AlGLIB objects.
 | |
| *************************************************************************/
 | |
| void idwserialize(idwmodel &obj, std::ostream &s_out)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_alloc_start(&serializer);
 | |
|     alglib_impl::idwalloc(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask
 | |
|     alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out);
 | |
|     alglib_impl::idwserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| /*************************************************************************
 | |
| This function unserializes data structure from stream.
 | |
| *************************************************************************/
 | |
| void idwunserialize(const std::istream &s_in, idwmodel &obj)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in);
 | |
|     alglib_impl::idwunserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function creates buffer  structure  which  can  be  used  to  perform
 | |
| parallel  IDW  model  evaluations  (with  one  IDW  model  instance  being
 | |
| used from multiple threads, as long as  different  threads  use  different
 | |
| instances of buffer).
 | |
| 
 | |
| This buffer object can be used with  idwtscalcbuf()  function  (here  "ts"
 | |
| stands for "thread-safe", "buf" is a suffix which denotes  function  which
 | |
| reuses previously allocated output space).
 | |
| 
 | |
| How to use it:
 | |
| * create IDW model structure or load it from file
 | |
| * call idwcreatecalcbuffer(), once per thread working with IDW model  (you
 | |
|   should call this function only AFTER model initialization, see below for
 | |
|   more information)
 | |
| * call idwtscalcbuf() from different threads,  with  each  thread  working
 | |
|   with its own copy of buffer object.
 | |
| 
 | |
| INPUT PARAMETERS
 | |
|     S           -   IDW model
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     Buf         -   external buffer.
 | |
| 
 | |
| 
 | |
| IMPORTANT: buffer object should be used only with  IDW model object  which
 | |
|            was used to initialize buffer. Any attempt to use buffer   with
 | |
|            different object is dangerous - you may  get  memory  violation
 | |
|            error because sizes of internal arrays do not fit to dimensions
 | |
|            of the IDW structure.
 | |
| 
 | |
| IMPORTANT: you  should  call  this function only for model which was built
 | |
|            with model builder (or unserialized from file). Sizes  of  some
 | |
|            internal structures are determined only after model  is  built,
 | |
|            so buffer object created before model construction  stage  will
 | |
|            be useless (and any attempt to use it will result in exception).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Sergey Bochkanov
 | |
| *************************************************************************/
 | |
| void idwcreatecalcbuffer(const idwmodel &s, idwcalcbuffer &buf, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwcreatecalcbuffer(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), const_cast<alglib_impl::idwcalcbuffer*>(buf.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine creates builder object used  to  generate IDW  model  from
 | |
| irregularly sampled (scattered) dataset.  Multidimensional  scalar/vector-
 | |
| -valued are supported.
 | |
| 
 | |
| Builder object is used to fit model to data as follows:
 | |
| * builder object is created with idwbuildercreate() function
 | |
| * dataset is added with idwbuildersetpoints() function
 | |
| * one of the modern IDW algorithms is chosen with either:
 | |
|   * idwbuildersetalgomstab()            - Multilayer STABilized algorithm (interpolation)
 | |
|   Alternatively, one of the textbook algorithms can be chosen (not recommended):
 | |
|   * idwbuildersetalgotextbookshepard()  - textbook Shepard algorithm
 | |
|   * idwbuildersetalgotextbookmodshepard()-textbook modified Shepard algorithm
 | |
| * finally, model construction is performed with idwfit() function.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     NX  -   dimensionality of the argument, NX>=1
 | |
|     NY  -   dimensionality of the function being modeled, NY>=1;
 | |
|             NY=1 corresponds to classic scalar function, NY>=1 corresponds
 | |
|             to vector-valued function.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State-  builder object
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildercreate(const ae_int_t nx, const ae_int_t ny, idwbuilder &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwbuildercreate(nx, ny, const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function changes number of layers used by IDW-MSTAB algorithm.
 | |
| 
 | |
| The more layers you have, the finer details can  be  reproduced  with  IDW
 | |
| model. The less layers you have, the less memory and CPU time is  consumed
 | |
| by the model.
 | |
| 
 | |
| Memory consumption grows linearly with layers count,  running  time  grows
 | |
| sub-linearly.
 | |
| 
 | |
| The default number of layers is 16, which allows you to reproduce  details
 | |
| at distance down to SRad/65536. You will rarely need to change it.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     NLayers -   NLayers>=1, the number of layers used by the model.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetnlayers(const idwbuilder &state, const ae_int_t nlayers, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwbuildersetnlayers(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), nlayers, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset to the builder object.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     XY      -   points, array[N,NX+NY]. One row  corresponds to  one point
 | |
|                 in the dataset. First NX elements  are  coordinates,  next
 | |
|                 NY elements are function values. Array may  be larger than
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset, N>=0.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetpoints(const idwbuilder &state, const real_2d_array &xy, const ae_int_t n, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwbuildersetpoints(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset to the builder object.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     XY      -   points, array[N,NX+NY]. One row  corresponds to  one point
 | |
|                 in the dataset. First NX elements  are  coordinates,  next
 | |
|                 NY elements are function values. Array may  be larger than
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset, N>=0.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void idwbuildersetpoints(const idwbuilder &state, const real_2d_array &xy, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
| 
 | |
|     n = xy.rows();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwbuildersetpoints(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, &_alglib_env_state);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets IDW model  construction  algorithm  to  the  Multilayer
 | |
| Stabilized IDW method (IDW-MSTAB), a  latest  incarnation  of  the inverse
 | |
| distance weighting interpolation which fixes shortcomings of  the original
 | |
| and modified Shepard's variants.
 | |
| 
 | |
| The distinctive features of IDW-MSTAB are:
 | |
| 1) exact interpolation  is  pursued  (as  opposed  to  fitting  and  noise
 | |
|    suppression)
 | |
| 2) improved robustness when compared with that of other algorithms:
 | |
|    * MSTAB shows almost no strange  fitting  artifacts  like  ripples  and
 | |
|      sharp spikes (unlike N-dimensional splines and HRBFs)
 | |
|    * MSTAB does not return function values far from the  interval  spanned
 | |
|      by the dataset; say, if all your points have |f|<=1, you  can be sure
 | |
|      that model value won't deviate too much from [-1,+1]
 | |
| 3) good model construction time competing with that of HRBFs  and  bicubic
 | |
|    splines
 | |
| 4) ability to work with any number of dimensions, starting from NX=1
 | |
| 
 | |
| The drawbacks of IDW-MSTAB (and all IDW algorithms in general) are:
 | |
| 1) dependence of the model evaluation time on the search radius
 | |
| 2) bad extrapolation properties, models built by this method  are  usually
 | |
|    conservative in their predictions
 | |
| 
 | |
| Thus, IDW-MSTAB is  a  good  "default"  option  if  you  want  to  perform
 | |
| scattered multidimensional interpolation. Although it has  its  drawbacks,
 | |
| it is easy to use and robust, which makes it a good first step.
 | |
| 
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     SRad    -   initial search radius, SRad>0 is required. A model  value
 | |
|                 is obtained by "smart" averaging  of  the  dataset  points
 | |
|                 within search radius.
 | |
| 
 | |
| NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
 | |
|         datasets with non-distinct points. In case non-distinct points are
 | |
|         found, an average value for this point will be calculated.
 | |
| 
 | |
| NOTE 2: the memory requirements for model storage are O(NPoints*NLayers).
 | |
|         The model construction needs twice as much memory as model storage.
 | |
| 
 | |
| NOTE 3: by default 16 IDW layers are built which is enough for most cases.
 | |
|         You can change this parameter with idwbuildersetnlayers()  method.
 | |
|         Larger values may be necessary if you need to reproduce  extrafine
 | |
|         details at distances smaller than SRad/65536.  Smaller value   may
 | |
|         be necessary if you have to save memory and  computing  time,  and
 | |
|         ready to sacrifice some model quality.
 | |
| 
 | |
| 
 | |
| ALGORITHM DESCRIPTION
 | |
| 
 | |
| ALGLIB implementation of IDW is somewhat similar to the modified Shepard's
 | |
| method (one with search radius R) but overcomes several of its  drawbacks,
 | |
| namely:
 | |
| 1) a tendency to show stepwise behavior for uniform datasets
 | |
| 2) a tendency to show terrible interpolation properties for highly
 | |
|    nonuniform datasets which often arise in geospatial tasks
 | |
|   (function values are densely sampled across multiple separated
 | |
|   "tracks")
 | |
| 
 | |
| IDW-MSTAB method performs several passes over dataset and builds a sequence
 | |
| of progressively refined IDW models  (layers),  which starts from one with
 | |
| largest search radius SRad  and continues to smaller  search  radii  until
 | |
| required number of  layers  is  built.  Highest  layers  reproduce  global
 | |
| behavior of the target function at larger distances  whilst  lower  layers
 | |
| reproduce fine details at smaller distances.
 | |
| 
 | |
| Each layer is an IDW model built with following modifications:
 | |
| * weights go to zero when distance approach to the current search radius
 | |
| * an additional regularizing term is added to the distance: w=1/(d^2+lambda)
 | |
| * an additional fictional term with unit weight and zero function value is
 | |
|   added in order to promote continuity  properties  at  the  isolated  and
 | |
|   boundary points
 | |
| 
 | |
| By default, 16 layers is built, which is enough for most  cases.  You  can
 | |
| change this parameter with idwbuildersetnlayers() method.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetalgomstab(const idwbuilder &state, const double srad, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwbuildersetalgomstab(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), srad, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets  IDW  model  construction  algorithm  to  the  textbook
 | |
| Shepard's algorithm with custom (user-specified) power parameter.
 | |
| 
 | |
| IMPORTANT: we do NOT recommend using textbook IDW algorithms because  they
 | |
|            have terrible interpolation properties. Use MSTAB in all cases.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     P       -   power parameter, P>0; good value to start with is 2.0
 | |
| 
 | |
| NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
 | |
|         datasets with non-distinct points. In case non-distinct points are
 | |
|         found, an average value for this point will be calculated.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetalgotextbookshepard(const idwbuilder &state, const double p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwbuildersetalgotextbookshepard(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), p, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets  IDW  model  construction  algorithm  to the 'textbook'
 | |
| modified Shepard's algorithm with user-specified search radius.
 | |
| 
 | |
| IMPORTANT: we do NOT recommend using textbook IDW algorithms because  they
 | |
|            have terrible interpolation properties. Use MSTAB in all cases.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     R       -   search radius
 | |
| 
 | |
| NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
 | |
|         datasets with non-distinct points. In case non-distinct points are
 | |
|         found, an average value for this point will be calculated.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetalgotextbookmodshepard(const idwbuilder &state, const double r, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwbuildersetalgotextbookmodshepard(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), r, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets prior term (model value at infinity) as  user-specified
 | |
| value.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
|     V       -   value for user-defined prior
 | |
| 
 | |
| NOTE: for vector-valued models all components of the prior are set to same
 | |
|       user-specified value
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 29.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetuserterm(const idwbuilder &state, const double v, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwbuildersetuserterm(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), v, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets constant prior term (model value at infinity).
 | |
| 
 | |
| Constant prior term is determined as mean value over dataset.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 29.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetconstterm(const idwbuilder &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwbuildersetconstterm(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets zero prior term (model value at infinity).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 29.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetzeroterm(const idwbuilder &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::idwbuildersetzeroterm(const_cast<alglib_impl::idwbuilder*>(state.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| IDW interpolation: scalar target, 1-dimensional argument
 | |
| 
 | |
| NOTE: this function modifies internal temporaries of the  IDW  model, thus
 | |
|       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
 | |
|       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
 | |
|       thread buffer object.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S   -   IDW interpolant built with IDW builder
 | |
|     X0  -   argument value
 | |
| 
 | |
| Result:
 | |
|     IDW interpolant S(X0)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double idwcalc1(const idwmodel &s, const double x0, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::idwcalc1(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), x0, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| IDW interpolation: scalar target, 2-dimensional argument
 | |
| 
 | |
| NOTE: this function modifies internal temporaries of the  IDW  model, thus
 | |
|       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
 | |
|       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
 | |
|       thread buffer object.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   IDW interpolant built with IDW builder
 | |
|     X0, X1  -   argument value
 | |
| 
 | |
| Result:
 | |
|     IDW interpolant S(X0,X1)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double idwcalc2(const idwmodel &s, const double x0, const double x1, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::idwcalc2(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), x0, x1, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| IDW interpolation: scalar target, 3-dimensional argument
 | |
| 
 | |
| NOTE: this function modifies internal temporaries of the  IDW  model, thus
 | |
|       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
 | |
|       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
 | |
|       thread buffer object.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   IDW interpolant built with IDW builder
 | |
|     X0,X1,X2-   argument value
 | |
| 
 | |
| Result:
 | |
|     IDW interpolant S(X0,X1,X2)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double idwcalc3(const idwmodel &s, const double x0, const double x1, const double x2, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::idwcalc3(const_cast<alglib_impl::idwmodel*>(s.c_ptr()), x0, x1, x2, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the IDW model at the given point.
 | |
| 
 | |
| This is general function which can be used for arbitrary NX (dimension  of
 | |
| the space of arguments) and NY (dimension of the function itself). However
 | |
| when  you  have  NY=1  you  may  find more convenient to  use  idwcalc1(),
 | |
| idwcalc2() or idwcalc3().
 | |
| 
 | |
| NOTE: this function modifies internal temporaries of the  IDW  model, thus
 | |
|       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
 | |
|       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
 | |
|       thread buffer object.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   IDW model
 | |
|     X       -   coordinates, array[NX]. X may have more than NX  elements,
 | |
|                 in this case only leading NX will be used.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is out-parameter and will  be
 | |
|                 reallocated after call to this function. In case you  want
 | |
|                 to reuse previously allocated Y, you may use idwcalcbuf(),
 | |
|                 which reallocates Y only when it is too small.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwcalc(const idwmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the IDW model at the given point.
 | |
| 
 | |
| Same as idwcalc(), but does not reallocate Y when in is large enough to
 | |
| store function values.
 | |
| 
 | |
| NOTE: this function modifies internal temporaries of the  IDW  model, thus
 | |
|       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
 | |
|       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
 | |
|       thread buffer object.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   IDW model
 | |
|     X       -   coordinates, array[NX]. X may have more than NX  elements,
 | |
|                 in this case only leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwcalcbuf(const idwmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the IDW model at the given point, using
 | |
| external  buffer  object  (internal  temporaries  of  IDW  model  are  not
 | |
| modified).
 | |
| 
 | |
| This function allows to use same IDW model object  in  different  threads,
 | |
| assuming  that  different   threads  use different instances of the buffer
 | |
| structure.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   IDW model, may be shared between different threads
 | |
|     Buf     -   buffer object created for this particular instance of  IDW
 | |
|                 model with idwcreatecalcbuffer().
 | |
|     X       -   coordinates, array[NX]. X may have more than NX  elements,
 | |
|                 in this case only  leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwtscalcbuf(const idwmodel &s, const idwcalcbuffer &buf, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits IDW model to the dataset using current IDW construction
 | |
| algorithm. A model being built and fitting report are returned.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Model   -   an IDW model built with current algorithm
 | |
|     Rep     -   model fitting report, fields of this structure contain
 | |
|                 information about average fitting errors.
 | |
| 
 | |
| NOTE: although IDW-MSTAB algorithm is an  interpolation  method,  i.e.  it
 | |
|       tries to fit the model exactly, it can  handle  datasets  with  non-
 | |
|       distinct points which can not be fit exactly; in such  cases  least-
 | |
|       squares fitting is performed.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwfit(const idwbuilder &state, idwmodel &model, idwreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| Barycentric interpolant.
 | |
| *************************************************************************/
 | |
| _barycentricinterpolant_owner::_barycentricinterpolant_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_barycentricinterpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::barycentricinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricinterpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::barycentricinterpolant));
 | |
|     alglib_impl::_barycentricinterpolant_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _barycentricinterpolant_owner::_barycentricinterpolant_owner(const _barycentricinterpolant_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_barycentricinterpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricinterpolant copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::barycentricinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricinterpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::barycentricinterpolant));
 | |
|     alglib_impl::_barycentricinterpolant_init_copy(p_struct, const_cast<alglib_impl::barycentricinterpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _barycentricinterpolant_owner& _barycentricinterpolant_owner::operator=(const _barycentricinterpolant_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: barycentricinterpolant assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricinterpolant assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_barycentricinterpolant_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::barycentricinterpolant));
 | |
|     alglib_impl::_barycentricinterpolant_init_copy(p_struct, const_cast<alglib_impl::barycentricinterpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _barycentricinterpolant_owner::~_barycentricinterpolant_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_barycentricinterpolant_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::barycentricinterpolant* _barycentricinterpolant_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::barycentricinterpolant* _barycentricinterpolant_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::barycentricinterpolant*>(p_struct);
 | |
| }
 | |
| barycentricinterpolant::barycentricinterpolant() : _barycentricinterpolant_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| barycentricinterpolant::barycentricinterpolant(const barycentricinterpolant &rhs):_barycentricinterpolant_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| barycentricinterpolant& barycentricinterpolant::operator=(const barycentricinterpolant &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _barycentricinterpolant_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| barycentricinterpolant::~barycentricinterpolant()
 | |
| {
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Rational interpolation using barycentric formula
 | |
| 
 | |
| F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))
 | |
| 
 | |
| Input parameters:
 | |
|     B   -   barycentric interpolant built with one of model building
 | |
|             subroutines.
 | |
|     T   -   interpolation point
 | |
| 
 | |
| Result:
 | |
|     barycentric interpolant F(t)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double barycentriccalc(const barycentricinterpolant &b, const double t, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::barycentriccalc(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), t, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Differentiation of barycentric interpolant: first derivative.
 | |
| 
 | |
| Algorithm used in this subroutine is very robust and should not fail until
 | |
| provided with values too close to MaxRealNumber  (usually  MaxRealNumber/N
 | |
| or greater will overflow).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B   -   barycentric interpolant built with one of model building
 | |
|             subroutines.
 | |
|     T   -   interpolation point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   barycentric interpolant at T
 | |
|     DF  -   first derivative
 | |
| 
 | |
| NOTE
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricdiff1(const barycentricinterpolant &b, const double t, double &f, double &df, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::barycentricdiff1(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), t, &f, &df, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Differentiation of barycentric interpolant: first/second derivatives.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B   -   barycentric interpolant built with one of model building
 | |
|             subroutines.
 | |
|     T   -   interpolation point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   barycentric interpolant at T
 | |
|     DF  -   first derivative
 | |
|     D2F -   second derivative
 | |
| 
 | |
| NOTE: this algorithm may fail due to overflow/underflor if  used  on  data
 | |
| whose values are close to MaxRealNumber or MinRealNumber.  Use more robust
 | |
| BarycentricDiff1() subroutine in such cases.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricdiff2(const barycentricinterpolant &b, const double t, double &f, double &df, double &d2f, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::barycentricdiff2(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), t, &f, &df, &d2f, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the argument.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B       -   rational interpolant in barycentric form
 | |
|     CA, CB  -   transformation coefficients: x = CA*t + CB
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     B       -   transformed interpolant with X replaced by T
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 19.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentriclintransx(const barycentricinterpolant &b, const double ca, const double cb, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::barycentriclintransx(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), ca, cb, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  subroutine   performs   linear  transformation  of  the  barycentric
 | |
| interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B       -   rational interpolant in barycentric form
 | |
|     CA, CB  -   transformation coefficients: B2(x) = CA*B(x) + CB
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     B       -   transformed interpolant
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 19.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentriclintransy(const barycentricinterpolant &b, const double ca, const double cb, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::barycentriclintransy(const_cast<alglib_impl::barycentricinterpolant*>(b.c_ptr()), ca, cb, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Extracts X/Y/W arrays from rational interpolant
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B   -   barycentric interpolant
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     N   -   nodes count, N>0
 | |
|     X   -   interpolation nodes, array[0..N-1]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     W   -   barycentric weights, array[0..N-1]
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricunpack(const barycentricinterpolant &b, ae_int_t &n, real_1d_array &x, real_1d_array &y, real_1d_array &w, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Rational interpolant from X/Y/W arrays
 | |
| 
 | |
| F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   interpolation nodes, array[0..N-1]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     W   -   barycentric weights, array[0..N-1]
 | |
|     N   -   nodes count, N>0
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     B   -   barycentric interpolant built from (X, Y, W)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricbuildxyw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, barycentricinterpolant &b, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Rational interpolant without poles
 | |
| 
 | |
| The subroutine constructs the rational interpolating function without real
 | |
| poles  (see  'Barycentric rational interpolation with no  poles  and  high
 | |
| rates of approximation', Michael S. Floater. and  Kai  Hormann,  for  more
 | |
| information on this subject).
 | |
| 
 | |
| Input parameters:
 | |
|     X   -   interpolation nodes, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     N   -   number of nodes, N>0.
 | |
|     D   -   order of the interpolation scheme, 0 <= D <= N-1.
 | |
|             D<0 will cause an error.
 | |
|             D>=N it will be replaced with D=N-1.
 | |
|             if you don't know what D to choose, use small value about 3-5.
 | |
| 
 | |
| Output parameters:
 | |
|     B   -   barycentric interpolant.
 | |
| 
 | |
| Note:
 | |
|     this algorithm always succeeds and calculates the weights  with  close
 | |
|     to machine precision.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 17.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricbuildfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t d, barycentricinterpolant &b, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| Fits least squares (LS) circle (or NX-dimensional sphere) to data  (a  set
 | |
| of points in NX-dimensional space).
 | |
| 
 | |
| Least squares circle minimizes sum of squared deviations between distances
 | |
| from points to the center and  some  "candidate"  radius,  which  is  also
 | |
| fitted to the data.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     R       -   radius
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 07.05.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitspherels(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &r, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fits minimum circumscribed (MC) circle (or NX-dimensional sphere) to  data
 | |
| (a set of points in NX-dimensional space).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     RHi     -   radius
 | |
| 
 | |
| NOTE: this function is an easy-to-use wrapper around more powerful "expert"
 | |
|       function fitspherex().
 | |
| 
 | |
|       This  wrapper  is optimized  for  ease of use and stability - at the
 | |
|       cost of somewhat lower  performance  (we  have  to  use  very  tight
 | |
|       stopping criteria for inner optimizer because we want to  make  sure
 | |
|       that it will converge on any dataset).
 | |
| 
 | |
|       If you are ready to experiment with settings of  "expert"  function,
 | |
|       you can achieve ~2-4x speedup over standard "bulletproof" settings.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitspheremc(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rhi, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fits maximum inscribed circle (or NX-dimensional sphere) to data (a set of
 | |
| points in NX-dimensional space).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     RLo     -   radius
 | |
| 
 | |
| NOTE: this function is an easy-to-use wrapper around more powerful "expert"
 | |
|       function fitspherex().
 | |
| 
 | |
|       This  wrapper  is optimized  for  ease of use and stability - at the
 | |
|       cost of somewhat lower  performance  (we  have  to  use  very  tight
 | |
|       stopping criteria for inner optimizer because we want to  make  sure
 | |
|       that it will converge on any dataset).
 | |
| 
 | |
|       If you are ready to experiment with settings of  "expert"  function,
 | |
|       you can achieve ~2-4x speedup over standard "bulletproof" settings.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitspheremi(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fits minimum zone circle (or NX-dimensional sphere)  to  data  (a  set  of
 | |
| points in NX-dimensional space).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     RLo     -   radius of inscribed circle
 | |
|     RHo     -   radius of circumscribed circle
 | |
| 
 | |
| NOTE: this function is an easy-to-use wrapper around more powerful "expert"
 | |
|       function fitspherex().
 | |
| 
 | |
|       This  wrapper  is optimized  for  ease of use and stability - at the
 | |
|       cost of somewhat lower  performance  (we  have  to  use  very  tight
 | |
|       stopping criteria for inner optimizer because we want to  make  sure
 | |
|       that it will converge on any dataset).
 | |
| 
 | |
|       If you are ready to experiment with settings of  "expert"  function,
 | |
|       you can achieve ~2-4x speedup over standard "bulletproof" settings.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitspheremz(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fitting minimum circumscribed, maximum inscribed or minimum  zone  circles
 | |
| (or NX-dimensional spheres)  to  data  (a  set of points in NX-dimensional
 | |
| space).
 | |
| 
 | |
| This  is  expert  function  which  allows  to  tweak  many  parameters  of
 | |
| underlying nonlinear solver:
 | |
| * stopping criteria for inner iterations
 | |
| * number of outer iterations
 | |
| * penalty coefficient used to handle  nonlinear  constraints  (we  convert
 | |
|   unconstrained nonsmooth optimization problem ivolving max() and/or min()
 | |
|   operations to quadratically constrained smooth one).
 | |
| 
 | |
| You may tweak all these parameters or only some  of  them,  leaving  other
 | |
| ones at their default state - just specify zero  value,  and  solver  will
 | |
| fill it with appropriate default one.
 | |
| 
 | |
| These comments also include some discussion of  approach  used  to  handle
 | |
| such unusual fitting problem,  its  stability,  drawbacks  of  alternative
 | |
| methods, and convergence properties.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
|     ProblemType-used to encode problem type:
 | |
|                 * 0 for least squares circle
 | |
|                 * 1 for minimum circumscribed circle/sphere fitting (MC)
 | |
|                 * 2 for  maximum inscribed circle/sphere fitting (MI)
 | |
|                 * 3 for minimum zone circle fitting (difference between
 | |
|                     Rhi and Rlo is minimized), denoted as MZ
 | |
|     EpsX    -   stopping condition for NLC optimizer:
 | |
|                 * must be non-negative
 | |
|                 * use 0 to choose default value (1.0E-12 is used by default)
 | |
|                 * you may specify larger values, up to 1.0E-6, if you want
 | |
|                   to   speed-up   solver;   NLC   solver  performs several
 | |
|                   preconditioned  outer  iterations,   so   final   result
 | |
|                   typically has precision much better than EpsX.
 | |
|     AULIts  -   number of outer iterations performed by NLC optimizer:
 | |
|                 * must be non-negative
 | |
|                 * use 0 to choose default value (20 is used by default)
 | |
|                 * you may specify values smaller than 20 if you want to
 | |
|                   speed up solver; 10 often results in good combination of
 | |
|                   precision and speed; sometimes you may get good results
 | |
|                   with just 6 outer iterations.
 | |
|                 Ignored for ProblemType=0.
 | |
|     Penalty -   penalty coefficient for NLC optimizer:
 | |
|                 * must be non-negative
 | |
|                 * use 0 to choose default value (1.0E6 in current version)
 | |
|                 * it should be really large, 1.0E6...1.0E7 is a good value
 | |
|                   to start from;
 | |
|                 * generally, default value is good enough
 | |
|                 Ignored for ProblemType=0.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     RLo     -   radius:
 | |
|                 * for ProblemType=2,3, radius of the inscribed sphere
 | |
|                 * for ProblemType=0 - radius of the least squares sphere
 | |
|                 * for ProblemType=1 - zero
 | |
|     RHo     -   radius:
 | |
|                 * for ProblemType=1,3, radius of the circumscribed sphere
 | |
|                 * for ProblemType=0 - radius of the least squares sphere
 | |
|                 * for ProblemType=2 - zero
 | |
| 
 | |
| NOTE: ON THE UNIQUENESS OF SOLUTIONS
 | |
| 
 | |
| ALGLIB provides solution to several related circle fitting  problems:   MC
 | |
| (minimum circumscribed), MI (maximum inscribed)   and   MZ  (minimum zone)
 | |
| fitting, LS (least squares) fitting.
 | |
| 
 | |
| It  is  important  to  note  that  among these problems only MC and LS are
 | |
| convex and have unique solution independently from starting point.
 | |
| 
 | |
| As  for MI,  it  may (or  may  not, depending on dataset properties)  have
 | |
| multiple solutions, and it always  has  one degenerate solution C=infinity
 | |
| which corresponds to infinitely large radius. Thus, there are no guarantees
 | |
| that solution to  MI returned by this solver will be the best one (and  no
 | |
| one can provide you with such guarantee because problem is  NP-hard).  The
 | |
| only guarantee you have is that this solution is locally optimal, i.e.  it
 | |
| can not be improved by infinitesimally small tweaks in the parameters.
 | |
| 
 | |
| It  is  also  possible  to "run away" to infinity when  started  from  bad
 | |
| initial point located outside of point cloud (or when point cloud does not
 | |
| span entire circumference/surface of the sphere).
 | |
| 
 | |
| Finally,  MZ (minimum zone circle) stands somewhere between MC  and  MI in
 | |
| stability. It is somewhat regularized by "circumscribed" term of the merit
 | |
| function; however, solutions to  MZ may be non-unique, and in some unlucky
 | |
| cases it is also possible to "run away to infinity".
 | |
| 
 | |
| 
 | |
| NOTE: ON THE NONLINEARLY CONSTRAINED PROGRAMMING APPROACH
 | |
| 
 | |
| The problem formulation for MC  (minimum circumscribed   circle;  for  the
 | |
| sake of simplicity we omit MZ and MI here) is:
 | |
| 
 | |
|         [     [         ]2 ]
 | |
|     min [ max [ XY[i]-C ]  ]
 | |
|      C  [  i  [         ]  ]
 | |
| 
 | |
| i.e. it is unconstrained nonsmooth optimization problem of finding  "best"
 | |
| central point, with radius R being unambiguously  determined  from  C.  In
 | |
| order to move away from non-smoothness we use following reformulation:
 | |
| 
 | |
|         [   ]                  [         ]2
 | |
|     min [ R ] subject to R>=0, [ XY[i]-C ]  <= R^2
 | |
|     C,R [   ]                  [         ]
 | |
| 
 | |
| i.e. it becomes smooth quadratically constrained optimization problem with
 | |
| linear target function. Such problem statement is 100% equivalent  to  the
 | |
| original nonsmooth one, but much easier  to  approach.  We solve  it  with
 | |
| MinNLC solver provided by ALGLIB.
 | |
| 
 | |
| 
 | |
| NOTE: ON INSTABILITY OF SEQUENTIAL LINEARIZATION APPROACH
 | |
| 
 | |
| ALGLIB  has  nonlinearly  constrained  solver which proved to be stable on
 | |
| such problems. However, some authors proposed to linearize constraints  in
 | |
| the vicinity of current approximation (Ci,Ri) and to get next  approximate
 | |
| solution (Ci+1,Ri+1) as solution to linear programming problem. Obviously,
 | |
| LP problems are easier than nonlinearly constrained ones.
 | |
| 
 | |
| Indeed,  such approach  to   MC/MI/MZ   resulted   in  ~10-20x increase in
 | |
| performance (when compared with NLC solver). However, it turned  out  that
 | |
| in some cases linearized model fails to predict correct direction for next
 | |
| step and tells us that we converged to solution even when we are still 2-4
 | |
| digits of precision away from it.
 | |
| 
 | |
| It is important that it is not failure of LP solver - it is failure of the
 | |
| linear model;  even  when  solved  exactly,  it  fails  to  handle  subtle
 | |
| nonlinearities which arise near the solution. We validated it by comparing
 | |
| results returned by ALGLIB linear solver with that of MATLAB.
 | |
| 
 | |
| In our experiments with linearization:
 | |
| * MC failed most often, at both realistic and synthetic datasets
 | |
| * MI sometimes failed, but sometimes succeeded
 | |
| * MZ often  succeeded; our guess is that presence of two independent  sets
 | |
|   of constraints (one set for Rlo and another one for Rhi) and  two  terms
 | |
|   in the target function (Rlo and Rhi) regularizes task,  so  when  linear
 | |
|   model fails to handle nonlinearities from Rlo, it uses  Rhi  as  a  hint
 | |
|   (and vice versa).
 | |
| 
 | |
| Because linearization approach failed to achieve stable results, we do not
 | |
| include it in ALGLIB.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitspherex(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, const ae_int_t problemtype, const double epsx, const ae_int_t aulits, const double penalty, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| 1-dimensional spline interpolant
 | |
| *************************************************************************/
 | |
| _spline1dinterpolant_owner::_spline1dinterpolant_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline1dinterpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::spline1dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dinterpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline1dinterpolant));
 | |
|     alglib_impl::_spline1dinterpolant_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline1dinterpolant_owner::_spline1dinterpolant_owner(const _spline1dinterpolant_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline1dinterpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dinterpolant copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::spline1dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dinterpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline1dinterpolant));
 | |
|     alglib_impl::_spline1dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline1dinterpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline1dinterpolant_owner& _spline1dinterpolant_owner::operator=(const _spline1dinterpolant_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline1dinterpolant assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dinterpolant assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_spline1dinterpolant_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline1dinterpolant));
 | |
|     alglib_impl::_spline1dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline1dinterpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _spline1dinterpolant_owner::~_spline1dinterpolant_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_spline1dinterpolant_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::spline1dinterpolant* _spline1dinterpolant_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::spline1dinterpolant* _spline1dinterpolant_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::spline1dinterpolant*>(p_struct);
 | |
| }
 | |
| spline1dinterpolant::spline1dinterpolant() : _spline1dinterpolant_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| spline1dinterpolant::spline1dinterpolant(const spline1dinterpolant &rhs):_spline1dinterpolant_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| spline1dinterpolant& spline1dinterpolant::operator=(const spline1dinterpolant &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _spline1dinterpolant_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| spline1dinterpolant::~spline1dinterpolant()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Spline fitting report:
 | |
|     RMSError        RMS error
 | |
|     AvgError        average error
 | |
|     AvgRelError     average relative error (for non-zero Y[I])
 | |
|     MaxError        maximum error
 | |
| 
 | |
| Fields  below are  filled  by   obsolete    functions   (Spline1DFitCubic,
 | |
| Spline1DFitHermite). Modern fitting functions do NOT fill these fields:
 | |
|     TaskRCond       reciprocal of task's condition number
 | |
| *************************************************************************/
 | |
| _spline1dfitreport_owner::_spline1dfitreport_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline1dfitreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::spline1dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dfitreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline1dfitreport));
 | |
|     alglib_impl::_spline1dfitreport_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline1dfitreport_owner::_spline1dfitreport_owner(const _spline1dfitreport_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline1dfitreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dfitreport copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::spline1dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline1dfitreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline1dfitreport));
 | |
|     alglib_impl::_spline1dfitreport_init_copy(p_struct, const_cast<alglib_impl::spline1dfitreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline1dfitreport_owner& _spline1dfitreport_owner::operator=(const _spline1dfitreport_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline1dfitreport assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline1dfitreport assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_spline1dfitreport_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline1dfitreport));
 | |
|     alglib_impl::_spline1dfitreport_init_copy(p_struct, const_cast<alglib_impl::spline1dfitreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _spline1dfitreport_owner::~_spline1dfitreport_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_spline1dfitreport_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::spline1dfitreport* _spline1dfitreport_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::spline1dfitreport* _spline1dfitreport_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::spline1dfitreport*>(p_struct);
 | |
| }
 | |
| spline1dfitreport::spline1dfitreport() : _spline1dfitreport_owner() ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror)
 | |
| {
 | |
| }
 | |
| 
 | |
| spline1dfitreport::spline1dfitreport(const spline1dfitreport &rhs):_spline1dfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror)
 | |
| {
 | |
| }
 | |
| 
 | |
| spline1dfitreport& spline1dfitreport::operator=(const spline1dfitreport &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _spline1dfitreport_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| spline1dfitreport::~spline1dfitreport()
 | |
| {
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds linear spline interpolant
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   spline nodes, array[0..N-1]
 | |
|     Y   -   function values, array[0..N-1]
 | |
|     N   -   points count (optional):
 | |
|             * N>=2
 | |
|             * if given, only first N points are used to build spline
 | |
|             * if not given, automatically detected from X/Y sizes
 | |
|               (len(X) must be equal to len(Y))
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 24.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds linear spline interpolant
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   spline nodes, array[0..N-1]
 | |
|     Y   -   function values, array[0..N-1]
 | |
|     N   -   points count (optional):
 | |
|             * N>=2
 | |
|             * if given, only first N points are used to build spline
 | |
|             * if not given, automatically detected from X/Y sizes
 | |
|               (len(X) must be equal to len(Y))
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 24.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dbuildlinear(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildlinear': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds cubic spline interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1].
 | |
|     Y           -   function values, array[0..N-1].
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds cubic spline interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1].
 | |
|     Y           -   function values, array[0..N-1].
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dbuildcubic(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t boundltype;
 | |
|     double boundl;
 | |
|     ae_int_t boundrtype;
 | |
|     double boundr;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildcubic': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     boundltype = 0;
 | |
|     boundl = 0;
 | |
|     boundrtype = 0;
 | |
|     boundr = 0;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at nodes x[], it calculates and returns table of function derivatives  d[]
 | |
| (calculated at the same nodes x[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes
 | |
|     Y           -   function values
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     D           -   derivative values at X[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| Derivative values are correctly reordered on return, so  D[I]  is  always
 | |
| equal to S'(X[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at nodes x[], it calculates and returns table of function derivatives  d[]
 | |
| (calculated at the same nodes x[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes
 | |
|     Y           -   function values
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     D           -   derivative values at X[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| Derivative values are correctly reordered on return, so  D[I]  is  always
 | |
| equal to S'(X[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dgriddiffcubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t boundltype;
 | |
|     double boundl;
 | |
|     ae_int_t boundrtype;
 | |
|     double boundr;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dgriddiffcubic': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     boundltype = 0;
 | |
|     boundl = 0;
 | |
|     boundrtype = 0;
 | |
|     boundr = 0;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at  nodes  x[],  it  calculates  and  returns  tables  of first and second
 | |
| function derivatives d1[] and d2[] (calculated at the same nodes x[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes
 | |
|     Y           -   function values
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     D1          -   S' values at X[]
 | |
|     D2          -   S'' values at X[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| Derivative values are correctly reordered on return, so  D[I]  is  always
 | |
| equal to S'(X[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, real_1d_array &d1, real_1d_array &d2, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at  nodes  x[],  it  calculates  and  returns  tables  of first and second
 | |
| function derivatives d1[] and d2[] (calculated at the same nodes x[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes
 | |
|     Y           -   function values
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     D1          -   S' values at X[]
 | |
|     D2          -   S'' values at X[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| Derivative values are correctly reordered on return, so  D[I]  is  always
 | |
| equal to S'(X[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dgriddiff2cubic(const real_1d_array &x, const real_1d_array &y, real_1d_array &d1, real_1d_array &d2, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t boundltype;
 | |
|     double boundl;
 | |
|     ae_int_t boundrtype;
 | |
|     double boundr;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dgriddiff2cubic': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     boundltype = 0;
 | |
|     boundl = 0;
 | |
|     boundrtype = 0;
 | |
|     boundr = 0;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
 | |
| function values y2[] (calculated at x2[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   old spline nodes
 | |
|     Y           -   function values
 | |
|     X2           -  new spline nodes
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points from X/Y are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
|     N2          -   new points count:
 | |
|                     * N2>=2
 | |
|                     * if given, only first N2 points from X2 are used
 | |
|                     * if not given, automatically detected from X2 size
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F2          -   function values at X2[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller  may pass unsorted array.
 | |
| Function  values  are correctly reordered on  return, so F2[I]  is  always
 | |
| equal to S(X2[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
 | |
| function values y2[] (calculated at x2[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   old spline nodes
 | |
|     Y           -   function values
 | |
|     X2           -  new spline nodes
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points from X/Y are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
|     N2          -   new points count:
 | |
|                     * N2>=2
 | |
|                     * if given, only first N2 points from X2 are used
 | |
|                     * if not given, automatically detected from X2 size
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F2          -   function values at X2[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller  may pass unsorted array.
 | |
| Function  values  are correctly reordered on  return, so F2[I]  is  always
 | |
| equal to S(X2[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dconvcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t boundltype;
 | |
|     double boundl;
 | |
|     ae_int_t boundrtype;
 | |
|     double boundr;
 | |
|     ae_int_t n2;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dconvcubic': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     boundltype = 0;
 | |
|     boundl = 0;
 | |
|     boundrtype = 0;
 | |
|     boundr = 0;
 | |
|     n2 = x2.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
 | |
| function values y2[] and derivatives d2[] (calculated at x2[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   old spline nodes
 | |
|     Y           -   function values
 | |
|     X2           -  new spline nodes
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points from X/Y are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
|     N2          -   new points count:
 | |
|                     * N2>=2
 | |
|                     * if given, only first N2 points from X2 are used
 | |
|                     * if not given, automatically detected from X2 size
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F2          -   function values at X2[]
 | |
|     D2          -   first derivatives at X2[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller  may pass unsorted array.
 | |
| Function  values  are correctly reordered on  return, so F2[I]  is  always
 | |
| equal to S(X2[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
 | |
| function values y2[] and derivatives d2[] (calculated at x2[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   old spline nodes
 | |
|     Y           -   function values
 | |
|     X2           -  new spline nodes
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points from X/Y are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
|     N2          -   new points count:
 | |
|                     * N2>=2
 | |
|                     * if given, only first N2 points from X2 are used
 | |
|                     * if not given, automatically detected from X2 size
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F2          -   function values at X2[]
 | |
|     D2          -   first derivatives at X2[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller  may pass unsorted array.
 | |
| Function  values  are correctly reordered on  return, so F2[I]  is  always
 | |
| equal to S(X2[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dconvdiffcubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t boundltype;
 | |
|     double boundl;
 | |
|     ae_int_t boundrtype;
 | |
|     double boundr;
 | |
|     ae_int_t n2;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dconvdiffcubic': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     boundltype = 0;
 | |
|     boundl = 0;
 | |
|     boundrtype = 0;
 | |
|     boundr = 0;
 | |
|     n2 = x2.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
 | |
| function  values  y2[],  first  and  second  derivatives  d2[]  and  dd2[]
 | |
| (calculated at x2[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   old spline nodes
 | |
|     Y           -   function values
 | |
|     X2           -  new spline nodes
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points from X/Y are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
|     N2          -   new points count:
 | |
|                     * N2>=2
 | |
|                     * if given, only first N2 points from X2 are used
 | |
|                     * if not given, automatically detected from X2 size
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F2          -   function values at X2[]
 | |
|     D2          -   first derivatives at X2[]
 | |
|     DD2         -   second derivatives at X2[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller  may pass unsorted array.
 | |
| Function  values  are correctly reordered on  return, so F2[I]  is  always
 | |
| equal to S(X2[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t boundltype, const double boundl, const ae_int_t boundrtype, const double boundr, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
 | |
| function  values  y2[],  first  and  second  derivatives  d2[]  and  dd2[]
 | |
| (calculated at x2[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   old spline nodes
 | |
|     Y           -   function values
 | |
|     X2           -  new spline nodes
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points from X/Y are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
|     N2          -   new points count:
 | |
|                     * N2>=2
 | |
|                     * if given, only first N2 points from X2 are used
 | |
|                     * if not given, automatically detected from X2 size
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F2          -   function values at X2[]
 | |
|     D2          -   first derivatives at X2[]
 | |
|     DD2         -   second derivatives at X2[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller  may pass unsorted array.
 | |
| Function  values  are correctly reordered on  return, so F2[I]  is  always
 | |
| equal to S(X2[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dconvdiff2cubic(const real_1d_array &x, const real_1d_array &y, const real_1d_array &x2, real_1d_array &y2, real_1d_array &d2, real_1d_array &dd2, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t boundltype;
 | |
|     double boundl;
 | |
|     ae_int_t boundrtype;
 | |
|     double boundr;
 | |
|     ae_int_t n2;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dconvdiff2cubic': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     boundltype = 0;
 | |
|     boundl = 0;
 | |
|     boundrtype = 0;
 | |
|     boundr = 0;
 | |
|     n2 = x2.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds Catmull-Rom spline interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1].
 | |
|     Y           -   function values, array[0..N-1].
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundType   -   boundary condition type:
 | |
|                     * -1 for periodic boundary condition
 | |
|                     *  0 for parabolically terminated spline (default)
 | |
|     Tension     -   tension parameter:
 | |
|                     * tension=0   corresponds to classic Catmull-Rom spline (default)
 | |
|                     * 0<tension<1 corresponds to more general form - cardinal spline
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void 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)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds Catmull-Rom spline interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1].
 | |
|     Y           -   function values, array[0..N-1].
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundType   -   boundary condition type:
 | |
|                     * -1 for periodic boundary condition
 | |
|                     *  0 for parabolically terminated spline (default)
 | |
|     Tension     -   tension parameter:
 | |
|                     * tension=0   corresponds to classic Catmull-Rom spline (default)
 | |
|                     * 0<tension<1 corresponds to more general form - cardinal spline
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dbuildcatmullrom(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t boundtype;
 | |
|     double tension;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildcatmullrom': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     boundtype = 0;
 | |
|     tension = 0;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds Hermite spline interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1]
 | |
|     Y           -   function values, array[0..N-1]
 | |
|     D           -   derivatives, array[0..N-1]
 | |
|     N           -   points count (optional):
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant.
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds Hermite spline interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1]
 | |
|     Y           -   function values, array[0..N-1]
 | |
|     D           -   derivatives, array[0..N-1]
 | |
|     N           -   points count (optional):
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant.
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dbuildhermite(const real_1d_array &x, const real_1d_array &y, const real_1d_array &d, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()) || (x.length()!=d.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildhermite': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds Akima spline interpolant
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1]
 | |
|     Y           -   function values, array[0..N-1]
 | |
|     N           -   points count (optional):
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 24.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds Akima spline interpolant
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1]
 | |
|     Y           -   function values, array[0..N-1]
 | |
|     N           -   points count (optional):
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 24.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dbuildakima(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildakima': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates the value of the spline at the given point X.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant
 | |
|     X   -   point
 | |
| 
 | |
| Result:
 | |
|     S(x)
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double spline1dcalc(const spline1dinterpolant &c, const double x, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::spline1dcalc(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), x, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine differentiates the spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X   -   point
 | |
| 
 | |
| Result:
 | |
|     S   -   S(x)
 | |
|     DS  -   S'(x)
 | |
|     D2S -   S''(x)
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 24.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1ddiff(const spline1dinterpolant &c, const double x, double &s, double &ds, double &d2s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline1ddiff(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), x, &s, &ds, &d2s, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine unpacks the spline into the coefficients table.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X   -   point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Tbl -   coefficients table, unpacked format, array[0..N-2, 0..5].
 | |
|             For I = 0...N-2:
 | |
|                 Tbl[I,0] = X[i]
 | |
|                 Tbl[I,1] = X[i+1]
 | |
|                 Tbl[I,2] = C0
 | |
|                 Tbl[I,3] = C1
 | |
|                 Tbl[I,4] = C2
 | |
|                 Tbl[I,5] = C3
 | |
|             On [x[i], x[i+1]] spline is equals to:
 | |
|                 S(x) = C0 + C1*t + C2*t^2 + C3*t^3
 | |
|                 t = x-x[i]
 | |
| 
 | |
| NOTE:
 | |
|     You  can rebuild spline with  Spline1DBuildHermite()  function,  which
 | |
|     accepts as inputs function values and derivatives at nodes, which  are
 | |
|     easy to calculate when you have coefficients.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 29.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dunpack(const spline1dinterpolant &c, ae_int_t &n, real_2d_array &tbl, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline1dunpack(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), &n, const_cast<alglib_impl::ae_matrix*>(tbl.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline argument.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     A, B-   transformation coefficients: x = A*t + B
 | |
| Result:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dlintransx(const spline1dinterpolant &c, const double a, const double b, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline1dlintransx(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), a, b, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     A, B-   transformation coefficients: S2(x) = A*S(x) + B
 | |
| Result:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dlintransy(const spline1dinterpolant &c, const double a, const double b, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline1dlintransy(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), a, b, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine integrates the spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X   -   right bound of the integration interval [a, x],
 | |
|             here 'a' denotes min(x[])
 | |
| Result:
 | |
|     integral(S(t)dt,a,x)
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double spline1dintegrate(const spline1dinterpolant &c, const double x, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::spline1dintegrate(const_cast<alglib_impl::spline1dinterpolant*>(c.c_ptr()), x, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fitting by smoothing (penalized) cubic spline.
 | |
| 
 | |
| This function approximates N scattered points (some of X[] may be equal to
 | |
| each other) by cubic spline with M  nodes  at  equidistant  grid  spanning
 | |
| interval [min(x,xc),max(x,xc)].
 | |
| 
 | |
| The problem is regularized by adding nonlinearity penalty to  usual  least
 | |
| squares penalty function:
 | |
| 
 | |
|     MERIT_FUNC = F_LS + F_NL
 | |
| 
 | |
| where F_LS is a least squares error  term,  and  F_NL  is  a  nonlinearity
 | |
| penalty which is roughly proportional to LambdaNS*integral{ S''(x)^2*dx }.
 | |
| Algorithm applies automatic renormalization of F_NL  which  makes  penalty
 | |
| term roughly invariant to scaling of X[] and changes in M.
 | |
| 
 | |
| This function is a new edition  of  penalized  regression  spline fitting,
 | |
| a fast and compact one which needs much less resources that  its  previous
 | |
| version: just O(maxMN) memory and O(maxMN*log(maxMN)) time.
 | |
| 
 | |
| NOTE: it is OK to run this function with both M<<N and M>>N;  say,  it  is
 | |
|       possible to process 100 points with 1000-node spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   points, array[0..N-1].
 | |
|     Y           -   function values, array[0..N-1].
 | |
|     N           -   number of points (optional):
 | |
|                     * N>0
 | |
|                     * if given, only first N elements of X/Y are processed
 | |
|                     * if not given, automatically determined from lengths
 | |
|     M           -   number of basis functions ( = number_of_nodes), M>=4.
 | |
|     LambdaNS    -   LambdaNS>=0, regularization  constant  passed by user.
 | |
|                     It penalizes nonlinearity in the regression spline.
 | |
|                     Possible values to start from are 0.00001, 0.1, 1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     S   -   spline interpolant.
 | |
|     Rep -   Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 27.08.2019 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double lambdans, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fitting by smoothing (penalized) cubic spline.
 | |
| 
 | |
| This function approximates N scattered points (some of X[] may be equal to
 | |
| each other) by cubic spline with M  nodes  at  equidistant  grid  spanning
 | |
| interval [min(x,xc),max(x,xc)].
 | |
| 
 | |
| The problem is regularized by adding nonlinearity penalty to  usual  least
 | |
| squares penalty function:
 | |
| 
 | |
|     MERIT_FUNC = F_LS + F_NL
 | |
| 
 | |
| where F_LS is a least squares error  term,  and  F_NL  is  a  nonlinearity
 | |
| penalty which is roughly proportional to LambdaNS*integral{ S''(x)^2*dx }.
 | |
| Algorithm applies automatic renormalization of F_NL  which  makes  penalty
 | |
| term roughly invariant to scaling of X[] and changes in M.
 | |
| 
 | |
| This function is a new edition  of  penalized  regression  spline fitting,
 | |
| a fast and compact one which needs much less resources that  its  previous
 | |
| version: just O(maxMN) memory and O(maxMN*log(maxMN)) time.
 | |
| 
 | |
| NOTE: it is OK to run this function with both M<<N and M>>N;  say,  it  is
 | |
|       possible to process 100 points with 1000-node spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   points, array[0..N-1].
 | |
|     Y           -   function values, array[0..N-1].
 | |
|     N           -   number of points (optional):
 | |
|                     * N>0
 | |
|                     * if given, only first N elements of X/Y are processed
 | |
|                     * if not given, automatically determined from lengths
 | |
|     M           -   number of basis functions ( = number_of_nodes), M>=4.
 | |
|     LambdaNS    -   LambdaNS>=0, regularization  constant  passed by user.
 | |
|                     It penalizes nonlinearity in the regression spline.
 | |
|                     Possible values to start from are 0.00001, 0.1, 1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     S   -   spline interpolant.
 | |
|     Rep -   Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 27.08.2019 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double lambdans, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfit': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function builds monotone cubic Hermite interpolant. This interpolant
 | |
| is monotonic in [x(0),x(n-1)] and is constant outside of this interval.
 | |
| 
 | |
| In  case  y[]  form  non-monotonic  sequence,  interpolant  is  piecewise
 | |
| monotonic.  Say, for x=(0,1,2,3,4)  and  y=(0,1,2,1,0)  interpolant  will
 | |
| monotonically grow at [0..2] and monotonically decrease at [2..4].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1]. Subroutine automatically
 | |
|                     sorts points, so caller may pass unsorted array.
 | |
|     Y           -   function values, array[0..N-1]
 | |
|     N           -   the number of points(N>=2).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant.
 | |
| 
 | |
|  -- ALGLIB PROJECT --
 | |
|      Copyright 21.06.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function builds monotone cubic Hermite interpolant. This interpolant
 | |
| is monotonic in [x(0),x(n-1)] and is constant outside of this interval.
 | |
| 
 | |
| In  case  y[]  form  non-monotonic  sequence,  interpolant  is  piecewise
 | |
| monotonic.  Say, for x=(0,1,2,3,4)  and  y=(0,1,2,1,0)  interpolant  will
 | |
| monotonically grow at [0..2] and monotonically decrease at [2..4].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1]. Subroutine automatically
 | |
|                     sorts points, so caller may pass unsorted array.
 | |
|     Y           -   function values, array[0..N-1]
 | |
|     N           -   the number of points(N>=2).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant.
 | |
| 
 | |
|  -- ALGLIB PROJECT --
 | |
|      Copyright 21.06.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dbuildmonotone(const real_1d_array &x, const real_1d_array &y, spline1dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dbuildmonotone': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| Parametric spline inteprolant: 2-dimensional curve.
 | |
| 
 | |
| You should not try to access its members directly - use PSpline2XXXXXXXX()
 | |
| functions instead.
 | |
| *************************************************************************/
 | |
| _pspline2interpolant_owner::_pspline2interpolant_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_pspline2interpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::pspline2interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline2interpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::pspline2interpolant));
 | |
|     alglib_impl::_pspline2interpolant_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _pspline2interpolant_owner::_pspline2interpolant_owner(const _pspline2interpolant_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_pspline2interpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline2interpolant copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::pspline2interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline2interpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::pspline2interpolant));
 | |
|     alglib_impl::_pspline2interpolant_init_copy(p_struct, const_cast<alglib_impl::pspline2interpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _pspline2interpolant_owner& _pspline2interpolant_owner::operator=(const _pspline2interpolant_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: pspline2interpolant assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline2interpolant assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_pspline2interpolant_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::pspline2interpolant));
 | |
|     alglib_impl::_pspline2interpolant_init_copy(p_struct, const_cast<alglib_impl::pspline2interpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _pspline2interpolant_owner::~_pspline2interpolant_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_pspline2interpolant_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::pspline2interpolant* _pspline2interpolant_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::pspline2interpolant* _pspline2interpolant_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::pspline2interpolant*>(p_struct);
 | |
| }
 | |
| pspline2interpolant::pspline2interpolant() : _pspline2interpolant_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| pspline2interpolant::pspline2interpolant(const pspline2interpolant &rhs):_pspline2interpolant_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| pspline2interpolant& pspline2interpolant::operator=(const pspline2interpolant &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _pspline2interpolant_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| pspline2interpolant::~pspline2interpolant()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Parametric spline inteprolant: 3-dimensional curve.
 | |
| 
 | |
| You should not try to access its members directly - use PSpline3XXXXXXXX()
 | |
| functions instead.
 | |
| *************************************************************************/
 | |
| _pspline3interpolant_owner::_pspline3interpolant_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_pspline3interpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::pspline3interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline3interpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::pspline3interpolant));
 | |
|     alglib_impl::_pspline3interpolant_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _pspline3interpolant_owner::_pspline3interpolant_owner(const _pspline3interpolant_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_pspline3interpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline3interpolant copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::pspline3interpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::pspline3interpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::pspline3interpolant));
 | |
|     alglib_impl::_pspline3interpolant_init_copy(p_struct, const_cast<alglib_impl::pspline3interpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _pspline3interpolant_owner& _pspline3interpolant_owner::operator=(const _pspline3interpolant_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: pspline3interpolant assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: pspline3interpolant assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_pspline3interpolant_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::pspline3interpolant));
 | |
|     alglib_impl::_pspline3interpolant_init_copy(p_struct, const_cast<alglib_impl::pspline3interpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _pspline3interpolant_owner::~_pspline3interpolant_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_pspline3interpolant_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::pspline3interpolant* _pspline3interpolant_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::pspline3interpolant* _pspline3interpolant_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::pspline3interpolant*>(p_struct);
 | |
| }
 | |
| pspline3interpolant::pspline3interpolant() : _pspline3interpolant_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| pspline3interpolant::pspline3interpolant(const pspline3interpolant &rhs):_pspline3interpolant_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| pspline3interpolant& pspline3interpolant::operator=(const pspline3interpolant &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _pspline3interpolant_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| pspline3interpolant::~pspline3interpolant()
 | |
| {
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  builds  non-periodic 2-dimensional parametric spline  which
 | |
| starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY  -   points, array[0..N-1,0..1].
 | |
|             XY[I,0:1] corresponds to the Ith point.
 | |
|             Order of points is important!
 | |
|     N   -   points count, N>=5 for Akima splines, N>=2 for other types  of
 | |
|             splines.
 | |
|     ST  -   spline type:
 | |
|             * 0     Akima spline
 | |
|             * 1     parabolically terminated Catmull-Rom spline (Tension=0)
 | |
|             * 2     parabolically terminated cubic spline
 | |
|     PT  -   parameterization type:
 | |
|             * 0     uniform
 | |
|             * 1     chord length
 | |
|             * 2     centripetal
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
| 
 | |
| 
 | |
| NOTES:
 | |
| * this function  assumes  that  there all consequent points  are distinct.
 | |
|   I.e. (x0,y0)<>(x1,y1),  (x1,y1)<>(x2,y2),  (x2,y2)<>(x3,y3)  and  so on.
 | |
|   However, non-consequent points may coincide, i.e. we can  have  (x0,y0)=
 | |
|   =(x2,y2).
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  builds  non-periodic 3-dimensional parametric spline  which
 | |
| starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]).
 | |
| 
 | |
| Same as PSpline2Build() function, but for 3D, so we  won't  duplicate  its
 | |
| description here.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3build(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  builds  periodic  2-dimensional  parametric  spline  which
 | |
| starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then
 | |
| back to (X[0],Y[0]).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY  -   points, array[0..N-1,0..1].
 | |
|             XY[I,0:1] corresponds to the Ith point.
 | |
|             XY[N-1,0:1] must be different from XY[0,0:1].
 | |
|             Order of points is important!
 | |
|     N   -   points count, N>=3 for other types of splines.
 | |
|     ST  -   spline type:
 | |
|             * 1     Catmull-Rom spline (Tension=0) with cyclic boundary conditions
 | |
|             * 2     cubic spline with cyclic boundary conditions
 | |
|     PT  -   parameterization type:
 | |
|             * 0     uniform
 | |
|             * 1     chord length
 | |
|             * 2     centripetal
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
| 
 | |
| 
 | |
| NOTES:
 | |
| * this function  assumes  that there all consequent points  are  distinct.
 | |
|   I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2),  (x2,y2)<>(x3,y3)  and  so  on.
 | |
|   However, non-consequent points may coincide, i.e. we can  have  (x0,y0)=
 | |
|   =(x2,y2).
 | |
| * last point of sequence is NOT equal to the first  point.  You  shouldn't
 | |
|   make curve "explicitly periodic" by making them equal.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline2interpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  builds  periodic  3-dimensional  parametric  spline  which
 | |
| starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1])
 | |
| and then back to (X[0],Y[0],Z[0]).
 | |
| 
 | |
| Same as PSpline2Build() function, but for 3D, so we  won't  duplicate  its
 | |
| description here.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3buildperiodic(const real_2d_array &xy, const ae_int_t n, const ae_int_t st, const ae_int_t pt, pspline3interpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function returns vector of parameter values correspoding to points.
 | |
| 
 | |
| I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P)  we
 | |
| have
 | |
|     (X[0],Y[0]) = PSpline2Calc(P,U[0]),
 | |
|     (X[1],Y[1]) = PSpline2Calc(P,U[1]),
 | |
|     (X[2],Y[2]) = PSpline2Calc(P,U[2]),
 | |
|     ...
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     N   -   array size
 | |
|     T   -   array[0..N-1]
 | |
| 
 | |
| 
 | |
| NOTES:
 | |
| * for non-periodic splines U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]=1
 | |
| * for periodic splines     U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]<1
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2parametervalues(const pspline2interpolant &p, ae_int_t &n, real_1d_array &t, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::pspline2parametervalues(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), &n, const_cast<alglib_impl::ae_vector*>(t.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function returns vector of parameter values correspoding to points.
 | |
| 
 | |
| Same as PSpline2ParameterValues(), but for 3D.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3parametervalues(const pspline3interpolant &p, ae_int_t &n, real_1d_array &t, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::pspline3parametervalues(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), &n, const_cast<alglib_impl::ae_vector*>(t.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  the value of the parametric spline for a  given
 | |
| value of parameter T
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-position
 | |
|     Y   -   Y-position
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2calc(const pspline2interpolant &p, const double t, double &x, double &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::pspline2calc(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), t, &x, &y, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  the value of the parametric spline for a  given
 | |
| value of parameter T.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-position
 | |
|     Y   -   Y-position
 | |
|     Z   -   Z-position
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3calc(const pspline3interpolant &p, const double t, double &x, double &y, double &z, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::pspline3calc(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), t, &x, &y, &z, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  tangent vector for a given value of parameter T
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X    -   X-component of tangent vector (normalized)
 | |
|     Y    -   Y-component of tangent vector (normalized)
 | |
| 
 | |
| NOTE:
 | |
|     X^2+Y^2 is either 1 (for non-zero tangent vector) or 0.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2tangent(const pspline2interpolant &p, const double t, double &x, double &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::pspline2tangent(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), t, &x, &y, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  tangent vector for a given value of parameter T
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X    -   X-component of tangent vector (normalized)
 | |
|     Y    -   Y-component of tangent vector (normalized)
 | |
|     Z    -   Z-component of tangent vector (normalized)
 | |
| 
 | |
| NOTE:
 | |
|     X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3tangent(const pspline3interpolant &p, const double t, double &x, double &y, double &z, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::pspline3tangent(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), t, &x, &y, &z, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates derivative, i.e. it returns (dX/dT,dY/dT).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-value
 | |
|     DX  -   X-derivative
 | |
|     Y   -   Y-value
 | |
|     DY  -   Y-derivative
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2diff(const pspline2interpolant &p, const double t, double &x, double &dx, double &y, double &dy, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::pspline2diff(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), t, &x, &dx, &y, &dy, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-value
 | |
|     DX  -   X-derivative
 | |
|     Y   -   Y-value
 | |
|     DY  -   Y-derivative
 | |
|     Z   -   Z-value
 | |
|     DZ  -   Z-derivative
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3diff(const pspline3interpolant &p, const double t, double &x, double &dx, double &y, double &dy, double &z, double &dz, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::pspline3diff(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), t, &x, &dx, &y, &dy, &z, &dz, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates first and second derivative with respect to T.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-value
 | |
|     DX  -   derivative
 | |
|     D2X -   second derivative
 | |
|     Y   -   Y-value
 | |
|     DY  -   derivative
 | |
|     D2Y -   second derivative
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2diff2(const pspline2interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::pspline2diff2(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), t, &x, &dx, &d2x, &y, &dy, &d2y, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates first and second derivative with respect to T.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-value
 | |
|     DX  -   derivative
 | |
|     D2X -   second derivative
 | |
|     Y   -   Y-value
 | |
|     DY  -   derivative
 | |
|     D2Y -   second derivative
 | |
|     Z   -   Z-value
 | |
|     DZ  -   derivative
 | |
|     D2Z -   second derivative
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3diff2(const pspline3interpolant &p, const double t, double &x, double &dx, double &d2x, double &y, double &dy, double &d2y, double &z, double &dz, double &d2z, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::pspline3diff2(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), t, &x, &dx, &d2x, &y, &dy, &d2y, &z, &dz, &d2z, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  arc length, i.e. length of  curve  between  t=a
 | |
| and t=b.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     A,B -   parameter values corresponding to arc ends:
 | |
|             * B>A will result in positive length returned
 | |
|             * B<A will result in negative length returned
 | |
| 
 | |
| RESULT:
 | |
|     length of arc starting at T=A and ending at T=B.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double pspline2arclength(const pspline2interpolant &p, const double a, const double b, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::pspline2arclength(const_cast<alglib_impl::pspline2interpolant*>(p.c_ptr()), a, b, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  arc length, i.e. length of  curve  between  t=a
 | |
| and t=b.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     A,B -   parameter values corresponding to arc ends:
 | |
|             * B>A will result in positive length returned
 | |
|             * B<A will result in negative length returned
 | |
| 
 | |
| RESULT:
 | |
|     length of arc starting at T=A and ending at T=B.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double pspline3arclength(const pspline3interpolant &p, const double a, const double b, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::pspline3arclength(const_cast<alglib_impl::pspline3interpolant*>(p.c_ptr()), a, b, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
 | |
| Peucker algorithm. This  function  performs PARAMETRIC fit, i.e. it can be
 | |
| used to fit curves like circles.
 | |
| 
 | |
| On  input  it  accepts dataset which describes parametric multidimensional
 | |
| curve X(t), with X being vector, and t taking values in [0,N), where N  is
 | |
| a number of points in dataset. As result, it returns reduced  dataset  X2,
 | |
| which can be used to build  parametric  curve  X2(t),  which  approximates
 | |
| X(t) with desired precision (or has specified number of sections).
 | |
| 
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array of multidimensional points:
 | |
|                 * at least N elements, leading N elements are used if more
 | |
|                   than N elements were specified
 | |
|                 * order of points is IMPORTANT because  it  is  parametric
 | |
|                   fit
 | |
|                 * each row of array is one point which has D coordinates
 | |
|     N       -   number of elements in X
 | |
|     D       -   number of dimensions (elements per row of X)
 | |
|     StopM   -   stopping condition - desired number of sections:
 | |
|                 * at most M sections are generated by this function
 | |
|                 * less than M sections can be generated if we have N<M
 | |
|                   (or some X are non-distinct).
 | |
|                 * zero StopM means that algorithm does not stop after
 | |
|                   achieving some pre-specified section count
 | |
|     StopEps -   stopping condition - desired precision:
 | |
|                 * algorithm stops after error in each section is at most Eps
 | |
|                 * zero Eps means that algorithm does not stop after
 | |
|                   achieving some pre-specified precision
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X2      -   array of corner points for piecewise approximation,
 | |
|                 has length NSections+1 or zero (for NSections=0).
 | |
|     Idx2    -   array of indexes (parameter values):
 | |
|                 * has length NSections+1 or zero (for NSections=0).
 | |
|                 * each element of Idx2 corresponds to same-numbered
 | |
|                   element of X2
 | |
|                 * each element of Idx2 is index of  corresponding  element
 | |
|                   of X2 at original array X, i.e. I-th  row  of  X2  is
 | |
|                   Idx2[I]-th row of X.
 | |
|                 * elements of Idx2 can be treated as parameter values
 | |
|                   which should be used when building new parametric curve
 | |
|                 * Idx2[0]=0, Idx2[NSections]=N-1
 | |
|     NSections-  number of sections found by algorithm, NSections<=M,
 | |
|                 NSections can be zero for degenerate datasets
 | |
|                 (N<=1 or all X[] are non-distinct).
 | |
| 
 | |
| NOTE: algorithm stops after:
 | |
|       a) dividing curve into StopM sections
 | |
|       b) achieving required precision StopEps
 | |
|       c) dividing curve into N-1 sections
 | |
|       If both StopM and StopEps are non-zero, algorithm is stopped by  the
 | |
|       FIRST criterion which is satisfied. In case both StopM  and  StopEps
 | |
|       are zero, algorithm stops because of (c).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.10.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| 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)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| 3-dimensional spline inteprolant
 | |
| *************************************************************************/
 | |
| _spline3dinterpolant_owner::_spline3dinterpolant_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline3dinterpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::spline3dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline3dinterpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline3dinterpolant));
 | |
|     alglib_impl::_spline3dinterpolant_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline3dinterpolant_owner::_spline3dinterpolant_owner(const _spline3dinterpolant_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline3dinterpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline3dinterpolant copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::spline3dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline3dinterpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline3dinterpolant));
 | |
|     alglib_impl::_spline3dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline3dinterpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline3dinterpolant_owner& _spline3dinterpolant_owner::operator=(const _spline3dinterpolant_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline3dinterpolant assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline3dinterpolant assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_spline3dinterpolant_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline3dinterpolant));
 | |
|     alglib_impl::_spline3dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline3dinterpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _spline3dinterpolant_owner::~_spline3dinterpolant_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_spline3dinterpolant_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::spline3dinterpolant* _spline3dinterpolant_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::spline3dinterpolant* _spline3dinterpolant_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::spline3dinterpolant*>(p_struct);
 | |
| }
 | |
| spline3dinterpolant::spline3dinterpolant() : _spline3dinterpolant_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| spline3dinterpolant::spline3dinterpolant(const spline3dinterpolant &rhs):_spline3dinterpolant_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| spline3dinterpolant& spline3dinterpolant::operator=(const spline3dinterpolant &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _spline3dinterpolant_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| spline3dinterpolant::~spline3dinterpolant()
 | |
| {
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates the value of the trilinear or tricubic spline at
 | |
| the given point (X,Y,Z).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   coefficients table.
 | |
|             Built by BuildBilinearSpline or BuildBicubicSpline.
 | |
|     X, Y,
 | |
|     Z   -   point
 | |
| 
 | |
| Result:
 | |
|     S(x,y,z)
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double spline3dcalc(const spline3dinterpolant &c, const double x, const double y, const double z, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::spline3dcalc(const_cast<alglib_impl::spline3dinterpolant*>(c.c_ptr()), x, y, z, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline argument.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C       -   spline interpolant
 | |
|     AX, BX  -   transformation coefficients: x = A*u + B
 | |
|     AY, BY  -   transformation coefficients: y = A*v + B
 | |
|     AZ, BZ  -   transformation coefficients: z = A*w + B
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dlintransxyz(const spline3dinterpolant &c, const double ax, const double bx, const double ay, const double by, const double az, const double bz, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline3dlintransxyz(const_cast<alglib_impl::spline3dinterpolant*>(c.c_ptr()), ax, bx, ay, by, az, bz, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     A, B-   transformation coefficients: S2(x,y) = A*S(x,y,z) + B
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dlintransf(const spline3dinterpolant &c, const double a, const double b, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline3dlintransf(const_cast<alglib_impl::spline3dinterpolant*>(c.c_ptr()), a, b, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Trilinear spline resampling
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A           -   array[0..OldXCount*OldYCount*OldZCount-1], function
 | |
|                     values at the old grid, :
 | |
|                         A[0]        x=0,y=0,z=0
 | |
|                         A[1]        x=1,y=0,z=0
 | |
|                         A[..]       ...
 | |
|                         A[..]       x=oldxcount-1,y=0,z=0
 | |
|                         A[..]       x=0,y=1,z=0
 | |
|                         A[..]       ...
 | |
|                         ...
 | |
|     OldZCount   -   old Z-count, OldZCount>1
 | |
|     OldYCount   -   old Y-count, OldYCount>1
 | |
|     OldXCount   -   old X-count, OldXCount>1
 | |
|     NewZCount   -   new Z-count, NewZCount>1
 | |
|     NewYCount   -   new Y-count, NewYCount>1
 | |
|     NewXCount   -   new X-count, NewXCount>1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     B           -   array[0..NewXCount*NewYCount*NewZCount-1], function
 | |
|                     values at the new grid:
 | |
|                         B[0]        x=0,y=0,z=0
 | |
|                         B[1]        x=1,y=0,z=0
 | |
|                         B[..]       ...
 | |
|                         B[..]       x=newxcount-1,y=0,z=0
 | |
|                         B[..]       x=0,y=1,z=0
 | |
|                         B[..]       ...
 | |
|                         ...
 | |
| 
 | |
|   -- ALGLIB routine --
 | |
|      26.04.2012
 | |
|      Copyright by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dresampletrilinear(const real_1d_array &a, const ae_int_t oldzcount, const ae_int_t oldycount, const ae_int_t oldxcount, const ae_int_t newzcount, const ae_int_t newycount, const ae_int_t newxcount, real_1d_array &b, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds trilinear vector-valued spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   spline abscissas,  array[0..N-1]
 | |
|     Y   -   spline ordinates,  array[0..M-1]
 | |
|     Z   -   spline applicates, array[0..L-1]
 | |
|     F   -   function values, array[0..M*N*L*D-1]:
 | |
|             * first D elements store D values at (X[0],Y[0],Z[0])
 | |
|             * next D elements store D values at (X[1],Y[0],Z[0])
 | |
|             * next D elements store D values at (X[2],Y[0],Z[0])
 | |
|             * ...
 | |
|             * next D elements store D values at (X[0],Y[1],Z[0])
 | |
|             * next D elements store D values at (X[1],Y[1],Z[0])
 | |
|             * next D elements store D values at (X[2],Y[1],Z[0])
 | |
|             * ...
 | |
|             * next D elements store D values at (X[0],Y[0],Z[1])
 | |
|             * next D elements store D values at (X[1],Y[0],Z[1])
 | |
|             * next D elements store D values at (X[2],Y[0],Z[1])
 | |
|             * ...
 | |
|             * general form - D function values at (X[i],Y[j]) are stored
 | |
|               at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1].
 | |
|     M,N,
 | |
|     L   -   grid size, M>=2, N>=2, L>=2
 | |
|     D   -   vector dimension, D>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dbuildtrilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &z, const ae_int_t l, const real_1d_array &f, const ae_int_t d, spline3dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates bilinear or bicubic vector-valued spline at the
 | |
| given point (X,Y,Z).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y,
 | |
|     Z   -   point
 | |
|     F   -   output buffer, possibly preallocated array. In case array size
 | |
|             is large enough to store result, it is not reallocated.  Array
 | |
|             which is too short will be reallocated
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   array[D] (or larger) which stores function values
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dcalcvbuf(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates trilinear or tricubic vector-valued spline at the
 | |
| given point (X,Y,Z).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y,
 | |
|     Z   -   point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   array[D] which stores function values.  F is out-parameter and
 | |
|             it  is  reallocated  after  call to this function. In case you
 | |
|             want  to    reuse  previously  allocated  F,   you   may   use
 | |
|             Spline2DCalcVBuf(),  which  reallocates  F only when it is too
 | |
|             small.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dcalcv(const spline3dinterpolant &c, const double x, const double y, const double z, real_1d_array &f, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine unpacks tri-dimensional spline into the coefficients table
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
| 
 | |
| Result:
 | |
|     N   -   grid size (X)
 | |
|     M   -   grid size (Y)
 | |
|     L   -   grid size (Z)
 | |
|     D   -   number of components
 | |
|     SType-  spline type. Currently, only one spline type is supported:
 | |
|             trilinear spline, as indicated by SType=1.
 | |
|     Tbl -   spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13].
 | |
|             For T=0..D-1 (component index), I = 0...N-2 (x index),
 | |
|             J=0..M-2 (y index), K=0..L-2 (z index):
 | |
|                 Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1),
 | |
| 
 | |
|                 Q-th row stores decomposition for T-th component of the
 | |
|                 vector-valued function
 | |
| 
 | |
|                 Tbl[Q,0] = X[i]
 | |
|                 Tbl[Q,1] = X[i+1]
 | |
|                 Tbl[Q,2] = Y[j]
 | |
|                 Tbl[Q,3] = Y[j+1]
 | |
|                 Tbl[Q,4] = Z[k]
 | |
|                 Tbl[Q,5] = Z[k+1]
 | |
| 
 | |
|                 Tbl[Q,6] = C000
 | |
|                 Tbl[Q,7] = C100
 | |
|                 Tbl[Q,8] = C010
 | |
|                 Tbl[Q,9] = C110
 | |
|                 Tbl[Q,10]= C001
 | |
|                 Tbl[Q,11]= C101
 | |
|                 Tbl[Q,12]= C011
 | |
|                 Tbl[Q,13]= C111
 | |
|             On each grid square spline is equals to:
 | |
|                 S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1)
 | |
|                 t = x-x[j]
 | |
|                 u = y-y[i]
 | |
|                 v = z-z[k]
 | |
| 
 | |
|             NOTE: format of Tbl is given for SType=1. Future versions of
 | |
|                   ALGLIB can use different formats for different values of
 | |
|                   SType.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dunpackv(const spline3dinterpolant &c, ae_int_t &n, ae_int_t &m, ae_int_t &l, ae_int_t &d, ae_int_t &stype, real_2d_array &tbl, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| Conversion from barycentric representation to Chebyshev basis.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   polynomial in barycentric form
 | |
|     A,B -   base interval for Chebyshev polynomials (see below)
 | |
|             A<>B
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     T   -   coefficients of Chebyshev representation;
 | |
|             P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 },
 | |
|             where Ti - I-th Chebyshev polynomial.
 | |
| 
 | |
| NOTES:
 | |
|     barycentric interpolant passed as P may be either polynomial  obtained
 | |
|     from  polynomial  interpolation/ fitting or rational function which is
 | |
|     NOT polynomial. We can't distinguish between these two cases, and this
 | |
|     algorithm just tries to work assuming that P IS a polynomial.  If not,
 | |
|     algorithm will return results, but they won't have any meaning.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbar2cheb(const barycentricinterpolant &p, const double a, const double b, real_1d_array &t, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Conversion from Chebyshev basis to barycentric representation.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     T   -   coefficients of Chebyshev representation;
 | |
|             P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N },
 | |
|             where Ti - I-th Chebyshev polynomial.
 | |
|     N   -   number of coefficients:
 | |
|             * if given, only leading N elements of T are used
 | |
|             * if not given, automatically determined from size of T
 | |
|     A,B -   base interval for Chebyshev polynomials (see above)
 | |
|             A<B
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   polynomial in barycentric form
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialcheb2bar(const real_1d_array &t, const ae_int_t n, const double a, const double b, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Conversion from Chebyshev basis to barycentric representation.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     T   -   coefficients of Chebyshev representation;
 | |
|             P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N },
 | |
|             where Ti - I-th Chebyshev polynomial.
 | |
|     N   -   number of coefficients:
 | |
|             * if given, only leading N elements of T are used
 | |
|             * if not given, automatically determined from size of T
 | |
|     A,B -   base interval for Chebyshev polynomials (see above)
 | |
|             A<B
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   polynomial in barycentric form
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void polynomialcheb2bar(const real_1d_array &t, const double a, const double b, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
| 
 | |
|     n = t.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Conversion from barycentric representation to power basis.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   polynomial in barycentric form
 | |
|     C   -   offset (see below); 0.0 is used as default value.
 | |
|     S   -   scale (see below);  1.0 is used as default value. S<>0.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
 | |
|     N   -   number of coefficients (polynomial degree plus 1)
 | |
| 
 | |
| NOTES:
 | |
| 1.  this function accepts offset and scale, which can be  set  to  improve
 | |
|     numerical properties of polynomial. For example, if P was obtained  as
 | |
|     result of interpolation on [-1,+1],  you  can  set  C=0  and  S=1  and
 | |
|     represent  P  as sum of 1, x, x^2, x^3 and so on. In most cases you it
 | |
|     is exactly what you need.
 | |
| 
 | |
|     However, if your interpolation model was built on [999,1001], you will
 | |
|     see significant growth of numerical errors when using {1, x, x^2, x^3}
 | |
|     as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3
 | |
|     will be better option. Such representation can be  obtained  by  using
 | |
|     1000.0 as offset C and 1.0 as scale S.
 | |
| 
 | |
| 2.  power basis is ill-conditioned and tricks described above can't  solve
 | |
|     this problem completely. This function  will  return  coefficients  in
 | |
|     any  case,  but  for  N>8  they  will  become unreliable. However, N's
 | |
|     less than 5 are pretty safe.
 | |
| 
 | |
| 3.  barycentric interpolant passed as P may be either polynomial  obtained
 | |
|     from  polynomial  interpolation/ fitting or rational function which is
 | |
|     NOT polynomial. We can't distinguish between these two cases, and this
 | |
|     algorithm just tries to work assuming that P IS a polynomial.  If not,
 | |
|     algorithm will return results, but they won't have any meaning.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbar2pow(const barycentricinterpolant &p, const double c, const double s, real_1d_array &a, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Conversion from barycentric representation to power basis.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   polynomial in barycentric form
 | |
|     C   -   offset (see below); 0.0 is used as default value.
 | |
|     S   -   scale (see below);  1.0 is used as default value. S<>0.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
 | |
|     N   -   number of coefficients (polynomial degree plus 1)
 | |
| 
 | |
| NOTES:
 | |
| 1.  this function accepts offset and scale, which can be  set  to  improve
 | |
|     numerical properties of polynomial. For example, if P was obtained  as
 | |
|     result of interpolation on [-1,+1],  you  can  set  C=0  and  S=1  and
 | |
|     represent  P  as sum of 1, x, x^2, x^3 and so on. In most cases you it
 | |
|     is exactly what you need.
 | |
| 
 | |
|     However, if your interpolation model was built on [999,1001], you will
 | |
|     see significant growth of numerical errors when using {1, x, x^2, x^3}
 | |
|     as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3
 | |
|     will be better option. Such representation can be  obtained  by  using
 | |
|     1000.0 as offset C and 1.0 as scale S.
 | |
| 
 | |
| 2.  power basis is ill-conditioned and tricks described above can't  solve
 | |
|     this problem completely. This function  will  return  coefficients  in
 | |
|     any  case,  but  for  N>8  they  will  become unreliable. However, N's
 | |
|     less than 5 are pretty safe.
 | |
| 
 | |
| 3.  barycentric interpolant passed as P may be either polynomial  obtained
 | |
|     from  polynomial  interpolation/ fitting or rational function which is
 | |
|     NOT polynomial. We can't distinguish between these two cases, and this
 | |
|     algorithm just tries to work assuming that P IS a polynomial.  If not,
 | |
|     algorithm will return results, but they won't have any meaning.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void polynomialbar2pow(const barycentricinterpolant &p, real_1d_array &a, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     double c;
 | |
|     double s;
 | |
| 
 | |
|     c = 0;
 | |
|     s = 1;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Conversion from power basis to barycentric representation.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
 | |
|     N   -   number of coefficients (polynomial degree plus 1)
 | |
|             * if given, only leading N elements of A are used
 | |
|             * if not given, automatically determined from size of A
 | |
|     C   -   offset (see below); 0.0 is used as default value.
 | |
|     S   -   scale (see below);  1.0 is used as default value. S<>0.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   polynomial in barycentric form
 | |
| 
 | |
| 
 | |
| NOTES:
 | |
| 1.  this function accepts offset and scale, which can be  set  to  improve
 | |
|     numerical properties of polynomial. For example, if you interpolate on
 | |
|     [-1,+1],  you  can  set C=0 and S=1 and convert from sum of 1, x, x^2,
 | |
|     x^3 and so on. In most cases you it is exactly what you need.
 | |
| 
 | |
|     However, if your interpolation model was built on [999,1001], you will
 | |
|     see significant growth of numerical errors when using {1, x, x^2, x^3}
 | |
|     as  input  basis.  Converting  from  sum  of  1, (x-1000), (x-1000)^2,
 | |
|     (x-1000)^3 will be better option (you have to specify 1000.0 as offset
 | |
|     C and 1.0 as scale S).
 | |
| 
 | |
| 2.  power basis is ill-conditioned and tricks described above can't  solve
 | |
|     this problem completely. This function  will  return barycentric model
 | |
|     in any case, but for N>8 accuracy well degrade. However, N's less than
 | |
|     5 are pretty safe.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialpow2bar(const real_1d_array &a, const ae_int_t n, const double c, const double s, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Conversion from power basis to barycentric representation.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
 | |
|     N   -   number of coefficients (polynomial degree plus 1)
 | |
|             * if given, only leading N elements of A are used
 | |
|             * if not given, automatically determined from size of A
 | |
|     C   -   offset (see below); 0.0 is used as default value.
 | |
|     S   -   scale (see below);  1.0 is used as default value. S<>0.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   polynomial in barycentric form
 | |
| 
 | |
| 
 | |
| NOTES:
 | |
| 1.  this function accepts offset and scale, which can be  set  to  improve
 | |
|     numerical properties of polynomial. For example, if you interpolate on
 | |
|     [-1,+1],  you  can  set C=0 and S=1 and convert from sum of 1, x, x^2,
 | |
|     x^3 and so on. In most cases you it is exactly what you need.
 | |
| 
 | |
|     However, if your interpolation model was built on [999,1001], you will
 | |
|     see significant growth of numerical errors when using {1, x, x^2, x^3}
 | |
|     as  input  basis.  Converting  from  sum  of  1, (x-1000), (x-1000)^2,
 | |
|     (x-1000)^3 will be better option (you have to specify 1000.0 as offset
 | |
|     C and 1.0 as scale S).
 | |
| 
 | |
| 2.  power basis is ill-conditioned and tricks described above can't  solve
 | |
|     this problem completely. This function  will  return barycentric model
 | |
|     in any case, but for N>8 accuracy well degrade. However, N's less than
 | |
|     5 are pretty safe.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void polynomialpow2bar(const real_1d_array &a, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     double c;
 | |
|     double s;
 | |
| 
 | |
|     n = a.length();
 | |
|     c = 0;
 | |
|     s = 1;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant: generation of the model on the general grid.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   abscissas, array[0..N-1]
 | |
|     Y   -   function values, array[0..N-1]
 | |
|     N   -   number of points, N>=1
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbuild(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant: generation of the model on the general grid.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   abscissas, array[0..N-1]
 | |
|     Y   -   function values, array[0..N-1]
 | |
|     N   -   number of points, N>=1
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void polynomialbuild(const real_1d_array &x, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialbuild': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant: generation of the model on equidistant grid.
 | |
| This function has O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     Y   -   function values at the nodes, array[0..N-1]
 | |
|     N   -   number of points, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 03.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant: generation of the model on equidistant grid.
 | |
| This function has O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     Y   -   function values at the nodes, array[0..N-1]
 | |
|     N   -   number of points, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 03.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void polynomialbuildeqdist(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
| 
 | |
|     n = y.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant on Chebyshev grid (first kind).
 | |
| This function has O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     Y   -   function values at the nodes, array[0..N-1],
 | |
|             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)))
 | |
|     N   -   number of points, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 03.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant on Chebyshev grid (first kind).
 | |
| This function has O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     Y   -   function values at the nodes, array[0..N-1],
 | |
|             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)))
 | |
|     N   -   number of points, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 03.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void polynomialbuildcheb1(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
| 
 | |
|     n = y.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant on Chebyshev grid (second kind).
 | |
| This function has O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     Y   -   function values at the nodes, array[0..N-1],
 | |
|             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)))
 | |
|     N   -   number of points, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 03.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, const ae_int_t n, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant on Chebyshev grid (second kind).
 | |
| This function has O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     Y   -   function values at the nodes, array[0..N-1],
 | |
|             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)))
 | |
|     N   -   number of points, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 03.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void polynomialbuildcheb2(const double a, const double b, const real_1d_array &y, barycentricinterpolant &p, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
| 
 | |
|     n = y.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Fast equidistant polynomial interpolation function with O(N) complexity
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     N   -   number of points on equidistant grid, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
|     T   -   position where P(x) is calculated
 | |
| 
 | |
| RESULT
 | |
|     value of the Lagrange interpolant at T
 | |
| 
 | |
| IMPORTANT
 | |
|     this function provides fast interface which is not overflow-safe
 | |
|     nor it is very precise.
 | |
|     the best option is to use  PolynomialBuildEqDist()/BarycentricCalc()
 | |
|     subroutines unless you are pretty sure that your data will not result
 | |
|     in overflow.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::polynomialcalceqdist(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fast equidistant polynomial interpolation function with O(N) complexity
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     N   -   number of points on equidistant grid, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
|     T   -   position where P(x) is calculated
 | |
| 
 | |
| RESULT
 | |
|     value of the Lagrange interpolant at T
 | |
| 
 | |
| IMPORTANT
 | |
|     this function provides fast interface which is not overflow-safe
 | |
|     nor it is very precise.
 | |
|     the best option is to use  PolynomialBuildEqDist()/BarycentricCalc()
 | |
|     subroutines unless you are pretty sure that your data will not result
 | |
|     in overflow.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| double polynomialcalceqdist(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
| 
 | |
|     n = f.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::polynomialcalceqdist(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Fast polynomial interpolation function on Chebyshev points (first kind)
 | |
| with O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     N   -   number of points on Chebyshev grid (first kind),
 | |
|             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))
 | |
|             for N=1 a constant model is constructed.
 | |
|     T   -   position where P(x) is calculated
 | |
| 
 | |
| RESULT
 | |
|     value of the Lagrange interpolant at T
 | |
| 
 | |
| IMPORTANT
 | |
|     this function provides fast interface which is not overflow-safe
 | |
|     nor it is very precise.
 | |
|     the best option is to use  PolIntBuildCheb1()/BarycentricCalc()
 | |
|     subroutines unless you are pretty sure that your data will not result
 | |
|     in overflow.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::polynomialcalccheb1(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fast polynomial interpolation function on Chebyshev points (first kind)
 | |
| with O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     N   -   number of points on Chebyshev grid (first kind),
 | |
|             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))
 | |
|             for N=1 a constant model is constructed.
 | |
|     T   -   position where P(x) is calculated
 | |
| 
 | |
| RESULT
 | |
|     value of the Lagrange interpolant at T
 | |
| 
 | |
| IMPORTANT
 | |
|     this function provides fast interface which is not overflow-safe
 | |
|     nor it is very precise.
 | |
|     the best option is to use  PolIntBuildCheb1()/BarycentricCalc()
 | |
|     subroutines unless you are pretty sure that your data will not result
 | |
|     in overflow.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| double polynomialcalccheb1(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
| 
 | |
|     n = f.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::polynomialcalccheb1(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Fast polynomial interpolation function on Chebyshev points (second kind)
 | |
| with O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     N   -   number of points on Chebyshev grid (second kind),
 | |
|             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))
 | |
|             for N=1 a constant model is constructed.
 | |
|     T   -   position where P(x) is calculated
 | |
| 
 | |
| RESULT
 | |
|     value of the Lagrange interpolant at T
 | |
| 
 | |
| IMPORTANT
 | |
|     this function provides fast interface which is not overflow-safe
 | |
|     nor it is very precise.
 | |
|     the best option is to use PolIntBuildCheb2()/BarycentricCalc()
 | |
|     subroutines unless you are pretty sure that your data will not result
 | |
|     in overflow.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const ae_int_t n, const double t, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::polynomialcalccheb2(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fast polynomial interpolation function on Chebyshev points (second kind)
 | |
| with O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     N   -   number of points on Chebyshev grid (second kind),
 | |
|             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))
 | |
|             for N=1 a constant model is constructed.
 | |
|     T   -   position where P(x) is calculated
 | |
| 
 | |
| RESULT
 | |
|     value of the Lagrange interpolant at T
 | |
| 
 | |
| IMPORTANT
 | |
|     this function provides fast interface which is not overflow-safe
 | |
|     nor it is very precise.
 | |
|     the best option is to use PolIntBuildCheb2()/BarycentricCalc()
 | |
|     subroutines unless you are pretty sure that your data will not result
 | |
|     in overflow.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| double polynomialcalccheb2(const double a, const double b, const real_1d_array &f, const double t, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
| 
 | |
|     n = f.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::polynomialcalccheb2(a, b, const_cast<alglib_impl::ae_vector*>(f.c_ptr()), n, t, &_alglib_env_state);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| Polynomial fitting report:
 | |
|     TaskRCond       reciprocal of task's condition number
 | |
|     RMSError        RMS error
 | |
|     AvgError        average error
 | |
|     AvgRelError     average relative error (for non-zero Y[I])
 | |
|     MaxError        maximum error
 | |
| *************************************************************************/
 | |
| _polynomialfitreport_owner::_polynomialfitreport_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_polynomialfitreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::polynomialfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialfitreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::polynomialfitreport));
 | |
|     alglib_impl::_polynomialfitreport_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _polynomialfitreport_owner::_polynomialfitreport_owner(const _polynomialfitreport_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_polynomialfitreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: polynomialfitreport copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::polynomialfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::polynomialfitreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::polynomialfitreport));
 | |
|     alglib_impl::_polynomialfitreport_init_copy(p_struct, const_cast<alglib_impl::polynomialfitreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _polynomialfitreport_owner& _polynomialfitreport_owner::operator=(const _polynomialfitreport_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: polynomialfitreport assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: polynomialfitreport assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_polynomialfitreport_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::polynomialfitreport));
 | |
|     alglib_impl::_polynomialfitreport_init_copy(p_struct, const_cast<alglib_impl::polynomialfitreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _polynomialfitreport_owner::~_polynomialfitreport_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_polynomialfitreport_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::polynomialfitreport* _polynomialfitreport_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::polynomialfitreport* _polynomialfitreport_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::polynomialfitreport*>(p_struct);
 | |
| }
 | |
| polynomialfitreport::polynomialfitreport() : _polynomialfitreport_owner() ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror)
 | |
| {
 | |
| }
 | |
| 
 | |
| polynomialfitreport::polynomialfitreport(const polynomialfitreport &rhs):_polynomialfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror)
 | |
| {
 | |
| }
 | |
| 
 | |
| polynomialfitreport& polynomialfitreport::operator=(const polynomialfitreport &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _polynomialfitreport_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| polynomialfitreport::~polynomialfitreport()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Barycentric fitting report:
 | |
|     RMSError        RMS error
 | |
|     AvgError        average error
 | |
|     AvgRelError     average relative error (for non-zero Y[I])
 | |
|     MaxError        maximum error
 | |
|     TaskRCond       reciprocal of task's condition number
 | |
| *************************************************************************/
 | |
| _barycentricfitreport_owner::_barycentricfitreport_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_barycentricfitreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::barycentricfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricfitreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::barycentricfitreport));
 | |
|     alglib_impl::_barycentricfitreport_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _barycentricfitreport_owner::_barycentricfitreport_owner(const _barycentricfitreport_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_barycentricfitreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricfitreport copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::barycentricfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::barycentricfitreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::barycentricfitreport));
 | |
|     alglib_impl::_barycentricfitreport_init_copy(p_struct, const_cast<alglib_impl::barycentricfitreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _barycentricfitreport_owner& _barycentricfitreport_owner::operator=(const _barycentricfitreport_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: barycentricfitreport assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: barycentricfitreport assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_barycentricfitreport_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::barycentricfitreport));
 | |
|     alglib_impl::_barycentricfitreport_init_copy(p_struct, const_cast<alglib_impl::barycentricfitreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _barycentricfitreport_owner::~_barycentricfitreport_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_barycentricfitreport_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::barycentricfitreport* _barycentricfitreport_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::barycentricfitreport* _barycentricfitreport_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::barycentricfitreport*>(p_struct);
 | |
| }
 | |
| barycentricfitreport::barycentricfitreport() : _barycentricfitreport_owner() ,taskrcond(p_struct->taskrcond),dbest(p_struct->dbest),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror)
 | |
| {
 | |
| }
 | |
| 
 | |
| barycentricfitreport::barycentricfitreport(const barycentricfitreport &rhs):_barycentricfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),dbest(p_struct->dbest),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror)
 | |
| {
 | |
| }
 | |
| 
 | |
| barycentricfitreport& barycentricfitreport::operator=(const barycentricfitreport &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _barycentricfitreport_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| barycentricfitreport::~barycentricfitreport()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Least squares fitting report. This structure contains informational fields
 | |
| which are set by fitting functions provided by this unit.
 | |
| 
 | |
| Different functions initialize different sets of  fields,  so  you  should
 | |
| read documentation on specific function you used in order  to  know  which
 | |
| fields are initialized.
 | |
| 
 | |
|     TaskRCond       reciprocal of task's condition number
 | |
|     IterationsCount number of internal iterations
 | |
| 
 | |
|     VarIdx          if user-supplied gradient contains errors  which  were
 | |
|                     detected by nonlinear fitter, this  field  is  set  to
 | |
|                     index  of  the  first  component  of gradient which is
 | |
|                     suspected to be spoiled by bugs.
 | |
| 
 | |
|     RMSError        RMS error
 | |
|     AvgError        average error
 | |
|     AvgRelError     average relative error (for non-zero Y[I])
 | |
|     MaxError        maximum error
 | |
| 
 | |
|     WRMSError       weighted RMS error
 | |
| 
 | |
|     CovPar          covariance matrix for parameters, filled by some solvers
 | |
|     ErrPar          vector of errors in parameters, filled by some solvers
 | |
|     ErrCurve        vector of fit errors -  variability  of  the  best-fit
 | |
|                     curve, filled by some solvers.
 | |
|     Noise           vector of per-point noise estimates, filled by
 | |
|                     some solvers.
 | |
|     R2              coefficient of determination (non-weighted, non-adjusted),
 | |
|                     filled by some solvers.
 | |
| *************************************************************************/
 | |
| _lsfitreport_owner::_lsfitreport_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_lsfitreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::lsfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::lsfitreport));
 | |
|     alglib_impl::_lsfitreport_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _lsfitreport_owner::_lsfitreport_owner(const _lsfitreport_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_lsfitreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitreport copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::lsfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::lsfitreport));
 | |
|     alglib_impl::_lsfitreport_init_copy(p_struct, const_cast<alglib_impl::lsfitreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _lsfitreport_owner& _lsfitreport_owner::operator=(const _lsfitreport_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: lsfitreport assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitreport assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_lsfitreport_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::lsfitreport));
 | |
|     alglib_impl::_lsfitreport_init_copy(p_struct, const_cast<alglib_impl::lsfitreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _lsfitreport_owner::~_lsfitreport_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_lsfitreport_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::lsfitreport* _lsfitreport_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::lsfitreport* _lsfitreport_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::lsfitreport*>(p_struct);
 | |
| }
 | |
| lsfitreport::lsfitreport() : _lsfitreport_owner() ,taskrcond(p_struct->taskrcond),iterationscount(p_struct->iterationscount),varidx(p_struct->varidx),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror),wrmserror(p_struct->wrmserror),covpar(&p_struct->covpar),errpar(&p_struct->errpar),errcurve(&p_struct->errcurve),noise(&p_struct->noise),r2(p_struct->r2)
 | |
| {
 | |
| }
 | |
| 
 | |
| lsfitreport::lsfitreport(const lsfitreport &rhs):_lsfitreport_owner(rhs) ,taskrcond(p_struct->taskrcond),iterationscount(p_struct->iterationscount),varidx(p_struct->varidx),rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),avgrelerror(p_struct->avgrelerror),maxerror(p_struct->maxerror),wrmserror(p_struct->wrmserror),covpar(&p_struct->covpar),errpar(&p_struct->errpar),errcurve(&p_struct->errcurve),noise(&p_struct->noise),r2(p_struct->r2)
 | |
| {
 | |
| }
 | |
| 
 | |
| lsfitreport& lsfitreport::operator=(const lsfitreport &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _lsfitreport_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| lsfitreport::~lsfitreport()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear fitter.
 | |
| 
 | |
| You should use ALGLIB functions to work with fitter.
 | |
| Never try to access its fields directly!
 | |
| *************************************************************************/
 | |
| _lsfitstate_owner::_lsfitstate_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_lsfitstate_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::lsfitstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitstate), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::lsfitstate));
 | |
|     alglib_impl::_lsfitstate_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _lsfitstate_owner::_lsfitstate_owner(const _lsfitstate_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_lsfitstate_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitstate copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::lsfitstate*)alglib_impl::ae_malloc(sizeof(alglib_impl::lsfitstate), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::lsfitstate));
 | |
|     alglib_impl::_lsfitstate_init_copy(p_struct, const_cast<alglib_impl::lsfitstate*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _lsfitstate_owner& _lsfitstate_owner::operator=(const _lsfitstate_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: lsfitstate assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: lsfitstate assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_lsfitstate_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::lsfitstate));
 | |
|     alglib_impl::_lsfitstate_init_copy(p_struct, const_cast<alglib_impl::lsfitstate*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _lsfitstate_owner::~_lsfitstate_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_lsfitstate_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::lsfitstate* _lsfitstate_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::lsfitstate* _lsfitstate_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::lsfitstate*>(p_struct);
 | |
| }
 | |
| lsfitstate::lsfitstate() : _lsfitstate_owner() ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),xupdated(p_struct->xupdated),c(&p_struct->c),f(p_struct->f),g(&p_struct->g),h(&p_struct->h),x(&p_struct->x)
 | |
| {
 | |
| }
 | |
| 
 | |
| lsfitstate::lsfitstate(const lsfitstate &rhs):_lsfitstate_owner(rhs) ,needf(p_struct->needf),needfg(p_struct->needfg),needfgh(p_struct->needfgh),xupdated(p_struct->xupdated),c(&p_struct->c),f(p_struct->f),g(&p_struct->g),h(&p_struct->h),x(&p_struct->x)
 | |
| {
 | |
| }
 | |
| 
 | |
| lsfitstate& lsfitstate::operator=(const lsfitstate &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _lsfitstate_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| lsfitstate::~lsfitstate()
 | |
| {
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
 | |
| Peucker algorithm, which stops after generating specified number of linear
 | |
| sections.
 | |
| 
 | |
| IMPORTANT:
 | |
| * it does NOT perform least-squares fitting; it  builds  curve,  but  this
 | |
|   curve does not minimize some least squares metric.  See  description  of
 | |
|   RDP algorithm (say, in Wikipedia) for more details on WHAT is performed.
 | |
| * this function does NOT work with parametric curves  (i.e.  curves  which
 | |
|   can be represented as {X(t),Y(t)}. It works with curves   which  can  be
 | |
|   represented as Y(X). Thus,  it  is  impossible  to  model  figures  like
 | |
|   circles  with  this  functions.
 | |
|   If  you  want  to  work  with  parametric   curves,   you   should   use
 | |
|   ParametricRDPFixed() function provided  by  "Parametric"  subpackage  of
 | |
|   "Interpolation" package.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array of X-coordinates:
 | |
|                 * at least N elements
 | |
|                 * can be unordered (points are automatically sorted)
 | |
|                 * this function may accept non-distinct X (see below for
 | |
|                   more information on handling of such inputs)
 | |
|     Y       -   array of Y-coordinates:
 | |
|                 * at least N elements
 | |
|     N       -   number of elements in X/Y
 | |
|     M       -   desired number of sections:
 | |
|                 * at most M sections are generated by this function
 | |
|                 * less than M sections can be generated if we have N<M
 | |
|                   (or some X are non-distinct).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X2      -   X-values of corner points for piecewise approximation,
 | |
|                 has length NSections+1 or zero (for NSections=0).
 | |
|     Y2      -   Y-values of corner points,
 | |
|                 has length NSections+1 or zero (for NSections=0).
 | |
|     NSections-  number of sections found by algorithm, NSections<=M,
 | |
|                 NSections can be zero for degenerate datasets
 | |
|                 (N<=1 or all X[] are non-distinct).
 | |
| 
 | |
| NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is  a  first  point  of
 | |
|       curve, (X2[NSection-1],Y2[NSection-1]) is the last point.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.10.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void 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)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
 | |
| Peucker algorithm, which stops after achieving desired precision.
 | |
| 
 | |
| IMPORTANT:
 | |
| * it performs non-least-squares fitting; it builds curve, but  this  curve
 | |
|   does not minimize some least squares  metric.  See  description  of  RDP
 | |
|   algorithm (say, in Wikipedia) for more details on WHAT is performed.
 | |
| * this function does NOT work with parametric curves  (i.e.  curves  which
 | |
|   can be represented as {X(t),Y(t)}. It works with curves   which  can  be
 | |
|   represented as Y(X). Thus, it is impossible to model figures like circles
 | |
|   with this functions.
 | |
|   If  you  want  to  work  with  parametric   curves,   you   should   use
 | |
|   ParametricRDPFixed() function provided  by  "Parametric"  subpackage  of
 | |
|   "Interpolation" package.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array of X-coordinates:
 | |
|                 * at least N elements
 | |
|                 * can be unordered (points are automatically sorted)
 | |
|                 * this function may accept non-distinct X (see below for
 | |
|                   more information on handling of such inputs)
 | |
|     Y       -   array of Y-coordinates:
 | |
|                 * at least N elements
 | |
|     N       -   number of elements in X/Y
 | |
|     Eps     -   positive number, desired precision.
 | |
| 
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X2      -   X-values of corner points for piecewise approximation,
 | |
|                 has length NSections+1 or zero (for NSections=0).
 | |
|     Y2      -   Y-values of corner points,
 | |
|                 has length NSections+1 or zero (for NSections=0).
 | |
|     NSections-  number of sections found by algorithm,
 | |
|                 NSections can be zero for degenerate datasets
 | |
|                 (N<=1 or all X[] are non-distinct).
 | |
| 
 | |
| NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is  a  first  point  of
 | |
|       curve, (X2[NSection-1],Y2[NSection-1]) is the last point.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.10.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lstfitpiecewiselinearrdp(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)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fitting by polynomials in barycentric form. This function provides  simple
 | |
| unterface for unconstrained unweighted fitting. See  PolynomialFitWC()  if
 | |
| you need constrained fitting.
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO:
 | |
|     PolynomialFitWC()
 | |
| 
 | |
| NOTES:
 | |
|     you can convert P from barycentric form  to  the  power  or  Chebyshev
 | |
|     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
 | |
|     POLINT subpackage.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     N   -   number of points, N>0
 | |
|             * if given, only leading N elements of X/Y are used
 | |
|             * if not given, automatically determined from sizes of X/Y
 | |
|     M   -   number of basis functions (= polynomial_degree + 1), M>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearW() subroutine:
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|     P   -   interpolant in barycentric form.
 | |
|     Rep -   report, same format as in LSFitLinearW() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 10.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Fitting by polynomials in barycentric form. This function provides  simple
 | |
| unterface for unconstrained unweighted fitting. See  PolynomialFitWC()  if
 | |
| you need constrained fitting.
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO:
 | |
|     PolynomialFitWC()
 | |
| 
 | |
| NOTES:
 | |
|     you can convert P from barycentric form  to  the  power  or  Chebyshev
 | |
|     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
 | |
|     POLINT subpackage.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     N   -   number of points, N>0
 | |
|             * if given, only leading N elements of X/Y are used
 | |
|             * if not given, automatically determined from sizes of X/Y
 | |
|     M   -   number of basis functions (= polynomial_degree + 1), M>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearW() subroutine:
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|     P   -   interpolant in barycentric form.
 | |
|     Rep -   report, same format as in LSFitLinearW() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 10.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void polynomialfit(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialfit': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted  fitting by polynomials in barycentric form, with constraints  on
 | |
| function values or first derivatives.
 | |
| 
 | |
| Small regularizing term is used when solving constrained tasks (to improve
 | |
| stability).
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO:
 | |
|     PolynomialFit()
 | |
| 
 | |
| NOTES:
 | |
|     you can convert P from barycentric form  to  the  power  or  Chebyshev
 | |
|     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
 | |
|     POLINT subpackage.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points, N>0.
 | |
|             * if given, only leading N elements of X/Y/W are used
 | |
|             * if not given, automatically determined from sizes of X/Y/W
 | |
|     XC  -   points where polynomial values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that P(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that P'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints, 0<=K<M.
 | |
|             K=0 means no constraints (XC/YC/DC are not used in such cases)
 | |
|     M   -   number of basis functions (= polynomial_degree + 1), M>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearW() subroutine:
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|     P   -   interpolant in barycentric form.
 | |
|     Rep -   report, same format as in LSFitLinearW() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained regression splines:
 | |
| * even simple constraints can be inconsistent, see  Wikipedia  article  on
 | |
|   this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints is NOT GUARANTEED.
 | |
| * in the one special cases, however, we can  guarantee  consistency.  This
 | |
|   case  is:  M>1  and constraints on the function values (NOT DERIVATIVES)
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 10.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted  fitting by polynomials in barycentric form, with constraints  on
 | |
| function values or first derivatives.
 | |
| 
 | |
| Small regularizing term is used when solving constrained tasks (to improve
 | |
| stability).
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO:
 | |
|     PolynomialFit()
 | |
| 
 | |
| NOTES:
 | |
|     you can convert P from barycentric form  to  the  power  or  Chebyshev
 | |
|     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
 | |
|     POLINT subpackage.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points, N>0.
 | |
|             * if given, only leading N elements of X/Y/W are used
 | |
|             * if not given, automatically determined from sizes of X/Y/W
 | |
|     XC  -   points where polynomial values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that P(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that P'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints, 0<=K<M.
 | |
|             K=0 means no constraints (XC/YC/DC are not used in such cases)
 | |
|     M   -   number of basis functions (= polynomial_degree + 1), M>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearW() subroutine:
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|     P   -   interpolant in barycentric form.
 | |
|     Rep -   report, same format as in LSFitLinearW() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained regression splines:
 | |
| * even simple constraints can be inconsistent, see  Wikipedia  article  on
 | |
|   this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints is NOT GUARANTEED.
 | |
| * in the one special cases, however, we can  guarantee  consistency.  This
 | |
|   case  is:  M>1  and constraints on the function values (NOT DERIVATIVES)
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 10.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void polynomialfitwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, barycentricinterpolant &p, polynomialfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t k;
 | |
|     if( (x.length()!=y.length()) || (x.length()!=w.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size");
 | |
|     if( (xc.length()!=yc.length()) || (xc.length()!=dc.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'polynomialfitwc': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     k = xc.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates value of four-parameter logistic (4PL)  model  at
 | |
| specified point X. 4PL model has following form:
 | |
| 
 | |
|     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   current point, X>=0:
 | |
|                 * zero X is correctly handled even for B<=0
 | |
|                 * negative X results in exception.
 | |
|     A, B, C, D- parameters of 4PL model:
 | |
|                 * A is unconstrained
 | |
|                 * B is unconstrained; zero or negative values are handled
 | |
|                   correctly.
 | |
|                 * C>0, non-positive value results in exception
 | |
|                 * D is unconstrained
 | |
| 
 | |
| RESULT:
 | |
|     model value at X
 | |
| 
 | |
| NOTE: if B=0, denominator is assumed to be equal to 2.0 even  for  zero  X
 | |
|       (strictly speaking, 0^0 is undefined).
 | |
| 
 | |
| NOTE: this function also throws exception  if  all  input  parameters  are
 | |
|       correct, but overflow was detected during calculations.
 | |
| 
 | |
| NOTE: this function performs a lot of checks;  if  you  need  really  high
 | |
|       performance, consider evaluating model  yourself,  without  checking
 | |
|       for degenerate cases.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.05.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double logisticcalc4(const double x, const double a, const double b, const double c, const double d, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::logisticcalc4(x, a, b, c, d, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates value of five-parameter logistic (5PL)  model  at
 | |
| specified point X. 5PL model has following form:
 | |
| 
 | |
|     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   current point, X>=0:
 | |
|                 * zero X is correctly handled even for B<=0
 | |
|                 * negative X results in exception.
 | |
|     A, B, C, D, G- parameters of 5PL model:
 | |
|                 * A is unconstrained
 | |
|                 * B is unconstrained; zero or negative values are handled
 | |
|                   correctly.
 | |
|                 * C>0, non-positive value results in exception
 | |
|                 * D is unconstrained
 | |
|                 * G>0, non-positive value results in exception
 | |
| 
 | |
| RESULT:
 | |
|     model value at X
 | |
| 
 | |
| NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even  for
 | |
|       zero X (strictly speaking, 0^0 is undefined).
 | |
| 
 | |
| NOTE: this function also throws exception  if  all  input  parameters  are
 | |
|       correct, but overflow was detected during calculations.
 | |
| 
 | |
| NOTE: this function performs a lot of checks;  if  you  need  really  high
 | |
|       performance, consider evaluating model  yourself,  without  checking
 | |
|       for degenerate cases.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.05.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double logisticcalc5(const double x, const double a, const double b, const double c, const double d, const double g, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::logisticcalc5(x, a, b, c, d, g, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits four-parameter logistic (4PL) model  to  data  provided
 | |
| by user. 4PL model has following form:
 | |
| 
 | |
|     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
 | |
| 
 | |
| Here:
 | |
|     * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL)
 | |
|     * B>=0
 | |
|     * C>0
 | |
| 
 | |
| IMPORTANT: output of this function is constrained in  such  way that  B>0.
 | |
|            Because 4PL model is symmetric with respect to B, there  is  no
 | |
|            need to explore  B<0.  Constraining  B  makes  algorithm easier
 | |
|            to stabilize and debug.
 | |
|            Users  who  for  some  reason  prefer to work with negative B's
 | |
|            should transform output themselves (swap A and D, replace B  by
 | |
|            -B).
 | |
| 
 | |
| 4PL fitting is implemented as follows:
 | |
| * we perform small number of restarts from random locations which helps to
 | |
|   solve problem of bad local extrema. Locations are only partially  random
 | |
|   - we use input data to determine good  initial  guess,  but  we  include
 | |
|   controlled amount of randomness.
 | |
| * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
 | |
|   parameters B and C - it allows us to find good  initial  guess  for  the
 | |
|   second stage without risk of running into "flat spot".
 | |
| * second  Levenberg-Marquardt  round  is   performed   without   excessive
 | |
|   constraints. Results from the previous round are used as initial guess.
 | |
| * after fitting is done, we compare results with best values found so far,
 | |
|   rewrite "best solution" if needed, and move to next random location.
 | |
| 
 | |
| Overall algorithm is very stable and is not prone to  bad  local  extrema.
 | |
| Furthermore, it automatically scales when input data have  very  large  or
 | |
| very small range.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N], stores X-values.
 | |
|                 MUST include only non-negative numbers  (but  may  include
 | |
|                 zero values). Can be unsorted.
 | |
|     Y       -   array[N], values to fit.
 | |
|     N       -   number of points. If N is less than  length  of  X/Y, only
 | |
|                 leading N elements are used.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     A, B, C, D- parameters of 4PL model
 | |
|     Rep     -   fitting report. This structure has many fields,  but  ONLY
 | |
|                 ONES LISTED BELOW ARE SET:
 | |
|                 * Rep.IterationsCount - number of iterations performed
 | |
|                 * Rep.RMSError - root-mean-square error
 | |
|                 * Rep.AvgError - average absolute error
 | |
|                 * Rep.AvgRelError - average relative error (calculated for
 | |
|                   non-zero Y-values)
 | |
|                 * Rep.MaxError - maximum absolute error
 | |
|                 * Rep.R2 - coefficient of determination,  R-squared.  This
 | |
|                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
 | |
|                   of nonlinear  regression  there  are  multiple  ways  to
 | |
|                   define R2, each of them giving different results).
 | |
| 
 | |
| NOTE: for stability reasons the B parameter is restricted by [1/1000,1000]
 | |
|       range. It prevents  algorithm from making trial steps  deep into the
 | |
|       area of bad parameters.
 | |
| 
 | |
| NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
 | |
|       LogisticCalc4() function.
 | |
| 
 | |
| NOTE: if you need better control over fitting process than provided by this
 | |
|       function, you may use LogisticFit45X().
 | |
| 
 | |
| NOTE: step is automatically scaled according to scale of parameters  being
 | |
|       fitted before we compare its length with EpsX. Thus,  this  function
 | |
|       can be used to fit data with very small or very large values without
 | |
|       changing EpsX.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.02.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void logisticfit4(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, double &a, double &b, double &c, double &d, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits four-parameter logistic (4PL) model  to  data  provided
 | |
| by user, with optional constraints on parameters A and D.  4PL  model  has
 | |
| following form:
 | |
| 
 | |
|     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
 | |
| 
 | |
| Here:
 | |
|     * A, D - with optional equality constraints
 | |
|     * B>=0
 | |
|     * C>0
 | |
| 
 | |
| IMPORTANT: output of this function is constrained in  such  way that  B>0.
 | |
|            Because 4PL model is symmetric with respect to B, there  is  no
 | |
|            need to explore  B<0.  Constraining  B  makes  algorithm easier
 | |
|            to stabilize and debug.
 | |
|            Users  who  for  some  reason  prefer to work with negative B's
 | |
|            should transform output themselves (swap A and D, replace B  by
 | |
|            -B).
 | |
| 
 | |
| 4PL fitting is implemented as follows:
 | |
| * we perform small number of restarts from random locations which helps to
 | |
|   solve problem of bad local extrema. Locations are only partially  random
 | |
|   - we use input data to determine good  initial  guess,  but  we  include
 | |
|   controlled amount of randomness.
 | |
| * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
 | |
|   parameters B and C - it allows us to find good  initial  guess  for  the
 | |
|   second stage without risk of running into "flat spot".
 | |
| * second  Levenberg-Marquardt  round  is   performed   without   excessive
 | |
|   constraints. Results from the previous round are used as initial guess.
 | |
| * after fitting is done, we compare results with best values found so far,
 | |
|   rewrite "best solution" if needed, and move to next random location.
 | |
| 
 | |
| Overall algorithm is very stable and is not prone to  bad  local  extrema.
 | |
| Furthermore, it automatically scales when input data have  very  large  or
 | |
| very small range.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N], stores X-values.
 | |
|                 MUST include only non-negative numbers  (but  may  include
 | |
|                 zero values). Can be unsorted.
 | |
|     Y       -   array[N], values to fit.
 | |
|     N       -   number of points. If N is less than  length  of  X/Y, only
 | |
|                 leading N elements are used.
 | |
|     CnstrLeft-  optional equality constraint for model value at the   left
 | |
|                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
 | |
|                 not need constraint on the model value at X=0 (in C++  you
 | |
|                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
 | |
|                 Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
|     CnstrRight- optional equality constraint for model value at X=infinity.
 | |
|                 Specify NAN (Not-a-Number) if you do not  need  constraint
 | |
|                 on the model value (in C++  you can pass alglib::fp_nan as
 | |
|                 parameter, in  C# it will  be Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     A, B, C, D- parameters of 4PL model
 | |
|     Rep     -   fitting report. This structure has many fields,  but  ONLY
 | |
|                 ONES LISTED BELOW ARE SET:
 | |
|                 * Rep.IterationsCount - number of iterations performed
 | |
|                 * Rep.RMSError - root-mean-square error
 | |
|                 * Rep.AvgError - average absolute error
 | |
|                 * Rep.AvgRelError - average relative error (calculated for
 | |
|                   non-zero Y-values)
 | |
|                 * Rep.MaxError - maximum absolute error
 | |
|                 * Rep.R2 - coefficient of determination,  R-squared.  This
 | |
|                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
 | |
|                   of nonlinear  regression  there  are  multiple  ways  to
 | |
|                   define R2, each of them giving different results).
 | |
| 
 | |
| NOTE: for stability reasons the B parameter is restricted by [1/1000,1000]
 | |
|       range. It prevents  algorithm from making trial steps  deep into the
 | |
|       area of bad parameters.
 | |
| 
 | |
| NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
 | |
|       LogisticCalc4() function.
 | |
| 
 | |
| NOTE: if you need better control over fitting process than provided by this
 | |
|       function, you may use LogisticFit45X().
 | |
| 
 | |
| NOTE: step is automatically scaled according to scale of parameters  being
 | |
|       fitted before we compare its length with EpsX. Thus,  this  function
 | |
|       can be used to fit data with very small or very large values without
 | |
|       changing EpsX.
 | |
| 
 | |
| EQUALITY CONSTRAINTS ON PARAMETERS
 | |
| 
 | |
| 4PL/5PL solver supports equality constraints on model values at  the  left
 | |
| boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
 | |
| completely optional and you can specify both of them, only  one  -  or  no
 | |
| constraints at all.
 | |
| 
 | |
| Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
 | |
| fitting), and CnstrRight contains right  one.  For  4PL,  left  constraint
 | |
| ALWAYS corresponds to parameter A, and right one is ALWAYS  constraint  on
 | |
| D. That's because 4PL model is normalized in such way that B>=0.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.02.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void logisticfit4ec(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, double &a, double &b, double &c, double &d, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits five-parameter logistic (5PL) model  to  data  provided
 | |
| by user. 5PL model has following form:
 | |
| 
 | |
|     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
 | |
| 
 | |
| Here:
 | |
|     * A, D - unconstrained
 | |
|     * B - unconstrained
 | |
|     * C>0
 | |
|     * G>0
 | |
| 
 | |
| IMPORTANT: unlike in  4PL  fitting,  output  of  this  function   is   NOT
 | |
|            constrained in  such  way that B is guaranteed to be  positive.
 | |
|            Furthermore,  unlike  4PL,  5PL  model  is  NOT  symmetric with
 | |
|            respect to B, so you can NOT transform model to equivalent one,
 | |
|            with B having desired sign (>0 or <0).
 | |
| 
 | |
| 5PL fitting is implemented as follows:
 | |
| * we perform small number of restarts from random locations which helps to
 | |
|   solve problem of bad local extrema. Locations are only partially  random
 | |
|   - we use input data to determine good  initial  guess,  but  we  include
 | |
|   controlled amount of randomness.
 | |
| * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
 | |
|   parameters B and C - it allows us to find good  initial  guess  for  the
 | |
|   second stage without risk of running into "flat spot".  Parameter  G  is
 | |
|   fixed at G=1.
 | |
| * second  Levenberg-Marquardt  round  is   performed   without   excessive
 | |
|   constraints on B and C, but with G still equal to 1.  Results  from  the
 | |
|   previous round are used as initial guess.
 | |
| * third Levenberg-Marquardt round relaxes constraints on G  and  tries  two
 | |
|   different models - one with B>0 and one with B<0.
 | |
| * after fitting is done, we compare results with best values found so far,
 | |
|   rewrite "best solution" if needed, and move to next random location.
 | |
| 
 | |
| Overall algorithm is very stable and is not prone to  bad  local  extrema.
 | |
| Furthermore, it automatically scales when input data have  very  large  or
 | |
| very small range.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N], stores X-values.
 | |
|                 MUST include only non-negative numbers  (but  may  include
 | |
|                 zero values). Can be unsorted.
 | |
|     Y       -   array[N], values to fit.
 | |
|     N       -   number of points. If N is less than  length  of  X/Y, only
 | |
|                 leading N elements are used.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     A,B,C,D,G-  parameters of 5PL model
 | |
|     Rep     -   fitting report. This structure has many fields,  but  ONLY
 | |
|                 ONES LISTED BELOW ARE SET:
 | |
|                 * Rep.IterationsCount - number of iterations performed
 | |
|                 * Rep.RMSError - root-mean-square error
 | |
|                 * Rep.AvgError - average absolute error
 | |
|                 * Rep.AvgRelError - average relative error (calculated for
 | |
|                   non-zero Y-values)
 | |
|                 * Rep.MaxError - maximum absolute error
 | |
|                 * Rep.R2 - coefficient of determination,  R-squared.  This
 | |
|                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
 | |
|                   of nonlinear  regression  there  are  multiple  ways  to
 | |
|                   define R2, each of them giving different results).
 | |
| 
 | |
| NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
 | |
|       range, and G is restricted by [1/10,10] range. It prevents algorithm
 | |
|       from making trial steps deep into the area of bad parameters.
 | |
| 
 | |
| NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
 | |
|       LogisticCalc5() function.
 | |
| 
 | |
| NOTE: if you need better control over fitting process than provided by this
 | |
|       function, you may use LogisticFit45X().
 | |
| 
 | |
| NOTE: step is automatically scaled according to scale of parameters  being
 | |
|       fitted before we compare its length with EpsX. Thus,  this  function
 | |
|       can be used to fit data with very small or very large values without
 | |
|       changing EpsX.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.02.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void logisticfit5(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits five-parameter logistic (5PL) model  to  data  provided
 | |
| by user, subject to optional equality constraints on parameters A  and  D.
 | |
| 5PL model has following form:
 | |
| 
 | |
|     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
 | |
| 
 | |
| Here:
 | |
|     * A, D - with optional equality constraints
 | |
|     * B - unconstrained
 | |
|     * C>0
 | |
|     * G>0
 | |
| 
 | |
| IMPORTANT: unlike in  4PL  fitting,  output  of  this  function   is   NOT
 | |
|            constrained in  such  way that B is guaranteed to be  positive.
 | |
|            Furthermore,  unlike  4PL,  5PL  model  is  NOT  symmetric with
 | |
|            respect to B, so you can NOT transform model to equivalent one,
 | |
|            with B having desired sign (>0 or <0).
 | |
| 
 | |
| 5PL fitting is implemented as follows:
 | |
| * we perform small number of restarts from random locations which helps to
 | |
|   solve problem of bad local extrema. Locations are only partially  random
 | |
|   - we use input data to determine good  initial  guess,  but  we  include
 | |
|   controlled amount of randomness.
 | |
| * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
 | |
|   parameters B and C - it allows us to find good  initial  guess  for  the
 | |
|   second stage without risk of running into "flat spot".  Parameter  G  is
 | |
|   fixed at G=1.
 | |
| * second  Levenberg-Marquardt  round  is   performed   without   excessive
 | |
|   constraints on B and C, but with G still equal to 1.  Results  from  the
 | |
|   previous round are used as initial guess.
 | |
| * third Levenberg-Marquardt round relaxes constraints on G  and  tries  two
 | |
|   different models - one with B>0 and one with B<0.
 | |
| * after fitting is done, we compare results with best values found so far,
 | |
|   rewrite "best solution" if needed, and move to next random location.
 | |
| 
 | |
| Overall algorithm is very stable and is not prone to  bad  local  extrema.
 | |
| Furthermore, it automatically scales when input data have  very  large  or
 | |
| very small range.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N], stores X-values.
 | |
|                 MUST include only non-negative numbers  (but  may  include
 | |
|                 zero values). Can be unsorted.
 | |
|     Y       -   array[N], values to fit.
 | |
|     N       -   number of points. If N is less than  length  of  X/Y, only
 | |
|                 leading N elements are used.
 | |
|     CnstrLeft-  optional equality constraint for model value at the   left
 | |
|                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
 | |
|                 not need constraint on the model value at X=0 (in C++  you
 | |
|                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
 | |
|                 Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
|     CnstrRight- optional equality constraint for model value at X=infinity.
 | |
|                 Specify NAN (Not-a-Number) if you do not  need  constraint
 | |
|                 on the model value (in C++  you can pass alglib::fp_nan as
 | |
|                 parameter, in  C# it will  be Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     A,B,C,D,G-  parameters of 5PL model
 | |
|     Rep     -   fitting report. This structure has many fields,  but  ONLY
 | |
|                 ONES LISTED BELOW ARE SET:
 | |
|                 * Rep.IterationsCount - number of iterations performed
 | |
|                 * Rep.RMSError - root-mean-square error
 | |
|                 * Rep.AvgError - average absolute error
 | |
|                 * Rep.AvgRelError - average relative error (calculated for
 | |
|                   non-zero Y-values)
 | |
|                 * Rep.MaxError - maximum absolute error
 | |
|                 * Rep.R2 - coefficient of determination,  R-squared.  This
 | |
|                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
 | |
|                   of nonlinear  regression  there  are  multiple  ways  to
 | |
|                   define R2, each of them giving different results).
 | |
| 
 | |
| NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
 | |
|       range, and G is restricted by [1/10,10] range. It prevents algorithm
 | |
|       from making trial steps deep into the area of bad parameters.
 | |
| 
 | |
| NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
 | |
|       LogisticCalc5() function.
 | |
| 
 | |
| NOTE: if you need better control over fitting process than provided by this
 | |
|       function, you may use LogisticFit45X().
 | |
| 
 | |
| NOTE: step is automatically scaled according to scale of parameters  being
 | |
|       fitted before we compare its length with EpsX. Thus,  this  function
 | |
|       can be used to fit data with very small or very large values without
 | |
|       changing EpsX.
 | |
| 
 | |
| EQUALITY CONSTRAINTS ON PARAMETERS
 | |
| 
 | |
| 5PL solver supports equality constraints on model  values  at   the   left
 | |
| boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
 | |
| completely optional and you can specify both of them, only  one  -  or  no
 | |
| constraints at all.
 | |
| 
 | |
| Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
 | |
| fitting), and CnstrRight contains right  one.
 | |
| 
 | |
| Unlike 4PL one, 5PL model is NOT symmetric with respect to  change in sign
 | |
| of B. Thus, negative B's are possible, and left constraint  may  constrain
 | |
| parameter A (for positive B's)  -  or  parameter  D  (for  negative  B's).
 | |
| Similarly changes meaning of right constraint.
 | |
| 
 | |
| You do not have to decide what parameter to  constrain  -  algorithm  will
 | |
| automatically determine correct parameters as fitting progresses. However,
 | |
| question highlighted above is important when you interpret fitting results.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.02.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void logisticfit5ec(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This is "expert" 4PL/5PL fitting function, which can be used if  you  need
 | |
| better control over fitting process than provided  by  LogisticFit4()  or
 | |
| LogisticFit5().
 | |
| 
 | |
| This function fits model of the form
 | |
| 
 | |
|     F(x|A,B,C,D)   = D+(A-D)/(1+Power(x/C,B))           (4PL model)
 | |
| 
 | |
| or
 | |
| 
 | |
|     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)    (5PL model)
 | |
| 
 | |
| Here:
 | |
|     * A, D - unconstrained
 | |
|     * B>=0 for 4PL, unconstrained for 5PL
 | |
|     * C>0
 | |
|     * G>0 (if present)
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N], stores X-values.
 | |
|                 MUST include only non-negative numbers  (but  may  include
 | |
|                 zero values). Can be unsorted.
 | |
|     Y       -   array[N], values to fit.
 | |
|     N       -   number of points. If N is less than  length  of  X/Y, only
 | |
|                 leading N elements are used.
 | |
|     CnstrLeft-  optional equality constraint for model value at the   left
 | |
|                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
 | |
|                 not need constraint on the model value at X=0 (in C++  you
 | |
|                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
 | |
|                 Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
|     CnstrRight- optional equality constraint for model value at X=infinity.
 | |
|                 Specify NAN (Not-a-Number) if you do not  need  constraint
 | |
|                 on the model value (in C++  you can pass alglib::fp_nan as
 | |
|                 parameter, in  C# it will  be Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
|     Is4PL   -   whether 4PL or 5PL models are fitted
 | |
|     LambdaV -   regularization coefficient, LambdaV>=0.
 | |
|                 Set it to zero unless you know what you are doing.
 | |
|     EpsX    -   stopping condition (step size), EpsX>=0.
 | |
|                 Zero value means that small step is automatically chosen.
 | |
|                 See notes below for more information.
 | |
|     RsCnt   -   number of repeated restarts from  random  points.  4PL/5PL
 | |
|                 models are prone to problem of bad local extrema. Utilizing
 | |
|                 multiple random restarts allows  us  to  improve algorithm
 | |
|                 convergence.
 | |
|                 RsCnt>=0.
 | |
|                 Zero value means that function automatically choose  small
 | |
|                 amount of restarts (recommended).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     A, B, C, D- parameters of 4PL model
 | |
|     G       -   parameter of 5PL model; for Is4PL=True, G=1 is returned.
 | |
|     Rep     -   fitting report. This structure has many fields,  but  ONLY
 | |
|                 ONES LISTED BELOW ARE SET:
 | |
|                 * Rep.IterationsCount - number of iterations performed
 | |
|                 * Rep.RMSError - root-mean-square error
 | |
|                 * Rep.AvgError - average absolute error
 | |
|                 * Rep.AvgRelError - average relative error (calculated for
 | |
|                   non-zero Y-values)
 | |
|                 * Rep.MaxError - maximum absolute error
 | |
|                 * Rep.R2 - coefficient of determination,  R-squared.  This
 | |
|                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
 | |
|                   of nonlinear  regression  there  are  multiple  ways  to
 | |
|                   define R2, each of them giving different results).
 | |
| 
 | |
| NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
 | |
|       range, and G is restricted by [1/10,10] range. It prevents algorithm
 | |
|       from making trial steps deep into the area of bad parameters.
 | |
| 
 | |
| NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
 | |
|       LogisticCalc5() function.
 | |
| 
 | |
| NOTE: step is automatically scaled according to scale of parameters  being
 | |
|       fitted before we compare its length with EpsX. Thus,  this  function
 | |
|       can be used to fit data with very small or very large values without
 | |
|       changing EpsX.
 | |
| 
 | |
| EQUALITY CONSTRAINTS ON PARAMETERS
 | |
| 
 | |
| 4PL/5PL solver supports equality constraints on model values at  the  left
 | |
| boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
 | |
| completely optional and you can specify both of them, only  one  -  or  no
 | |
| constraints at all.
 | |
| 
 | |
| Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
 | |
| fitting), and CnstrRight contains right  one.  For  4PL,  left  constraint
 | |
| ALWAYS corresponds to parameter A, and right one is ALWAYS  constraint  on
 | |
| D. That's because 4PL model is normalized in such way that B>=0.
 | |
| 
 | |
| For 5PL model things are different. Unlike  4PL  one,  5PL  model  is  NOT
 | |
| symmetric with respect to  change  in  sign  of  B. Thus, negative B's are
 | |
| possible, and left constraint may constrain parameter A (for positive B's)
 | |
| - or parameter D (for negative B's). Similarly changes  meaning  of  right
 | |
| constraint.
 | |
| 
 | |
| You do not have to decide what parameter to  constrain  -  algorithm  will
 | |
| automatically determine correct parameters as fitting progresses. However,
 | |
| question highlighted above is important when you interpret fitting results.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.02.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void logisticfit45x(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const double cnstrleft, const double cnstrright, const bool is4pl, const double lambdav, const double epsx, const ae_int_t rscnt, double &a, double &b, double &c, double &d, double &g, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Weghted rational least  squares  fitting  using  Floater-Hormann  rational
 | |
| functions  with  optimal  D  chosen  from  [0,9],  with  constraints   and
 | |
| individual weights.
 | |
| 
 | |
| Equidistant  grid  with M node on [min(x),max(x)]  is  used to build basis
 | |
| functions. Different values of D are tried, optimal D (least WEIGHTED root
 | |
| mean square error) is chosen.  Task  is  linear,  so  linear least squares
 | |
| solver  is  used.  Complexity  of  this  computational  scheme is O(N*M^2)
 | |
| (mostly dominated by the least squares solver).
 | |
| 
 | |
| SEE ALSO
 | |
| * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual
 | |
|   weights and constraints.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points, N>0.
 | |
|     XC  -   points where function values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that S(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that S'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints, 0<=K<M.
 | |
|             K=0 means no constraints (XC/YC/DC are not used in such cases)
 | |
|     M   -   number of basis functions ( = number_of_nodes), M>=2.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearWC() subroutine.
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|                         -1 means another errors in parameters passed
 | |
|                            (N<=0, for example)
 | |
|     B   -   barycentric interpolant.
 | |
|     Rep -   report, same format as in LSFitLinearWC() subroutine.
 | |
|             Following fields are set:
 | |
|             * DBest         best value of the D parameter
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroutine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained barycentric interpolants:
 | |
| * excessive  constraints  can  be  inconsistent.   Floater-Hormann   basis
 | |
|   functions aren't as flexible as splines (although they are very smooth).
 | |
| * the more evenly constraints are spread across [min(x),max(x)],  the more
 | |
|   chances that they will be consistent
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints IS NOT GUARANTEED.
 | |
| * in the several special cases, however, we CAN guarantee consistency.
 | |
| * one of this cases is constraints on the function  VALUES at the interval
 | |
|   boundaries. Note that consustency of the  constraints  on  the  function
 | |
|   DERIVATIVES is NOT guaranteed (you can use in such cases  cubic  splines
 | |
|   which are more flexible).
 | |
| * another  special  case  is ONE constraint on the function value (OR, but
 | |
|   not AND, derivative) anywhere in the interval
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricfitfloaterhormannwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Rational least squares fitting using  Floater-Hormann  rational  functions
 | |
| with optimal D chosen from [0,9].
 | |
| 
 | |
| Equidistant  grid  with M node on [min(x),max(x)]  is  used to build basis
 | |
| functions. Different values of D are tried, optimal  D  (least  root  mean
 | |
| square error) is chosen.  Task  is  linear, so linear least squares solver
 | |
| is used. Complexity  of  this  computational  scheme is  O(N*M^2)  (mostly
 | |
| dominated by the least squares solver).
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     N   -   number of points, N>0.
 | |
|     M   -   number of basis functions ( = number_of_nodes), M>=2.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearWC() subroutine.
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|     B   -   barycentric interpolant.
 | |
|     Rep -   report, same format as in LSFitLinearWC() subroutine.
 | |
|             Following fields are set:
 | |
|             * DBest         best value of the D parameter
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricfitfloaterhormann(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, barycentricinterpolant &b, barycentricfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted fitting by cubic  spline,  with constraints on function values or
 | |
| derivatives.
 | |
| 
 | |
| Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is  used to build
 | |
| basis functions. Basis functions are cubic splines with continuous  second
 | |
| derivatives  and  non-fixed first  derivatives  at  interval  ends.  Small
 | |
| regularizing term is used  when  solving  constrained  tasks  (to  improve
 | |
| stability).
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO
 | |
|     Spline1DFitHermiteWC()  -   fitting by Hermite splines (more flexible,
 | |
|                                 less smooth)
 | |
|     Spline1DFitCubic()      -   "lightweight" fitting  by  cubic  splines,
 | |
|                                 without invididual weights and constraints
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points (optional):
 | |
|             * N>0
 | |
|             * if given, only first N elements of X/Y/W are processed
 | |
|             * if not given, automatically determined from X/Y/W sizes
 | |
|     XC  -   points where spline values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that S(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that S'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints (optional):
 | |
|             * 0<=K<M.
 | |
|             * K=0 means no constraints (XC/YC/DC are not used)
 | |
|             * if given, only first K elements of XC/YC/DC are used
 | |
|             * if not given, automatically determined from XC/YC/DC
 | |
|     M   -   number of basis functions ( = number_of_nodes+2), M>=4.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearWC() subroutine.
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|     S   -   spline interpolant.
 | |
|     Rep -   report, same format as in LSFitLinearWC() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained regression splines:
 | |
| * excessive constraints can be inconsistent. Splines are  piecewise  cubic
 | |
|   functions, and it is easy to create an example, where  large  number  of
 | |
|   constraints  concentrated  in  small  area will result in inconsistency.
 | |
|   Just because spline is not flexible enough to satisfy all of  them.  And
 | |
|   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
 | |
|   consistent.
 | |
| * the more evenly constraints are spread across [min(x),max(x)],  the more
 | |
|   chances that they will be consistent
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints IS NOT GUARANTEED.
 | |
| * in the several special cases, however, we CAN guarantee consistency.
 | |
| * one of this cases is constraints  on  the  function  values  AND/OR  its
 | |
|   derivatives at the interval boundaries.
 | |
| * another  special  case  is ONE constraint on the function value (OR, but
 | |
|   not AND, derivative) anywhere in the interval
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted fitting by cubic  spline,  with constraints on function values or
 | |
| derivatives.
 | |
| 
 | |
| Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is  used to build
 | |
| basis functions. Basis functions are cubic splines with continuous  second
 | |
| derivatives  and  non-fixed first  derivatives  at  interval  ends.  Small
 | |
| regularizing term is used  when  solving  constrained  tasks  (to  improve
 | |
| stability).
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO
 | |
|     Spline1DFitHermiteWC()  -   fitting by Hermite splines (more flexible,
 | |
|                                 less smooth)
 | |
|     Spline1DFitCubic()      -   "lightweight" fitting  by  cubic  splines,
 | |
|                                 without invididual weights and constraints
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points (optional):
 | |
|             * N>0
 | |
|             * if given, only first N elements of X/Y/W are processed
 | |
|             * if not given, automatically determined from X/Y/W sizes
 | |
|     XC  -   points where spline values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that S(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that S'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints (optional):
 | |
|             * 0<=K<M.
 | |
|             * K=0 means no constraints (XC/YC/DC are not used)
 | |
|             * if given, only first K elements of XC/YC/DC are used
 | |
|             * if not given, automatically determined from XC/YC/DC
 | |
|     M   -   number of basis functions ( = number_of_nodes+2), M>=4.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearWC() subroutine.
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|     S   -   spline interpolant.
 | |
|     Rep -   report, same format as in LSFitLinearWC() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained regression splines:
 | |
| * excessive constraints can be inconsistent. Splines are  piecewise  cubic
 | |
|   functions, and it is easy to create an example, where  large  number  of
 | |
|   constraints  concentrated  in  small  area will result in inconsistency.
 | |
|   Just because spline is not flexible enough to satisfy all of  them.  And
 | |
|   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
 | |
|   consistent.
 | |
| * the more evenly constraints are spread across [min(x),max(x)],  the more
 | |
|   chances that they will be consistent
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints IS NOT GUARANTEED.
 | |
| * in the several special cases, however, we CAN guarantee consistency.
 | |
| * one of this cases is constraints  on  the  function  values  AND/OR  its
 | |
|   derivatives at the interval boundaries.
 | |
| * another  special  case  is ONE constraint on the function value (OR, but
 | |
|   not AND, derivative) anywhere in the interval
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dfitcubicwc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t k;
 | |
|     if( (x.length()!=y.length()) || (x.length()!=w.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size");
 | |
|     if( (xc.length()!=yc.length()) || (xc.length()!=dc.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitcubicwc': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     k = xc.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted  fitting  by Hermite spline,  with constraints on function values
 | |
| or first derivatives.
 | |
| 
 | |
| Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is  used  to  build
 | |
| basis functions. Basis functions are Hermite splines.  Small  regularizing
 | |
| term is used when solving constrained tasks (to improve stability).
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO
 | |
|     Spline1DFitCubicWC()    -   fitting by Cubic splines (less flexible,
 | |
|                                 more smooth)
 | |
|     Spline1DFitHermite()    -   "lightweight" Hermite fitting, without
 | |
|                                 invididual weights and constraints
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points (optional):
 | |
|             * N>0
 | |
|             * if given, only first N elements of X/Y/W are processed
 | |
|             * if not given, automatically determined from X/Y/W sizes
 | |
|     XC  -   points where spline values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that S(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that S'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints (optional):
 | |
|             * 0<=K<M.
 | |
|             * K=0 means no constraints (XC/YC/DC are not used)
 | |
|             * if given, only first K elements of XC/YC/DC are used
 | |
|             * if not given, automatically determined from XC/YC/DC
 | |
|     M   -   number of basis functions (= 2 * number of nodes),
 | |
|             M>=4,
 | |
|             M IS EVEN!
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearW() subroutine:
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|                         -2 means odd M was passed (which is not supported)
 | |
|                         -1 means another errors in parameters passed
 | |
|                            (N<=0, for example)
 | |
|     S   -   spline interpolant.
 | |
|     Rep -   report, same format as in LSFitLinearW() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine supports only even M's
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained regression splines:
 | |
| * excessive constraints can be inconsistent. Splines are  piecewise  cubic
 | |
|   functions, and it is easy to create an example, where  large  number  of
 | |
|   constraints  concentrated  in  small  area will result in inconsistency.
 | |
|   Just because spline is not flexible enough to satisfy all of  them.  And
 | |
|   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
 | |
|   consistent.
 | |
| * the more evenly constraints are spread across [min(x),max(x)],  the more
 | |
|   chances that they will be consistent
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints is NOT GUARANTEED.
 | |
| * in the several special cases, however, we can guarantee consistency.
 | |
| * one of this cases is  M>=4  and   constraints  on   the  function  value
 | |
|   (AND/OR its derivative) at the interval boundaries.
 | |
| * another special case is M>=4  and  ONE  constraint on the function value
 | |
|   (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)]
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t k, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted  fitting  by Hermite spline,  with constraints on function values
 | |
| or first derivatives.
 | |
| 
 | |
| Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is  used  to  build
 | |
| basis functions. Basis functions are Hermite splines.  Small  regularizing
 | |
| term is used when solving constrained tasks (to improve stability).
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO
 | |
|     Spline1DFitCubicWC()    -   fitting by Cubic splines (less flexible,
 | |
|                                 more smooth)
 | |
|     Spline1DFitHermite()    -   "lightweight" Hermite fitting, without
 | |
|                                 invididual weights and constraints
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points (optional):
 | |
|             * N>0
 | |
|             * if given, only first N elements of X/Y/W are processed
 | |
|             * if not given, automatically determined from X/Y/W sizes
 | |
|     XC  -   points where spline values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that S(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that S'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints (optional):
 | |
|             * 0<=K<M.
 | |
|             * K=0 means no constraints (XC/YC/DC are not used)
 | |
|             * if given, only first K elements of XC/YC/DC are used
 | |
|             * if not given, automatically determined from XC/YC/DC
 | |
|     M   -   number of basis functions (= 2 * number of nodes),
 | |
|             M>=4,
 | |
|             M IS EVEN!
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearW() subroutine:
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|                         -2 means odd M was passed (which is not supported)
 | |
|                         -1 means another errors in parameters passed
 | |
|                            (N<=0, for example)
 | |
|     S   -   spline interpolant.
 | |
|     Rep -   report, same format as in LSFitLinearW() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine supports only even M's
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained regression splines:
 | |
| * excessive constraints can be inconsistent. Splines are  piecewise  cubic
 | |
|   functions, and it is easy to create an example, where  large  number  of
 | |
|   constraints  concentrated  in  small  area will result in inconsistency.
 | |
|   Just because spline is not flexible enough to satisfy all of  them.  And
 | |
|   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
 | |
|   consistent.
 | |
| * the more evenly constraints are spread across [min(x),max(x)],  the more
 | |
|   chances that they will be consistent
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints is NOT GUARANTEED.
 | |
| * in the several special cases, however, we can guarantee consistency.
 | |
| * one of this cases is  M>=4  and   constraints  on   the  function  value
 | |
|   (AND/OR its derivative) at the interval boundaries.
 | |
| * another special case is M>=4  and  ONE  constraint on the function value
 | |
|   (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)]
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dfithermitewc(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &xc, const real_1d_array &yc, const integer_1d_array &dc, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t k;
 | |
|     if( (x.length()!=y.length()) || (x.length()!=w.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size");
 | |
|     if( (xc.length()!=yc.length()) || (xc.length()!=dc.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfithermitewc': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     k = xc.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Least squares fitting by cubic spline.
 | |
| 
 | |
| This subroutine is "lightweight" alternative for more complex and feature-
 | |
| rich Spline1DFitCubicWC().  See  Spline1DFitCubicWC() for more information
 | |
| about subroutine parameters (we don't duplicate it here because of length)
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Least squares fitting by cubic spline.
 | |
| 
 | |
| This subroutine is "lightweight" alternative for more complex and feature-
 | |
| rich Spline1DFitCubicWC().  See  Spline1DFitCubicWC() for more information
 | |
| about subroutine parameters (we don't duplicate it here because of length)
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dfitcubic(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitcubic': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Least squares fitting by Hermite spline.
 | |
| 
 | |
| This subroutine is "lightweight" alternative for more complex and feature-
 | |
| rich Spline1DFitHermiteWC().  See Spline1DFitHermiteWC()  description  for
 | |
| more information about subroutine parameters (we don't duplicate  it  here
 | |
| because of length).
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Least squares fitting by Hermite spline.
 | |
| 
 | |
| This subroutine is "lightweight" alternative for more complex and feature-
 | |
| rich Spline1DFitHermiteWC().  See Spline1DFitHermiteWC()  description  for
 | |
| more information about subroutine parameters (we don't duplicate  it  here
 | |
| because of length).
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dfithermite(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfithermite': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted linear least squares fitting.
 | |
| 
 | |
| QR decomposition is used to reduce task to MxM, then triangular solver  or
 | |
| SVD-based solver is used depending on condition number of the  system.  It
 | |
| allows to maximize speed and retain decent accuracy.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     W       -   array[0..N-1]  Weights  corresponding to function  values.
 | |
|                 Each summand in square  sum  of  approximation  deviations
 | |
|                 from  given  values  is  multiplied  by  the   square   of
 | |
|                 corresponding weight.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I, J] - value of J-th basis function in I-th point.
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 * -1    incorrect N/M were specified
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * Rep.TaskRCond     reciprocal of condition number
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| ERRORS IN PARAMETERS
 | |
| 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
| 
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
| 
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
| 
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitlinearw(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted linear least squares fitting.
 | |
| 
 | |
| QR decomposition is used to reduce task to MxM, then triangular solver  or
 | |
| SVD-based solver is used depending on condition number of the  system.  It
 | |
| allows to maximize speed and retain decent accuracy.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     W       -   array[0..N-1]  Weights  corresponding to function  values.
 | |
|                 Each summand in square  sum  of  approximation  deviations
 | |
|                 from  given  values  is  multiplied  by  the   square   of
 | |
|                 corresponding weight.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I, J] - value of J-th basis function in I-th point.
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 * -1    incorrect N/M were specified
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * Rep.TaskRCond     reciprocal of condition number
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| ERRORS IN PARAMETERS
 | |
| 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
| 
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
| 
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
| 
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| 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)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearw': looks like one of arguments has wrong size");
 | |
|     n = y.length();
 | |
|     m = fmatrix.cols();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted constained linear least squares fitting.
 | |
| 
 | |
| This  is  variation  of LSFitLinearW(), which searchs for min|A*x=b| given
 | |
| that  K  additional  constaints  C*x=bc are satisfied. It reduces original
 | |
| task to modified one: min|B*y-d| WITHOUT constraints,  then LSFitLinearW()
 | |
| is called.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     W       -   array[0..N-1]  Weights  corresponding to function  values.
 | |
|                 Each summand in square  sum  of  approximation  deviations
 | |
|                 from  given  values  is  multiplied  by  the   square   of
 | |
|                 corresponding weight.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I,J] - value of J-th basis function in I-th point.
 | |
|     CMatrix -   a table of constaints, array[0..K-1,0..M].
 | |
|                 I-th row of CMatrix corresponds to I-th linear constraint:
 | |
|                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
|     K       -   number of constraints, 0 <= K < M
 | |
|                 K=0 corresponds to absence of constraints.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 * -3    either   too   many  constraints  (M   or   more),
 | |
|                         degenerate  constraints   (some   constraints  are
 | |
|                         repetead twice) or inconsistent  constraints  were
 | |
|                         specified.
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| ERRORS IN PARAMETERS
 | |
| 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
 | |
|             account boundary/linear constraints! Presence  of  constraints
 | |
|             changes distribution of errors, but there is no  easy  way  to
 | |
|             account for constraints when you calculate covariance matrix.
 | |
| 
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
| 
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
| 
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
| 
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 07.09.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted constained linear least squares fitting.
 | |
| 
 | |
| This  is  variation  of LSFitLinearW(), which searchs for min|A*x=b| given
 | |
| that  K  additional  constaints  C*x=bc are satisfied. It reduces original
 | |
| task to modified one: min|B*y-d| WITHOUT constraints,  then LSFitLinearW()
 | |
| is called.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     W       -   array[0..N-1]  Weights  corresponding to function  values.
 | |
|                 Each summand in square  sum  of  approximation  deviations
 | |
|                 from  given  values  is  multiplied  by  the   square   of
 | |
|                 corresponding weight.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I,J] - value of J-th basis function in I-th point.
 | |
|     CMatrix -   a table of constaints, array[0..K-1,0..M].
 | |
|                 I-th row of CMatrix corresponds to I-th linear constraint:
 | |
|                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
|     K       -   number of constraints, 0 <= K < M
 | |
|                 K=0 corresponds to absence of constraints.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 * -3    either   too   many  constraints  (M   or   more),
 | |
|                         degenerate  constraints   (some   constraints  are
 | |
|                         repetead twice) or inconsistent  constraints  were
 | |
|                         specified.
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| ERRORS IN PARAMETERS
 | |
| 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
 | |
|             account boundary/linear constraints! Presence  of  constraints
 | |
|             changes distribution of errors, but there is no  easy  way  to
 | |
|             account for constraints when you calculate covariance matrix.
 | |
| 
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
| 
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
| 
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
| 
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 07.09.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void lsfitlinearwc(const real_1d_array &y, const real_1d_array &w, const real_2d_array &fmatrix, const real_2d_array &cmatrix, ae_int_t &info, real_1d_array &c, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     ae_int_t k;
 | |
|     if( (y.length()!=w.length()) || (y.length()!=fmatrix.rows()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size");
 | |
|     if( (fmatrix.cols()!=cmatrix.cols()-1))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearwc': looks like one of arguments has wrong size");
 | |
|     n = y.length();
 | |
|     m = fmatrix.cols();
 | |
|     k = cmatrix.rows();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Linear least squares fitting.
 | |
| 
 | |
| QR decomposition is used to reduce task to MxM, then triangular solver  or
 | |
| SVD-based solver is used depending on condition number of the  system.  It
 | |
| allows to maximize speed and retain decent accuracy.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I, J] - value of J-th basis function in I-th point.
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * Rep.TaskRCond     reciprocal of condition number
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| ERRORS IN PARAMETERS
 | |
| 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
| 
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
| 
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
| 
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitlinear(const real_1d_array &y, const real_2d_array &fmatrix, const ae_int_t n, const ae_int_t m, ae_int_t &info, real_1d_array &c, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Linear least squares fitting.
 | |
| 
 | |
| QR decomposition is used to reduce task to MxM, then triangular solver  or
 | |
| SVD-based solver is used depending on condition number of the  system.  It
 | |
| allows to maximize speed and retain decent accuracy.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I, J] - value of J-th basis function in I-th point.
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * Rep.TaskRCond     reciprocal of condition number
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| ERRORS IN PARAMETERS
 | |
| 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
| 
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
| 
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
| 
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| 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)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     if( (y.length()!=fmatrix.rows()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinear': looks like one of arguments has wrong size");
 | |
|     n = y.length();
 | |
|     m = fmatrix.cols();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Constained linear least squares fitting.
 | |
| 
 | |
| This  is  variation  of LSFitLinear(),  which searchs for min|A*x=b| given
 | |
| that  K  additional  constaints  C*x=bc are satisfied. It reduces original
 | |
| task to modified one: min|B*y-d| WITHOUT constraints,  then  LSFitLinear()
 | |
| is called.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I,J] - value of J-th basis function in I-th point.
 | |
|     CMatrix -   a table of constaints, array[0..K-1,0..M].
 | |
|                 I-th row of CMatrix corresponds to I-th linear constraint:
 | |
|                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
|     K       -   number of constraints, 0 <= K < M
 | |
|                 K=0 corresponds to absence of constraints.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 * -3    either   too   many  constraints  (M   or   more),
 | |
|                         degenerate  constraints   (some   constraints  are
 | |
|                         repetead twice) or inconsistent  constraints  were
 | |
|                         specified.
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| ERRORS IN PARAMETERS
 | |
| 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
 | |
|             account boundary/linear constraints! Presence  of  constraints
 | |
|             changes distribution of errors, but there is no  easy  way  to
 | |
|             account for constraints when you calculate covariance matrix.
 | |
| 
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
| 
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
| 
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
| 
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 07.09.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitlinearc(const real_1d_array &y, const real_2d_array &fmatrix, const real_2d_array &cmatrix, const ae_int_t n, const ae_int_t m, const ae_int_t k, ae_int_t &info, real_1d_array &c, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Constained linear least squares fitting.
 | |
| 
 | |
| This  is  variation  of LSFitLinear(),  which searchs for min|A*x=b| given
 | |
| that  K  additional  constaints  C*x=bc are satisfied. It reduces original
 | |
| task to modified one: min|B*y-d| WITHOUT constraints,  then  LSFitLinear()
 | |
| is called.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I,J] - value of J-th basis function in I-th point.
 | |
|     CMatrix -   a table of constaints, array[0..K-1,0..M].
 | |
|                 I-th row of CMatrix corresponds to I-th linear constraint:
 | |
|                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
|     K       -   number of constraints, 0 <= K < M
 | |
|                 K=0 corresponds to absence of constraints.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 * -3    either   too   many  constraints  (M   or   more),
 | |
|                         degenerate  constraints   (some   constraints  are
 | |
|                         repetead twice) or inconsistent  constraints  were
 | |
|                         specified.
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| ERRORS IN PARAMETERS
 | |
| 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
 | |
|             account boundary/linear constraints! Presence  of  constraints
 | |
|             changes distribution of errors, but there is no  easy  way  to
 | |
|             account for constraints when you calculate covariance matrix.
 | |
| 
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
| 
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
| 
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
| 
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 07.09.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| 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)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     ae_int_t k;
 | |
|     if( (y.length()!=fmatrix.rows()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size");
 | |
|     if( (fmatrix.cols()!=cmatrix.cols()-1))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitlinearc': looks like one of arguments has wrong size");
 | |
|     n = y.length();
 | |
|     m = fmatrix.cols();
 | |
|     k = cmatrix.rows();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted nonlinear least squares fitting using function values only.
 | |
| 
 | |
| Combination of numerical differentiation and secant updates is used to
 | |
| obtain function Jacobian.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     W       -   weights, array[0..N-1]
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     DiffStep-   numerical differentiation step;
 | |
|                 should not be very small or large;
 | |
|                 large = loss of accuracy
 | |
|                 small = growth of round-off errors
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 18.10.2008 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted nonlinear least squares fitting using function values only.
 | |
| 
 | |
| Combination of numerical differentiation and secant updates is used to
 | |
| obtain function Jacobian.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     W       -   weights, array[0..N-1]
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     DiffStep-   numerical differentiation step;
 | |
|                 should not be very small or large;
 | |
|                 large = loss of accuracy
 | |
|                 small = growth of round-off errors
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 18.10.2008 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void lsfitcreatewf(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const double diffstep, lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     ae_int_t k;
 | |
|     if( (x.rows()!=y.length()) || (x.rows()!=w.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatewf': looks like one of arguments has wrong size");
 | |
|     n = x.rows();
 | |
|     m = x.cols();
 | |
|     k = c.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting using function values only.
 | |
| 
 | |
| Combination of numerical differentiation and secant updates is used to
 | |
| obtain function Jacobian.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     DiffStep-   numerical differentiation step;
 | |
|                 should not be very small or large;
 | |
|                 large = loss of accuracy
 | |
|                 small = growth of round-off errors
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 18.10.2008 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const double diffstep, lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting using function values only.
 | |
| 
 | |
| Combination of numerical differentiation and secant updates is used to
 | |
| obtain function Jacobian.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     DiffStep-   numerical differentiation step;
 | |
|                 should not be very small or large;
 | |
|                 large = loss of accuracy
 | |
|                 small = growth of round-off errors
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 18.10.2008 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void lsfitcreatef(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const double diffstep, lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     ae_int_t k;
 | |
|     if( (x.rows()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatef': looks like one of arguments has wrong size");
 | |
|     n = x.rows();
 | |
|     m = x.cols();
 | |
|     k = c.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted nonlinear least squares fitting using gradient only.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]) and its gradient.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     W       -   weights, array[0..N-1]
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     CheapFG -   boolean flag, which is:
 | |
|                 * True  if both function and gradient calculation complexity
 | |
|                         are less than O(M^2).  An improved  algorithm  can
 | |
|                         be  used  which corresponds  to  FGJ  scheme  from
 | |
|                         MINLM unit.
 | |
|                 * False otherwise.
 | |
|                         Standard Jacibian-bases  Levenberg-Marquardt  algo
 | |
|                         will be used (FJ scheme).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
| See also:
 | |
|     LSFitResults
 | |
|     LSFitCreateFG (fitting without weights)
 | |
|     LSFitCreateWFGH (fitting using Hessian)
 | |
|     LSFitCreateFGH (fitting using Hessian, without weights)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const bool cheapfg, lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted nonlinear least squares fitting using gradient only.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]) and its gradient.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     W       -   weights, array[0..N-1]
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     CheapFG -   boolean flag, which is:
 | |
|                 * True  if both function and gradient calculation complexity
 | |
|                         are less than O(M^2).  An improved  algorithm  can
 | |
|                         be  used  which corresponds  to  FGJ  scheme  from
 | |
|                         MINLM unit.
 | |
|                 * False otherwise.
 | |
|                         Standard Jacibian-bases  Levenberg-Marquardt  algo
 | |
|                         will be used (FJ scheme).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
| See also:
 | |
|     LSFitResults
 | |
|     LSFitCreateFG (fitting without weights)
 | |
|     LSFitCreateWFGH (fitting using Hessian)
 | |
|     LSFitCreateFGH (fitting using Hessian, without weights)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void lsfitcreatewfg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const bool cheapfg, lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     ae_int_t k;
 | |
|     if( (x.rows()!=y.length()) || (x.rows()!=w.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatewfg': looks like one of arguments has wrong size");
 | |
|     n = x.rows();
 | |
|     m = x.cols();
 | |
|     k = c.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting using gradient only, without individual
 | |
| weights.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]) and its gradient.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     CheapFG -   boolean flag, which is:
 | |
|                 * True  if both function and gradient calculation complexity
 | |
|                         are less than O(M^2).  An improved  algorithm  can
 | |
|                         be  used  which corresponds  to  FGJ  scheme  from
 | |
|                         MINLM unit.
 | |
|                 * False otherwise.
 | |
|                         Standard Jacibian-bases  Levenberg-Marquardt  algo
 | |
|                         will be used (FJ scheme).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatefg(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, const bool cheapfg, lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting using gradient only, without individual
 | |
| weights.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]) and its gradient.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     CheapFG -   boolean flag, which is:
 | |
|                 * True  if both function and gradient calculation complexity
 | |
|                         are less than O(M^2).  An improved  algorithm  can
 | |
|                         be  used  which corresponds  to  FGJ  scheme  from
 | |
|                         MINLM unit.
 | |
|                 * False otherwise.
 | |
|                         Standard Jacibian-bases  Levenberg-Marquardt  algo
 | |
|                         will be used (FJ scheme).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| 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)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     ae_int_t k;
 | |
|     if( (x.rows()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatefg': looks like one of arguments has wrong size");
 | |
|     n = x.rows();
 | |
|     m = x.cols();
 | |
|     k = c.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted nonlinear least squares fitting using gradient/Hessian.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses f(c,x[i]), its gradient and its Hessian.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     W       -   weights, array[0..N-1]
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatewfgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &w, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted nonlinear least squares fitting using gradient/Hessian.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses f(c,x[i]), its gradient and its Hessian.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     W       -   weights, array[0..N-1]
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| 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)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     ae_int_t k;
 | |
|     if( (x.rows()!=y.length()) || (x.rows()!=w.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatewfgh': looks like one of arguments has wrong size");
 | |
|     n = x.rows();
 | |
|     m = x.cols();
 | |
|     k = c.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting using gradient/Hessian, without individial
 | |
| weights.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses f(c,x[i]), its gradient and its Hessian.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, const ae_int_t n, const ae_int_t m, const ae_int_t k, lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting using gradient/Hessian, without individial
 | |
| weights.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses f(c,x[i]), its gradient and its Hessian.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void lsfitcreatefgh(const real_2d_array &x, const real_1d_array &y, const real_1d_array &c, lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     ae_int_t k;
 | |
|     if( (x.rows()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitcreatefgh': looks like one of arguments has wrong size");
 | |
|     n = x.rows();
 | |
|     m = x.cols();
 | |
|     k = c.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| Stopping conditions for nonlinear least squares fitting.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
|     EpsX    -   >=0
 | |
|                 The subroutine finishes its work if  on  k+1-th  iteration
 | |
|                 the condition |v|<=EpsX is fulfilled, where:
 | |
|                 * |.| means Euclidian norm
 | |
|                 * v - scaled step vector, v[i]=dx[i]/s[i]
 | |
|                 * dx - ste pvector, dx=X(k+1)-X(k)
 | |
|                 * s - scaling coefficients set by LSFitSetScale()
 | |
|     MaxIts  -   maximum number of iterations. If MaxIts=0, the  number  of
 | |
|                 iterations   is    unlimited.   Only   Levenberg-Marquardt
 | |
|                 iterations  are  counted  (L-BFGS/CG  iterations  are  NOT
 | |
|                 counted because their cost is very low compared to that of
 | |
|                 LM).
 | |
| 
 | |
| NOTE
 | |
| 
 | |
| Passing EpsX=0  and  MaxIts=0  (simultaneously)  will  lead  to  automatic
 | |
| stopping criterion selection (according to the scheme used by MINLM unit).
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetcond(const lsfitstate &state, const double epsx, const ae_int_t maxits, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::lsfitsetcond(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), epsx, maxits, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets maximum step length
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
|     StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
 | |
|                 want to limit step length.
 | |
| 
 | |
| Use this subroutine when you optimize target function which contains exp()
 | |
| or  other  fast  growing  functions,  and optimization algorithm makes too
 | |
| large  steps  which  leads  to overflow. This function allows us to reject
 | |
| steps  that  are  too  large  (and  therefore  expose  us  to the possible
 | |
| overflow) without actually calculating function value at the x+stp*d.
 | |
| 
 | |
| NOTE: non-zero StpMax leads to moderate  performance  degradation  because
 | |
| intermediate  step  of  preconditioned L-BFGS optimization is incompatible
 | |
| with limits on step size.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.04.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetstpmax(const lsfitstate &state, const double stpmax, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::lsfitsetstpmax(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), stpmax, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function turns on/off reporting.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
|     NeedXRep-   whether iteration reports are needed or not
 | |
| 
 | |
| When reports are needed, State.C (current parameters) and State.F (current
 | |
| value of fitting function) are reported.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 15.08.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetxrep(const lsfitstate &state, const bool needxrep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::lsfitsetxrep(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), needxrep, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets scaling coefficients for underlying optimizer.
 | |
| 
 | |
| ALGLIB optimizers use scaling matrices to test stopping  conditions  (step
 | |
| size and gradient are scaled before comparison with tolerances).  Scale of
 | |
| the I-th variable is a translation invariant measure of:
 | |
| a) "how large" the variable is
 | |
| b) how large the step should be to make significant changes in the function
 | |
| 
 | |
| Generally, scale is NOT considered to be a form of preconditioner.  But LM
 | |
| optimizer is unique in that it uses scaling matrix both  in  the  stopping
 | |
| condition tests and as Marquardt damping factor.
 | |
| 
 | |
| Proper scaling is very important for the algorithm performance. It is less
 | |
| important for the quality of results, but still has some influence (it  is
 | |
| easier  to  converge  when  variables  are  properly  scaled, so premature
 | |
| stopping is possible when very badly scalled variables are  combined  with
 | |
| relaxed stopping conditions).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure stores algorithm state
 | |
|     S       -   array[N], non-zero scaling coefficients
 | |
|                 S[i] may be negative, sign doesn't matter.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.01.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetscale(const lsfitstate &state, const real_1d_array &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::lsfitsetscale(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), const_cast<alglib_impl::ae_vector*>(s.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets boundary constraints for underlying optimizer
 | |
| 
 | |
| Boundary constraints are inactive by default (after initial creation).
 | |
| They are preserved until explicitly turned off with another SetBC() call.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure stores algorithm state
 | |
|     BndL    -   lower bounds, array[K].
 | |
|                 If some (all) variables are unbounded, you may specify
 | |
|                 very small number or -INF (latter is recommended because
 | |
|                 it will allow solver to use better algorithm).
 | |
|     BndU    -   upper bounds, array[K].
 | |
|                 If some (all) variables are unbounded, you may specify
 | |
|                 very large number or +INF (latter is recommended because
 | |
|                 it will allow solver to use better algorithm).
 | |
| 
 | |
| NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th
 | |
| variable will be "frozen" at X[i]=BndL[i]=BndU[i].
 | |
| 
 | |
| NOTE 2: unlike other constrained optimization algorithms, this solver  has
 | |
| following useful properties:
 | |
| * bound constraints are always satisfied exactly
 | |
| * function is evaluated only INSIDE area specified by bound constraints
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.01.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetbc(const lsfitstate &state, const real_1d_array &bndl, const real_1d_array &bndu, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets linear constraints for underlying optimizer
 | |
| 
 | |
| Linear constraints are inactive by default (after initial creation).
 | |
| They are preserved until explicitly turned off with another SetLC() call.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure stores algorithm state
 | |
|     C       -   linear constraints, array[K,N+1].
 | |
|                 Each row of C represents one constraint, either equality
 | |
|                 or inequality (see below):
 | |
|                 * first N elements correspond to coefficients,
 | |
|                 * last element corresponds to the right part.
 | |
|                 All elements of C (including right part) must be finite.
 | |
|     CT      -   type of constraints, array[K]:
 | |
|                 * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1]
 | |
|                 * if CT[i]=0, then I-th constraint is C[i,*]*x  = C[i,n+1]
 | |
|                 * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1]
 | |
|     K       -   number of equality/inequality constraints, K>=0:
 | |
|                 * if given, only leading K elements of C/CT are used
 | |
|                 * if not given, automatically determined from sizes of C/CT
 | |
| 
 | |
| IMPORTANT: if you have linear constraints, it is strongly  recommended  to
 | |
|            set scale of variables with lsfitsetscale(). QP solver which is
 | |
|            used to calculate linearly constrained steps heavily relies  on
 | |
|            good scaling of input problems.
 | |
| 
 | |
| NOTE: linear  (non-box)  constraints  are  satisfied only approximately  -
 | |
|       there  always  exists some violation due  to  numerical  errors  and
 | |
|       algorithmic limitations.
 | |
| 
 | |
| NOTE: general linear constraints  add  significant  overhead  to  solution
 | |
|       process. Although solver performs roughly same amount of  iterations
 | |
|       (when compared  with  similar  box-only  constrained  problem), each
 | |
|       iteration   now    involves  solution  of  linearly  constrained  QP
 | |
|       subproblem, which requires ~3-5 times more Cholesky  decompositions.
 | |
|       Thus, if you can reformulate your problem in such way  this  it  has
 | |
|       only box constraints, it may be beneficial to do so.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 29.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetlc(const lsfitstate &state, const real_2d_array &c, const integer_1d_array &ct, const ae_int_t k, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets linear constraints for underlying optimizer
 | |
| 
 | |
| Linear constraints are inactive by default (after initial creation).
 | |
| They are preserved until explicitly turned off with another SetLC() call.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure stores algorithm state
 | |
|     C       -   linear constraints, array[K,N+1].
 | |
|                 Each row of C represents one constraint, either equality
 | |
|                 or inequality (see below):
 | |
|                 * first N elements correspond to coefficients,
 | |
|                 * last element corresponds to the right part.
 | |
|                 All elements of C (including right part) must be finite.
 | |
|     CT      -   type of constraints, array[K]:
 | |
|                 * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1]
 | |
|                 * if CT[i]=0, then I-th constraint is C[i,*]*x  = C[i,n+1]
 | |
|                 * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1]
 | |
|     K       -   number of equality/inequality constraints, K>=0:
 | |
|                 * if given, only leading K elements of C/CT are used
 | |
|                 * if not given, automatically determined from sizes of C/CT
 | |
| 
 | |
| IMPORTANT: if you have linear constraints, it is strongly  recommended  to
 | |
|            set scale of variables with lsfitsetscale(). QP solver which is
 | |
|            used to calculate linearly constrained steps heavily relies  on
 | |
|            good scaling of input problems.
 | |
| 
 | |
| NOTE: linear  (non-box)  constraints  are  satisfied only approximately  -
 | |
|       there  always  exists some violation due  to  numerical  errors  and
 | |
|       algorithmic limitations.
 | |
| 
 | |
| NOTE: general linear constraints  add  significant  overhead  to  solution
 | |
|       process. Although solver performs roughly same amount of  iterations
 | |
|       (when compared  with  similar  box-only  constrained  problem), each
 | |
|       iteration   now    involves  solution  of  linearly  constrained  QP
 | |
|       subproblem, which requires ~3-5 times more Cholesky  decompositions.
 | |
|       Thus, if you can reformulate your problem in such way  this  it  has
 | |
|       only box constraints, it may be beneficial to do so.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 29.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void lsfitsetlc(const lsfitstate &state, const real_2d_array &c, const integer_1d_array &ct, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t k;
 | |
|     if( (c.rows()!=ct.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'lsfitsetlc': looks like one of arguments has wrong size");
 | |
|     k = c.rows();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function provides reverse communication interface
 | |
| Reverse communication interface is not documented or recommended to use.
 | |
| See below for functions which provide better documented API
 | |
| *************************************************************************/
 | |
| bool lsfititeration(const lsfitstate &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     ae_bool result = alglib_impl::lsfititeration(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<bool*>(&result));
 | |
| }
 | |
| 
 | |
| 
 | |
| void lsfitfit(lsfitstate &state,
 | |
|     void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr),
 | |
|     void  (*rep)(const real_1d_array &c, double func, void *ptr), 
 | |
|     void *ptr,
 | |
|     const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'lsfitfit()' (func is NULL)", &_alglib_env_state);
 | |
|     while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) )
 | |
|     {
 | |
|         _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN
 | |
|                 if( state.needf )
 | |
|                 {
 | |
|                     func(state.c, state.x, state.f, ptr);
 | |
|                     continue;
 | |
|                 }
 | |
|         if( state.xupdated )
 | |
|         {
 | |
|             if( rep!=NULL )
 | |
|                 rep(state.c, state.f, ptr);
 | |
|             continue;
 | |
|         }
 | |
|         goto lbl_no_callback;
 | |
|         _ALGLIB_CALLBACK_EXCEPTION_GUARD_END
 | |
|     lbl_no_callback:
 | |
|         alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)", &_alglib_env_state);
 | |
|     }
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| void lsfitfit(lsfitstate &state,
 | |
|     void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr),
 | |
|     void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
 | |
|     void  (*rep)(const real_1d_array &c, double func, void *ptr), 
 | |
|     void *ptr,
 | |
|     const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'lsfitfit()' (func is NULL)", &_alglib_env_state);
 | |
|     alglib_impl::ae_assert(grad!=NULL, "ALGLIB: error in 'lsfitfit()' (grad is NULL)", &_alglib_env_state);
 | |
|     while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) )
 | |
|     {
 | |
|         _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN
 | |
|                 if( state.needf )
 | |
|                 {
 | |
|                     func(state.c, state.x, state.f, ptr);
 | |
|                     continue;
 | |
|                 }
 | |
|                 if( state.needfg )
 | |
|                 {
 | |
|                     grad(state.c, state.x, state.f, state.g, ptr);
 | |
|                     continue;
 | |
|                 }
 | |
|         if( state.xupdated )
 | |
|         {
 | |
|             if( rep!=NULL )
 | |
|                 rep(state.c, state.f, ptr);
 | |
|             continue;
 | |
|         }
 | |
|         goto lbl_no_callback;
 | |
|         _ALGLIB_CALLBACK_EXCEPTION_GUARD_END
 | |
|     lbl_no_callback:
 | |
|         alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)", &_alglib_env_state);
 | |
|     }
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| void lsfitfit(lsfitstate &state,
 | |
|     void (*func)(const real_1d_array &c, const real_1d_array &x, double &func, void *ptr),
 | |
|     void (*grad)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, void *ptr),
 | |
|     void (*hess)(const real_1d_array &c, const real_1d_array &x, double &func, real_1d_array &grad, real_2d_array &hess, void *ptr),
 | |
|     void  (*rep)(const real_1d_array &c, double func, void *ptr), 
 | |
|     void *ptr,
 | |
|     const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::ae_assert(func!=NULL, "ALGLIB: error in 'lsfitfit()' (func is NULL)", &_alglib_env_state);
 | |
|     alglib_impl::ae_assert(grad!=NULL, "ALGLIB: error in 'lsfitfit()' (grad is NULL)", &_alglib_env_state);
 | |
|     alglib_impl::ae_assert(hess!=NULL, "ALGLIB: error in 'lsfitfit()' (hess is NULL)", &_alglib_env_state);
 | |
|     while( alglib_impl::lsfititeration(state.c_ptr(), &_alglib_env_state) )
 | |
|     {
 | |
|         _ALGLIB_CALLBACK_EXCEPTION_GUARD_BEGIN
 | |
|                 if( state.needf )
 | |
|                 {
 | |
|                     func(state.c, state.x, state.f, ptr);
 | |
|                     continue;
 | |
|                 }
 | |
|                 if( state.needfg )
 | |
|                 {
 | |
|                     grad(state.c, state.x, state.f, state.g, ptr);
 | |
|                     continue;
 | |
|                 }
 | |
|                 if( state.needfgh )
 | |
|                 {
 | |
|                     hess(state.c, state.x, state.f, state.g, state.h, ptr);
 | |
|                     continue;
 | |
|                 }
 | |
|         if( state.xupdated )
 | |
|         {
 | |
|             if( rep!=NULL )
 | |
|                 rep(state.c, state.f, ptr);
 | |
|             continue;
 | |
|         }
 | |
|         goto lbl_no_callback;
 | |
|         _ALGLIB_CALLBACK_EXCEPTION_GUARD_END
 | |
|     lbl_no_callback:
 | |
|         alglib_impl::ae_assert(ae_false, "ALGLIB: error in 'lsfitfit' (some derivatives were not provided?)", &_alglib_env_state);
 | |
|     }
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting results.
 | |
| 
 | |
| Called after return from LSFitFit().
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   algorithm state
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   completion code:
 | |
|                     * -8    optimizer   detected  NAN/INF  in  the  target
 | |
|                             function and/or gradient
 | |
|                     * -7    gradient verification failed.
 | |
|                             See LSFitSetGradientCheck() for more information.
 | |
|                     * -3    inconsistent constraints
 | |
|                     *  2    relative step is no more than EpsX.
 | |
|                     *  5    MaxIts steps was taken
 | |
|                     *  7    stopping conditions are too stringent,
 | |
|                             further improvement is impossible
 | |
|     C       -   array[0..K-1], solution
 | |
|     Rep     -   optimization report. On success following fields are set:
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
|                 * WRMSError         weighted rms error on the (X,Y).
 | |
| 
 | |
| ERRORS IN PARAMETERS
 | |
| 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(J*CovPar*J')),
 | |
|                     where J is Jacobian matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
 | |
|             account boundary/linear constraints! Presence  of  constraints
 | |
|             changes distribution of errors, but there is no  easy  way  to
 | |
|             account for constraints when you calculate covariance matrix.
 | |
| 
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
| 
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
| 
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
| 
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitresults(const lsfitstate &state, ae_int_t &info, real_1d_array &c, lsfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  subroutine  turns  on  verification  of  the  user-supplied analytic
 | |
| gradient:
 | |
| * user calls this subroutine before fitting begins
 | |
| * LSFitFit() is called
 | |
| * prior to actual fitting, for  each  point  in  data  set  X_i  and  each
 | |
|   component  of  parameters  being  fited C_j algorithm performs following
 | |
|   steps:
 | |
|   * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j],
 | |
|     where C_j is j-th parameter and S[j] is a scale of j-th parameter
 | |
|   * if needed, steps are bounded with respect to constraints on C[]
 | |
|   * F(X_i|C) is evaluated at these trial points
 | |
|   * we perform one more evaluation in the middle point of the interval
 | |
|   * we  build  cubic  model using function values and derivatives at trial
 | |
|     points and we compare its prediction with actual value in  the  middle
 | |
|     point
 | |
|   * in case difference between prediction and actual value is higher  than
 | |
|     some predetermined threshold, algorithm stops with completion code -7;
 | |
|     Rep.VarIdx is set to index of the parameter with incorrect derivative.
 | |
| * after verification is over, algorithm proceeds to the actual optimization.
 | |
| 
 | |
| NOTE 1: verification needs N*K (points count * parameters count)  gradient
 | |
|         evaluations. It is very costly and you should use it only for  low
 | |
|         dimensional  problems,  when  you  want  to  be  sure  that you've
 | |
|         correctly calculated analytic derivatives. You should not  use  it
 | |
|         in the production code  (unless  you  want  to  check  derivatives
 | |
|         provided by some third party).
 | |
| 
 | |
| NOTE 2: you  should  carefully  choose  TestStep. Value which is too large
 | |
|         (so large that function behaviour is significantly non-cubic) will
 | |
|         lead to false alarms. You may use  different  step  for  different
 | |
|         parameters by means of setting scale with LSFitSetScale().
 | |
| 
 | |
| NOTE 3: this function may lead to false positives. In case it reports that
 | |
|         I-th  derivative was calculated incorrectly, you may decrease test
 | |
|         step  and  try  one  more  time  - maybe your function changes too
 | |
|         sharply  and  your  step  is  too  large for such rapidly chanding
 | |
|         function.
 | |
| 
 | |
| NOTE 4: this function works only for optimizers created with LSFitCreateWFG()
 | |
|         or LSFitCreateFG() constructors.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State       -   structure used to store algorithm state
 | |
|     TestStep    -   verification step:
 | |
|                     * TestStep=0 turns verification off
 | |
|                     * TestStep>0 activates verification
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 15.06.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetgradientcheck(const lsfitstate &state, const double teststep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::lsfitsetgradientcheck(const_cast<alglib_impl::lsfitstate*>(state.c_ptr()), teststep, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| 2-dimensional spline inteprolant
 | |
| *************************************************************************/
 | |
| _spline2dinterpolant_owner::_spline2dinterpolant_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline2dinterpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::spline2dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dinterpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline2dinterpolant));
 | |
|     alglib_impl::_spline2dinterpolant_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline2dinterpolant_owner::_spline2dinterpolant_owner(const _spline2dinterpolant_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline2dinterpolant_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dinterpolant copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::spline2dinterpolant*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dinterpolant), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline2dinterpolant));
 | |
|     alglib_impl::_spline2dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline2dinterpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline2dinterpolant_owner& _spline2dinterpolant_owner::operator=(const _spline2dinterpolant_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline2dinterpolant assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dinterpolant assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_spline2dinterpolant_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline2dinterpolant));
 | |
|     alglib_impl::_spline2dinterpolant_init_copy(p_struct, const_cast<alglib_impl::spline2dinterpolant*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _spline2dinterpolant_owner::~_spline2dinterpolant_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_spline2dinterpolant_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::spline2dinterpolant* _spline2dinterpolant_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::spline2dinterpolant* _spline2dinterpolant_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::spline2dinterpolant*>(p_struct);
 | |
| }
 | |
| spline2dinterpolant::spline2dinterpolant() : _spline2dinterpolant_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| spline2dinterpolant::spline2dinterpolant(const spline2dinterpolant &rhs):_spline2dinterpolant_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| spline2dinterpolant& spline2dinterpolant::operator=(const spline2dinterpolant &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _spline2dinterpolant_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| spline2dinterpolant::~spline2dinterpolant()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares solver used to fit 2D splines to data
 | |
| *************************************************************************/
 | |
| _spline2dbuilder_owner::_spline2dbuilder_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline2dbuilder_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::spline2dbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dbuilder), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline2dbuilder));
 | |
|     alglib_impl::_spline2dbuilder_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline2dbuilder_owner::_spline2dbuilder_owner(const _spline2dbuilder_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline2dbuilder_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dbuilder copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::spline2dbuilder*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dbuilder), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline2dbuilder));
 | |
|     alglib_impl::_spline2dbuilder_init_copy(p_struct, const_cast<alglib_impl::spline2dbuilder*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline2dbuilder_owner& _spline2dbuilder_owner::operator=(const _spline2dbuilder_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline2dbuilder assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dbuilder assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_spline2dbuilder_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline2dbuilder));
 | |
|     alglib_impl::_spline2dbuilder_init_copy(p_struct, const_cast<alglib_impl::spline2dbuilder*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _spline2dbuilder_owner::~_spline2dbuilder_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_spline2dbuilder_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::spline2dbuilder* _spline2dbuilder_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::spline2dbuilder* _spline2dbuilder_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::spline2dbuilder*>(p_struct);
 | |
| }
 | |
| spline2dbuilder::spline2dbuilder() : _spline2dbuilder_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| spline2dbuilder::spline2dbuilder(const spline2dbuilder &rhs):_spline2dbuilder_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| spline2dbuilder& spline2dbuilder::operator=(const spline2dbuilder &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _spline2dbuilder_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| spline2dbuilder::~spline2dbuilder()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Spline 2D fitting report:
 | |
|     rmserror        RMS error
 | |
|     avgerror        average error
 | |
|     maxerror        maximum error
 | |
|     r2              coefficient of determination,  R-squared, 1-RSS/TSS
 | |
| *************************************************************************/
 | |
| _spline2dfitreport_owner::_spline2dfitreport_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline2dfitreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::spline2dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dfitreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline2dfitreport));
 | |
|     alglib_impl::_spline2dfitreport_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline2dfitreport_owner::_spline2dfitreport_owner(const _spline2dfitreport_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_spline2dfitreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dfitreport copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::spline2dfitreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::spline2dfitreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline2dfitreport));
 | |
|     alglib_impl::_spline2dfitreport_init_copy(p_struct, const_cast<alglib_impl::spline2dfitreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _spline2dfitreport_owner& _spline2dfitreport_owner::operator=(const _spline2dfitreport_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: spline2dfitreport assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: spline2dfitreport assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_spline2dfitreport_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::spline2dfitreport));
 | |
|     alglib_impl::_spline2dfitreport_init_copy(p_struct, const_cast<alglib_impl::spline2dfitreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _spline2dfitreport_owner::~_spline2dfitreport_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_spline2dfitreport_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::spline2dfitreport* _spline2dfitreport_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::spline2dfitreport* _spline2dfitreport_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::spline2dfitreport*>(p_struct);
 | |
| }
 | |
| spline2dfitreport::spline2dfitreport() : _spline2dfitreport_owner() ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2)
 | |
| {
 | |
| }
 | |
| 
 | |
| spline2dfitreport::spline2dfitreport(const spline2dfitreport &rhs):_spline2dfitreport_owner(rhs) ,rmserror(p_struct->rmserror),avgerror(p_struct->avgerror),maxerror(p_struct->maxerror),r2(p_struct->r2)
 | |
| {
 | |
| }
 | |
| 
 | |
| spline2dfitreport& spline2dfitreport::operator=(const spline2dfitreport &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _spline2dfitreport_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| spline2dfitreport::~spline2dfitreport()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function serializes data structure to string.
 | |
| 
 | |
| Important properties of s_out:
 | |
| * it contains alphanumeric characters, dots, underscores, minus signs
 | |
| * these symbols are grouped into words, which are separated by spaces
 | |
|   and Windows-style (CR+LF) newlines
 | |
| * although  serializer  uses  spaces and CR+LF as separators, you can 
 | |
|   replace any separator character by arbitrary combination of spaces,
 | |
|   tabs, Windows or Unix newlines. It allows flexible reformatting  of
 | |
|   the  string  in  case you want to include it into text or XML file. 
 | |
|   But you should not insert separators into the middle of the "words"
 | |
|   nor you should change case of letters.
 | |
| * s_out can be freely moved between 32-bit and 64-bit systems, little
 | |
|   and big endian machines, and so on. You can serialize structure  on
 | |
|   32-bit machine and unserialize it on 64-bit one (or vice versa), or
 | |
|   serialize  it  on  SPARC  and  unserialize  on  x86.  You  can also 
 | |
|   serialize  it  in  C++ version of ALGLIB and unserialize in C# one, 
 | |
|   and vice versa.
 | |
| *************************************************************************/
 | |
| void spline2dserialize(spline2dinterpolant &obj, std::string &s_out)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
|     alglib_impl::ae_int_t ssize;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_alloc_start(&serializer);
 | |
|     alglib_impl::spline2dalloc(&serializer, obj.c_ptr(), &state);
 | |
|     ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer);
 | |
|     s_out.clear();
 | |
|     s_out.reserve((size_t)(ssize+1));
 | |
|     alglib_impl::ae_serializer_sstart_str(&serializer, &s_out);
 | |
|     alglib_impl::spline2dserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| /*************************************************************************
 | |
| This function unserializes data structure from string.
 | |
| *************************************************************************/
 | |
| void spline2dunserialize(const std::string &s_in, spline2dinterpolant &obj)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_ustart_str(&serializer, &s_in);
 | |
|     alglib_impl::spline2dunserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function serializes data structure to C++ stream.
 | |
| 
 | |
| Data stream generated by this function is same as  string  representation
 | |
| generated  by  string  version  of  serializer - alphanumeric characters,
 | |
| dots, underscores, minus signs, which are grouped into words separated by
 | |
| spaces and CR+LF.
 | |
| 
 | |
| We recommend you to read comments on string version of serializer to find
 | |
| out more about serialization of AlGLIB objects.
 | |
| *************************************************************************/
 | |
| void spline2dserialize(spline2dinterpolant &obj, std::ostream &s_out)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_alloc_start(&serializer);
 | |
|     alglib_impl::spline2dalloc(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask
 | |
|     alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out);
 | |
|     alglib_impl::spline2dserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| /*************************************************************************
 | |
| This function unserializes data structure from stream.
 | |
| *************************************************************************/
 | |
| void spline2dunserialize(const std::istream &s_in, spline2dinterpolant &obj)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in);
 | |
|     alglib_impl::spline2dunserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates the value of the bilinear or bicubic spline  at
 | |
| the given point X.
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   2D spline object.
 | |
|             Built by spline2dbuildbilinearv or spline2dbuildbicubicv.
 | |
|     X, Y-   point
 | |
| 
 | |
| Result:
 | |
|     S(x,y)
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 05.07.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double spline2dcalc(const spline2dinterpolant &c, const double x, const double y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::spline2dcalc(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), x, y, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates the value of the bilinear or bicubic spline  at
 | |
| the given point X and its derivatives.
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y-   point
 | |
| 
 | |
| Output parameters:
 | |
|     F   -   S(x,y)
 | |
|     FX  -   dS(x,y)/dX
 | |
|     FY  -   dS(x,y)/dY
 | |
|     FXY -   d2S(x,y)/dXdY
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 05.07.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2ddiff(const spline2dinterpolant &c, const double x, const double y, double &f, double &fx, double &fy, double &fxy, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2ddiff(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), x, y, &f, &fx, &fy, &fxy, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates bilinear or bicubic vector-valued spline at the
 | |
| given point (X,Y).
 | |
| 
 | |
| If you need just some specific component of vector-valued spline, you  can
 | |
| use spline2dcalcvi() function.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y-   point
 | |
|     F   -   output buffer, possibly preallocated array. In case array size
 | |
|             is large enough to store result, it is not reallocated.  Array
 | |
|             which is too short will be reallocated
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   array[D] (or larger) which stores function values
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dcalcvbuf(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates specific component of vector-valued bilinear or
 | |
| bicubic spline at the given point (X,Y).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y-   point
 | |
|     I   -   component index, in [0,D). An exception is generated for out
 | |
|             of range values.
 | |
| 
 | |
| RESULT:
 | |
|     value of I-th component
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double spline2dcalcvi(const spline2dinterpolant &c, const double x, const double y, const ae_int_t i, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::spline2dcalcvi(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), x, y, i, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates bilinear or bicubic vector-valued spline at the
 | |
| given point (X,Y).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y-   point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   array[D] which stores function values.  F is out-parameter and
 | |
|             it  is  reallocated  after  call to this function. In case you
 | |
|             want  to    reuse  previously  allocated  F,   you   may   use
 | |
|             Spline2DCalcVBuf(),  which  reallocates  F only when it is too
 | |
|             small.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 16.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dcalcv(const spline2dinterpolant &c, const double x, const double y, real_1d_array &f, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates value of  specific  component  of  bilinear  or
 | |
| bicubic vector-valued spline and its derivatives.
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y-   point
 | |
|     I   -   component index, in [0,D)
 | |
| 
 | |
| Output parameters:
 | |
|     F   -   S(x,y)
 | |
|     FX  -   dS(x,y)/dX
 | |
|     FY  -   dS(x,y)/dY
 | |
|     FXY -   d2S(x,y)/dXdY
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 05.07.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2ddiffvi(const spline2dinterpolant &c, const double x, const double y, const ae_int_t i, double &f, double &fx, double &fy, double &fxy, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2ddiffvi(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), x, y, i, &f, &fx, &fy, &fxy, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline argument.
 | |
| 
 | |
| Input parameters:
 | |
|     C       -   spline interpolant
 | |
|     AX, BX  -   transformation coefficients: x = A*t + B
 | |
|     AY, BY  -   transformation coefficients: y = A*u + B
 | |
| Result:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dlintransxy(const spline2dinterpolant &c, const double ax, const double bx, const double ay, const double by, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dlintransxy(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), ax, bx, ay, by, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline.
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   spline interpolant.
 | |
|     A, B-   transformation coefficients: S2(x,y) = A*S(x,y) + B
 | |
| 
 | |
| Output parameters:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dlintransf(const spline2dinterpolant &c, const double a, const double b, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dlintransf(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), a, b, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine makes the copy of the spline model.
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
| Output parameters:
 | |
|     CC  -   spline copy
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 29.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dcopy(const spline2dinterpolant &c, spline2dinterpolant &cc, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dcopy(const_cast<alglib_impl::spline2dinterpolant*>(c.c_ptr()), const_cast<alglib_impl::spline2dinterpolant*>(cc.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Bicubic spline resampling
 | |
| 
 | |
| Input parameters:
 | |
|     A           -   function values at the old grid,
 | |
|                     array[0..OldHeight-1, 0..OldWidth-1]
 | |
|     OldHeight   -   old grid height, OldHeight>1
 | |
|     OldWidth    -   old grid width, OldWidth>1
 | |
|     NewHeight   -   new grid height, NewHeight>1
 | |
|     NewWidth    -   new grid width, NewWidth>1
 | |
| 
 | |
| Output parameters:
 | |
|     B           -   function values at the new grid,
 | |
|                     array[0..NewHeight-1, 0..NewWidth-1]
 | |
| 
 | |
|   -- ALGLIB routine --
 | |
|      15 May, 2007
 | |
|      Copyright by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dresamplebicubic(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| Bilinear spline resampling
 | |
| 
 | |
| Input parameters:
 | |
|     A           -   function values at the old grid,
 | |
|                     array[0..OldHeight-1, 0..OldWidth-1]
 | |
|     OldHeight   -   old grid height, OldHeight>1
 | |
|     OldWidth    -   old grid width, OldWidth>1
 | |
|     NewHeight   -   new grid height, NewHeight>1
 | |
|     NewWidth    -   new grid width, NewWidth>1
 | |
| 
 | |
| Output parameters:
 | |
|     B           -   function values at the new grid,
 | |
|                     array[0..NewHeight-1, 0..NewWidth-1]
 | |
| 
 | |
|   -- ALGLIB routine --
 | |
|      09.07.2007
 | |
|      Copyright by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dresamplebilinear(const real_2d_array &a, const ae_int_t oldheight, const ae_int_t oldwidth, real_2d_array &b, const ae_int_t newheight, const ae_int_t newwidth, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds bilinear vector-valued spline.
 | |
| 
 | |
| Input parameters:
 | |
|     X   -   spline abscissas, array[0..N-1]
 | |
|     Y   -   spline ordinates, array[0..M-1]
 | |
|     F   -   function values, array[0..M*N*D-1]:
 | |
|             * first D elements store D values at (X[0],Y[0])
 | |
|             * next D elements store D values at (X[1],Y[0])
 | |
|             * general form - D function values at (X[i],Y[j]) are stored
 | |
|               at F[D*(J*N+I)...D*(J*N+I)+D-1].
 | |
|     M,N -   grid size, M>=2, N>=2
 | |
|     D   -   vector dimension, D>=1
 | |
| 
 | |
| Output parameters:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 16.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildbilinearv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds bicubic vector-valued spline.
 | |
| 
 | |
| Input parameters:
 | |
|     X   -   spline abscissas, array[0..N-1]
 | |
|     Y   -   spline ordinates, array[0..M-1]
 | |
|     F   -   function values, array[0..M*N*D-1]:
 | |
|             * first D elements store D values at (X[0],Y[0])
 | |
|             * next D elements store D values at (X[1],Y[0])
 | |
|             * general form - D function values at (X[i],Y[j]) are stored
 | |
|               at F[D*(J*N+I)...D*(J*N+I)+D-1].
 | |
|     M,N -   grid size, M>=2, N>=2
 | |
|     D   -   vector dimension, D>=1
 | |
| 
 | |
| Output parameters:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 16.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildbicubicv(const real_1d_array &x, const ae_int_t n, const real_1d_array &y, const ae_int_t m, const real_1d_array &f, const ae_int_t d, spline2dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine unpacks two-dimensional spline into the coefficients table
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   spline interpolant.
 | |
| 
 | |
| Result:
 | |
|     M, N-   grid size (x-axis and y-axis)
 | |
|     D   -   number of components
 | |
|     Tbl -   coefficients table, unpacked format,
 | |
|             D - components: [0..(N-1)*(M-1)*D-1, 0..19].
 | |
|             For T=0..D-1 (component index), I = 0...N-2 (x index),
 | |
|             J=0..M-2 (y index):
 | |
|                 K :=  T + I*D + J*D*(N-1)
 | |
| 
 | |
|                 K-th row stores decomposition for T-th component of the
 | |
|                 vector-valued function
 | |
| 
 | |
|                 Tbl[K,0] = X[i]
 | |
|                 Tbl[K,1] = X[i+1]
 | |
|                 Tbl[K,2] = Y[j]
 | |
|                 Tbl[K,3] = Y[j+1]
 | |
|                 Tbl[K,4] = C00
 | |
|                 Tbl[K,5] = C01
 | |
|                 Tbl[K,6] = C02
 | |
|                 Tbl[K,7] = C03
 | |
|                 Tbl[K,8] = C10
 | |
|                 Tbl[K,9] = C11
 | |
|                 ...
 | |
|                 Tbl[K,19] = C33
 | |
|             On each grid square spline is equals to:
 | |
|                 S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3)
 | |
|                 t = x-x[j]
 | |
|                 u = y-y[i]
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 16.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dunpackv(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, ae_int_t &d, real_2d_array &tbl, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine was deprecated in ALGLIB 3.6.0
 | |
| 
 | |
| We recommend you to switch  to  Spline2DBuildBilinearV(),  which  is  more
 | |
| flexible and accepts its arguments in more convenient order.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 05.07.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildbilinear(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine was deprecated in ALGLIB 3.6.0
 | |
| 
 | |
| We recommend you to switch  to  Spline2DBuildBicubicV(),  which  is  more
 | |
| flexible and accepts its arguments in more convenient order.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 05.07.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildbicubic(const real_1d_array &x, const real_1d_array &y, const real_2d_array &f, const ae_int_t m, const ae_int_t n, spline2dinterpolant &c, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine was deprecated in ALGLIB 3.6.0
 | |
| 
 | |
| We recommend you to switch  to  Spline2DUnpackV(),  which is more flexible
 | |
| and accepts its arguments in more convenient order.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 29.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dunpack(const spline2dinterpolant &c, ae_int_t &m, ae_int_t &n, real_2d_array &tbl, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine creates least squares solver used to  fit  2D  splines  to
 | |
| irregularly sampled (scattered) data.
 | |
| 
 | |
| Solver object is used to perform spline fits as follows:
 | |
| * solver object is created with spline2dbuildercreate() function
 | |
| * dataset is added with spline2dbuildersetpoints() function
 | |
| * fit area is chosen:
 | |
|   * spline2dbuildersetarea()     - for user-defined area
 | |
|   * spline2dbuildersetareaauto() - for automatically chosen area
 | |
| * number of grid nodes is chosen with spline2dbuildersetgrid()
 | |
| * prior term is chosen with one of the following functions:
 | |
|   * spline2dbuildersetlinterm()   to set linear prior
 | |
|   * spline2dbuildersetconstterm() to set constant prior
 | |
|   * spline2dbuildersetzeroterm()  to set zero prior
 | |
|   * spline2dbuildersetuserterm()  to set user-defined constant prior
 | |
| * solver algorithm is chosen with either:
 | |
|   * spline2dbuildersetalgoblocklls() - BlockLLS algorithm, medium-scale problems
 | |
|   * spline2dbuildersetalgofastddm()  - FastDDM algorithm, large-scale problems
 | |
| * finally, fitting itself is performed with spline2dfit() function.
 | |
| 
 | |
| Most of the steps above can be omitted,  solver  is  configured with  good
 | |
| defaults. The minimum is to call:
 | |
| * spline2dbuildercreate() to create solver object
 | |
| * spline2dbuildersetpoints() to specify dataset
 | |
| * spline2dbuildersetgrid() to tell how many nodes you need
 | |
| * spline2dfit() to perform fit
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     D   -   positive number, number of Y-components: D=1 for simple scalar
 | |
|             fit, D>1 for vector-valued spline fitting.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     S   -   solver object
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 29.01.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildercreate(const ae_int_t d, spline2dbuilder &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildercreate(d, const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets constant prior term (model is a sum of  bicubic  spline
 | |
| and global prior, which can be linear, constant, user-defined  constant or
 | |
| zero).
 | |
| 
 | |
| Constant prior term is determined by least squares fitting.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
|     V       -   value for user-defined prior
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetuserterm(const spline2dbuilder &state, const double v, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetuserterm(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), v, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets linear prior term (model is a sum of bicubic spline and
 | |
| global  prior,  which  can  be  linear, constant, user-defined constant or
 | |
| zero).
 | |
| 
 | |
| Linear prior term is determined by least squares fitting.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetlinterm(const spline2dbuilder &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetlinterm(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets constant prior term (model is a sum of  bicubic  spline
 | |
| and global prior, which can be linear, constant, user-defined  constant or
 | |
| zero).
 | |
| 
 | |
| Constant prior term is determined by least squares fitting.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetconstterm(const spline2dbuilder &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetconstterm(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets zero prior term (model is a sum of bicubic  spline  and
 | |
| global  prior,  which  can  be  linear, constant, user-defined constant or
 | |
| zero).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetzeroterm(const spline2dbuilder &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetzeroterm(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset to the builder object.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     XY      -   points, array[N,2+D]. One  row  corresponds to  one  point
 | |
|                 in the dataset. First 2  elements  are  coordinates,  next
 | |
|                 D  elements are function values. Array may  be larger than
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetpoints(const spline2dbuilder &state, const real_2d_array &xy, const ae_int_t n, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetpoints(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets area where 2D spline interpolant is built. "Auto" means
 | |
| that area extent is determined automatically from dataset extent.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetareaauto(const spline2dbuilder &state, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetareaauto(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  sets  area  where  2D  spline  interpolant  is   built  to
 | |
| user-defined one: [XA,XB]*[YA,YB]
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     XA,XB   -   spatial extent in the first (X) dimension, XA<XB
 | |
|     YA,YB   -   spatial extent in the second (Y) dimension, YA<YB
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetarea(const spline2dbuilder &state, const double xa, const double xb, const double ya, const double yb, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetarea(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), xa, xb, ya, yb, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  sets  nodes  count  for  2D spline interpolant. Fitting is
 | |
| performed on area defined with one of the "setarea"  functions;  this  one
 | |
| sets number of nodes placed upon the fitting area.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     KX      -   nodes count for the first (X) dimension; fitting  interval
 | |
|                 [XA,XB] is separated into KX-1 subintervals, with KX nodes
 | |
|                 created at the boundaries.
 | |
|     KY      -   nodes count for the first (Y) dimension; fitting  interval
 | |
|                 [YA,YB] is separated into KY-1 subintervals, with KY nodes
 | |
|                 created at the boundaries.
 | |
| 
 | |
| NOTE: at  least  4  nodes  is  created in each dimension, so KX and KY are
 | |
|       silently increased if needed.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetgrid(const spline2dbuilder &state, const ae_int_t kx, const ae_int_t ky, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetgrid(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), kx, ky, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  allows  you to choose least squares solver used to perform
 | |
| fitting. This function sets solver algorithm to "FastDDM", which  performs
 | |
| fast parallel fitting by splitting problem into smaller chunks and merging
 | |
| results together.
 | |
| 
 | |
| This solver is optimized for large-scale problems, starting  from  256x256
 | |
| grids, and up to 10000x10000 grids. Of course, it will  work  for  smaller
 | |
| grids too.
 | |
| 
 | |
| More detailed description of the algorithm is given below:
 | |
| * algorithm generates hierarchy  of  nested  grids,  ranging  from  ~16x16
 | |
|   (topmost "layer" of the model) to ~KX*KY one (final layer). Upper layers
 | |
|   model global behavior of the function, lower layers are  used  to  model
 | |
|   fine details. Moving from layer to layer doubles grid density.
 | |
| * fitting  is  started  from  topmost  layer, subsequent layers are fitted
 | |
|   using residuals from previous ones.
 | |
| * user may choose to skip generation of upper layers and generate  only  a
 | |
|   few bottom ones, which  will  result  in  much  better  performance  and
 | |
|   parallelization efficiency, at the cost of algorithm inability to "patch"
 | |
|   large holes in the dataset.
 | |
| * every layer is regularized using progressively increasing regularization
 | |
|   coefficient; thus, increasing  LambdaV  penalizes  fine  details  first,
 | |
|   leaving lower frequencies almost intact for a while.
 | |
| * after fitting is done, all layers are merged together into  one  bicubic
 | |
|   spline
 | |
| 
 | |
| IMPORTANT: regularization coefficient used by  this  solver  is  different
 | |
|            from the one used by  BlockLLS.  Latter  utilizes  nonlinearity
 | |
|            penalty,  which  is  global  in  nature  (large  regularization
 | |
|            results in global linear trend being  extracted);  this  solver
 | |
|            uses another, localized form of penalty, which is suitable  for
 | |
|            parallel processing.
 | |
| 
 | |
| Notes on memory and performance:
 | |
| * memory requirements: most memory is consumed  during  modeling   of  the
 | |
|   higher layers; ~[512*NPoints] bytes is required for a  model  with  full
 | |
|   hierarchy of grids being generated. However, if you skip a  few  topmost
 | |
|   layers, you will get nearly constant (wrt. points count and  grid  size)
 | |
|   memory consumption.
 | |
| * serial running time: O(K*K)+O(NPoints) for a KxK grid
 | |
| * parallelism potential: good. You may get  nearly  linear  speed-up  when
 | |
|   performing fitting with just a few layers. Adding more layers results in
 | |
|   model becoming more global, which somewhat  reduces  efficiency  of  the
 | |
|   parallel code.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     NLayers -   number of layers in the model:
 | |
|                 * NLayers>=1 means that up  to  chosen  number  of  bottom
 | |
|                   layers is fitted
 | |
|                 * NLayers=0 means that maximum number of layers is  chosen
 | |
|                   (according to current grid size)
 | |
|                 * NLayers<=-1 means that up to |NLayers| topmost layers is
 | |
|                   skipped
 | |
|                 Recommendations:
 | |
|                 * good "default" value is 2 layers
 | |
|                 * you may need  more  layers,  if  your  dataset  is  very
 | |
|                   irregular and you want to "patch"  large  holes.  For  a
 | |
|                   grid step H (equal to AreaWidth/GridSize) you may expect
 | |
|                   that last layer reproduces variations at distance H (and
 | |
|                   can patch holes that wide); that higher  layers  operate
 | |
|                   at distances 2*H, 4*H, 8*H and so on.
 | |
|                 * good value for "bullletproof" mode is  NLayers=0,  which
 | |
|                   results in complete hierarchy of layers being generated.
 | |
|     LambdaV -   regularization coefficient, chosen in such a way  that  it
 | |
|                 penalizes bottom layers (fine details) first.
 | |
|                 LambdaV>=0, zero value means that no penalty is applied.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetalgofastddm(const spline2dbuilder &state, const ae_int_t nlayers, const double lambdav, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetalgofastddm(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), nlayers, lambdav, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  allows  you to choose least squares solver used to perform
 | |
| fitting. This function sets solver algorithm to "BlockLLS", which performs
 | |
| least squares fitting  with  fast  sparse  direct  solver,  with  optional
 | |
| nonsmoothness penalty being applied.
 | |
| 
 | |
| Nonlinearity penalty has the following form:
 | |
| 
 | |
|                           [                                            ]
 | |
|     P() ~ Lambda* integral[ (d2S/dx2)^2 + 2*(d2S/dxdy)^2 + (d2S/dy2)^2 ]dxdy
 | |
|                           [                                            ]
 | |
| 
 | |
| here integral is calculated over entire grid, and "~" means "proportional"
 | |
| because integral is normalized after calcilation. Extremely  large  values
 | |
| of Lambda result in linear fit being performed.
 | |
| 
 | |
| NOTE: this algorithm is the most robust and controllable one,  but  it  is
 | |
|       limited by 512x512 grids and (say) up to 1.000.000 points.  However,
 | |
|       ALGLIB has one more  spline  solver:  FastDDM  algorithm,  which  is
 | |
|       intended for really large-scale problems (in 10M-100M range). FastDDM
 | |
|       algorithm also has better parallelism properties.
 | |
| 
 | |
| More information on BlockLLS solver:
 | |
| * memory requirements: ~[32*K^3+256*NPoints]  bytes  for  KxK  grid   with
 | |
|   NPoints-sized dataset
 | |
| * serial running time: O(K^4+NPoints)
 | |
| * parallelism potential: limited. You may get some sublinear gain when
 | |
|   working with large grids (K's in 256..512 range)
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     LambdaNS-   non-negative value:
 | |
|                 * positive value means that some smoothing is applied
 | |
|                 * zero value means  that  no  smoothing  is  applied,  and
 | |
|                   corresponding entries of design matrix  are  numerically
 | |
|                   zero and dropped from consideration.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetalgoblocklls(const spline2dbuilder &state, const double lambdans, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetalgoblocklls(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), lambdans, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  allows  you to choose least squares solver used to perform
 | |
| fitting. This function sets solver algorithm to "NaiveLLS".
 | |
| 
 | |
| IMPORTANT: NaiveLLS is NOT intended to be used in  real  life  code!  This
 | |
|            algorithm solves problem by generated dense (K^2)x(K^2+NPoints)
 | |
|            matrix and solves  linear  least  squares  problem  with  dense
 | |
|            solver.
 | |
| 
 | |
|            It is here just  to  test  BlockLLS  against  reference  solver
 | |
|            (and maybe for someone trying to compare well optimized  solver
 | |
|            against straightforward approach to the LLS problem).
 | |
| 
 | |
| More information on naive LLS solver:
 | |
| * memory requirements: ~[8*K^4+256*NPoints] bytes for KxK grid.
 | |
| * serial running time: O(K^6+NPoints) for KxK grid
 | |
| * when compared with BlockLLS,  NaiveLLS  has ~K  larger memory demand and
 | |
|   ~K^2  larger running time.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     LambdaNS-   nonsmoothness penalty
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetalgonaivells(const spline2dbuilder &state, const double lambdans, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::spline2dbuildersetalgonaivells(const_cast<alglib_impl::spline2dbuilder*>(state.c_ptr()), lambdans, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits bicubic spline to current dataset, using current  area/
 | |
| grid and current LLS solver.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   spline 2D builder object
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     S       -   2D spline, fit result
 | |
|     Rep     -   fitting report, which provides some additional info  about
 | |
|                 errors, R2 coefficient and so on.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dfit(const spline2dbuilder &state, spline2dinterpolant &s, spline2dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| Buffer object which is used to perform nearest neighbor  requests  in  the
 | |
| multithreaded mode (multiple threads working with same KD-tree object).
 | |
| 
 | |
| This object should be created with KDTreeCreateBuffer().
 | |
| *************************************************************************/
 | |
| _rbfcalcbuffer_owner::_rbfcalcbuffer_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_rbfcalcbuffer_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::rbfcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfcalcbuffer), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::rbfcalcbuffer));
 | |
|     alglib_impl::_rbfcalcbuffer_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _rbfcalcbuffer_owner::_rbfcalcbuffer_owner(const _rbfcalcbuffer_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_rbfcalcbuffer_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfcalcbuffer copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::rbfcalcbuffer*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfcalcbuffer), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::rbfcalcbuffer));
 | |
|     alglib_impl::_rbfcalcbuffer_init_copy(p_struct, const_cast<alglib_impl::rbfcalcbuffer*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _rbfcalcbuffer_owner& _rbfcalcbuffer_owner::operator=(const _rbfcalcbuffer_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: rbfcalcbuffer assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfcalcbuffer assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_rbfcalcbuffer_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::rbfcalcbuffer));
 | |
|     alglib_impl::_rbfcalcbuffer_init_copy(p_struct, const_cast<alglib_impl::rbfcalcbuffer*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _rbfcalcbuffer_owner::~_rbfcalcbuffer_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_rbfcalcbuffer_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::rbfcalcbuffer* _rbfcalcbuffer_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::rbfcalcbuffer* _rbfcalcbuffer_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::rbfcalcbuffer*>(p_struct);
 | |
| }
 | |
| rbfcalcbuffer::rbfcalcbuffer() : _rbfcalcbuffer_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| rbfcalcbuffer::rbfcalcbuffer(const rbfcalcbuffer &rhs):_rbfcalcbuffer_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| rbfcalcbuffer& rbfcalcbuffer::operator=(const rbfcalcbuffer &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _rbfcalcbuffer_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| rbfcalcbuffer::~rbfcalcbuffer()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| RBF model.
 | |
| 
 | |
| Never try to directly work with fields of this object - always use  ALGLIB
 | |
| functions to use this object.
 | |
| *************************************************************************/
 | |
| _rbfmodel_owner::_rbfmodel_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_rbfmodel_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::rbfmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfmodel), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::rbfmodel));
 | |
|     alglib_impl::_rbfmodel_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _rbfmodel_owner::_rbfmodel_owner(const _rbfmodel_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_rbfmodel_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfmodel copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::rbfmodel*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfmodel), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::rbfmodel));
 | |
|     alglib_impl::_rbfmodel_init_copy(p_struct, const_cast<alglib_impl::rbfmodel*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _rbfmodel_owner& _rbfmodel_owner::operator=(const _rbfmodel_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: rbfmodel assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfmodel assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_rbfmodel_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::rbfmodel));
 | |
|     alglib_impl::_rbfmodel_init_copy(p_struct, const_cast<alglib_impl::rbfmodel*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _rbfmodel_owner::~_rbfmodel_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_rbfmodel_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::rbfmodel* _rbfmodel_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::rbfmodel* _rbfmodel_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::rbfmodel*>(p_struct);
 | |
| }
 | |
| rbfmodel::rbfmodel() : _rbfmodel_owner() 
 | |
| {
 | |
| }
 | |
| 
 | |
| rbfmodel::rbfmodel(const rbfmodel &rhs):_rbfmodel_owner(rhs) 
 | |
| {
 | |
| }
 | |
| 
 | |
| rbfmodel& rbfmodel::operator=(const rbfmodel &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _rbfmodel_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| rbfmodel::~rbfmodel()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| RBF solution report:
 | |
| * TerminationType   -   termination type, positive values - success,
 | |
|                         non-positive - failure.
 | |
| 
 | |
| Fields which are set by modern RBF solvers (hierarchical):
 | |
| * RMSError          -   root-mean-square error; NAN for old solvers (ML, QNN)
 | |
| * MaxError          -   maximum error; NAN for old solvers (ML, QNN)
 | |
| *************************************************************************/
 | |
| _rbfreport_owner::_rbfreport_owner()
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_rbfreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     p_struct = (alglib_impl::rbfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::rbfreport));
 | |
|     alglib_impl::_rbfreport_init(p_struct, &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _rbfreport_owner::_rbfreport_owner(const _rbfreport_owner &rhs)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
|         if( p_struct!=NULL )
 | |
|         {
 | |
|             alglib_impl::_rbfreport_destroy(p_struct);
 | |
|             alglib_impl::ae_free(p_struct);
 | |
|         }
 | |
|         p_struct = NULL;
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     p_struct = NULL;
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfreport copy constructor failure (source is not initialized)", &_state);
 | |
|     p_struct = (alglib_impl::rbfreport*)alglib_impl::ae_malloc(sizeof(alglib_impl::rbfreport), &_state);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::rbfreport));
 | |
|     alglib_impl::_rbfreport_init_copy(p_struct, const_cast<alglib_impl::rbfreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
| }
 | |
| 
 | |
| _rbfreport_owner& _rbfreport_owner::operator=(const _rbfreport_owner &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _state;
 | |
|     
 | |
|     alglib_impl::ae_state_init(&_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_state.error_msg);
 | |
|         return *this;
 | |
| #endif
 | |
|     }
 | |
|     alglib_impl::ae_state_set_break_jump(&_state, &_break_jump);
 | |
|     alglib_impl::ae_assert(p_struct!=NULL, "ALGLIB: rbfreport assignment constructor failure (destination is not initialized)", &_state);
 | |
|     alglib_impl::ae_assert(rhs.p_struct!=NULL, "ALGLIB: rbfreport assignment constructor failure (source is not initialized)", &_state);
 | |
|     alglib_impl::_rbfreport_destroy(p_struct);
 | |
|     memset(p_struct, 0, sizeof(alglib_impl::rbfreport));
 | |
|     alglib_impl::_rbfreport_init_copy(p_struct, const_cast<alglib_impl::rbfreport*>(rhs.p_struct), &_state, ae_false);
 | |
|     ae_state_clear(&_state);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| _rbfreport_owner::~_rbfreport_owner()
 | |
| {
 | |
|     if( p_struct!=NULL )
 | |
|     {
 | |
|         alglib_impl::_rbfreport_destroy(p_struct);
 | |
|         ae_free(p_struct);
 | |
|     }
 | |
| }
 | |
| 
 | |
| alglib_impl::rbfreport* _rbfreport_owner::c_ptr()
 | |
| {
 | |
|     return p_struct;
 | |
| }
 | |
| 
 | |
| alglib_impl::rbfreport* _rbfreport_owner::c_ptr() const
 | |
| {
 | |
|     return const_cast<alglib_impl::rbfreport*>(p_struct);
 | |
| }
 | |
| rbfreport::rbfreport() : _rbfreport_owner() ,rmserror(p_struct->rmserror),maxerror(p_struct->maxerror),arows(p_struct->arows),acols(p_struct->acols),annz(p_struct->annz),iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype)
 | |
| {
 | |
| }
 | |
| 
 | |
| rbfreport::rbfreport(const rbfreport &rhs):_rbfreport_owner(rhs) ,rmserror(p_struct->rmserror),maxerror(p_struct->maxerror),arows(p_struct->arows),acols(p_struct->acols),annz(p_struct->annz),iterationscount(p_struct->iterationscount),nmv(p_struct->nmv),terminationtype(p_struct->terminationtype)
 | |
| {
 | |
| }
 | |
| 
 | |
| rbfreport& rbfreport::operator=(const rbfreport &rhs)
 | |
| {
 | |
|     if( this==&rhs )
 | |
|         return *this;
 | |
|     _rbfreport_owner::operator=(rhs);
 | |
|     return *this;
 | |
| }
 | |
| 
 | |
| rbfreport::~rbfreport()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function serializes data structure to string.
 | |
| 
 | |
| Important properties of s_out:
 | |
| * it contains alphanumeric characters, dots, underscores, minus signs
 | |
| * these symbols are grouped into words, which are separated by spaces
 | |
|   and Windows-style (CR+LF) newlines
 | |
| * although  serializer  uses  spaces and CR+LF as separators, you can 
 | |
|   replace any separator character by arbitrary combination of spaces,
 | |
|   tabs, Windows or Unix newlines. It allows flexible reformatting  of
 | |
|   the  string  in  case you want to include it into text or XML file. 
 | |
|   But you should not insert separators into the middle of the "words"
 | |
|   nor you should change case of letters.
 | |
| * s_out can be freely moved between 32-bit and 64-bit systems, little
 | |
|   and big endian machines, and so on. You can serialize structure  on
 | |
|   32-bit machine and unserialize it on 64-bit one (or vice versa), or
 | |
|   serialize  it  on  SPARC  and  unserialize  on  x86.  You  can also 
 | |
|   serialize  it  in  C++ version of ALGLIB and unserialize in C# one, 
 | |
|   and vice versa.
 | |
| *************************************************************************/
 | |
| void rbfserialize(rbfmodel &obj, std::string &s_out)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
|     alglib_impl::ae_int_t ssize;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_alloc_start(&serializer);
 | |
|     alglib_impl::rbfalloc(&serializer, obj.c_ptr(), &state);
 | |
|     ssize = alglib_impl::ae_serializer_get_alloc_size(&serializer);
 | |
|     s_out.clear();
 | |
|     s_out.reserve((size_t)(ssize+1));
 | |
|     alglib_impl::ae_serializer_sstart_str(&serializer, &s_out);
 | |
|     alglib_impl::rbfserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_assert( s_out.length()<=(size_t)ssize, "ALGLIB: serialization integrity error", &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| /*************************************************************************
 | |
| This function unserializes data structure from string.
 | |
| *************************************************************************/
 | |
| void rbfunserialize(const std::string &s_in, rbfmodel &obj)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_ustart_str(&serializer, &s_in);
 | |
|     alglib_impl::rbfunserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function serializes data structure to C++ stream.
 | |
| 
 | |
| Data stream generated by this function is same as  string  representation
 | |
| generated  by  string  version  of  serializer - alphanumeric characters,
 | |
| dots, underscores, minus signs, which are grouped into words separated by
 | |
| spaces and CR+LF.
 | |
| 
 | |
| We recommend you to read comments on string version of serializer to find
 | |
| out more about serialization of AlGLIB objects.
 | |
| *************************************************************************/
 | |
| void rbfserialize(rbfmodel &obj, std::ostream &s_out)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_alloc_start(&serializer);
 | |
|     alglib_impl::rbfalloc(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_get_alloc_size(&serializer); // not actually needed, but we have to ask
 | |
|     alglib_impl::ae_serializer_sstart_stream(&serializer, &s_out);
 | |
|     alglib_impl::rbfserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| /*************************************************************************
 | |
| This function unserializes data structure from stream.
 | |
| *************************************************************************/
 | |
| void rbfunserialize(const std::istream &s_in, rbfmodel &obj)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state state;
 | |
|     alglib_impl::ae_serializer serializer;
 | |
| 
 | |
|     alglib_impl::ae_state_init(&state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&state, &_break_jump);
 | |
|     alglib_impl::ae_serializer_init(&serializer);
 | |
|     alglib_impl::ae_serializer_ustart_stream(&serializer, &s_in);
 | |
|     alglib_impl::rbfunserialize(&serializer, obj.c_ptr(), &state);
 | |
|     alglib_impl::ae_serializer_stop(&serializer, &state);
 | |
|     alglib_impl::ae_serializer_clear(&serializer);
 | |
|     alglib_impl::ae_state_clear(&state);
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function creates RBF  model  for  a  scalar (NY=1)  or  vector (NY>1)
 | |
| function in a NX-dimensional space (NX>=1).
 | |
| 
 | |
| Newly created model is empty. It can be used for interpolation right after
 | |
| creation, but it just returns zeros. You have to add points to the  model,
 | |
| tune interpolation settings, and then  call  model  construction  function
 | |
| rbfbuildmodel() which will update model according to your specification.
 | |
| 
 | |
| USAGE:
 | |
| 1. User creates model with rbfcreate()
 | |
| 2. User adds dataset with rbfsetpoints() (points do NOT have to  be  on  a
 | |
|    regular grid) or rbfsetpointsandscales().
 | |
| 3. (OPTIONAL) User chooses polynomial term by calling:
 | |
|    * rbflinterm() to set linear term
 | |
|    * rbfconstterm() to set constant term
 | |
|    * rbfzeroterm() to set zero term
 | |
|    By default, linear term is used.
 | |
| 4. User tweaks algorithm properties with  rbfsetalgohierarchical()  method
 | |
|    (or chooses one of the legacy algorithms - QNN  (rbfsetalgoqnn)  or  ML
 | |
|    (rbfsetalgomultilayer)).
 | |
| 5. User calls rbfbuildmodel() function which rebuilds model  according  to
 | |
|    the specification
 | |
| 6. User may call rbfcalc() to calculate model value at the specified point,
 | |
|    rbfgridcalc() to  calculate   model  values at the points of the regular
 | |
|    grid. User may extract model coefficients with rbfunpack() call.
 | |
| 
 | |
| IMPORTANT: we recommend you to use latest model construction  algorithm  -
 | |
|            hierarchical RBFs, which is activated by rbfsetalgohierarchical()
 | |
|            function. This algorithm is the fastest one, and  most  memory-
 | |
|            efficient.
 | |
|            However,  it  is  incompatible  with older versions  of  ALGLIB
 | |
|            (pre-3.11). So, if you serialize hierarchical model,  you  will
 | |
|            be unable to load it in pre-3.11 ALGLIB. Other model types (QNN
 | |
|            and RBF-ML) are still backward-compatible.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     NX      -   dimension of the space, NX>=1
 | |
|     NY      -   function dimension, NY>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     S       -   RBF model (initially equals to zero)
 | |
| 
 | |
| NOTE 1: memory requirements. RBF models require amount of memory  which is
 | |
|         proportional  to the number of data points. Some additional memory
 | |
|         is allocated during model construction, but most of this memory is
 | |
|         freed after model coefficients  are  calculated.  Amount  of  this
 | |
|         additional memory depends on model  construction  algorithm  being
 | |
|         used.
 | |
| 
 | |
| NOTE 2: prior to ALGLIB version 3.11, RBF models supported  only  NX=2  or
 | |
|         NX=3. Any  attempt  to  create  single-dimensional  or  more  than
 | |
|         3-dimensional RBF model resulted in exception.
 | |
| 
 | |
|         ALGLIB 3.11 supports any NX>0, but models created with  NX!=2  and
 | |
|         NX!=3 are incompatible with (a) older versions of ALGLIB, (b)  old
 | |
|         model construction algorithms (QNN or RBF-ML).
 | |
| 
 | |
|         So, if you create a model with NX=2 or NX=3,  then,  depending  on
 | |
|         specific  model construction algorithm being chosen, you will (QNN
 | |
|         and RBF-ML) or will not (HierarchicalRBF) get backward compatibility
 | |
|         with older versions of ALGLIB. You have a choice here.
 | |
| 
 | |
|         However, if you create a model with NX neither 2 nor 3,  you  have
 | |
|         no backward compatibility from the start, and you  are  forced  to
 | |
|         use hierarchical RBFs and ALGLIB 3.11 or later.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011, 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfcreate(const ae_int_t nx, const ae_int_t ny, rbfmodel &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfcreate(nx, ny, const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function creates buffer  structure  which  can  be  used  to  perform
 | |
| parallel  RBF  model  evaluations  (with  one  RBF  model  instance  being
 | |
| used from multiple threads, as long as  different  threads  use  different
 | |
| instances of buffer).
 | |
| 
 | |
| This buffer object can be used with  rbftscalcbuf()  function  (here  "ts"
 | |
| stands for "thread-safe", "buf" is a suffix which denotes  function  which
 | |
| reuses previously allocated output space).
 | |
| 
 | |
| How to use it:
 | |
| * create RBF model structure with rbfcreate()
 | |
| * load data, tune parameters
 | |
| * call rbfbuildmodel()
 | |
| * call rbfcreatecalcbuffer(), once per thread working with RBF model  (you
 | |
|   should call this function only AFTER call to rbfbuildmodel(), see  below
 | |
|   for more information)
 | |
| * call rbftscalcbuf() from different threads,  with  each  thread  working
 | |
|   with its own copy of buffer object.
 | |
| 
 | |
| INPUT PARAMETERS
 | |
|     S           -   RBF model
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     Buf         -   external buffer.
 | |
| 
 | |
| 
 | |
| IMPORTANT: buffer object should be used only with  RBF model object  which
 | |
|            was used to initialize buffer. Any attempt to use buffer   with
 | |
|            different object is dangerous - you may  get  memory  violation
 | |
|            error because sizes of internal arrays do not fit to dimensions
 | |
|            of RBF structure.
 | |
| 
 | |
| IMPORTANT: you  should  call  this function only for model which was built
 | |
|            with rbfbuildmodel() function, after successful  invocation  of
 | |
|            rbfbuildmodel().  Sizes   of   some   internal  structures  are
 | |
|            determined only after model is built, so buffer object  created
 | |
|            before model  construction  stage  will  be  useless  (and  any
 | |
|            attempt to use it will result in exception).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.04.2016 by Sergey Bochkanov
 | |
| *************************************************************************/
 | |
| void rbfcreatecalcbuffer(const rbfmodel &s, rbfcalcbuffer &buf, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfcreatecalcbuffer(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::rbfcalcbuffer*>(buf.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| IMPORTANT: ALGLIB version 3.11 and later allows you to specify  a  set  of
 | |
|            per-dimension scales. Interpolation radii are multiplied by the
 | |
|            scale vector. It may be useful if you have mixed spatio-temporal
 | |
|            data (say, a set of 3D slices recorded at different times).
 | |
|            You should call rbfsetpointsandscales() function  to  use  this
 | |
|            feature.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by rbfcreate() call.
 | |
|     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
 | |
|                 in the dataset. First NX elements  are  coordinates,  next
 | |
|                 NY elements are function values. Array may  be larger than
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset
 | |
| 
 | |
| After you've added dataset and (optionally) tuned algorithm  settings  you
 | |
| should call rbfbuildmodel() in order to build a model for you.
 | |
| 
 | |
| NOTE: dataset added by this function is not saved during model serialization.
 | |
|       MODEL ITSELF is serialized, but data used to build it are not.
 | |
| 
 | |
|       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
 | |
|       unserialize it, then you will get an empty RBF model with no dataset
 | |
|       being attached.
 | |
| 
 | |
|       From the other side, if you call rbfbuildmodel() between (1) and (2),
 | |
|       then after (2) you will get your fully constructed RBF model  -  but
 | |
|       again with no dataset attached, so subsequent calls to rbfbuildmodel()
 | |
|       will produce empty model.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy, const ae_int_t n, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetpoints(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| IMPORTANT: ALGLIB version 3.11 and later allows you to specify  a  set  of
 | |
|            per-dimension scales. Interpolation radii are multiplied by the
 | |
|            scale vector. It may be useful if you have mixed spatio-temporal
 | |
|            data (say, a set of 3D slices recorded at different times).
 | |
|            You should call rbfsetpointsandscales() function  to  use  this
 | |
|            feature.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by rbfcreate() call.
 | |
|     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
 | |
|                 in the dataset. First NX elements  are  coordinates,  next
 | |
|                 NY elements are function values. Array may  be larger than
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset
 | |
| 
 | |
| After you've added dataset and (optionally) tuned algorithm  settings  you
 | |
| should call rbfbuildmodel() in order to build a model for you.
 | |
| 
 | |
| NOTE: dataset added by this function is not saved during model serialization.
 | |
|       MODEL ITSELF is serialized, but data used to build it are not.
 | |
| 
 | |
|       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
 | |
|       unserialize it, then you will get an empty RBF model with no dataset
 | |
|       being attached.
 | |
| 
 | |
|       From the other side, if you call rbfbuildmodel() between (1) and (2),
 | |
|       then after (2) you will get your fully constructed RBF model  -  but
 | |
|       again with no dataset attached, so subsequent calls to rbfbuildmodel()
 | |
|       will produce empty model.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void rbfsetpoints(const rbfmodel &s, const real_2d_array &xy, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
| 
 | |
|     n = xy.rows();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetpoints(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::ae_matrix*>(xy.c_ptr()), n, &_alglib_env_state);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset and a vector of per-dimension scales.
 | |
| 
 | |
| It may be useful if you have mixed spatio-temporal data - say, a set of 3D
 | |
| slices recorded at different times. Such data typically require  different
 | |
| RBF radii for spatial and temporal dimensions. ALGLIB solves this  problem
 | |
| by specifying single RBF radius, which is (optionally) multiplied  by  the
 | |
| scale vector.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| IMPORTANT: only HierarchicalRBF algorithm can work with scaled points. So,
 | |
|            using this function results in RBF models which can be used  in
 | |
|            ALGLIB 3.11 or later. Previous versions of the library will  be
 | |
|            unable  to unserialize models produced by HierarchicalRBF algo.
 | |
| 
 | |
|            Any attempt to use this function with RBF-ML or QNN  algorithms
 | |
|            will result  in  -3  error  code   being   returned  (incorrect
 | |
|            algorithm).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     R       -   RBF model, initialized by rbfcreate() call.
 | |
|     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
 | |
|                 in the dataset. First NX elements  are  coordinates,  next
 | |
|                 NY elements are function values. Array may  be larger than
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset
 | |
|     S       -   array[NX], scale vector, S[i]>0.
 | |
| 
 | |
| After you've added dataset and (optionally) tuned algorithm  settings  you
 | |
| should call rbfbuildmodel() in order to build a model for you.
 | |
| 
 | |
| NOTE: dataset added by this function is not saved during model serialization.
 | |
|       MODEL ITSELF is serialized, but data used to build it are not.
 | |
| 
 | |
|       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
 | |
|       unserialize it, then you will get an empty RBF model with no dataset
 | |
|       being attached.
 | |
| 
 | |
|       From the other side, if you call rbfbuildmodel() between (1) and (2),
 | |
|       then after (2) you will get your fully constructed RBF model  -  but
 | |
|       again with no dataset attached, so subsequent calls to rbfbuildmodel()
 | |
|       will produce empty model.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetpointsandscales(const rbfmodel &r, const real_2d_array &xy, const ae_int_t n, const real_1d_array &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset and a vector of per-dimension scales.
 | |
| 
 | |
| It may be useful if you have mixed spatio-temporal data - say, a set of 3D
 | |
| slices recorded at different times. Such data typically require  different
 | |
| RBF radii for spatial and temporal dimensions. ALGLIB solves this  problem
 | |
| by specifying single RBF radius, which is (optionally) multiplied  by  the
 | |
| scale vector.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| IMPORTANT: only HierarchicalRBF algorithm can work with scaled points. So,
 | |
|            using this function results in RBF models which can be used  in
 | |
|            ALGLIB 3.11 or later. Previous versions of the library will  be
 | |
|            unable  to unserialize models produced by HierarchicalRBF algo.
 | |
| 
 | |
|            Any attempt to use this function with RBF-ML or QNN  algorithms
 | |
|            will result  in  -3  error  code   being   returned  (incorrect
 | |
|            algorithm).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     R       -   RBF model, initialized by rbfcreate() call.
 | |
|     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
 | |
|                 in the dataset. First NX elements  are  coordinates,  next
 | |
|                 NY elements are function values. Array may  be larger than
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset
 | |
|     S       -   array[NX], scale vector, S[i]>0.
 | |
| 
 | |
| After you've added dataset and (optionally) tuned algorithm  settings  you
 | |
| should call rbfbuildmodel() in order to build a model for you.
 | |
| 
 | |
| NOTE: dataset added by this function is not saved during model serialization.
 | |
|       MODEL ITSELF is serialized, but data used to build it are not.
 | |
| 
 | |
|       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
 | |
|       unserialize it, then you will get an empty RBF model with no dataset
 | |
|       being attached.
 | |
| 
 | |
|       From the other side, if you call rbfbuildmodel() between (1) and (2),
 | |
|       then after (2) you will get your fully constructed RBF model  -  but
 | |
|       again with no dataset attached, so subsequent calls to rbfbuildmodel()
 | |
|       will produce empty model.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void rbfsetpointsandscales(const rbfmodel &r, const real_2d_array &xy, const real_1d_array &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
| 
 | |
|     n = xy.rows();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
 | |
|            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
 | |
|            requires less memory than QNN and RBF-ML. It is especially good
 | |
|            for large-scale interpolation problems. So, we recommend you to
 | |
|            consider Hierarchical RBF as default option.
 | |
| 
 | |
| ==========================================================================
 | |
| 
 | |
| This  function  sets  RBF interpolation algorithm. ALGLIB supports several
 | |
| RBF algorithms with different properties.
 | |
| 
 | |
| This algorithm is called RBF-QNN and  it  is  good  for  point  sets  with
 | |
| following properties:
 | |
| a) all points are distinct
 | |
| b) all points are well separated.
 | |
| c) points  distribution  is  approximately  uniform.  There is no "contour
 | |
|    lines", clusters of points, or other small-scale structures.
 | |
| 
 | |
| Algorithm description:
 | |
| 1) interpolation centers are allocated to data points
 | |
| 2) interpolation radii are calculated as distances to the  nearest centers
 | |
|    times Q coefficient (where Q is a value from [0.75,1.50]).
 | |
| 3) after  performing (2) radii are transformed in order to avoid situation
 | |
|    when single outlier has very large radius and  influences  many  points
 | |
|    across all dataset. Transformation has following form:
 | |
|        new_r[i] = min(r[i],Z*median(r[]))
 | |
|    where r[i] is I-th radius, median()  is a median  radius across  entire
 | |
|    dataset, Z is user-specified value which controls amount  of  deviation
 | |
|    from median radius.
 | |
| 
 | |
| When (a) is violated,  we  will  be unable to build RBF model. When (b) or
 | |
| (c) are violated, model will be built, but interpolation quality  will  be
 | |
| low. See http://www.alglib.net/interpolation/ for more information on this
 | |
| subject.
 | |
| 
 | |
| This algorithm is used by default.
 | |
| 
 | |
| Additional Q parameter controls smoothness properties of the RBF basis:
 | |
| * Q<0.75 will give perfectly conditioned basis,  but  terrible  smoothness
 | |
|   properties (RBF interpolant will have sharp peaks around function values)
 | |
| * Q around 1.0 gives good balance between smoothness and condition number
 | |
| * Q>1.5 will lead to badly conditioned systems and slow convergence of the
 | |
|   underlying linear solver (although smoothness will be very good)
 | |
| * Q>2.0 will effectively make optimizer useless because it won't  converge
 | |
|   within reasonable amount of iterations. It is possible to set such large
 | |
|   Q, but it is advised not to do so.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     Q       -   Q parameter, Q>0, recommended value - 1.0
 | |
|     Z       -   Z parameter, Z>0, recommended value - 5.0
 | |
| 
 | |
| NOTE: this   function  has   some   serialization-related  subtleties.  We
 | |
|       recommend you to study serialization examples from ALGLIB  Reference
 | |
|       Manual if you want to perform serialization of your models.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetalgoqnn(const rbfmodel &s, const double q, const double z, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetalgoqnn(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), q, z, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
 | |
|            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
 | |
|            requires less memory than QNN and RBF-ML. It is especially good
 | |
|            for large-scale interpolation problems. So, we recommend you to
 | |
|            consider Hierarchical RBF as default option.
 | |
| 
 | |
| ==========================================================================
 | |
| 
 | |
| This  function  sets  RBF interpolation algorithm. ALGLIB supports several
 | |
| RBF algorithms with different properties.
 | |
| 
 | |
| This algorithm is called RBF-QNN and  it  is  good  for  point  sets  with
 | |
| following properties:
 | |
| a) all points are distinct
 | |
| b) all points are well separated.
 | |
| c) points  distribution  is  approximately  uniform.  There is no "contour
 | |
|    lines", clusters of points, or other small-scale structures.
 | |
| 
 | |
| Algorithm description:
 | |
| 1) interpolation centers are allocated to data points
 | |
| 2) interpolation radii are calculated as distances to the  nearest centers
 | |
|    times Q coefficient (where Q is a value from [0.75,1.50]).
 | |
| 3) after  performing (2) radii are transformed in order to avoid situation
 | |
|    when single outlier has very large radius and  influences  many  points
 | |
|    across all dataset. Transformation has following form:
 | |
|        new_r[i] = min(r[i],Z*median(r[]))
 | |
|    where r[i] is I-th radius, median()  is a median  radius across  entire
 | |
|    dataset, Z is user-specified value which controls amount  of  deviation
 | |
|    from median radius.
 | |
| 
 | |
| When (a) is violated,  we  will  be unable to build RBF model. When (b) or
 | |
| (c) are violated, model will be built, but interpolation quality  will  be
 | |
| low. See http://www.alglib.net/interpolation/ for more information on this
 | |
| subject.
 | |
| 
 | |
| This algorithm is used by default.
 | |
| 
 | |
| Additional Q parameter controls smoothness properties of the RBF basis:
 | |
| * Q<0.75 will give perfectly conditioned basis,  but  terrible  smoothness
 | |
|   properties (RBF interpolant will have sharp peaks around function values)
 | |
| * Q around 1.0 gives good balance between smoothness and condition number
 | |
| * Q>1.5 will lead to badly conditioned systems and slow convergence of the
 | |
|   underlying linear solver (although smoothness will be very good)
 | |
| * Q>2.0 will effectively make optimizer useless because it won't  converge
 | |
|   within reasonable amount of iterations. It is possible to set such large
 | |
|   Q, but it is advised not to do so.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     Q       -   Q parameter, Q>0, recommended value - 1.0
 | |
|     Z       -   Z parameter, Z>0, recommended value - 5.0
 | |
| 
 | |
| NOTE: this   function  has   some   serialization-related  subtleties.  We
 | |
|       recommend you to study serialization examples from ALGLIB  Reference
 | |
|       Manual if you want to perform serialization of your models.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void rbfsetalgoqnn(const rbfmodel &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     double q;
 | |
|     double z;
 | |
| 
 | |
|     q = 1.0;
 | |
|     z = 5.0;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetalgoqnn(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), q, z, &_alglib_env_state);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
 | |
|            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
 | |
|            requires less memory than QNN and RBF-ML. It is especially good
 | |
|            for large-scale interpolation problems. So, we recommend you to
 | |
|            consider Hierarchical RBF as default option.
 | |
| 
 | |
| ==========================================================================
 | |
| 
 | |
| This  function  sets  RBF interpolation algorithm. ALGLIB supports several
 | |
| RBF algorithms with different properties.
 | |
| 
 | |
| This  algorithm is called RBF-ML. It builds  multilayer  RBF  model,  i.e.
 | |
| model with subsequently decreasing  radii,  which  allows  us  to  combine
 | |
| smoothness (due to  large radii of  the first layers) with  exactness (due
 | |
| to small radii of the last layers) and fast convergence.
 | |
| 
 | |
| Internally RBF-ML uses many different  means  of acceleration, from sparse
 | |
| matrices  to  KD-trees,  which  results in algorithm whose working time is
 | |
| roughly proportional to N*log(N)*Density*RBase^2*NLayers,  where  N  is  a
 | |
| number of points, Density is an average density if points per unit of  the
 | |
| interpolation space, RBase is an initial radius, NLayers is  a  number  of
 | |
| layers.
 | |
| 
 | |
| RBF-ML is good for following kinds of interpolation problems:
 | |
| 1. "exact" problems (perfect fit) with well separated points
 | |
| 2. least squares problems with arbitrary distribution of points (algorithm
 | |
|    gives  perfect  fit  where it is possible, and resorts to least squares
 | |
|    fit in the hard areas).
 | |
| 3. noisy problems where  we  want  to  apply  some  controlled  amount  of
 | |
|    smoothing.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     RBase   -   RBase parameter, RBase>0
 | |
|     NLayers -   NLayers parameter, NLayers>0, recommended value  to  start
 | |
|                 with - about 5.
 | |
|     LambdaV -   regularization value, can be useful when  solving  problem
 | |
|                 in the least squares sense.  Optimal  lambda  is  problem-
 | |
|                 dependent and require trial and error. In our  experience,
 | |
|                 good lambda can be as large as 0.1, and you can use  0.001
 | |
|                 as initial guess.
 | |
|                 Default  value  - 0.01, which is used when LambdaV is  not
 | |
|                 given.  You  can  specify  zero  value,  but  it  is   not
 | |
|                 recommended to do so.
 | |
| 
 | |
| TUNING ALGORITHM
 | |
| 
 | |
| In order to use this algorithm you have to choose three parameters:
 | |
| * initial radius RBase
 | |
| * number of layers in the model NLayers
 | |
| * regularization coefficient LambdaV
 | |
| 
 | |
| Initial radius is easy to choose - you can pick any number  several  times
 | |
| larger  than  the  average  distance between points. Algorithm won't break
 | |
| down if you choose radius which is too large (model construction time will
 | |
| increase, but model will be built correctly).
 | |
| 
 | |
| Choose such number of layers that RLast=RBase/2^(NLayers-1)  (radius  used
 | |
| by  the  last  layer)  will  be  smaller than the typical distance between
 | |
| points.  In  case  model  error  is  too large, you can increase number of
 | |
| layers.  Having  more  layers  will make model construction and evaluation
 | |
| proportionally slower, but it will allow you to have model which precisely
 | |
| fits your data. From the other side, if you want to  suppress  noise,  you
 | |
| can DECREASE number of layers to make your model less flexible.
 | |
| 
 | |
| Regularization coefficient LambdaV controls smoothness of  the  individual
 | |
| models built for each layer. We recommend you to use default value in case
 | |
| you don't want to tune this parameter,  because  having  non-zero  LambdaV
 | |
| accelerates and stabilizes internal iterative algorithm. In case you  want
 | |
| to suppress noise you can use  LambdaV  as  additional  parameter  (larger
 | |
| value = more smoothness) to tune.
 | |
| 
 | |
| TYPICAL ERRORS
 | |
| 
 | |
| 1. Using  initial  radius  which is too large. Memory requirements  of the
 | |
|    RBF-ML are roughly proportional to N*Density*RBase^2 (where Density  is
 | |
|    an average density of points per unit of the interpolation  space).  In
 | |
|    the extreme case of the very large RBase we will need O(N^2)  units  of
 | |
|    memory - and many layers in order to decrease radius to some reasonably
 | |
|    small value.
 | |
| 
 | |
| 2. Using too small number of layers - RBF models with large radius are not
 | |
|    flexible enough to reproduce small variations in the  target  function.
 | |
|    You  need  many  layers  with  different radii, from large to small, in
 | |
|    order to have good model.
 | |
| 
 | |
| 3. Using  initial  radius  which  is  too  small.  You will get model with
 | |
|    "holes" in the areas which are too far away from interpolation centers.
 | |
|    However, algorithm will work correctly (and quickly) in this case.
 | |
| 
 | |
| 4. Using too many layers - you will get too large and too slow model. This
 | |
|    model  will  perfectly  reproduce  your function, but maybe you will be
 | |
|    able to achieve similar results with less layers (and less memory).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.03.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdav, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetalgomultilayer(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), rbase, nlayers, lambdav, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
 | |
|            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
 | |
|            requires less memory than QNN and RBF-ML. It is especially good
 | |
|            for large-scale interpolation problems. So, we recommend you to
 | |
|            consider Hierarchical RBF as default option.
 | |
| 
 | |
| ==========================================================================
 | |
| 
 | |
| This  function  sets  RBF interpolation algorithm. ALGLIB supports several
 | |
| RBF algorithms with different properties.
 | |
| 
 | |
| This  algorithm is called RBF-ML. It builds  multilayer  RBF  model,  i.e.
 | |
| model with subsequently decreasing  radii,  which  allows  us  to  combine
 | |
| smoothness (due to  large radii of  the first layers) with  exactness (due
 | |
| to small radii of the last layers) and fast convergence.
 | |
| 
 | |
| Internally RBF-ML uses many different  means  of acceleration, from sparse
 | |
| matrices  to  KD-trees,  which  results in algorithm whose working time is
 | |
| roughly proportional to N*log(N)*Density*RBase^2*NLayers,  where  N  is  a
 | |
| number of points, Density is an average density if points per unit of  the
 | |
| interpolation space, RBase is an initial radius, NLayers is  a  number  of
 | |
| layers.
 | |
| 
 | |
| RBF-ML is good for following kinds of interpolation problems:
 | |
| 1. "exact" problems (perfect fit) with well separated points
 | |
| 2. least squares problems with arbitrary distribution of points (algorithm
 | |
|    gives  perfect  fit  where it is possible, and resorts to least squares
 | |
|    fit in the hard areas).
 | |
| 3. noisy problems where  we  want  to  apply  some  controlled  amount  of
 | |
|    smoothing.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     RBase   -   RBase parameter, RBase>0
 | |
|     NLayers -   NLayers parameter, NLayers>0, recommended value  to  start
 | |
|                 with - about 5.
 | |
|     LambdaV -   regularization value, can be useful when  solving  problem
 | |
|                 in the least squares sense.  Optimal  lambda  is  problem-
 | |
|                 dependent and require trial and error. In our  experience,
 | |
|                 good lambda can be as large as 0.1, and you can use  0.001
 | |
|                 as initial guess.
 | |
|                 Default  value  - 0.01, which is used when LambdaV is  not
 | |
|                 given.  You  can  specify  zero  value,  but  it  is   not
 | |
|                 recommended to do so.
 | |
| 
 | |
| TUNING ALGORITHM
 | |
| 
 | |
| In order to use this algorithm you have to choose three parameters:
 | |
| * initial radius RBase
 | |
| * number of layers in the model NLayers
 | |
| * regularization coefficient LambdaV
 | |
| 
 | |
| Initial radius is easy to choose - you can pick any number  several  times
 | |
| larger  than  the  average  distance between points. Algorithm won't break
 | |
| down if you choose radius which is too large (model construction time will
 | |
| increase, but model will be built correctly).
 | |
| 
 | |
| Choose such number of layers that RLast=RBase/2^(NLayers-1)  (radius  used
 | |
| by  the  last  layer)  will  be  smaller than the typical distance between
 | |
| points.  In  case  model  error  is  too large, you can increase number of
 | |
| layers.  Having  more  layers  will make model construction and evaluation
 | |
| proportionally slower, but it will allow you to have model which precisely
 | |
| fits your data. From the other side, if you want to  suppress  noise,  you
 | |
| can DECREASE number of layers to make your model less flexible.
 | |
| 
 | |
| Regularization coefficient LambdaV controls smoothness of  the  individual
 | |
| models built for each layer. We recommend you to use default value in case
 | |
| you don't want to tune this parameter,  because  having  non-zero  LambdaV
 | |
| accelerates and stabilizes internal iterative algorithm. In case you  want
 | |
| to suppress noise you can use  LambdaV  as  additional  parameter  (larger
 | |
| value = more smoothness) to tune.
 | |
| 
 | |
| TYPICAL ERRORS
 | |
| 
 | |
| 1. Using  initial  radius  which is too large. Memory requirements  of the
 | |
|    RBF-ML are roughly proportional to N*Density*RBase^2 (where Density  is
 | |
|    an average density of points per unit of the interpolation  space).  In
 | |
|    the extreme case of the very large RBase we will need O(N^2)  units  of
 | |
|    memory - and many layers in order to decrease radius to some reasonably
 | |
|    small value.
 | |
| 
 | |
| 2. Using too small number of layers - RBF models with large radius are not
 | |
|    flexible enough to reproduce small variations in the  target  function.
 | |
|    You  need  many  layers  with  different radii, from large to small, in
 | |
|    order to have good model.
 | |
| 
 | |
| 3. Using  initial  radius  which  is  too  small.  You will get model with
 | |
|    "holes" in the areas which are too far away from interpolation centers.
 | |
|    However, algorithm will work correctly (and quickly) in this case.
 | |
| 
 | |
| 4. Using too many layers - you will get too large and too slow model. This
 | |
|    model  will  perfectly  reproduce  your function, but maybe you will be
 | |
|    able to achieve similar results with less layers (and less memory).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.03.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void rbfsetalgomultilayer(const rbfmodel &s, const double rbase, const ae_int_t nlayers, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     double lambdav;
 | |
| 
 | |
|     lambdav = 0.01;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetalgomultilayer(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), rbase, nlayers, lambdav, &_alglib_env_state);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  sets  RBF interpolation algorithm. ALGLIB supports several
 | |
| RBF algorithms with different properties.
 | |
| 
 | |
| This  algorithm is called Hierarchical RBF. It  similar  to  its  previous
 | |
| incarnation, RBF-ML, i.e.  it  also  builds  a  sequence  of  models  with
 | |
| decreasing radii. However, it uses more economical way of  building  upper
 | |
| layers (ones with large radii), which results in faster model construction
 | |
| and evaluation, as well as smaller memory footprint during construction.
 | |
| 
 | |
| This algorithm has following important features:
 | |
| * ability to handle millions of points
 | |
| * controllable smoothing via nonlinearity penalization
 | |
| * support for NX-dimensional models with NX=1 or NX>3 (unlike QNN or RBF-ML)
 | |
| * support for specification of per-dimensional  radii  via  scale  vector,
 | |
|   which is set by means of rbfsetpointsandscales() function. This  feature
 | |
|   is useful if you solve  spatio-temporal  interpolation  problems,  where
 | |
|   different radii are required for spatial and temporal dimensions.
 | |
| 
 | |
| Running times are roughly proportional to:
 | |
| * N*log(N)*NLayers - for model construction
 | |
| * N*NLayers - for model evaluation
 | |
| You may see that running time does not depend on search radius  or  points
 | |
| density, just on number of layers in the hierarchy.
 | |
| 
 | |
| IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.11
 | |
|            and  produces  models  which  are  INCOMPATIBLE  with  previous
 | |
|            versions of ALGLIB. You can  not  unserialize  models  produced
 | |
|            with this function in ALGLIB 3.10 or earlier.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by rbfcreate() call
 | |
|     RBase   -   RBase parameter, RBase>0
 | |
|     NLayers -   NLayers parameter, NLayers>0, recommended value  to  start
 | |
|                 with - about 5.
 | |
|     LambdaNS-   >=0, nonlinearity penalty coefficient, negative values are
 | |
|                 not allowed. This parameter adds controllable smoothing to
 | |
|                 the problem, which may reduce noise. Specification of non-
 | |
|                 zero lambda means that in addition to fitting error solver
 | |
|                 will  also  minimize   LambdaNS*|S''(x)|^2  (appropriately
 | |
|                 generalized to multiple dimensions.
 | |
| 
 | |
|                 Specification of exactly zero value means that no  penalty
 | |
|                 is added  (we  do  not  even  evaluate  matrix  of  second
 | |
|                 derivatives which is necessary for smoothing).
 | |
| 
 | |
|                 Calculation of nonlinearity penalty is costly - it results
 | |
|                 in  several-fold  increase  of  model  construction  time.
 | |
|                 Evaluation time remains the same.
 | |
| 
 | |
|                 Optimal  lambda  is  problem-dependent and requires  trial
 | |
|                 and  error.  Good  value to  start  from  is  1e-5...1e-6,
 | |
|                 which corresponds to slightly noticeable smoothing  of the
 | |
|                 function.  Value  1e-2  usually  means  that  quite  heavy
 | |
|                 smoothing is applied.
 | |
| 
 | |
| TUNING ALGORITHM
 | |
| 
 | |
| In order to use this algorithm you have to choose three parameters:
 | |
| * initial radius RBase
 | |
| * number of layers in the model NLayers
 | |
| * penalty coefficient LambdaNS
 | |
| 
 | |
| Initial radius is easy to choose - you can pick any number  several  times
 | |
| larger  than  the  average  distance between points. Algorithm won't break
 | |
| down if you choose radius which is too large (model construction time will
 | |
| increase, but model will be built correctly).
 | |
| 
 | |
| Choose such number of layers that RLast=RBase/2^(NLayers-1)  (radius  used
 | |
| by  the  last  layer)  will  be  smaller than the typical distance between
 | |
| points.  In  case  model  error  is  too large, you can increase number of
 | |
| layers.  Having  more  layers  will make model construction and evaluation
 | |
| proportionally slower, but it will allow you to have model which precisely
 | |
| fits your data. From the other side, if you want to  suppress  noise,  you
 | |
| can DECREASE number of layers to make your model less flexible (or specify
 | |
| non-zero LambdaNS).
 | |
| 
 | |
| TYPICAL ERRORS
 | |
| 
 | |
| 1. Using too small number of layers - RBF models with large radius are not
 | |
|    flexible enough to reproduce small variations in the  target  function.
 | |
|    You  need  many  layers  with  different radii, from large to small, in
 | |
|    order to have good model.
 | |
| 
 | |
| 2. Using  initial  radius  which  is  too  small.  You will get model with
 | |
|    "holes" in the areas which are too far away from interpolation centers.
 | |
|    However, algorithm will work correctly (and quickly) in this case.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetalgohierarchical(const rbfmodel &s, const double rbase, const ae_int_t nlayers, const double lambdans, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetalgohierarchical(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), rbase, nlayers, lambdans, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets linear term (model is a sum of radial  basis  functions
 | |
| plus linear polynomial). This function won't have effect until  next  call
 | |
| to RBFBuildModel().
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
| 
 | |
| NOTE: this   function  has   some   serialization-related  subtleties.  We
 | |
|       recommend you to study serialization examples from ALGLIB  Reference
 | |
|       Manual if you want to perform serialization of your models.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetlinterm(const rbfmodel &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetlinterm(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets constant term (model is a sum of radial basis functions
 | |
| plus constant).  This  function  won't  have  effect  until  next  call to
 | |
| RBFBuildModel().
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
| 
 | |
| NOTE: this   function  has   some   serialization-related  subtleties.  We
 | |
|       recommend you to study serialization examples from ALGLIB  Reference
 | |
|       Manual if you want to perform serialization of your models.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetconstterm(const rbfmodel &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetconstterm(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  sets  zero  term (model is a sum of radial basis functions
 | |
| without polynomial term). This function won't have effect until next  call
 | |
| to RBFBuildModel().
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
| 
 | |
| NOTE: this   function  has   some   serialization-related  subtleties.  We
 | |
|       recommend you to study serialization examples from ALGLIB  Reference
 | |
|       Manual if you want to perform serialization of your models.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetzeroterm(const rbfmodel &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetzeroterm(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets basis function type, which can be:
 | |
| * 0 for classic Gaussian
 | |
| * 1 for fast and compact bell-like basis function, which  becomes  exactly
 | |
|   zero at distance equal to 3*R (default option).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     BF      -   basis function type:
 | |
|                 * 0 - classic Gaussian
 | |
|                 * 1 - fast and compact one
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetv2bf(const rbfmodel &s, const ae_int_t bf, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetv2bf(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), bf, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets stopping criteria of the underlying linear  solver  for
 | |
| hierarchical (version 2) RBF constructor.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     MaxIts  -   this criterion will stop algorithm after MaxIts iterations.
 | |
|                 Typically a few hundreds iterations is required,  with 400
 | |
|                 being a good default value to start experimentation.
 | |
|                 Zero value means that default value will be selected.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetv2its(const rbfmodel &s, const ae_int_t maxits, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetv2its(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), maxits, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets support radius parameter  of  hierarchical  (version 2)
 | |
| RBF constructor.
 | |
| 
 | |
| Hierarchical RBF model achieves great speed-up  by removing from the model
 | |
| excessive (too dense) nodes. Say, if you have RBF radius equal to 1 meter,
 | |
| and two nodes are just 1 millimeter apart, you  may  remove  one  of  them
 | |
| without reducing model quality.
 | |
| 
 | |
| Support radius parameter is used to justify which points need removal, and
 | |
| which do not. If two points are less than  SUPPORT_R*CUR_RADIUS  units  of
 | |
| distance apart, one of them is removed from the model. The larger  support
 | |
| radius  is, the faster model  construction  AND  evaluation are.  However,
 | |
| too large values result in "bumpy" models.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     R       -   support radius coefficient, >=0.
 | |
|                 Recommended values are [0.1,0.4] range, with 0.1 being
 | |
|                 default value.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetv2supportr(const rbfmodel &s, const double r, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfsetv2supportr(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), r, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This   function  builds  RBF  model  and  returns  report  (contains  some
 | |
| information which can be used for evaluation of the algorithm properties).
 | |
| 
 | |
| Call to this function modifies RBF model by calculating its centers/radii/
 | |
| weights  and  saving  them  into  RBFModel  structure.  Initially RBFModel
 | |
| contain zero coefficients, but after call to this function  we  will  have
 | |
| coefficients which were calculated in order to fit our dataset.
 | |
| 
 | |
| After you called this function you can call RBFCalc(),  RBFGridCalc()  and
 | |
| other model calculation functions.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     Rep     -   report:
 | |
|                 * Rep.TerminationType:
 | |
|                   * -5 - non-distinct basis function centers were detected,
 | |
|                          interpolation  aborted;  only  QNN  returns  this
 | |
|                          error   code, other  algorithms  can  handle non-
 | |
|                          distinct nodes.
 | |
|                   * -4 - nonconvergence of the internal SVD solver
 | |
|                   * -3   incorrect model construction algorithm was chosen:
 | |
|                          QNN or RBF-ML, combined with one of the incompatible
 | |
|                          features - NX=1 or NX>3; points with per-dimension
 | |
|                          scales.
 | |
|                   *  1 - successful termination
 | |
|                   *  8 - a termination request was submitted via
 | |
|                          rbfrequesttermination() function.
 | |
| 
 | |
|                 Fields which are set only by modern RBF solvers (hierarchical
 | |
|                 or nonnegative; older solvers like QNN and ML initialize these
 | |
|                 fields by NANs):
 | |
|                 * rep.rmserror - root-mean-square error at nodes
 | |
|                 * rep.maxerror - maximum error at nodes
 | |
| 
 | |
|                 Fields are used for debugging purposes:
 | |
|                 * Rep.IterationsCount - iterations count of the LSQR solver
 | |
|                 * Rep.NMV - number of matrix-vector products
 | |
|                 * Rep.ARows - rows count for the system matrix
 | |
|                 * Rep.ACols - columns count for the system matrix
 | |
|                 * Rep.ANNZ - number of significantly non-zero elements
 | |
|                   (elements above some algorithm-determined threshold)
 | |
| 
 | |
| NOTE:  failure  to  build  model will leave current state of the structure
 | |
| unchanged.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfbuildmodel(const rbfmodel &s, rbfreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfbuildmodel(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), const_cast<alglib_impl::rbfreport*>(rep.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model in the given point.
 | |
| 
 | |
| IMPORTANT: this function works only with modern  (hierarchical)  RBFs.  It
 | |
|            can not be used with legacy (version 1) RBFs because older  RBF
 | |
|            code does not support 1-dimensional models.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=1
 | |
| (1-dimensional space). If you have 3-dimensional space, use rbfcalc3(). If
 | |
| you  have  2-dimensional  space,  use  rbfcalc3().  If  you  have  general
 | |
| situation (NX-dimensional space, NY-dimensional function)  you  should use
 | |
| generic rbfcalc().
 | |
| 
 | |
| If you want to perform parallel model evaluation  from  multiple  threads,
 | |
| use rbftscalcbuf() with per-thread buffer object.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>1
 | |
| * NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   X-coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfcalc1(const rbfmodel &s, const double x0, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::rbfcalc1(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), x0, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model in the given point.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=2
 | |
| (2-dimensional space). If you have 3-dimensional space, use rbfcalc3(). If
 | |
| you have general situation (NX-dimensional space, NY-dimensional function)
 | |
| you should use generic rbfcalc().
 | |
| 
 | |
| If  you  want  to  calculate  function  values  many times, consider using
 | |
| rbfgridcalc2v(), which is far more efficient than many subsequent calls to
 | |
| rbfcalc2().
 | |
| 
 | |
| If you want to perform parallel model evaluation  from  multiple  threads,
 | |
| use rbftscalcbuf() with per-thread buffer object.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>2
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   first coordinate, finite number
 | |
|     X1      -   second coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfcalc2(const rbfmodel &s, const double x0, const double x1, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::rbfcalc2(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), x0, x1, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates value of the RBF model in the given point.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=3
 | |
| (3-dimensional space). If you have 2-dimensional space, use rbfcalc2(). If
 | |
| you have general situation (NX-dimensional space, NY-dimensional function)
 | |
| you should use generic rbfcalc().
 | |
| 
 | |
| If  you  want  to  calculate  function  values  many times, consider using
 | |
| rbfgridcalc3v(), which is far more efficient than many subsequent calls to
 | |
| rbfcalc3().
 | |
| 
 | |
| If you want to perform parallel model evaluation  from  multiple  threads,
 | |
| use rbftscalcbuf() with per-thread buffer object.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>3
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   first coordinate, finite number
 | |
|     X1      -   second coordinate, finite number
 | |
|     X2      -   third coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfcalc3(const rbfmodel &s, const double x0, const double x1, const double x2, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::rbfcalc3(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), x0, x1, x2, &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the given point.
 | |
| 
 | |
| This is general function which can be used for arbitrary NX (dimension  of
 | |
| the space of arguments) and NY (dimension of the function itself). However
 | |
| when  you  have  NY=1  you  may  find more convenient to use rbfcalc2() or
 | |
| rbfcalc3().
 | |
| 
 | |
| If you want to perform parallel model evaluation  from  multiple  threads,
 | |
| use rbftscalcbuf() with per-thread buffer object.
 | |
| 
 | |
| This function returns 0.0 when model is not initialized.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X       -   coordinates, array[NX].
 | |
|                 X may have more than NX elements, in this case only
 | |
|                 leading NX will be used.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is out-parameter and
 | |
|                 reallocated after call to this function. In case you  want
 | |
|                 to reuse previously allocated Y, you may use RBFCalcBuf(),
 | |
|                 which reallocates Y only when it is too small.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfcalc(const rbfmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the given point.
 | |
| 
 | |
| Same as rbfcalc(), but does not reallocate Y when in is large enough to
 | |
| store function values.
 | |
| 
 | |
| If you want to perform parallel model evaluation  from  multiple  threads,
 | |
| use rbftscalcbuf() with per-thread buffer object.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X       -   coordinates, array[NX].
 | |
|                 X may have more than NX elements, in this case only
 | |
|                 leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfcalcbuf(const rbfmodel &s, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the given point, using
 | |
| external  buffer  object  (internal  temporaries  of  RBF  model  are  not
 | |
| modified).
 | |
| 
 | |
| This function allows to use same RBF model object  in  different  threads,
 | |
| assuming  that  different   threads  use  different  instances  of  buffer
 | |
| structure.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, may be shared between different threads
 | |
|     Buf     -   buffer object created for this particular instance of  RBF
 | |
|                 model with rbfcreatecalcbuffer().
 | |
|     X       -   coordinates, array[NX].
 | |
|                 X may have more than NX elements, in this case only
 | |
|                 leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbftscalcbuf(const rbfmodel &s, const rbfcalcbuffer &buf, const real_1d_array &x, real_1d_array &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This is legacy function for gridded calculation of RBF model.
 | |
| 
 | |
| It is superseded by rbfgridcalc2v() and  rbfgridcalc2vsubset()  functions.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc2(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)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF  model  at  the  regular  grid,
 | |
| which  has  N0*N1 points, with Point[I,J] = (X0[I], X1[J]).  Vector-valued
 | |
| RBF models are supported.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>2
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
 | |
|       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
 | |
|       processed serially.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, used in read-only mode, can be  shared  between
 | |
|                 multiple   invocations  of  this  function  from  multiple
 | |
|                 threads.
 | |
| 
 | |
|     X0      -   array of grid nodes, first coordinates, array[N0].
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N0      -   grid size (number of nodes) in the first dimension
 | |
| 
 | |
|     X1      -   array of grid nodes, second coordinates, array[N1]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N1      -   grid size (number of nodes) in the second dimension
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function values, array[NY*N0*N1], where NY is a  number of
 | |
|                 "output" vector values (this  function   supports  vector-
 | |
|                 valued RBF models). Y is out-variable and  is  reallocated
 | |
|                 by this function.
 | |
|                 Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), for:
 | |
|                 *  K=0...NY-1
 | |
|                 * I0=0...N0-1
 | |
|                 * I1=0...N1-1
 | |
| 
 | |
| NOTE: this function supports weakly ordered grid nodes, i.e. you may  have
 | |
|       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
 | |
|       benefits  due  to   duplication  of  points,  just  convenience  and
 | |
|       flexibility.
 | |
| 
 | |
| NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
 | |
|       structure in multiple threads calling  this function  for  different
 | |
|       grids.
 | |
| 
 | |
| NOTE: if you need function values on some subset  of  regular  grid, which
 | |
|       may be described as "several compact and  dense  islands",  you  may
 | |
|       use rbfgridcalc2vsubset().
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 27.01.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc2v(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, real_1d_array &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at some subset of regular
 | |
| grid:
 | |
| * grid has N0*N1 points, with Point[I,J] = (X0[I], X1[J])
 | |
| * only values at some subset of this grid are required
 | |
| Vector-valued RBF models are supported.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>2
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
 | |
|       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
 | |
|       processed serially.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, used in read-only mode, can be  shared  between
 | |
|                 multiple   invocations  of  this  function  from  multiple
 | |
|                 threads.
 | |
| 
 | |
|     X0      -   array of grid nodes, first coordinates, array[N0].
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N0      -   grid size (number of nodes) in the first dimension
 | |
| 
 | |
|     X1      -   array of grid nodes, second coordinates, array[N1]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N1      -   grid size (number of nodes) in the second dimension
 | |
| 
 | |
|     FlagY   -   array[N0*N1]:
 | |
|                 * Y[I0+I1*N0] corresponds to node (X0[I0],X1[I1])
 | |
|                 * it is a "bitmap" array which contains  False  for  nodes
 | |
|                   which are NOT calculated, and True for nodes  which  are
 | |
|                   required.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
 | |
|                 of "output" vector values (this function  supports vector-
 | |
|                 valued RBF models):
 | |
|                 * Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]),
 | |
|                   for K=0...NY-1, I0=0...N0-1, I1=0...N1-1.
 | |
|                 * elements of Y[] which correspond  to  FlagY[]=True   are
 | |
|                   loaded by model values (which may be  exactly  zero  for
 | |
|                   some nodes).
 | |
|                 * elements of Y[] which correspond to FlagY[]=False MAY be
 | |
|                   initialized by zeros OR may be calculated. This function
 | |
|                   processes  grid  as  a  hierarchy  of  nested blocks and
 | |
|                   micro-rows. If just one element of micro-row is required,
 | |
|                   entire micro-row (up to 8 nodes in the current  version,
 | |
|                   but no promises) is calculated.
 | |
| 
 | |
| NOTE: this function supports weakly ordered grid nodes, i.e. you may  have
 | |
|       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
 | |
|       benefits  due  to   duplication  of  points,  just  convenience  and
 | |
|       flexibility.
 | |
| 
 | |
| NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
 | |
|       structure in multiple threads calling  this function  for  different
 | |
|       grids.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 04.03.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc2vsubset(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const boolean_1d_array &flagy, real_1d_array &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF  model  at  the  regular  grid,
 | |
| which  has  N0*N1*N2  points,  with  Point[I,J,K] = (X0[I], X1[J], X2[K]).
 | |
| Vector-valued RBF models are supported.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>3
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
 | |
|       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
 | |
|       processed serially.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, used in read-only mode, can be  shared  between
 | |
|                 multiple   invocations  of  this  function  from  multiple
 | |
|                 threads.
 | |
| 
 | |
|     X0      -   array of grid nodes, first coordinates, array[N0].
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N0      -   grid size (number of nodes) in the first dimension
 | |
| 
 | |
|     X1      -   array of grid nodes, second coordinates, array[N1]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N1      -   grid size (number of nodes) in the second dimension
 | |
| 
 | |
|     X2      -   array of grid nodes, third coordinates, array[N2]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N2      -   grid size (number of nodes) in the third dimension
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
 | |
|                 of "output" vector values (this function  supports vector-
 | |
|                 valued RBF models). Y is out-variable and  is  reallocated
 | |
|                 by this function.
 | |
|                 Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]), for:
 | |
|                 *  K=0...NY-1
 | |
|                 * I0=0...N0-1
 | |
|                 * I1=0...N1-1
 | |
|                 * I2=0...N2-1
 | |
| 
 | |
| NOTE: this function supports weakly ordered grid nodes, i.e. you may  have
 | |
|       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
 | |
|       benefits  due  to   duplication  of  points,  just  convenience  and
 | |
|       flexibility.
 | |
| 
 | |
| NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
 | |
|       structure in multiple threads calling  this function  for  different
 | |
|       grids.
 | |
| 
 | |
| NOTE: if you need function values on some subset  of  regular  grid, which
 | |
|       may be described as "several compact and  dense  islands",  you  may
 | |
|       use rbfgridcalc3vsubset().
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 04.03.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc3v(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const real_1d_array &x2, const ae_int_t n2, real_1d_array &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at some subset of regular
 | |
| grid:
 | |
| * grid has N0*N1*N2 points, with Point[I,J,K] = (X0[I], X1[J], X2[K])
 | |
| * only values at some subset of this grid are required
 | |
| Vector-valued RBF models are supported.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>3
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   !
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   !
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
 | |
|       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
 | |
|       processed serially.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, used in read-only mode, can be  shared  between
 | |
|                 multiple   invocations  of  this  function  from  multiple
 | |
|                 threads.
 | |
| 
 | |
|     X0      -   array of grid nodes, first coordinates, array[N0].
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N0      -   grid size (number of nodes) in the first dimension
 | |
| 
 | |
|     X1      -   array of grid nodes, second coordinates, array[N1]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N1      -   grid size (number of nodes) in the second dimension
 | |
| 
 | |
|     X2      -   array of grid nodes, third coordinates, array[N2]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N2      -   grid size (number of nodes) in the third dimension
 | |
| 
 | |
|     FlagY   -   array[N0*N1*N2]:
 | |
|                 * Y[I0+I1*N0+I2*N0*N1] corresponds to node (X0[I0],X1[I1],X2[I2])
 | |
|                 * it is a "bitmap" array which contains  False  for  nodes
 | |
|                   which are NOT calculated, and True for nodes  which  are
 | |
|                   required.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
 | |
|                 of "output" vector values (this function  supports vector-
 | |
|                 valued RBF models):
 | |
|                 * Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]),
 | |
|                   for K=0...NY-1, I0=0...N0-1, I1=0...N1-1, I2=0...N2-1.
 | |
|                 * elements of Y[] which correspond  to  FlagY[]=True   are
 | |
|                   loaded by model values (which may be  exactly  zero  for
 | |
|                   some nodes).
 | |
|                 * elements of Y[] which correspond to FlagY[]=False MAY be
 | |
|                   initialized by zeros OR may be calculated. This function
 | |
|                   processes  grid  as  a  hierarchy  of  nested blocks and
 | |
|                   micro-rows. If just one element of micro-row is required,
 | |
|                   entire micro-row (up to 8 nodes in the current  version,
 | |
|                   but no promises) is calculated.
 | |
| 
 | |
| NOTE: this function supports weakly ordered grid nodes, i.e. you may  have
 | |
|       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
 | |
|       benefits  due  to   duplication  of  points,  just  convenience  and
 | |
|       flexibility.
 | |
| 
 | |
| NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
 | |
|       structure in multiple threads calling  this function  for  different
 | |
|       grids.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 04.03.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc3vsubset(const rbfmodel &s, const real_1d_array &x0, const ae_int_t n0, const real_1d_array &x1, const ae_int_t n1, const real_1d_array &x2, const ae_int_t n2, const boolean_1d_array &flagy, real_1d_array &y, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function "unpacks" RBF model by extracting its coefficients.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     NX      -   dimensionality of argument
 | |
|     NY      -   dimensionality of the target function
 | |
|     XWR     -   model information, array[NC,NX+NY+1].
 | |
|                 One row of the array corresponds to one basis function:
 | |
|                 * first NX columns  - coordinates of the center
 | |
|                 * next NY columns   - weights, one per dimension of the
 | |
|                                       function being modelled
 | |
|                 For ModelVersion=1:
 | |
|                 * last column       - radius, same for all dimensions of
 | |
|                                       the function being modelled
 | |
|                 For ModelVersion=2:
 | |
|                 * last NX columns   - radii, one per dimension
 | |
|     NC      -   number of the centers
 | |
|     V       -   polynomial  term , array[NY,NX+1]. One row per one
 | |
|                 dimension of the function being modelled. First NX
 | |
|                 elements are linear coefficients, V[NX] is equal to the
 | |
|                 constant part.
 | |
|     ModelVersion-version of the RBF model:
 | |
|                 * 1 - for models created by QNN and RBF-ML algorithms,
 | |
|                   compatible with ALGLIB 3.10 or earlier.
 | |
|                 * 2 - for models created by HierarchicalRBF, requires
 | |
|                   ALGLIB 3.11 or later
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfunpack(const rbfmodel &s, ae_int_t &nx, ae_int_t &ny, real_2d_array &xwr, ae_int_t &nc, real_2d_array &v, ae_int_t &modelversion, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function returns model version.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
| 
 | |
| RESULT:
 | |
|     * 1 - for models created by QNN and RBF-ML algorithms,
 | |
|       compatible with ALGLIB 3.10 or earlier.
 | |
|     * 2 - for models created by HierarchicalRBF, requires
 | |
|       ALGLIB 3.11 or later
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 06.07.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| ae_int_t rbfgetmodelversion(const rbfmodel &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::ae_int_t result = alglib_impl::rbfgetmodelversion(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<ae_int_t*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is used to peek into hierarchical RBF  construction  process
 | |
| from  some  other  thread  and  get current progress indicator. It returns
 | |
| value in [0,1].
 | |
| 
 | |
| IMPORTANT: only HRBFs (hierarchical RBFs) support  peeking  into  progress
 | |
|            indicator. Legacy RBF-ML and RBF-QNN do  not  support  it.  You
 | |
|            will always get 0 value.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S           -   RBF model object
 | |
| 
 | |
| RESULT:
 | |
|     progress value, in [0,1]
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.11.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfpeekprogress(const rbfmodel &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return 0;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     double result = alglib_impl::rbfpeekprogress(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return *(reinterpret_cast<double*>(&result));
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  is  used  to  submit  a  request  for  termination  of  the
 | |
| hierarchical RBF construction process from some other thread.  As  result,
 | |
| RBF construction is terminated smoothly (with proper deallocation  of  all
 | |
| necessary resources) and resultant model is filled by zeros.
 | |
| 
 | |
| A rep.terminationtype=8 will be returned upon receiving such request.
 | |
| 
 | |
| IMPORTANT: only  HRBFs  (hierarchical  RBFs) support termination requests.
 | |
|            Legacy RBF-ML and RBF-QNN do not  support  it.  An  attempt  to
 | |
|            terminate their construction will be ignored.
 | |
| 
 | |
| IMPORTANT: termination request flag is cleared when the model construction
 | |
|            starts. Thus, any pre-construction termination requests will be
 | |
|            silently ignored - only ones submitted AFTER  construction  has
 | |
|            actually began will be handled.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S           -   RBF model object
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.11.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfrequesttermination(const rbfmodel &s, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     alglib_impl::rbfrequesttermination(const_cast<alglib_impl::rbfmodel*>(s.c_ptr()), &_alglib_env_state);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD)
 | |
| /*************************************************************************
 | |
| This function is left for backward compatibility.
 | |
| Use fitspheremc() instead.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void nsfitspheremcc(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rhi, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is left for backward compatibility.
 | |
| Use fitspheremi() instead.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void nsfitspheremic(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is left for backward compatibility.
 | |
| Use fitspheremz() instead.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void nsfitspheremzc(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is left for backward compatibility.
 | |
| Use fitspherex() instead.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void nsfitspherex(const real_2d_array &xy, const ae_int_t npoints, const ae_int_t nx, const ae_int_t problemtype, const double epsx, const ae_int_t aulits, const double penalty, real_1d_array &cx, double &rlo, double &rhi, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is an obsolete and deprecated version of fitting by
 | |
| penalized cubic spline.
 | |
| 
 | |
| It was superseded by spline1dfit(), which is an orders of magnitude faster
 | |
| and more memory-efficient implementation.
 | |
| 
 | |
| Do NOT use this function in the new code!
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is an obsolete and deprecated version of fitting by
 | |
| penalized cubic spline.
 | |
| 
 | |
| It was superseded by spline1dfit(), which is an orders of magnitude faster
 | |
| and more memory-efficient implementation.
 | |
| 
 | |
| Do NOT use this function in the new code!
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dfitpenalized(const real_1d_array &x, const real_1d_array &y, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitpenalized': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is an obsolete and deprecated version of fitting by
 | |
| penalized cubic spline.
 | |
| 
 | |
| It was superseded by spline1dfit(), which is an orders of magnitude faster
 | |
| and more memory-efficient implementation.
 | |
| 
 | |
| Do NOT use this function in the new code!
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 19.10.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t n, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|     {
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
| #else
 | |
|         _ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
 | |
|         return;
 | |
| #endif
 | |
|     }
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is an obsolete and deprecated version of fitting by
 | |
| penalized cubic spline.
 | |
| 
 | |
| It was superseded by spline1dfit(), which is an orders of magnitude faster
 | |
| and more memory-efficient implementation.
 | |
| 
 | |
| Do NOT use this function in the new code!
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 19.10.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| #if !defined(AE_NO_EXCEPTIONS)
 | |
| void spline1dfitpenalizedw(const real_1d_array &x, const real_1d_array &y, const real_1d_array &w, const ae_int_t m, const double rho, ae_int_t &info, spline1dinterpolant &s, spline1dfitreport &rep, const xparams _xparams)
 | |
| {
 | |
|     jmp_buf _break_jump;
 | |
|     alglib_impl::ae_state _alglib_env_state;    
 | |
|     ae_int_t n;
 | |
|     if( (x.length()!=y.length()) || (x.length()!=w.length()))
 | |
|         _ALGLIB_CPP_EXCEPTION("Error while calling 'spline1dfitpenalizedw': looks like one of arguments has wrong size");
 | |
|     n = x.length();
 | |
|     alglib_impl::ae_state_init(&_alglib_env_state);
 | |
|     if( setjmp(_break_jump) )
 | |
|         _ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
 | |
|     ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
 | |
|     if( _xparams.flags!=0x0 )
 | |
|         ae_state_set_flags(&_alglib_env_state, _xparams.flags);
 | |
|     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);
 | |
| 
 | |
|     alglib_impl::ae_state_clear(&_alglib_env_state);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /////////////////////////////////////////////////////////////////////////
 | |
| //
 | |
| // THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE
 | |
| //
 | |
| /////////////////////////////////////////////////////////////////////////
 | |
| namespace alglib_impl
 | |
| {
 | |
| #if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD)
 | |
| static double idw_w0 = 1.0;
 | |
| static double idw_meps = 1.0E-50;
 | |
| static ae_int_t idw_defaultnlayers = 16;
 | |
| static double idw_defaultlambda0 = 0.3333;
 | |
| static void idw_errormetricsviacalc(idwbuilder* state,
 | |
|      idwmodel* model,
 | |
|      idwreport* rep,
 | |
|      ae_state *_state);
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD)
 | |
| static void ratint_barycentricnormalize(barycentricinterpolant* b,
 | |
|      ae_state *_state);
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD)
 | |
| static double spline1d_lambdareg = 1.0e-9;
 | |
| static double spline1d_cholreg = 1.0e-12;
 | |
| static void spline1d_spline1dgriddiffcubicinternal(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t boundltype,
 | |
|      double boundl,
 | |
|      ae_int_t boundrtype,
 | |
|      double boundr,
 | |
|      /* Real    */ ae_vector* d,
 | |
|      /* Real    */ ae_vector* a1,
 | |
|      /* Real    */ ae_vector* a2,
 | |
|      /* Real    */ ae_vector* a3,
 | |
|      /* Real    */ ae_vector* b,
 | |
|      /* Real    */ ae_vector* dt,
 | |
|      ae_state *_state);
 | |
| static void spline1d_heapsortpoints(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_state *_state);
 | |
| static void spline1d_heapsortppoints(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Integer */ ae_vector* p,
 | |
|      ae_int_t n,
 | |
|      ae_state *_state);
 | |
| static void spline1d_solvetridiagonal(/* Real    */ ae_vector* a,
 | |
|      /* Real    */ ae_vector* b,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      /* Real    */ ae_vector* d,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      ae_state *_state);
 | |
| static void spline1d_solvecyclictridiagonal(/* Real    */ ae_vector* a,
 | |
|      /* Real    */ ae_vector* b,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      /* Real    */ ae_vector* d,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      ae_state *_state);
 | |
| static double spline1d_diffthreepoint(double t,
 | |
|      double x0,
 | |
|      double f0,
 | |
|      double x1,
 | |
|      double f1,
 | |
|      double x2,
 | |
|      double f2,
 | |
|      ae_state *_state);
 | |
| static void spline1d_hermitecalc(double p0,
 | |
|      double m0,
 | |
|      double p1,
 | |
|      double m1,
 | |
|      double t,
 | |
|      double* s,
 | |
|      double* ds,
 | |
|      ae_state *_state);
 | |
| static double spline1d_rescaleval(double a0,
 | |
|      double b0,
 | |
|      double a1,
 | |
|      double b1,
 | |
|      double t,
 | |
|      ae_state *_state);
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD)
 | |
| static void parametric_pspline2par(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_int_t pt,
 | |
|      /* Real    */ ae_vector* p,
 | |
|      ae_state *_state);
 | |
| static void parametric_pspline3par(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_int_t pt,
 | |
|      /* Real    */ ae_vector* p,
 | |
|      ae_state *_state);
 | |
| static void parametric_rdpanalyzesectionpar(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t i0,
 | |
|      ae_int_t i1,
 | |
|      ae_int_t d,
 | |
|      ae_int_t* worstidx,
 | |
|      double* worsterror,
 | |
|      ae_state *_state);
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD)
 | |
| static void spline3d_spline3ddiff(spline3dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      double z,
 | |
|      double* f,
 | |
|      double* fx,
 | |
|      double* fy,
 | |
|      double* fxy,
 | |
|      ae_state *_state);
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD)
 | |
| static void lsfit_rdpanalyzesection(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t i0,
 | |
|      ae_int_t i1,
 | |
|      ae_int_t* worstidx,
 | |
|      double* worsterror,
 | |
|      ae_state *_state);
 | |
| static void lsfit_rdprecursive(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t i0,
 | |
|      ae_int_t i1,
 | |
|      double eps,
 | |
|      /* Real    */ ae_vector* xout,
 | |
|      /* Real    */ ae_vector* yout,
 | |
|      ae_int_t* nout,
 | |
|      ae_state *_state);
 | |
| static void lsfit_logisticfitinternal(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_bool is4pl,
 | |
|      double lambdav,
 | |
|      minlmstate* state,
 | |
|      minlmreport* replm,
 | |
|      /* Real    */ ae_vector* p1,
 | |
|      double* flast,
 | |
|      ae_state *_state);
 | |
| static void lsfit_logisticfit45errors(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      double a,
 | |
|      double b,
 | |
|      double c,
 | |
|      double d,
 | |
|      double g,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state);
 | |
| static void lsfit_spline1dfitinternal(ae_int_t st,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      spline1dinterpolant* s,
 | |
|      spline1dfitreport* rep,
 | |
|      ae_state *_state);
 | |
| static void lsfit_lsfitlinearinternal(/* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      /* Real    */ ae_matrix* fmatrix,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state);
 | |
| static void lsfit_lsfitclearrequestfields(lsfitstate* state,
 | |
|      ae_state *_state);
 | |
| static void lsfit_barycentriccalcbasis(barycentricinterpolant* b,
 | |
|      double t,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state);
 | |
| static void lsfit_internalchebyshevfit(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state);
 | |
| static void lsfit_barycentricfitwcfixedd(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      ae_int_t m,
 | |
|      ae_int_t d,
 | |
|      ae_int_t* info,
 | |
|      barycentricinterpolant* b,
 | |
|      barycentricfitreport* rep,
 | |
|      ae_state *_state);
 | |
| static void lsfit_clearreport(lsfitreport* rep, ae_state *_state);
 | |
| static void lsfit_estimateerrors(/* Real    */ ae_matrix* f1,
 | |
|      /* Real    */ ae_vector* f0,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* s,
 | |
|      ae_int_t n,
 | |
|      ae_int_t k,
 | |
|      lsfitreport* rep,
 | |
|      /* Real    */ ae_matrix* z,
 | |
|      ae_int_t zkind,
 | |
|      ae_state *_state);
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD)
 | |
| static double rbfv2_defaultlambdareg = 1.0E-6;
 | |
| static double rbfv2_defaultsupportr = 0.10;
 | |
| static ae_int_t rbfv2_defaultmaxits = 400;
 | |
| static ae_int_t rbfv2_defaultbf = 1;
 | |
| static ae_int_t rbfv2_maxnodesize = 6;
 | |
| static double rbfv2_complexitymultiplier = 100.0;
 | |
| static ae_bool rbfv2_rbfv2buildlinearmodel(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t modeltype,
 | |
|      /* Real    */ ae_matrix* v,
 | |
|      ae_state *_state);
 | |
| static void rbfv2_allocatecalcbuffer(rbfv2model* s,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_state *_state);
 | |
| static void rbfv2_convertandappendtree(kdtree* curtree,
 | |
|      ae_int_t n,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      /* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      ae_state *_state);
 | |
| static void rbfv2_converttreerec(kdtree* curtree,
 | |
|      ae_int_t n,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t nodeoffset,
 | |
|      ae_int_t nodesbase,
 | |
|      ae_int_t splitsbase,
 | |
|      ae_int_t cwbase,
 | |
|      /* Integer */ ae_vector* localnodes,
 | |
|      ae_int_t* localnodessize,
 | |
|      /* Real    */ ae_vector* localsplits,
 | |
|      ae_int_t* localsplitssize,
 | |
|      /* Real    */ ae_vector* localcw,
 | |
|      ae_int_t* localcwsize,
 | |
|      /* Real    */ ae_matrix* xybuf,
 | |
|      ae_state *_state);
 | |
| static void rbfv2_partialcalcrec(rbfv2model* s,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_int_t rootidx,
 | |
|      double invr2,
 | |
|      double queryr2,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state);
 | |
| static void rbfv2_partialrowcalcrec(rbfv2model* s,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_int_t rootidx,
 | |
|      double invr2,
 | |
|      double rquery2,
 | |
|      double rfar2,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      /* Real    */ ae_vector* rx,
 | |
|      /* Boolean */ ae_vector* rf,
 | |
|      ae_int_t rowsize,
 | |
|      /* Real    */ ae_vector* ry,
 | |
|      ae_state *_state);
 | |
| static void rbfv2_preparepartialquery(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* kdboxmin,
 | |
|      /* Real    */ ae_vector* kdboxmax,
 | |
|      ae_int_t nx,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_int_t* cnt,
 | |
|      ae_state *_state);
 | |
| static void rbfv2_partialqueryrec(/* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_int_t rootidx,
 | |
|      double queryr2,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* r2,
 | |
|      /* Integer */ ae_vector* offs,
 | |
|      ae_int_t* k,
 | |
|      ae_state *_state);
 | |
| static ae_int_t rbfv2_partialcountrec(/* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_int_t rootidx,
 | |
|      double queryr2,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      ae_state *_state);
 | |
| static void rbfv2_partialunpackrec(/* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      /* Real    */ ae_vector* s,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t rootidx,
 | |
|      double r,
 | |
|      /* Real    */ ae_matrix* xwr,
 | |
|      ae_int_t* k,
 | |
|      ae_state *_state);
 | |
| static ae_int_t rbfv2_designmatrixrowsize(/* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      /* Real    */ ae_vector* ri,
 | |
|      /* Integer */ ae_vector* kdroots,
 | |
|      /* Real    */ ae_vector* kdboxmin,
 | |
|      /* Real    */ ae_vector* kdboxmax,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t nh,
 | |
|      ae_int_t level,
 | |
|      double rcoeff,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      rbfv2calcbuffer* calcbuf,
 | |
|      ae_state *_state);
 | |
| static void rbfv2_designmatrixgeneraterow(/* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      /* Real    */ ae_vector* ri,
 | |
|      /* Integer */ ae_vector* kdroots,
 | |
|      /* Real    */ ae_vector* kdboxmin,
 | |
|      /* Real    */ ae_vector* kdboxmax,
 | |
|      /* Integer */ ae_vector* cwrange,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t nh,
 | |
|      ae_int_t level,
 | |
|      ae_int_t bf,
 | |
|      double rcoeff,
 | |
|      ae_int_t rowsperpoint,
 | |
|      double penalty,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      rbfv2calcbuffer* calcbuf,
 | |
|      /* Real    */ ae_vector* tmpr2,
 | |
|      /* Integer */ ae_vector* tmpoffs,
 | |
|      /* Integer */ ae_vector* rowidx,
 | |
|      /* Real    */ ae_vector* rowval,
 | |
|      ae_int_t* rowsize,
 | |
|      ae_state *_state);
 | |
| static void rbfv2_zerofill(rbfv2model* s,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t bf,
 | |
|      ae_state *_state);
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD)
 | |
| static double spline2d_cholreg = 1.0E-12;
 | |
| static double spline2d_lambdaregblocklls = 1.0E-6;
 | |
| static double spline2d_lambdaregfastddm = 1.0E-4;
 | |
| static double spline2d_lambdadecay = 0.5;
 | |
| static void spline2d_bicubiccalcderivatives(/* Real    */ ae_matrix* a,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t m,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_matrix* dx,
 | |
|      /* Real    */ ae_matrix* dy,
 | |
|      /* Real    */ ae_matrix* dxy,
 | |
|      ae_state *_state);
 | |
| static void spline2d_generatedesignmatrix(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      double smoothing,
 | |
|      double lambdareg,
 | |
|      spline1dinterpolant* basis1,
 | |
|      sparsematrix* av,
 | |
|      sparsematrix* ah,
 | |
|      ae_int_t* arows,
 | |
|      ae_state *_state);
 | |
| static void spline2d_updatesplinetable(/* Real    */ ae_vector* z,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t d,
 | |
|      spline1dinterpolant* basis1,
 | |
|      ae_int_t bfrad,
 | |
|      /* Real    */ ae_vector* ftbl,
 | |
|      ae_int_t m,
 | |
|      ae_int_t n,
 | |
|      ae_int_t scalexy,
 | |
|      ae_state *_state);
 | |
| static void spline2d_fastddmfit(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t basecasex,
 | |
|      ae_int_t basecasey,
 | |
|      ae_int_t maxcoresize,
 | |
|      ae_int_t interfacesize,
 | |
|      ae_int_t nlayers,
 | |
|      double smoothing,
 | |
|      ae_int_t lsqrcnt,
 | |
|      spline1dinterpolant* basis1,
 | |
|      spline2dinterpolant* spline,
 | |
|      spline2dfitreport* rep,
 | |
|      double tss,
 | |
|      ae_state *_state);
 | |
| static void spline2d_fastddmfitlayer(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t d,
 | |
|      ae_int_t scalexy,
 | |
|      /* Integer */ ae_vector* xyindex,
 | |
|      ae_int_t basecasex,
 | |
|      ae_int_t tilex0,
 | |
|      ae_int_t tilex1,
 | |
|      ae_int_t tilescountx,
 | |
|      ae_int_t basecasey,
 | |
|      ae_int_t tiley0,
 | |
|      ae_int_t tiley1,
 | |
|      ae_int_t tilescounty,
 | |
|      ae_int_t maxcoresize,
 | |
|      ae_int_t interfacesize,
 | |
|      ae_int_t lsqrcnt,
 | |
|      double lambdareg,
 | |
|      spline1dinterpolant* basis1,
 | |
|      ae_shared_pool* pool,
 | |
|      spline2dinterpolant* spline,
 | |
|      ae_state *_state);
 | |
| ae_bool _trypexec_spline2d_fastddmfitlayer(/* Real    */ ae_vector* xy,
 | |
|     ae_int_t d,
 | |
|     ae_int_t scalexy,
 | |
|     /* Integer */ ae_vector* xyindex,
 | |
|     ae_int_t basecasex,
 | |
|     ae_int_t tilex0,
 | |
|     ae_int_t tilex1,
 | |
|     ae_int_t tilescountx,
 | |
|     ae_int_t basecasey,
 | |
|     ae_int_t tiley0,
 | |
|     ae_int_t tiley1,
 | |
|     ae_int_t tilescounty,
 | |
|     ae_int_t maxcoresize,
 | |
|     ae_int_t interfacesize,
 | |
|     ae_int_t lsqrcnt,
 | |
|     double lambdareg,
 | |
|     spline1dinterpolant* basis1,
 | |
|     ae_shared_pool* pool,
 | |
|     spline2dinterpolant* spline, ae_state *_state);
 | |
| static void spline2d_blockllsfit(spline2dxdesignmatrix* xdesign,
 | |
|      ae_int_t lsqrcnt,
 | |
|      /* Real    */ ae_vector* z,
 | |
|      spline2dfitreport* rep,
 | |
|      double tss,
 | |
|      spline2dblockllsbuf* buf,
 | |
|      ae_state *_state);
 | |
| static void spline2d_naivellsfit(sparsematrix* av,
 | |
|      sparsematrix* ah,
 | |
|      ae_int_t arows,
 | |
|      /* Real    */ ae_vector* xy,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      ae_int_t lsqrcnt,
 | |
|      /* Real    */ ae_vector* z,
 | |
|      spline2dfitreport* rep,
 | |
|      double tss,
 | |
|      ae_state *_state);
 | |
| static ae_int_t spline2d_getcelloffset(ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t blockbandwidth,
 | |
|      ae_int_t i,
 | |
|      ae_int_t j,
 | |
|      ae_state *_state);
 | |
| static void spline2d_copycellto(ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t blockbandwidth,
 | |
|      /* Real    */ ae_matrix* blockata,
 | |
|      ae_int_t i,
 | |
|      ae_int_t j,
 | |
|      /* Real    */ ae_matrix* dst,
 | |
|      ae_int_t dst0,
 | |
|      ae_int_t dst1,
 | |
|      ae_state *_state);
 | |
| static void spline2d_flushtozerocell(ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t blockbandwidth,
 | |
|      /* Real    */ ae_matrix* blockata,
 | |
|      ae_int_t i,
 | |
|      ae_int_t j,
 | |
|      double eps,
 | |
|      ae_state *_state);
 | |
| static void spline2d_blockllsgenerateata(sparsematrix* ah,
 | |
|      ae_int_t ky0,
 | |
|      ae_int_t ky1,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      /* Real    */ ae_matrix* blockata,
 | |
|      sreal* mxata,
 | |
|      ae_state *_state);
 | |
| ae_bool _trypexec_spline2d_blockllsgenerateata(sparsematrix* ah,
 | |
|     ae_int_t ky0,
 | |
|     ae_int_t ky1,
 | |
|     ae_int_t kx,
 | |
|     ae_int_t ky,
 | |
|     /* Real    */ ae_matrix* blockata,
 | |
|     sreal* mxata, ae_state *_state);
 | |
| static ae_bool spline2d_blockllscholesky(/* Real    */ ae_matrix* blockata,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      /* Real    */ ae_matrix* trsmbuf2,
 | |
|      /* Real    */ ae_matrix* cholbuf2,
 | |
|      /* Real    */ ae_vector* cholbuf1,
 | |
|      ae_state *_state);
 | |
| static void spline2d_blockllstrsv(/* Real    */ ae_matrix* blockata,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_bool transu,
 | |
|      /* Real    */ ae_vector* b,
 | |
|      ae_state *_state);
 | |
| static void spline2d_computeresidualsfromscratch(/* Real    */ ae_vector* xy,
 | |
|      /* Real    */ ae_vector* yraw,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      ae_int_t scalexy,
 | |
|      spline2dinterpolant* spline,
 | |
|      ae_state *_state);
 | |
| ae_bool _trypexec_spline2d_computeresidualsfromscratch(/* Real    */ ae_vector* xy,
 | |
|     /* Real    */ ae_vector* yraw,
 | |
|     ae_int_t npoints,
 | |
|     ae_int_t d,
 | |
|     ae_int_t scalexy,
 | |
|     spline2dinterpolant* spline, ae_state *_state);
 | |
| static void spline2d_computeresidualsfromscratchrec(/* Real    */ ae_vector* xy,
 | |
|      /* Real    */ ae_vector* yraw,
 | |
|      ae_int_t pt0,
 | |
|      ae_int_t pt1,
 | |
|      ae_int_t chunksize,
 | |
|      ae_int_t d,
 | |
|      ae_int_t scalexy,
 | |
|      spline2dinterpolant* spline,
 | |
|      ae_shared_pool* pool,
 | |
|      ae_state *_state);
 | |
| ae_bool _trypexec_spline2d_computeresidualsfromscratchrec(/* Real    */ ae_vector* xy,
 | |
|     /* Real    */ ae_vector* yraw,
 | |
|     ae_int_t pt0,
 | |
|     ae_int_t pt1,
 | |
|     ae_int_t chunksize,
 | |
|     ae_int_t d,
 | |
|     ae_int_t scalexy,
 | |
|     spline2dinterpolant* spline,
 | |
|     ae_shared_pool* pool, ae_state *_state);
 | |
| static void spline2d_reorderdatasetandbuildindex(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      /* Real    */ ae_vector* shadow,
 | |
|      ae_int_t ns,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      /* Integer */ ae_vector* xyindex,
 | |
|      /* Integer */ ae_vector* bufi,
 | |
|      ae_state *_state);
 | |
| static void spline2d_rescaledatasetandrefineindex(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      /* Real    */ ae_vector* shadow,
 | |
|      ae_int_t ns,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      /* Integer */ ae_vector* xyindex,
 | |
|      /* Integer */ ae_vector* bufi,
 | |
|      ae_state *_state);
 | |
| static void spline2d_expandindexrows(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t d,
 | |
|      /* Real    */ ae_vector* shadow,
 | |
|      ae_int_t ns,
 | |
|      /* Integer */ ae_vector* cidx,
 | |
|      ae_int_t pt0,
 | |
|      ae_int_t pt1,
 | |
|      /* Integer */ ae_vector* xyindexprev,
 | |
|      ae_int_t row0,
 | |
|      ae_int_t row1,
 | |
|      /* Integer */ ae_vector* xyindexnew,
 | |
|      ae_int_t kxnew,
 | |
|      ae_int_t kynew,
 | |
|      ae_bool rootcall,
 | |
|      ae_state *_state);
 | |
| ae_bool _trypexec_spline2d_expandindexrows(/* Real    */ ae_vector* xy,
 | |
|     ae_int_t d,
 | |
|     /* Real    */ ae_vector* shadow,
 | |
|     ae_int_t ns,
 | |
|     /* Integer */ ae_vector* cidx,
 | |
|     ae_int_t pt0,
 | |
|     ae_int_t pt1,
 | |
|     /* Integer */ ae_vector* xyindexprev,
 | |
|     ae_int_t row0,
 | |
|     ae_int_t row1,
 | |
|     /* Integer */ ae_vector* xyindexnew,
 | |
|     ae_int_t kxnew,
 | |
|     ae_int_t kynew,
 | |
|     ae_bool rootcall, ae_state *_state);
 | |
| static void spline2d_reorderdatasetandbuildindexrec(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t d,
 | |
|      /* Real    */ ae_vector* shadow,
 | |
|      ae_int_t ns,
 | |
|      /* Integer */ ae_vector* cidx,
 | |
|      ae_int_t pt0,
 | |
|      ae_int_t pt1,
 | |
|      /* Integer */ ae_vector* xyindex,
 | |
|      ae_int_t idx0,
 | |
|      ae_int_t idx1,
 | |
|      ae_bool rootcall,
 | |
|      ae_state *_state);
 | |
| ae_bool _trypexec_spline2d_reorderdatasetandbuildindexrec(/* Real    */ ae_vector* xy,
 | |
|     ae_int_t d,
 | |
|     /* Real    */ ae_vector* shadow,
 | |
|     ae_int_t ns,
 | |
|     /* Integer */ ae_vector* cidx,
 | |
|     ae_int_t pt0,
 | |
|     ae_int_t pt1,
 | |
|     /* Integer */ ae_vector* xyindex,
 | |
|     ae_int_t idx0,
 | |
|     ae_int_t idx1,
 | |
|     ae_bool rootcall, ae_state *_state);
 | |
| static void spline2d_xdesigngenerate(/* Real    */ ae_vector* xy,
 | |
|      /* Integer */ ae_vector* xyindex,
 | |
|      ae_int_t kx0,
 | |
|      ae_int_t kx1,
 | |
|      ae_int_t kxtotal,
 | |
|      ae_int_t ky0,
 | |
|      ae_int_t ky1,
 | |
|      ae_int_t kytotal,
 | |
|      ae_int_t d,
 | |
|      double lambdareg,
 | |
|      double lambdans,
 | |
|      spline1dinterpolant* basis1,
 | |
|      spline2dxdesignmatrix* a,
 | |
|      ae_state *_state);
 | |
| static void spline2d_xdesignmv(spline2dxdesignmatrix* a,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state);
 | |
| static void spline2d_xdesignmtv(spline2dxdesignmatrix* a,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state);
 | |
| static void spline2d_xdesignblockata(spline2dxdesignmatrix* a,
 | |
|      /* Real    */ ae_matrix* blockata,
 | |
|      double* mxata,
 | |
|      ae_state *_state);
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD)
 | |
| static ae_int_t rbfv1_mxnx = 3;
 | |
| static double rbfv1_rbffarradius = 6;
 | |
| static double rbfv1_rbfnearradius = 2.1;
 | |
| static double rbfv1_rbfmlradius = 3;
 | |
| static double rbfv1_minbasecasecost = 100000;
 | |
| static ae_bool rbfv1_rbfv1buildlinearmodel(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t modeltype,
 | |
|      /* Real    */ ae_matrix* v,
 | |
|      ae_state *_state);
 | |
| static void rbfv1_buildrbfmodellsqr(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      /* Real    */ ae_matrix* xc,
 | |
|      /* Real    */ ae_vector* r,
 | |
|      ae_int_t n,
 | |
|      ae_int_t nc,
 | |
|      ae_int_t ny,
 | |
|      kdtree* pointstree,
 | |
|      kdtree* centerstree,
 | |
|      double epsort,
 | |
|      double epserr,
 | |
|      ae_int_t maxits,
 | |
|      ae_int_t* gnnz,
 | |
|      ae_int_t* snnz,
 | |
|      /* Real    */ ae_matrix* w,
 | |
|      ae_int_t* info,
 | |
|      ae_int_t* iterationscount,
 | |
|      ae_int_t* nmv,
 | |
|      ae_state *_state);
 | |
| static void rbfv1_buildrbfmlayersmodellsqr(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      /* Real    */ ae_matrix* xc,
 | |
|      double rval,
 | |
|      /* Real    */ ae_vector* r,
 | |
|      ae_int_t n,
 | |
|      ae_int_t* nc,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t nlayers,
 | |
|      kdtree* centerstree,
 | |
|      double epsort,
 | |
|      double epserr,
 | |
|      ae_int_t maxits,
 | |
|      double lambdav,
 | |
|      ae_int_t* annz,
 | |
|      /* Real    */ ae_matrix* w,
 | |
|      ae_int_t* info,
 | |
|      ae_int_t* iterationscount,
 | |
|      ae_int_t* nmv,
 | |
|      ae_state *_state);
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD)
 | |
| static double rbf_eps = 1.0E-6;
 | |
| static double rbf_rbffarradius = 6;
 | |
| static ae_int_t rbf_rbffirstversion = 0;
 | |
| static ae_int_t rbf_rbfversion2 = 2;
 | |
| static void rbf_rbfpreparenonserializablefields(rbfmodel* s,
 | |
|      ae_state *_state);
 | |
| static void rbf_initializev1(ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      rbfv1model* s,
 | |
|      ae_state *_state);
 | |
| static void rbf_initializev2(ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      rbfv2model* s,
 | |
|      ae_state *_state);
 | |
| static void rbf_clearreportfields(rbfreport* rep, ae_state *_state);
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(AE_COMPILE_IDW) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function creates buffer  structure  which  can  be  used  to  perform
 | |
| parallel  IDW  model  evaluations  (with  one  IDW  model  instance  being
 | |
| used from multiple threads, as long as  different  threads  use  different
 | |
| instances of buffer).
 | |
| 
 | |
| This buffer object can be used with  idwtscalcbuf()  function  (here  "ts"
 | |
| stands for "thread-safe", "buf" is a suffix which denotes  function  which
 | |
| reuses previously allocated output space).
 | |
| 
 | |
| How to use it:
 | |
| * create IDW model structure or load it from file
 | |
| * call idwcreatecalcbuffer(), once per thread working with IDW model  (you
 | |
|   should call this function only AFTER model initialization, see below for
 | |
|   more information)
 | |
| * call idwtscalcbuf() from different threads,  with  each  thread  working
 | |
|   with its own copy of buffer object.
 | |
| 
 | |
| INPUT PARAMETERS
 | |
|     S           -   IDW model
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     Buf         -   external buffer.
 | |
|     
 | |
|     
 | |
| IMPORTANT: buffer object should be used only with  IDW model object  which
 | |
|            was used to initialize buffer. Any attempt to use buffer   with
 | |
|            different object is dangerous - you may  get  memory  violation
 | |
|            error because sizes of internal arrays do not fit to dimensions
 | |
|            of the IDW structure.
 | |
|            
 | |
| IMPORTANT: you  should  call  this function only for model which was built
 | |
|            with model builder (or unserialized from file). Sizes  of  some
 | |
|            internal structures are determined only after model  is  built,
 | |
|            so buffer object created before model construction  stage  will
 | |
|            be useless (and any attempt to use it will result in exception).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Sergey Bochkanov
 | |
| *************************************************************************/
 | |
| void idwcreatecalcbuffer(idwmodel* s,
 | |
|      idwcalcbuffer* buf,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _idwcalcbuffer_clear(buf);
 | |
| 
 | |
|     ae_assert(s->nx>=1, "IDWCreateCalcBuffer: integrity check failed", _state);
 | |
|     ae_assert(s->ny>=1, "IDWCreateCalcBuffer: integrity check failed", _state);
 | |
|     ae_assert(s->nlayers>=0, "IDWCreateCalcBuffer: integrity check failed", _state);
 | |
|     ae_assert(s->algotype>=0, "IDWCreateCalcBuffer: integrity check failed", _state);
 | |
|     if( s->nlayers>=1&&s->algotype!=0 )
 | |
|     {
 | |
|         kdtreecreaterequestbuffer(&s->tree, &buf->requestbuffer, _state);
 | |
|     }
 | |
|     rvectorsetlengthatleast(&buf->x, s->nx, _state);
 | |
|     rvectorsetlengthatleast(&buf->y, s->ny, _state);
 | |
|     rvectorsetlengthatleast(&buf->tsyw, s->ny*ae_maxint(s->nlayers, 1, _state), _state);
 | |
|     rvectorsetlengthatleast(&buf->tsw, ae_maxint(s->nlayers, 1, _state), _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine creates builder object used  to  generate IDW  model  from
 | |
| irregularly sampled (scattered) dataset.  Multidimensional  scalar/vector-
 | |
| -valued are supported.
 | |
| 
 | |
| Builder object is used to fit model to data as follows:
 | |
| * builder object is created with idwbuildercreate() function
 | |
| * dataset is added with idwbuildersetpoints() function
 | |
| * one of the modern IDW algorithms is chosen with either:
 | |
|   * idwbuildersetalgomstab()            - Multilayer STABilized algorithm (interpolation)
 | |
|   Alternatively, one of the textbook algorithms can be chosen (not recommended):
 | |
|   * idwbuildersetalgotextbookshepard()  - textbook Shepard algorithm
 | |
|   * idwbuildersetalgotextbookmodshepard()-textbook modified Shepard algorithm
 | |
| * finally, model construction is performed with idwfit() function.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     NX  -   dimensionality of the argument, NX>=1
 | |
|     NY  -   dimensionality of the function being modeled, NY>=1;
 | |
|             NY=1 corresponds to classic scalar function, NY>=1 corresponds
 | |
|             to vector-valued function.
 | |
|     
 | |
| OUTPUT PARAMETERS:
 | |
|     State-  builder object
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildercreate(ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      idwbuilder* state,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _idwbuilder_clear(state);
 | |
| 
 | |
|     ae_assert(nx>=1, "IDWBuilderCreate: NX<=0", _state);
 | |
|     ae_assert(ny>=1, "IDWBuilderCreate: NY<=0", _state);
 | |
|     
 | |
|     /*
 | |
|      * We choose reasonable defaults for the algorithm:
 | |
|      * * MSTAB algorithm
 | |
|      * * 12 layers
 | |
|      * * default radius
 | |
|      * * default Lambda0
 | |
|      */
 | |
|     state->algotype = 2;
 | |
|     state->priortermtype = 2;
 | |
|     rvectorsetlengthatleast(&state->priortermval, ny, _state);
 | |
|     state->nlayers = idw_defaultnlayers;
 | |
|     state->r0 = (double)(0);
 | |
|     state->rdecay = 0.5;
 | |
|     state->lambda0 = idw_defaultlambda0;
 | |
|     state->lambdalast = (double)(0);
 | |
|     state->lambdadecay = 1.0;
 | |
|     
 | |
|     /*
 | |
|      * Other parameters, not used but initialized
 | |
|      */
 | |
|     state->shepardp = (double)(0);
 | |
|     
 | |
|     /*
 | |
|      * Initial dataset is empty
 | |
|      */
 | |
|     state->npoints = 0;
 | |
|     state->nx = nx;
 | |
|     state->ny = ny;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function changes number of layers used by IDW-MSTAB algorithm.
 | |
| 
 | |
| The more layers you have, the finer details can  be  reproduced  with  IDW
 | |
| model. The less layers you have, the less memory and CPU time is  consumed
 | |
| by the model.
 | |
| 
 | |
| Memory consumption grows linearly with layers count,  running  time  grows
 | |
| sub-linearly.
 | |
| 
 | |
| The default number of layers is 16, which allows you to reproduce  details
 | |
| at distance down to SRad/65536. You will rarely need to change it.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     NLayers -   NLayers>=1, the number of layers used by the model.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetnlayers(idwbuilder* state,
 | |
|      ae_int_t nlayers,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(nlayers>=1, "IDWBuilderSetNLayers: N<1", _state);
 | |
|     state->nlayers = nlayers;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset to the builder object.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     XY      -   points, array[N,NX+NY]. One row  corresponds to  one point
 | |
|                 in the dataset. First NX elements  are  coordinates,  next
 | |
|                 NY elements are function values. Array may  be larger than 
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements 
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset, N>=0.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetpoints(idwbuilder* state,
 | |
|      /* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t ew;
 | |
| 
 | |
| 
 | |
|     ae_assert(n>=0, "IDWBuilderSetPoints: N<0", _state);
 | |
|     ae_assert(xy->rows>=n, "IDWBuilderSetPoints: Rows(XY)<N", _state);
 | |
|     ae_assert(n==0||xy->cols>=state->nx+state->ny, "IDWBuilderSetPoints: Cols(XY)<NX+NY", _state);
 | |
|     ae_assert(apservisfinitematrix(xy, n, state->nx+state->ny, _state), "IDWBuilderSetPoints: XY contains infinite or NaN values!", _state);
 | |
|     state->npoints = n;
 | |
|     ew = state->nx+state->ny;
 | |
|     rvectorsetlengthatleast(&state->xy, n*ew, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=ew-1; j++)
 | |
|         {
 | |
|             state->xy.ptr.p_double[i*ew+j] = xy->ptr.pp_double[i][j];
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets IDW model  construction  algorithm  to  the  Multilayer
 | |
| Stabilized IDW method (IDW-MSTAB), a  latest  incarnation  of  the inverse
 | |
| distance weighting interpolation which fixes shortcomings of  the original
 | |
| and modified Shepard's variants.
 | |
| 
 | |
| The distinctive features of IDW-MSTAB are:
 | |
| 1) exact interpolation  is  pursued  (as  opposed  to  fitting  and  noise
 | |
|    suppression)
 | |
| 2) improved robustness when compared with that of other algorithms:
 | |
|    * MSTAB shows almost no strange  fitting  artifacts  like  ripples  and
 | |
|      sharp spikes (unlike N-dimensional splines and HRBFs)
 | |
|    * MSTAB does not return function values far from the  interval  spanned
 | |
|      by the dataset; say, if all your points have |f|<=1, you  can be sure
 | |
|      that model value won't deviate too much from [-1,+1]
 | |
| 3) good model construction time competing with that of HRBFs  and  bicubic
 | |
|    splines
 | |
| 4) ability to work with any number of dimensions, starting from NX=1
 | |
| 
 | |
| The drawbacks of IDW-MSTAB (and all IDW algorithms in general) are:
 | |
| 1) dependence of the model evaluation time on the search radius
 | |
| 2) bad extrapolation properties, models built by this method  are  usually
 | |
|    conservative in their predictions
 | |
| 
 | |
| Thus, IDW-MSTAB is  a  good  "default"  option  if  you  want  to  perform
 | |
| scattered multidimensional interpolation. Although it has  its  drawbacks,
 | |
| it is easy to use and robust, which makes it a good first step.
 | |
| 
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     SRad    -   initial search radius, SRad>0 is required. A model  value
 | |
|                 is obtained by "smart" averaging  of  the  dataset  points
 | |
|                 within search radius.
 | |
| 
 | |
| NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
 | |
|         datasets with non-distinct points. In case non-distinct points are
 | |
|         found, an average value for this point will be calculated.
 | |
|         
 | |
| NOTE 2: the memory requirements for model storage are O(NPoints*NLayers).
 | |
|         The model construction needs twice as much memory as model storage.
 | |
|   
 | |
| NOTE 3: by default 16 IDW layers are built which is enough for most cases.
 | |
|         You can change this parameter with idwbuildersetnlayers()  method.
 | |
|         Larger values may be necessary if you need to reproduce  extrafine
 | |
|         details at distances smaller than SRad/65536.  Smaller value   may
 | |
|         be necessary if you have to save memory and  computing  time,  and
 | |
|         ready to sacrifice some model quality.
 | |
| 
 | |
| 
 | |
| ALGORITHM DESCRIPTION
 | |
|   
 | |
| ALGLIB implementation of IDW is somewhat similar to the modified Shepard's
 | |
| method (one with search radius R) but overcomes several of its  drawbacks,
 | |
| namely:
 | |
| 1) a tendency to show stepwise behavior for uniform datasets
 | |
| 2) a tendency to show terrible interpolation properties for highly
 | |
|    nonuniform datasets which often arise in geospatial tasks
 | |
|   (function values are densely sampled across multiple separated
 | |
|   "tracks")
 | |
| 
 | |
| IDW-MSTAB method performs several passes over dataset and builds a sequence
 | |
| of progressively refined IDW models  (layers),  which starts from one with
 | |
| largest search radius SRad  and continues to smaller  search  radii  until
 | |
| required number of  layers  is  built.  Highest  layers  reproduce  global
 | |
| behavior of the target function at larger distances  whilst  lower  layers
 | |
| reproduce fine details at smaller distances.
 | |
| 
 | |
| Each layer is an IDW model built with following modifications:
 | |
| * weights go to zero when distance approach to the current search radius
 | |
| * an additional regularizing term is added to the distance: w=1/(d^2+lambda)
 | |
| * an additional fictional term with unit weight and zero function value is
 | |
|   added in order to promote continuity  properties  at  the  isolated  and
 | |
|   boundary points
 | |
|   
 | |
| By default, 16 layers is built, which is enough for most  cases.  You  can
 | |
| change this parameter with idwbuildersetnlayers() method.
 | |
|    
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetalgomstab(idwbuilder* state,
 | |
|      double srad,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(srad, _state), "IDWBuilderSetAlgoMSTAB: SRad is not finite", _state);
 | |
|     ae_assert(ae_fp_greater(srad,(double)(0)), "IDWBuilderSetAlgoMSTAB: SRad<=0", _state);
 | |
|     
 | |
|     /*
 | |
|      * Set algorithm
 | |
|      */
 | |
|     state->algotype = 2;
 | |
|     
 | |
|     /*
 | |
|      * Set options
 | |
|      */
 | |
|     state->r0 = srad;
 | |
|     state->rdecay = 0.5;
 | |
|     state->lambda0 = idw_defaultlambda0;
 | |
|     state->lambdalast = (double)(0);
 | |
|     state->lambdadecay = 1.0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets  IDW  model  construction  algorithm  to  the  textbook
 | |
| Shepard's algorithm with custom (user-specified) power parameter.
 | |
| 
 | |
| IMPORTANT: we do NOT recommend using textbook IDW algorithms because  they
 | |
|            have terrible interpolation properties. Use MSTAB in all cases.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     P       -   power parameter, P>0; good value to start with is 2.0
 | |
| 
 | |
| NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
 | |
|         datasets with non-distinct points. In case non-distinct points are
 | |
|         found, an average value for this point will be calculated.
 | |
|    
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetalgotextbookshepard(idwbuilder* state,
 | |
|      double p,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(p, _state), "IDWBuilderSetAlgoShepard: P is not finite", _state);
 | |
|     ae_assert(ae_fp_greater(p,(double)(0)), "IDWBuilderSetAlgoShepard: P<=0", _state);
 | |
|     
 | |
|     /*
 | |
|      * Set algorithm and options
 | |
|      */
 | |
|     state->algotype = 0;
 | |
|     state->shepardp = p;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets  IDW  model  construction  algorithm  to the 'textbook'
 | |
| modified Shepard's algorithm with user-specified search radius.
 | |
| 
 | |
| IMPORTANT: we do NOT recommend using textbook IDW algorithms because  they
 | |
|            have terrible interpolation properties. Use MSTAB in all cases.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
|     R       -   search radius
 | |
| 
 | |
| NOTE 1: IDW interpolation can  correctly  handle  ANY  dataset,  including
 | |
|         datasets with non-distinct points. In case non-distinct points are
 | |
|         found, an average value for this point will be calculated.
 | |
|    
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetalgotextbookmodshepard(idwbuilder* state,
 | |
|      double r,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(r, _state), "IDWBuilderSetAlgoModShepard: R is not finite", _state);
 | |
|     ae_assert(ae_fp_greater(r,(double)(0)), "IDWBuilderSetAlgoModShepard: R<=0", _state);
 | |
|     
 | |
|     /*
 | |
|      * Set algorithm and options
 | |
|      */
 | |
|     state->algotype = 1;
 | |
|     state->r0 = r;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets prior term (model value at infinity) as  user-specified
 | |
| value.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
|     V       -   value for user-defined prior
 | |
|     
 | |
| NOTE: for vector-valued models all components of the prior are set to same
 | |
|       user-specified value
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 29.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetuserterm(idwbuilder* state, double v, ae_state *_state)
 | |
| {
 | |
|     ae_int_t j;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(v, _state), "IDWBuilderSetUserTerm: infinite/NAN value passed", _state);
 | |
|     state->priortermtype = 0;
 | |
|     for(j=0; j<=state->ny-1; j++)
 | |
|     {
 | |
|         state->priortermval.ptr.p_double[j] = v;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets constant prior term (model value at infinity).
 | |
| 
 | |
| Constant prior term is determined as mean value over dataset.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 29.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetconstterm(idwbuilder* state, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     state->priortermtype = 2;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets zero prior term (model value at infinity).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 29.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwbuildersetzeroterm(idwbuilder* state, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     state->priortermtype = 3;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| IDW interpolation: scalar target, 1-dimensional argument
 | |
| 
 | |
| NOTE: this function modifies internal temporaries of the  IDW  model, thus
 | |
|       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
 | |
|       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
 | |
|       thread buffer object. 
 | |
|       
 | |
| INPUT PARAMETERS:
 | |
|     S   -   IDW interpolant built with IDW builder
 | |
|     X0  -   argument value
 | |
| 
 | |
| Result:
 | |
|     IDW interpolant S(X0)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double idwcalc1(idwmodel* s, double x0, ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(s->nx==1, "IDWCalc1: S.NX<>1", _state);
 | |
|     ae_assert(s->ny==1, "IDWCalc1: S.NY<>1", _state);
 | |
|     ae_assert(ae_isfinite(x0, _state), "IDWCalc1: X0 is INF or NAN", _state);
 | |
|     s->buffer.x.ptr.p_double[0] = x0;
 | |
|     idwtscalcbuf(s, &s->buffer, &s->buffer.x, &s->buffer.y, _state);
 | |
|     result = s->buffer.y.ptr.p_double[0];
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| IDW interpolation: scalar target, 2-dimensional argument
 | |
| 
 | |
| NOTE: this function modifies internal temporaries of the  IDW  model, thus
 | |
|       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
 | |
|       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
 | |
|       thread buffer object. 
 | |
|       
 | |
| INPUT PARAMETERS:
 | |
|     S       -   IDW interpolant built with IDW builder
 | |
|     X0, X1  -   argument value
 | |
| 
 | |
| Result:
 | |
|     IDW interpolant S(X0,X1)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double idwcalc2(idwmodel* s, double x0, double x1, ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(s->nx==2, "IDWCalc2: S.NX<>2", _state);
 | |
|     ae_assert(s->ny==1, "IDWCalc2: S.NY<>1", _state);
 | |
|     ae_assert(ae_isfinite(x0, _state), "IDWCalc2: X0 is INF or NAN", _state);
 | |
|     ae_assert(ae_isfinite(x1, _state), "IDWCalc2: X1 is INF or NAN", _state);
 | |
|     s->buffer.x.ptr.p_double[0] = x0;
 | |
|     s->buffer.x.ptr.p_double[1] = x1;
 | |
|     idwtscalcbuf(s, &s->buffer, &s->buffer.x, &s->buffer.y, _state);
 | |
|     result = s->buffer.y.ptr.p_double[0];
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| IDW interpolation: scalar target, 3-dimensional argument
 | |
| 
 | |
| NOTE: this function modifies internal temporaries of the  IDW  model, thus
 | |
|       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
 | |
|       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
 | |
|       thread buffer object. 
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   IDW interpolant built with IDW builder
 | |
|     X0,X1,X2-   argument value
 | |
| 
 | |
| Result:
 | |
|     IDW interpolant S(X0,X1,X2)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double idwcalc3(idwmodel* s,
 | |
|      double x0,
 | |
|      double x1,
 | |
|      double x2,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(s->nx==3, "IDWCalc3: S.NX<>3", _state);
 | |
|     ae_assert(s->ny==1, "IDWCalc3: S.NY<>1", _state);
 | |
|     ae_assert(ae_isfinite(x0, _state), "IDWCalc3: X0 is INF or NAN", _state);
 | |
|     ae_assert(ae_isfinite(x1, _state), "IDWCalc3: X1 is INF or NAN", _state);
 | |
|     ae_assert(ae_isfinite(x2, _state), "IDWCalc3: X2 is INF or NAN", _state);
 | |
|     s->buffer.x.ptr.p_double[0] = x0;
 | |
|     s->buffer.x.ptr.p_double[1] = x1;
 | |
|     s->buffer.x.ptr.p_double[2] = x2;
 | |
|     idwtscalcbuf(s, &s->buffer, &s->buffer.x, &s->buffer.y, _state);
 | |
|     result = s->buffer.y.ptr.p_double[0];
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the IDW model at the given point.
 | |
| 
 | |
| This is general function which can be used for arbitrary NX (dimension  of 
 | |
| the space of arguments) and NY (dimension of the function itself). However
 | |
| when  you  have  NY=1  you  may  find more convenient to  use  idwcalc1(),
 | |
| idwcalc2() or idwcalc3().
 | |
| 
 | |
| NOTE: this function modifies internal temporaries of the  IDW  model, thus
 | |
|       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
 | |
|       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
 | |
|       thread buffer object. 
 | |
|       
 | |
| INPUT PARAMETERS:
 | |
|     S       -   IDW model
 | |
|     X       -   coordinates, array[NX]. X may have more than NX  elements,
 | |
|                 in this case only leading NX will be used.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is out-parameter and will  be
 | |
|                 reallocated after call to this function. In case you  want
 | |
|                 to reuse previously allocated Y, you may use idwcalcbuf(),
 | |
|                 which reallocates Y only when it is too small.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwcalc(idwmodel* s,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     ae_vector_clear(y);
 | |
| 
 | |
|     idwtscalcbuf(s, &s->buffer, x, y, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the IDW model at the given point.
 | |
| 
 | |
| Same as idwcalc(), but does not reallocate Y when in is large enough to 
 | |
| store function values.
 | |
| 
 | |
| NOTE: this function modifies internal temporaries of the  IDW  model, thus
 | |
|       IT IS NOT  THREAD-SAFE!  If  you  want  to  perform  parallel  model
 | |
|       evaluation from the multiple threads, use idwtscalcbuf()  with  per-
 | |
|       thread buffer object. 
 | |
|       
 | |
| INPUT PARAMETERS:
 | |
|     S       -   IDW model
 | |
|     X       -   coordinates, array[NX]. X may have more than NX  elements,
 | |
|                 in this case only leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwcalcbuf(idwmodel* s,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     idwtscalcbuf(s, &s->buffer, x, y, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the IDW model at the given point, using
 | |
| external  buffer  object  (internal  temporaries  of  IDW  model  are  not
 | |
| modified).
 | |
| 
 | |
| This function allows to use same IDW model object  in  different  threads,
 | |
| assuming  that  different   threads  use different instances of the buffer
 | |
| structure.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   IDW model, may be shared between different threads
 | |
|     Buf     -   buffer object created for this particular instance of  IDW
 | |
|                 model with idwcreatecalcbuffer().
 | |
|     X       -   coordinates, array[NX]. X may have more than NX  elements,
 | |
|                 in this case only  leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwtscalcbuf(idwmodel* s,
 | |
|      idwcalcbuffer* buf,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t ew;
 | |
|     ae_int_t k;
 | |
|     ae_int_t layeridx;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
|     ae_int_t npoints;
 | |
|     double v;
 | |
|     double vv;
 | |
|     double f;
 | |
|     double p;
 | |
|     double r;
 | |
|     double eps;
 | |
|     double lambdacur;
 | |
|     double lambdadecay;
 | |
|     double invrdecay;
 | |
|     double invr;
 | |
|     ae_bool fastcalcpossible;
 | |
|     double wf0;
 | |
|     double ws0;
 | |
|     double wf1;
 | |
|     double ws1;
 | |
| 
 | |
| 
 | |
|     nx = s->nx;
 | |
|     ny = s->ny;
 | |
|     ae_assert(x->cnt>=nx, "IDWTsCalcBuf: Length(X)<NX", _state);
 | |
|     ae_assert(isfinitevector(x, nx, _state), "IDWTsCalcBuf: X contains infinite or NaN values", _state);
 | |
|     
 | |
|     /*
 | |
|      * Avoid spurious compiler warnings
 | |
|      */
 | |
|     wf0 = (double)(0);
 | |
|     ws0 = (double)(0);
 | |
|     wf1 = (double)(0);
 | |
|     ws1 = (double)(0);
 | |
|     
 | |
|     /*
 | |
|      * Allocate output
 | |
|      */
 | |
|     if( y->cnt<ny )
 | |
|     {
 | |
|         ae_vector_set_length(y, ny, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Quick exit for NLayers=0 (no dataset)
 | |
|      */
 | |
|     if( s->nlayers==0 )
 | |
|     {
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             y->ptr.p_double[j] = s->globalprior.ptr.p_double[j];
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Textbook Shepard's method
 | |
|      */
 | |
|     if( s->algotype==0 )
 | |
|     {
 | |
|         npoints = s->npoints;
 | |
|         ae_assert(npoints>0, "IDWTsCalcBuf: integrity check failed", _state);
 | |
|         eps = 1.0E-50;
 | |
|         ew = nx+ny;
 | |
|         p = s->shepardp;
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             y->ptr.p_double[j] = (double)(0);
 | |
|             buf->tsyw.ptr.p_double[j] = eps;
 | |
|         }
 | |
|         for(i=0; i<=npoints-1; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Compute squared distance
 | |
|              */
 | |
|             v = (double)(0);
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 vv = s->shepardxy.ptr.p_double[i*ew+j]-x->ptr.p_double[j];
 | |
|                 v = v+vv*vv;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Compute weight (with small regularizing addition)
 | |
|              */
 | |
|             v = ae_pow(v, p*0.5, _state);
 | |
|             v = 1/(eps+v);
 | |
|             
 | |
|             /*
 | |
|              * Accumulate
 | |
|              */
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 y->ptr.p_double[j] = y->ptr.p_double[j]+v*s->shepardxy.ptr.p_double[i*ew+nx+j];
 | |
|                 buf->tsyw.ptr.p_double[j] = buf->tsyw.ptr.p_double[j]+v;
 | |
|             }
 | |
|         }
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             y->ptr.p_double[j] = y->ptr.p_double[j]/buf->tsyw.ptr.p_double[j]+s->globalprior.ptr.p_double[j];
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Textbook modified Shepard's method
 | |
|      */
 | |
|     if( s->algotype==1 )
 | |
|     {
 | |
|         eps = 1.0E-50;
 | |
|         r = s->r0;
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             y->ptr.p_double[j] = (double)(0);
 | |
|             buf->tsyw.ptr.p_double[j] = eps;
 | |
|         }
 | |
|         k = kdtreetsqueryrnn(&s->tree, &buf->requestbuffer, x, r, ae_true, _state);
 | |
|         kdtreetsqueryresultsxy(&s->tree, &buf->requestbuffer, &buf->tsxy, _state);
 | |
|         kdtreetsqueryresultsdistances(&s->tree, &buf->requestbuffer, &buf->tsdist, _state);
 | |
|         for(i=0; i<=k-1; i++)
 | |
|         {
 | |
|             v = buf->tsdist.ptr.p_double[i];
 | |
|             v = (r-v)/(r*v+eps);
 | |
|             v = v*v;
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 y->ptr.p_double[j] = y->ptr.p_double[j]+v*buf->tsxy.ptr.pp_double[i][nx+j];
 | |
|                 buf->tsyw.ptr.p_double[j] = buf->tsyw.ptr.p_double[j]+v;
 | |
|             }
 | |
|         }
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             y->ptr.p_double[j] = y->ptr.p_double[j]/buf->tsyw.ptr.p_double[j]+s->globalprior.ptr.p_double[j];
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * MSTAB
 | |
|      */
 | |
|     if( s->algotype==2 )
 | |
|     {
 | |
|         ae_assert(ae_fp_eq(idw_w0,(double)(1)), "IDWTsCalcBuf: unexpected W0, integrity check failed", _state);
 | |
|         invrdecay = 1/s->rdecay;
 | |
|         invr = 1/s->r0;
 | |
|         lambdadecay = s->lambdadecay;
 | |
|         fastcalcpossible = (ny==1&&s->nlayers>=3)&&ae_fp_eq(lambdadecay,(double)(1));
 | |
|         if( fastcalcpossible )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Important special case, NY=1, no lambda-decay,
 | |
|              * we can perform optimized fast evaluation
 | |
|              */
 | |
|             wf0 = (double)(0);
 | |
|             ws0 = idw_w0;
 | |
|             wf1 = (double)(0);
 | |
|             ws1 = idw_w0;
 | |
|             for(j=0; j<=s->nlayers-1; j++)
 | |
|             {
 | |
|                 buf->tsyw.ptr.p_double[j] = (double)(0);
 | |
|                 buf->tsw.ptr.p_double[j] = idw_w0;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Setup variables for generic evaluation path
 | |
|              */
 | |
|             for(j=0; j<=ny*s->nlayers-1; j++)
 | |
|             {
 | |
|                 buf->tsyw.ptr.p_double[j] = (double)(0);
 | |
|             }
 | |
|             for(j=0; j<=s->nlayers-1; j++)
 | |
|             {
 | |
|                 buf->tsw.ptr.p_double[j] = idw_w0;
 | |
|             }
 | |
|         }
 | |
|         k = kdtreetsqueryrnnu(&s->tree, &buf->requestbuffer, x, s->r0, ae_true, _state);
 | |
|         kdtreetsqueryresultsxy(&s->tree, &buf->requestbuffer, &buf->tsxy, _state);
 | |
|         kdtreetsqueryresultsdistances(&s->tree, &buf->requestbuffer, &buf->tsdist, _state);
 | |
|         for(i=0; i<=k-1; i++)
 | |
|         {
 | |
|             lambdacur = s->lambda0;
 | |
|             vv = buf->tsdist.ptr.p_double[i]*invr;
 | |
|             if( fastcalcpossible )
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * Important special case, fast evaluation possible
 | |
|                  */
 | |
|                 v = vv*vv;
 | |
|                 v = (1-v)*(1-v)/(v+lambdacur);
 | |
|                 f = buf->tsxy.ptr.pp_double[i][nx+0];
 | |
|                 wf0 = wf0+v*f;
 | |
|                 ws0 = ws0+v;
 | |
|                 vv = vv*invrdecay;
 | |
|                 if( vv>=1.0 )
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
|                 v = vv*vv;
 | |
|                 v = (1-v)*(1-v)/(v+lambdacur);
 | |
|                 f = buf->tsxy.ptr.pp_double[i][nx+1];
 | |
|                 wf1 = wf1+v*f;
 | |
|                 ws1 = ws1+v;
 | |
|                 vv = vv*invrdecay;
 | |
|                 if( vv>=1.0 )
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
|                 for(layeridx=2; layeridx<=s->nlayers-1; layeridx++)
 | |
|                 {
 | |
|                     if( layeridx==s->nlayers-1 )
 | |
|                     {
 | |
|                         lambdacur = s->lambdalast;
 | |
|                     }
 | |
|                     v = vv*vv;
 | |
|                     v = (1-v)*(1-v)/(v+lambdacur);
 | |
|                     f = buf->tsxy.ptr.pp_double[i][nx+layeridx];
 | |
|                     buf->tsyw.ptr.p_double[layeridx] = buf->tsyw.ptr.p_double[layeridx]+v*f;
 | |
|                     buf->tsw.ptr.p_double[layeridx] = buf->tsw.ptr.p_double[layeridx]+v;
 | |
|                     vv = vv*invrdecay;
 | |
|                     if( vv>=1.0 )
 | |
|                     {
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * General case
 | |
|                  */
 | |
|                 for(layeridx=0; layeridx<=s->nlayers-1; layeridx++)
 | |
|                 {
 | |
|                     if( layeridx==s->nlayers-1 )
 | |
|                     {
 | |
|                         lambdacur = s->lambdalast;
 | |
|                     }
 | |
|                     if( vv>=1.0 )
 | |
|                     {
 | |
|                         break;
 | |
|                     }
 | |
|                     v = vv*vv;
 | |
|                     v = (1-v)*(1-v)/(v+lambdacur);
 | |
|                     for(j=0; j<=ny-1; j++)
 | |
|                     {
 | |
|                         f = buf->tsxy.ptr.pp_double[i][nx+layeridx*ny+j];
 | |
|                         buf->tsyw.ptr.p_double[layeridx*ny+j] = buf->tsyw.ptr.p_double[layeridx*ny+j]+v*f;
 | |
|                     }
 | |
|                     buf->tsw.ptr.p_double[layeridx] = buf->tsw.ptr.p_double[layeridx]+v;
 | |
|                     lambdacur = lambdacur*lambdadecay;
 | |
|                     vv = vv*invrdecay;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if( fastcalcpossible )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Important special case, finalize evaluations
 | |
|              */
 | |
|             buf->tsyw.ptr.p_double[0] = wf0;
 | |
|             buf->tsw.ptr.p_double[0] = ws0;
 | |
|             buf->tsyw.ptr.p_double[1] = wf1;
 | |
|             buf->tsw.ptr.p_double[1] = ws1;
 | |
|         }
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             y->ptr.p_double[j] = s->globalprior.ptr.p_double[j];
 | |
|         }
 | |
|         for(layeridx=0; layeridx<=s->nlayers-1; layeridx++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 y->ptr.p_double[j] = y->ptr.p_double[j]+buf->tsyw.ptr.p_double[layeridx*ny+j]/buf->tsw.ptr.p_double[layeridx];
 | |
|             }
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      *
 | |
|      */
 | |
|     ae_assert(ae_false, "IDWTsCalcBuf: unexpected AlgoType", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits IDW model to the dataset using current IDW construction
 | |
| algorithm. A model being built and fitting report are returned.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   builder object
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Model   -   an IDW model built with current algorithm
 | |
|     Rep     -   model fitting report, fields of this structure contain
 | |
|                 information about average fitting errors.
 | |
|                 
 | |
| NOTE: although IDW-MSTAB algorithm is an  interpolation  method,  i.e.  it
 | |
|       tries to fit the model exactly, it can  handle  datasets  with  non-
 | |
|       distinct points which can not be fit exactly; in such  cases  least-
 | |
|       squares fitting is performed.
 | |
|    
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwfit(idwbuilder* state,
 | |
|      idwmodel* model,
 | |
|      idwreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t layeridx;
 | |
|     ae_int_t srcidx;
 | |
|     double v;
 | |
|     double vv;
 | |
|     ae_int_t npoints;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
|     double rcur;
 | |
|     double lambdacur;
 | |
|     double rss;
 | |
|     double tss;
 | |
| 
 | |
|     _idwmodel_clear(model);
 | |
|     _idwreport_clear(rep);
 | |
| 
 | |
|     nx = state->nx;
 | |
|     ny = state->ny;
 | |
|     npoints = state->npoints;
 | |
|     
 | |
|     /*
 | |
|      * Clear report fields
 | |
|      */
 | |
|     rep->rmserror = (double)(0);
 | |
|     rep->avgerror = (double)(0);
 | |
|     rep->maxerror = (double)(0);
 | |
|     rep->r2 = 1.0;
 | |
|     
 | |
|     /*
 | |
|      * Quick exit for empty dataset
 | |
|      */
 | |
|     if( state->npoints==0 )
 | |
|     {
 | |
|         model->nx = nx;
 | |
|         model->ny = ny;
 | |
|         ae_vector_set_length(&model->globalprior, ny, _state);
 | |
|         for(i=0; i<=ny-1; i++)
 | |
|         {
 | |
|             model->globalprior.ptr.p_double[i] = (double)(0);
 | |
|         }
 | |
|         model->algotype = 0;
 | |
|         model->nlayers = 0;
 | |
|         model->r0 = (double)(1);
 | |
|         model->rdecay = 0.5;
 | |
|         model->lambda0 = (double)(0);
 | |
|         model->lambdalast = (double)(0);
 | |
|         model->lambdadecay = (double)(1);
 | |
|         model->shepardp = (double)(2);
 | |
|         model->npoints = 0;
 | |
|         idwcreatecalcbuffer(model, &model->buffer, _state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Compute temporaries which will be required later:
 | |
|      * * global mean
 | |
|      */
 | |
|     ae_assert(state->npoints>0, "IDWFit: integrity check failed", _state);
 | |
|     rvectorsetlengthatleast(&state->tmpmean, ny, _state);
 | |
|     for(j=0; j<=ny-1; j++)
 | |
|     {
 | |
|         state->tmpmean.ptr.p_double[j] = (double)(0);
 | |
|     }
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             state->tmpmean.ptr.p_double[j] = state->tmpmean.ptr.p_double[j]+state->xy.ptr.p_double[i*(nx+ny)+nx+j];
 | |
|         }
 | |
|     }
 | |
|     for(j=0; j<=ny-1; j++)
 | |
|     {
 | |
|         state->tmpmean.ptr.p_double[j] = state->tmpmean.ptr.p_double[j]/npoints;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Compute global prior
 | |
|      *
 | |
|      * NOTE: for original Shepard's method it is always mean value
 | |
|      */
 | |
|     rvectorsetlengthatleast(&model->globalprior, ny, _state);
 | |
|     for(j=0; j<=ny-1; j++)
 | |
|     {
 | |
|         model->globalprior.ptr.p_double[j] = state->tmpmean.ptr.p_double[j];
 | |
|     }
 | |
|     if( state->algotype!=0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Algorithm is set to one of the "advanced" versions with search
 | |
|          * radius which can handle non-mean prior term
 | |
|          */
 | |
|         if( state->priortermtype==0 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * User-specified prior
 | |
|              */
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 model->globalprior.ptr.p_double[j] = state->priortermval.ptr.p_double[j];
 | |
|             }
 | |
|         }
 | |
|         if( state->priortermtype==3 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Zero prior
 | |
|              */
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 model->globalprior.ptr.p_double[j] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Textbook Shepard
 | |
|      */
 | |
|     if( state->algotype==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Initialize model
 | |
|          */
 | |
|         model->algotype = 0;
 | |
|         model->nx = nx;
 | |
|         model->ny = ny;
 | |
|         model->nlayers = 1;
 | |
|         model->r0 = (double)(1);
 | |
|         model->rdecay = 0.5;
 | |
|         model->lambda0 = (double)(0);
 | |
|         model->lambdalast = (double)(0);
 | |
|         model->lambdadecay = (double)(1);
 | |
|         model->shepardp = state->shepardp;
 | |
|         
 | |
|         /*
 | |
|          * Copy dataset
 | |
|          */
 | |
|         rvectorsetlengthatleast(&model->shepardxy, npoints*(nx+ny), _state);
 | |
|         for(i=0; i<=npoints-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 model->shepardxy.ptr.p_double[i*(nx+ny)+j] = state->xy.ptr.p_double[i*(nx+ny)+j];
 | |
|             }
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 model->shepardxy.ptr.p_double[i*(nx+ny)+nx+j] = state->xy.ptr.p_double[i*(nx+ny)+nx+j]-model->globalprior.ptr.p_double[j];
 | |
|             }
 | |
|         }
 | |
|         model->npoints = npoints;
 | |
|         
 | |
|         /*
 | |
|          * Prepare internal buffer
 | |
|          * Evaluate report fields
 | |
|          */
 | |
|         idwcreatecalcbuffer(model, &model->buffer, _state);
 | |
|         idw_errormetricsviacalc(state, model, rep, _state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Textbook modified Shepard's method
 | |
|      */
 | |
|     if( state->algotype==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Initialize model
 | |
|          */
 | |
|         model->algotype = 1;
 | |
|         model->nx = nx;
 | |
|         model->ny = ny;
 | |
|         model->nlayers = 1;
 | |
|         model->r0 = state->r0;
 | |
|         model->rdecay = (double)(1);
 | |
|         model->lambda0 = (double)(0);
 | |
|         model->lambdalast = (double)(0);
 | |
|         model->lambdadecay = (double)(1);
 | |
|         model->shepardp = (double)(0);
 | |
|         
 | |
|         /*
 | |
|          * Build kd-tree search structure
 | |
|          */
 | |
|         rmatrixsetlengthatleast(&state->tmpxy, npoints, nx+ny, _state);
 | |
|         for(i=0; i<=npoints-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 state->tmpxy.ptr.pp_double[i][j] = state->xy.ptr.p_double[i*(nx+ny)+j];
 | |
|             }
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 state->tmpxy.ptr.pp_double[i][nx+j] = state->xy.ptr.p_double[i*(nx+ny)+nx+j]-model->globalprior.ptr.p_double[j];
 | |
|             }
 | |
|         }
 | |
|         kdtreebuild(&state->tmpxy, npoints, nx, ny, 2, &model->tree, _state);
 | |
|         
 | |
|         /*
 | |
|          * Prepare internal buffer
 | |
|          * Evaluate report fields
 | |
|          */
 | |
|         idwcreatecalcbuffer(model, &model->buffer, _state);
 | |
|         idw_errormetricsviacalc(state, model, rep, _state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * MSTAB algorithm
 | |
|      */
 | |
|     if( state->algotype==2 )
 | |
|     {
 | |
|         ae_assert(state->nlayers>=1, "IDWFit: integrity check failed", _state);
 | |
|         
 | |
|         /*
 | |
|          * Initialize model
 | |
|          */
 | |
|         model->algotype = 2;
 | |
|         model->nx = nx;
 | |
|         model->ny = ny;
 | |
|         model->nlayers = state->nlayers;
 | |
|         model->r0 = state->r0;
 | |
|         model->rdecay = 0.5;
 | |
|         model->lambda0 = state->lambda0;
 | |
|         model->lambdadecay = 1.0;
 | |
|         model->lambdalast = idw_meps;
 | |
|         model->shepardp = (double)(0);
 | |
|         
 | |
|         /*
 | |
|          * Build kd-tree search structure,
 | |
|          * prepare input residuals for the first layer of the model
 | |
|          */
 | |
|         rmatrixsetlengthatleast(&state->tmpxy, npoints, nx, _state);
 | |
|         rmatrixsetlengthatleast(&state->tmplayers, npoints, nx+ny*(state->nlayers+1), _state);
 | |
|         ivectorsetlengthatleast(&state->tmptags, npoints, _state);
 | |
|         for(i=0; i<=npoints-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 v = state->xy.ptr.p_double[i*(nx+ny)+j];
 | |
|                 state->tmpxy.ptr.pp_double[i][j] = v;
 | |
|                 state->tmplayers.ptr.pp_double[i][j] = v;
 | |
|             }
 | |
|             state->tmptags.ptr.p_int[i] = i;
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 state->tmplayers.ptr.pp_double[i][nx+j] = state->xy.ptr.p_double[i*(nx+ny)+nx+j]-model->globalprior.ptr.p_double[j];
 | |
|             }
 | |
|         }
 | |
|         kdtreebuildtagged(&state->tmpxy, &state->tmptags, npoints, nx, 0, 2, &state->tmptree, _state);
 | |
|         
 | |
|         /*
 | |
|          * Iteratively build layer by layer
 | |
|          */
 | |
|         rvectorsetlengthatleast(&state->tmpx, nx, _state);
 | |
|         rvectorsetlengthatleast(&state->tmpwy, ny, _state);
 | |
|         rvectorsetlengthatleast(&state->tmpw, ny, _state);
 | |
|         for(layeridx=0; layeridx<=state->nlayers-1; layeridx++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Determine layer metrics
 | |
|              */
 | |
|             rcur = model->r0*ae_pow(model->rdecay, (double)(layeridx), _state);
 | |
|             lambdacur = model->lambda0*ae_pow(model->lambdadecay, (double)(layeridx), _state);
 | |
|             if( layeridx==state->nlayers-1 )
 | |
|             {
 | |
|                 lambdacur = model->lambdalast;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * For each point compute residual from fitting with current layer
 | |
|              */
 | |
|             for(i=0; i<=npoints-1; i++)
 | |
|             {
 | |
|                 for(j=0; j<=nx-1; j++)
 | |
|                 {
 | |
|                     state->tmpx.ptr.p_double[j] = state->tmplayers.ptr.pp_double[i][j];
 | |
|                 }
 | |
|                 k = kdtreequeryrnn(&state->tmptree, &state->tmpx, rcur, ae_true, _state);
 | |
|                 kdtreequeryresultstags(&state->tmptree, &state->tmptags, _state);
 | |
|                 kdtreequeryresultsdistances(&state->tmptree, &state->tmpdist, _state);
 | |
|                 for(j=0; j<=ny-1; j++)
 | |
|                 {
 | |
|                     state->tmpwy.ptr.p_double[j] = (double)(0);
 | |
|                     state->tmpw.ptr.p_double[j] = idw_w0;
 | |
|                 }
 | |
|                 for(i0=0; i0<=k-1; i0++)
 | |
|                 {
 | |
|                     vv = state->tmpdist.ptr.p_double[i0]/rcur;
 | |
|                     vv = vv*vv;
 | |
|                     v = (1-vv)*(1-vv)/(vv+lambdacur);
 | |
|                     srcidx = state->tmptags.ptr.p_int[i0];
 | |
|                     for(j=0; j<=ny-1; j++)
 | |
|                     {
 | |
|                         state->tmpwy.ptr.p_double[j] = state->tmpwy.ptr.p_double[j]+v*state->tmplayers.ptr.pp_double[srcidx][nx+layeridx*ny+j];
 | |
|                         state->tmpw.ptr.p_double[j] = state->tmpw.ptr.p_double[j]+v;
 | |
|                     }
 | |
|                 }
 | |
|                 for(j=0; j<=ny-1; j++)
 | |
|                 {
 | |
|                     v = state->tmplayers.ptr.pp_double[i][nx+layeridx*ny+j];
 | |
|                     state->tmplayers.ptr.pp_double[i][nx+(layeridx+1)*ny+j] = v-state->tmpwy.ptr.p_double[j]/state->tmpw.ptr.p_double[j];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         kdtreebuild(&state->tmplayers, npoints, nx, ny*state->nlayers, 2, &model->tree, _state);
 | |
|         
 | |
|         /*
 | |
|          * Evaluate report fields
 | |
|          */
 | |
|         rep->rmserror = (double)(0);
 | |
|         rep->avgerror = (double)(0);
 | |
|         rep->maxerror = (double)(0);
 | |
|         rss = (double)(0);
 | |
|         tss = (double)(0);
 | |
|         for(i=0; i<=npoints-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 v = ae_fabs(state->tmplayers.ptr.pp_double[i][nx+state->nlayers*ny+j], _state);
 | |
|                 rep->rmserror = rep->rmserror+v*v;
 | |
|                 rep->avgerror = rep->avgerror+v;
 | |
|                 rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
 | |
|                 rss = rss+v*v;
 | |
|                 tss = tss+ae_sqr(state->xy.ptr.p_double[i*(nx+ny)+nx+j]-state->tmpmean.ptr.p_double[j], _state);
 | |
|             }
 | |
|         }
 | |
|         rep->rmserror = ae_sqrt(rep->rmserror/(npoints*ny), _state);
 | |
|         rep->avgerror = rep->avgerror/(npoints*ny);
 | |
|         rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state);
 | |
|         
 | |
|         /*
 | |
|          * Prepare internal buffer
 | |
|          */
 | |
|         idwcreatecalcbuffer(model, &model->buffer, _state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Unknown algorithm
 | |
|      */
 | |
|     ae_assert(ae_false, "IDWFit: integrity check failed, unexpected algorithm", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: allocation
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 28.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwalloc(ae_serializer* s, idwmodel* model, ae_state *_state)
 | |
| {
 | |
|     ae_bool processed;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Header
 | |
|      */
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     
 | |
|     /*
 | |
|      * Algorithm type and fields which are set for all algorithms
 | |
|      */
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     allocrealarray(s, &model->globalprior, -1, _state);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     
 | |
|     /*
 | |
|      * Algorithm-specific fields
 | |
|      */
 | |
|     processed = ae_false;
 | |
|     if( model->algotype==0 )
 | |
|     {
 | |
|         ae_serializer_alloc_entry(s);
 | |
|         allocrealarray(s, &model->shepardxy, -1, _state);
 | |
|         processed = ae_true;
 | |
|     }
 | |
|     if( model->algotype>0 )
 | |
|     {
 | |
|         kdtreealloc(s, &model->tree, _state);
 | |
|         processed = ae_true;
 | |
|     }
 | |
|     ae_assert(processed, "IDW: integrity check failed during serialization", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: serialization
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 28.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwserialize(ae_serializer* s, idwmodel* model, ae_state *_state)
 | |
| {
 | |
|     ae_bool processed;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Header
 | |
|      */
 | |
|     ae_serializer_serialize_int(s, getidwserializationcode(_state), _state);
 | |
|     
 | |
|     /*
 | |
|      * Algorithm type and fields which are set for all algorithms
 | |
|      */
 | |
|     ae_serializer_serialize_int(s, model->algotype, _state);
 | |
|     ae_serializer_serialize_int(s, model->nx, _state);
 | |
|     ae_serializer_serialize_int(s, model->ny, _state);
 | |
|     serializerealarray(s, &model->globalprior, -1, _state);
 | |
|     ae_serializer_serialize_int(s, model->nlayers, _state);
 | |
|     ae_serializer_serialize_double(s, model->r0, _state);
 | |
|     ae_serializer_serialize_double(s, model->rdecay, _state);
 | |
|     ae_serializer_serialize_double(s, model->lambda0, _state);
 | |
|     ae_serializer_serialize_double(s, model->lambdalast, _state);
 | |
|     ae_serializer_serialize_double(s, model->lambdadecay, _state);
 | |
|     ae_serializer_serialize_double(s, model->shepardp, _state);
 | |
|     
 | |
|     /*
 | |
|      * Algorithm-specific fields
 | |
|      */
 | |
|     processed = ae_false;
 | |
|     if( model->algotype==0 )
 | |
|     {
 | |
|         ae_serializer_serialize_int(s, model->npoints, _state);
 | |
|         serializerealarray(s, &model->shepardxy, -1, _state);
 | |
|         processed = ae_true;
 | |
|     }
 | |
|     if( model->algotype>0 )
 | |
|     {
 | |
|         kdtreeserialize(s, &model->tree, _state);
 | |
|         processed = ae_true;
 | |
|     }
 | |
|     ae_assert(processed, "IDW: integrity check failed during serialization", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: unserialization
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 28.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void idwunserialize(ae_serializer* s, idwmodel* model, ae_state *_state)
 | |
| {
 | |
|     ae_bool processed;
 | |
|     ae_int_t scode;
 | |
| 
 | |
|     _idwmodel_clear(model);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Header
 | |
|      */
 | |
|     ae_serializer_unserialize_int(s, &scode, _state);
 | |
|     ae_assert(scode==getidwserializationcode(_state), "IDWUnserialize: stream header corrupted", _state);
 | |
|     
 | |
|     /*
 | |
|      * Algorithm type and fields which are set for all algorithms
 | |
|      */
 | |
|     ae_serializer_unserialize_int(s, &model->algotype, _state);
 | |
|     ae_serializer_unserialize_int(s, &model->nx, _state);
 | |
|     ae_serializer_unserialize_int(s, &model->ny, _state);
 | |
|     unserializerealarray(s, &model->globalprior, _state);
 | |
|     ae_serializer_unserialize_int(s, &model->nlayers, _state);
 | |
|     ae_serializer_unserialize_double(s, &model->r0, _state);
 | |
|     ae_serializer_unserialize_double(s, &model->rdecay, _state);
 | |
|     ae_serializer_unserialize_double(s, &model->lambda0, _state);
 | |
|     ae_serializer_unserialize_double(s, &model->lambdalast, _state);
 | |
|     ae_serializer_unserialize_double(s, &model->lambdadecay, _state);
 | |
|     ae_serializer_unserialize_double(s, &model->shepardp, _state);
 | |
|     
 | |
|     /*
 | |
|      * Algorithm-specific fields
 | |
|      */
 | |
|     processed = ae_false;
 | |
|     if( model->algotype==0 )
 | |
|     {
 | |
|         ae_serializer_unserialize_int(s, &model->npoints, _state);
 | |
|         unserializerealarray(s, &model->shepardxy, _state);
 | |
|         processed = ae_true;
 | |
|     }
 | |
|     if( model->algotype>0 )
 | |
|     {
 | |
|         kdtreeunserialize(s, &model->tree, _state);
 | |
|         processed = ae_true;
 | |
|     }
 | |
|     ae_assert(processed, "IDW: integrity check failed during serialization", _state);
 | |
|     
 | |
|     /*
 | |
|      * Temporary buffers
 | |
|      */
 | |
|     idwcreatecalcbuffer(model, &model->buffer, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function evaluates error metrics for the model  using  IDWTsCalcBuf()
 | |
| to calculate model at each point.
 | |
| 
 | |
| NOTE: modern IDW algorithms (MSTAB, MSMOOTH) can generate residuals during
 | |
|       model construction, so they do not need this function  in  order  to
 | |
|       evaluate error metrics.
 | |
| 
 | |
| Following fields of Rep are filled:
 | |
| * rep.rmserror
 | |
| * rep.avgerror
 | |
| * rep.maxerror
 | |
| * rep.r2
 | |
|    
 | |
|   -- ALGLIB --
 | |
|      Copyright 22.10.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void idw_errormetricsviacalc(idwbuilder* state,
 | |
|      idwmodel* model,
 | |
|      idwreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t npoints;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double v;
 | |
|     double vv;
 | |
|     double rss;
 | |
|     double tss;
 | |
| 
 | |
| 
 | |
|     npoints = state->npoints;
 | |
|     nx = state->nx;
 | |
|     ny = state->ny;
 | |
|     if( npoints==0 )
 | |
|     {
 | |
|         rep->rmserror = (double)(0);
 | |
|         rep->avgerror = (double)(0);
 | |
|         rep->maxerror = (double)(0);
 | |
|         rep->r2 = (double)(1);
 | |
|         return;
 | |
|     }
 | |
|     rep->rmserror = (double)(0);
 | |
|     rep->avgerror = (double)(0);
 | |
|     rep->maxerror = (double)(0);
 | |
|     rss = (double)(0);
 | |
|     tss = (double)(0);
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             model->buffer.x.ptr.p_double[j] = state->xy.ptr.p_double[i*(nx+ny)+j];
 | |
|         }
 | |
|         idwtscalcbuf(model, &model->buffer, &model->buffer.x, &model->buffer.y, _state);
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             vv = state->xy.ptr.p_double[i*(nx+ny)+nx+j];
 | |
|             v = ae_fabs(vv-model->buffer.y.ptr.p_double[j], _state);
 | |
|             rep->rmserror = rep->rmserror+v*v;
 | |
|             rep->avgerror = rep->avgerror+v;
 | |
|             rep->maxerror = ae_maxreal(rep->maxerror, v, _state);
 | |
|             rss = rss+v*v;
 | |
|             tss = tss+ae_sqr(vv-state->tmpmean.ptr.p_double[j], _state);
 | |
|         }
 | |
|     }
 | |
|     rep->rmserror = ae_sqrt(rep->rmserror/(npoints*ny), _state);
 | |
|     rep->avgerror = rep->avgerror/(npoints*ny);
 | |
|     rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     idwcalcbuffer *p = (idwcalcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tsyw, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tsw, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->tsxy, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tsdist, 0, DT_REAL, _state, make_automatic);
 | |
|     _kdtreerequestbuffer_init(&p->requestbuffer, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwcalcbuffer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     idwcalcbuffer *dst = (idwcalcbuffer*)_dst;
 | |
|     idwcalcbuffer *src = (idwcalcbuffer*)_src;
 | |
|     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tsyw, &src->tsyw, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tsw, &src->tsw, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->tsxy, &src->tsxy, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tsdist, &src->tsdist, _state, make_automatic);
 | |
|     _kdtreerequestbuffer_init_copy(&dst->requestbuffer, &src->requestbuffer, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwcalcbuffer_clear(void* _p)
 | |
| {
 | |
|     idwcalcbuffer *p = (idwcalcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->x);
 | |
|     ae_vector_clear(&p->y);
 | |
|     ae_vector_clear(&p->tsyw);
 | |
|     ae_vector_clear(&p->tsw);
 | |
|     ae_matrix_clear(&p->tsxy);
 | |
|     ae_vector_clear(&p->tsdist);
 | |
|     _kdtreerequestbuffer_clear(&p->requestbuffer);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwcalcbuffer_destroy(void* _p)
 | |
| {
 | |
|     idwcalcbuffer *p = (idwcalcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->x);
 | |
|     ae_vector_destroy(&p->y);
 | |
|     ae_vector_destroy(&p->tsyw);
 | |
|     ae_vector_destroy(&p->tsw);
 | |
|     ae_matrix_destroy(&p->tsxy);
 | |
|     ae_vector_destroy(&p->tsdist);
 | |
|     _kdtreerequestbuffer_destroy(&p->requestbuffer);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwmodel_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     idwmodel *p = (idwmodel*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->globalprior, 0, DT_REAL, _state, make_automatic);
 | |
|     _kdtree_init(&p->tree, _state, make_automatic);
 | |
|     ae_vector_init(&p->shepardxy, 0, DT_REAL, _state, make_automatic);
 | |
|     _idwcalcbuffer_init(&p->buffer, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     idwmodel *dst = (idwmodel*)_dst;
 | |
|     idwmodel *src = (idwmodel*)_src;
 | |
|     dst->nx = src->nx;
 | |
|     dst->ny = src->ny;
 | |
|     ae_vector_init_copy(&dst->globalprior, &src->globalprior, _state, make_automatic);
 | |
|     dst->algotype = src->algotype;
 | |
|     dst->nlayers = src->nlayers;
 | |
|     dst->r0 = src->r0;
 | |
|     dst->rdecay = src->rdecay;
 | |
|     dst->lambda0 = src->lambda0;
 | |
|     dst->lambdalast = src->lambdalast;
 | |
|     dst->lambdadecay = src->lambdadecay;
 | |
|     dst->shepardp = src->shepardp;
 | |
|     _kdtree_init_copy(&dst->tree, &src->tree, _state, make_automatic);
 | |
|     dst->npoints = src->npoints;
 | |
|     ae_vector_init_copy(&dst->shepardxy, &src->shepardxy, _state, make_automatic);
 | |
|     _idwcalcbuffer_init_copy(&dst->buffer, &src->buffer, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwmodel_clear(void* _p)
 | |
| {
 | |
|     idwmodel *p = (idwmodel*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->globalprior);
 | |
|     _kdtree_clear(&p->tree);
 | |
|     ae_vector_clear(&p->shepardxy);
 | |
|     _idwcalcbuffer_clear(&p->buffer);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwmodel_destroy(void* _p)
 | |
| {
 | |
|     idwmodel *p = (idwmodel*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->globalprior);
 | |
|     _kdtree_destroy(&p->tree);
 | |
|     ae_vector_destroy(&p->shepardxy);
 | |
|     _idwcalcbuffer_destroy(&p->buffer);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     idwbuilder *p = (idwbuilder*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->priortermval, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->xy, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->tmpxy, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->tmplayers, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmptags, 0, DT_INT, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmpdist, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmpx, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmpwy, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmpw, 0, DT_REAL, _state, make_automatic);
 | |
|     _kdtree_init(&p->tmptree, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmpmean, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwbuilder_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     idwbuilder *dst = (idwbuilder*)_dst;
 | |
|     idwbuilder *src = (idwbuilder*)_src;
 | |
|     dst->priortermtype = src->priortermtype;
 | |
|     ae_vector_init_copy(&dst->priortermval, &src->priortermval, _state, make_automatic);
 | |
|     dst->algotype = src->algotype;
 | |
|     dst->nlayers = src->nlayers;
 | |
|     dst->r0 = src->r0;
 | |
|     dst->rdecay = src->rdecay;
 | |
|     dst->lambda0 = src->lambda0;
 | |
|     dst->lambdalast = src->lambdalast;
 | |
|     dst->lambdadecay = src->lambdadecay;
 | |
|     dst->shepardp = src->shepardp;
 | |
|     ae_vector_init_copy(&dst->xy, &src->xy, _state, make_automatic);
 | |
|     dst->npoints = src->npoints;
 | |
|     dst->nx = src->nx;
 | |
|     dst->ny = src->ny;
 | |
|     ae_matrix_init_copy(&dst->tmpxy, &src->tmpxy, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->tmplayers, &src->tmplayers, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmptags, &src->tmptags, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmpdist, &src->tmpdist, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmpx, &src->tmpx, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmpwy, &src->tmpwy, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmpw, &src->tmpw, _state, make_automatic);
 | |
|     _kdtree_init_copy(&dst->tmptree, &src->tmptree, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmpmean, &src->tmpmean, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwbuilder_clear(void* _p)
 | |
| {
 | |
|     idwbuilder *p = (idwbuilder*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->priortermval);
 | |
|     ae_vector_clear(&p->xy);
 | |
|     ae_matrix_clear(&p->tmpxy);
 | |
|     ae_matrix_clear(&p->tmplayers);
 | |
|     ae_vector_clear(&p->tmptags);
 | |
|     ae_vector_clear(&p->tmpdist);
 | |
|     ae_vector_clear(&p->tmpx);
 | |
|     ae_vector_clear(&p->tmpwy);
 | |
|     ae_vector_clear(&p->tmpw);
 | |
|     _kdtree_clear(&p->tmptree);
 | |
|     ae_vector_clear(&p->tmpmean);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwbuilder_destroy(void* _p)
 | |
| {
 | |
|     idwbuilder *p = (idwbuilder*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->priortermval);
 | |
|     ae_vector_destroy(&p->xy);
 | |
|     ae_matrix_destroy(&p->tmpxy);
 | |
|     ae_matrix_destroy(&p->tmplayers);
 | |
|     ae_vector_destroy(&p->tmptags);
 | |
|     ae_vector_destroy(&p->tmpdist);
 | |
|     ae_vector_destroy(&p->tmpx);
 | |
|     ae_vector_destroy(&p->tmpwy);
 | |
|     ae_vector_destroy(&p->tmpw);
 | |
|     _kdtree_destroy(&p->tmptree);
 | |
|     ae_vector_destroy(&p->tmpmean);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     idwreport *p = (idwreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     idwreport *dst = (idwreport*)_dst;
 | |
|     idwreport *src = (idwreport*)_src;
 | |
|     dst->rmserror = src->rmserror;
 | |
|     dst->avgerror = src->avgerror;
 | |
|     dst->maxerror = src->maxerror;
 | |
|     dst->r2 = src->r2;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwreport_clear(void* _p)
 | |
| {
 | |
|     idwreport *p = (idwreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _idwreport_destroy(void* _p)
 | |
| {
 | |
|     idwreport *p = (idwreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_RATINT) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Rational interpolation using barycentric formula
 | |
| 
 | |
| F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))
 | |
| 
 | |
| Input parameters:
 | |
|     B   -   barycentric interpolant built with one of model building
 | |
|             subroutines.
 | |
|     T   -   interpolation point
 | |
| 
 | |
| Result:
 | |
|     barycentric interpolant F(t)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double barycentriccalc(barycentricinterpolant* b,
 | |
|      double t,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double s1;
 | |
|     double s2;
 | |
|     double s;
 | |
|     double v;
 | |
|     ae_int_t i;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(!ae_isinf(t, _state), "BarycentricCalc: infinite T!", _state);
 | |
|     
 | |
|     /*
 | |
|      * special case: NaN
 | |
|      */
 | |
|     if( ae_isnan(t, _state) )
 | |
|     {
 | |
|         result = _state->v_nan;
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * special case: N=1
 | |
|      */
 | |
|     if( b->n==1 )
 | |
|     {
 | |
|         result = b->sy*b->y.ptr.p_double[0];
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Here we assume that task is normalized, i.e.:
 | |
|      * 1. abs(Y[i])<=1
 | |
|      * 2. abs(W[i])<=1
 | |
|      * 3. X[] is ordered
 | |
|      */
 | |
|     s = ae_fabs(t-b->x.ptr.p_double[0], _state);
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         v = b->x.ptr.p_double[i];
 | |
|         if( ae_fp_eq(v,t) )
 | |
|         {
 | |
|             result = b->sy*b->y.ptr.p_double[i];
 | |
|             return result;
 | |
|         }
 | |
|         v = ae_fabs(t-v, _state);
 | |
|         if( ae_fp_less(v,s) )
 | |
|         {
 | |
|             s = v;
 | |
|         }
 | |
|     }
 | |
|     s1 = (double)(0);
 | |
|     s2 = (double)(0);
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         v = s/(t-b->x.ptr.p_double[i]);
 | |
|         v = v*b->w.ptr.p_double[i];
 | |
|         s1 = s1+v*b->y.ptr.p_double[i];
 | |
|         s2 = s2+v;
 | |
|     }
 | |
|     result = b->sy*s1/s2;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Differentiation of barycentric interpolant: first derivative.
 | |
| 
 | |
| Algorithm used in this subroutine is very robust and should not fail until
 | |
| provided with values too close to MaxRealNumber  (usually  MaxRealNumber/N
 | |
| or greater will overflow).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B   -   barycentric interpolant built with one of model building
 | |
|             subroutines.
 | |
|     T   -   interpolation point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   barycentric interpolant at T
 | |
|     DF  -   first derivative
 | |
|     
 | |
| NOTE
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricdiff1(barycentricinterpolant* b,
 | |
|      double t,
 | |
|      double* f,
 | |
|      double* df,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double v;
 | |
|     double vv;
 | |
|     ae_int_t i;
 | |
|     ae_int_t k;
 | |
|     double n0;
 | |
|     double n1;
 | |
|     double d0;
 | |
|     double d1;
 | |
|     double s0;
 | |
|     double s1;
 | |
|     double xk;
 | |
|     double xi;
 | |
|     double xmin;
 | |
|     double xmax;
 | |
|     double xscale1;
 | |
|     double xoffs1;
 | |
|     double xscale2;
 | |
|     double xoffs2;
 | |
|     double xprev;
 | |
| 
 | |
|     *f = 0;
 | |
|     *df = 0;
 | |
| 
 | |
|     ae_assert(!ae_isinf(t, _state), "BarycentricDiff1: infinite T!", _state);
 | |
|     
 | |
|     /*
 | |
|      * special case: NaN
 | |
|      */
 | |
|     if( ae_isnan(t, _state) )
 | |
|     {
 | |
|         *f = _state->v_nan;
 | |
|         *df = _state->v_nan;
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * special case: N=1
 | |
|      */
 | |
|     if( b->n==1 )
 | |
|     {
 | |
|         *f = b->sy*b->y.ptr.p_double[0];
 | |
|         *df = (double)(0);
 | |
|         return;
 | |
|     }
 | |
|     if( ae_fp_eq(b->sy,(double)(0)) )
 | |
|     {
 | |
|         *f = (double)(0);
 | |
|         *df = (double)(0);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(ae_fp_greater(b->sy,(double)(0)), "BarycentricDiff1: internal error", _state);
 | |
|     
 | |
|     /*
 | |
|      * We assume than N>1 and B.SY>0. Find:
 | |
|      * 1. pivot point (X[i] closest to T)
 | |
|      * 2. width of interval containing X[i]
 | |
|      */
 | |
|     v = ae_fabs(b->x.ptr.p_double[0]-t, _state);
 | |
|     k = 0;
 | |
|     xmin = b->x.ptr.p_double[0];
 | |
|     xmax = b->x.ptr.p_double[0];
 | |
|     for(i=1; i<=b->n-1; i++)
 | |
|     {
 | |
|         vv = b->x.ptr.p_double[i];
 | |
|         if( ae_fp_less(ae_fabs(vv-t, _state),v) )
 | |
|         {
 | |
|             v = ae_fabs(vv-t, _state);
 | |
|             k = i;
 | |
|         }
 | |
|         xmin = ae_minreal(xmin, vv, _state);
 | |
|         xmax = ae_maxreal(xmax, vv, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * pivot point found, calculate dNumerator and dDenominator
 | |
|      */
 | |
|     xscale1 = 1/(xmax-xmin);
 | |
|     xoffs1 = -xmin/(xmax-xmin)+1;
 | |
|     xscale2 = (double)(2);
 | |
|     xoffs2 = (double)(-3);
 | |
|     t = t*xscale1+xoffs1;
 | |
|     t = t*xscale2+xoffs2;
 | |
|     xk = b->x.ptr.p_double[k];
 | |
|     xk = xk*xscale1+xoffs1;
 | |
|     xk = xk*xscale2+xoffs2;
 | |
|     v = t-xk;
 | |
|     n0 = (double)(0);
 | |
|     n1 = (double)(0);
 | |
|     d0 = (double)(0);
 | |
|     d1 = (double)(0);
 | |
|     xprev = (double)(-2);
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         xi = b->x.ptr.p_double[i];
 | |
|         xi = xi*xscale1+xoffs1;
 | |
|         xi = xi*xscale2+xoffs2;
 | |
|         ae_assert(ae_fp_greater(xi,xprev), "BarycentricDiff1: points are too close!", _state);
 | |
|         xprev = xi;
 | |
|         if( i!=k )
 | |
|         {
 | |
|             vv = ae_sqr(t-xi, _state);
 | |
|             s0 = (t-xk)/(t-xi);
 | |
|             s1 = (xk-xi)/vv;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             s0 = (double)(1);
 | |
|             s1 = (double)(0);
 | |
|         }
 | |
|         vv = b->w.ptr.p_double[i]*b->y.ptr.p_double[i];
 | |
|         n0 = n0+s0*vv;
 | |
|         n1 = n1+s1*vv;
 | |
|         vv = b->w.ptr.p_double[i];
 | |
|         d0 = d0+s0*vv;
 | |
|         d1 = d1+s1*vv;
 | |
|     }
 | |
|     *f = b->sy*n0/d0;
 | |
|     *df = (n1*d0-n0*d1)/ae_sqr(d0, _state);
 | |
|     if( ae_fp_neq(*df,(double)(0)) )
 | |
|     {
 | |
|         *df = ae_sign(*df, _state)*ae_exp(ae_log(ae_fabs(*df, _state), _state)+ae_log(b->sy, _state)+ae_log(xscale1, _state)+ae_log(xscale2, _state), _state);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Differentiation of barycentric interpolant: first/second derivatives.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B   -   barycentric interpolant built with one of model building
 | |
|             subroutines.
 | |
|     T   -   interpolation point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   barycentric interpolant at T
 | |
|     DF  -   first derivative
 | |
|     D2F -   second derivative
 | |
| 
 | |
| NOTE: this algorithm may fail due to overflow/underflor if  used  on  data
 | |
| whose values are close to MaxRealNumber or MinRealNumber.  Use more robust
 | |
| BarycentricDiff1() subroutine in such cases.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricdiff2(barycentricinterpolant* b,
 | |
|      double t,
 | |
|      double* f,
 | |
|      double* df,
 | |
|      double* d2f,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double v;
 | |
|     double vv;
 | |
|     ae_int_t i;
 | |
|     ae_int_t k;
 | |
|     double n0;
 | |
|     double n1;
 | |
|     double n2;
 | |
|     double d0;
 | |
|     double d1;
 | |
|     double d2;
 | |
|     double s0;
 | |
|     double s1;
 | |
|     double s2;
 | |
|     double xk;
 | |
|     double xi;
 | |
| 
 | |
|     *f = 0;
 | |
|     *df = 0;
 | |
|     *d2f = 0;
 | |
| 
 | |
|     ae_assert(!ae_isinf(t, _state), "BarycentricDiff1: infinite T!", _state);
 | |
|     
 | |
|     /*
 | |
|      * special case: NaN
 | |
|      */
 | |
|     if( ae_isnan(t, _state) )
 | |
|     {
 | |
|         *f = _state->v_nan;
 | |
|         *df = _state->v_nan;
 | |
|         *d2f = _state->v_nan;
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * special case: N=1
 | |
|      */
 | |
|     if( b->n==1 )
 | |
|     {
 | |
|         *f = b->sy*b->y.ptr.p_double[0];
 | |
|         *df = (double)(0);
 | |
|         *d2f = (double)(0);
 | |
|         return;
 | |
|     }
 | |
|     if( ae_fp_eq(b->sy,(double)(0)) )
 | |
|     {
 | |
|         *f = (double)(0);
 | |
|         *df = (double)(0);
 | |
|         *d2f = (double)(0);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * We assume than N>1 and B.SY>0. Find:
 | |
|      * 1. pivot point (X[i] closest to T)
 | |
|      * 2. width of interval containing X[i]
 | |
|      */
 | |
|     ae_assert(ae_fp_greater(b->sy,(double)(0)), "BarycentricDiff: internal error", _state);
 | |
|     *f = (double)(0);
 | |
|     *df = (double)(0);
 | |
|     *d2f = (double)(0);
 | |
|     v = ae_fabs(b->x.ptr.p_double[0]-t, _state);
 | |
|     k = 0;
 | |
|     for(i=1; i<=b->n-1; i++)
 | |
|     {
 | |
|         vv = b->x.ptr.p_double[i];
 | |
|         if( ae_fp_less(ae_fabs(vv-t, _state),v) )
 | |
|         {
 | |
|             v = ae_fabs(vv-t, _state);
 | |
|             k = i;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * pivot point found, calculate dNumerator and dDenominator
 | |
|      */
 | |
|     xk = b->x.ptr.p_double[k];
 | |
|     v = t-xk;
 | |
|     n0 = (double)(0);
 | |
|     n1 = (double)(0);
 | |
|     n2 = (double)(0);
 | |
|     d0 = (double)(0);
 | |
|     d1 = (double)(0);
 | |
|     d2 = (double)(0);
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         if( i!=k )
 | |
|         {
 | |
|             xi = b->x.ptr.p_double[i];
 | |
|             vv = ae_sqr(t-xi, _state);
 | |
|             s0 = (t-xk)/(t-xi);
 | |
|             s1 = (xk-xi)/vv;
 | |
|             s2 = -2*(xk-xi)/(vv*(t-xi));
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             s0 = (double)(1);
 | |
|             s1 = (double)(0);
 | |
|             s2 = (double)(0);
 | |
|         }
 | |
|         vv = b->w.ptr.p_double[i]*b->y.ptr.p_double[i];
 | |
|         n0 = n0+s0*vv;
 | |
|         n1 = n1+s1*vv;
 | |
|         n2 = n2+s2*vv;
 | |
|         vv = b->w.ptr.p_double[i];
 | |
|         d0 = d0+s0*vv;
 | |
|         d1 = d1+s1*vv;
 | |
|         d2 = d2+s2*vv;
 | |
|     }
 | |
|     *f = b->sy*n0/d0;
 | |
|     *df = b->sy*(n1*d0-n0*d1)/ae_sqr(d0, _state);
 | |
|     *d2f = b->sy*((n2*d0-n0*d2)*ae_sqr(d0, _state)-(n1*d0-n0*d1)*2*d0*d1)/ae_sqr(ae_sqr(d0, _state), _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the argument.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B       -   rational interpolant in barycentric form
 | |
|     CA, CB  -   transformation coefficients: x = CA*t + CB
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     B       -   transformed interpolant with X replaced by T
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 19.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentriclintransx(barycentricinterpolant* b,
 | |
|      double ca,
 | |
|      double cb,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double v;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * special case, replace by constant F(CB)
 | |
|      */
 | |
|     if( ae_fp_eq(ca,(double)(0)) )
 | |
|     {
 | |
|         b->sy = barycentriccalc(b, cb, _state);
 | |
|         v = (double)(1);
 | |
|         for(i=0; i<=b->n-1; i++)
 | |
|         {
 | |
|             b->y.ptr.p_double[i] = (double)(1);
 | |
|             b->w.ptr.p_double[i] = v;
 | |
|             v = -v;
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * general case: CA<>0
 | |
|      */
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         b->x.ptr.p_double[i] = (b->x.ptr.p_double[i]-cb)/ca;
 | |
|     }
 | |
|     if( ae_fp_less(ca,(double)(0)) )
 | |
|     {
 | |
|         for(i=0; i<=b->n-1; i++)
 | |
|         {
 | |
|             if( i<b->n-1-i )
 | |
|             {
 | |
|                 j = b->n-1-i;
 | |
|                 v = b->x.ptr.p_double[i];
 | |
|                 b->x.ptr.p_double[i] = b->x.ptr.p_double[j];
 | |
|                 b->x.ptr.p_double[j] = v;
 | |
|                 v = b->y.ptr.p_double[i];
 | |
|                 b->y.ptr.p_double[i] = b->y.ptr.p_double[j];
 | |
|                 b->y.ptr.p_double[j] = v;
 | |
|                 v = b->w.ptr.p_double[i];
 | |
|                 b->w.ptr.p_double[i] = b->w.ptr.p_double[j];
 | |
|                 b->w.ptr.p_double[j] = v;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  subroutine   performs   linear  transformation  of  the  barycentric
 | |
| interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B       -   rational interpolant in barycentric form
 | |
|     CA, CB  -   transformation coefficients: B2(x) = CA*B(x) + CB
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     B       -   transformed interpolant
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 19.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentriclintransy(barycentricinterpolant* b,
 | |
|      double ca,
 | |
|      double cb,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     double v;
 | |
| 
 | |
| 
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         b->y.ptr.p_double[i] = ca*b->sy*b->y.ptr.p_double[i]+cb;
 | |
|     }
 | |
|     b->sy = (double)(0);
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         b->sy = ae_maxreal(b->sy, ae_fabs(b->y.ptr.p_double[i], _state), _state);
 | |
|     }
 | |
|     if( ae_fp_greater(b->sy,(double)(0)) )
 | |
|     {
 | |
|         v = 1/b->sy;
 | |
|         ae_v_muld(&b->y.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Extracts X/Y/W arrays from rational interpolant
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B   -   barycentric interpolant
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     N   -   nodes count, N>0
 | |
|     X   -   interpolation nodes, array[0..N-1]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     W   -   barycentric weights, array[0..N-1]
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricunpack(barycentricinterpolant* b,
 | |
|      ae_int_t* n,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double v;
 | |
| 
 | |
|     *n = 0;
 | |
|     ae_vector_clear(x);
 | |
|     ae_vector_clear(y);
 | |
|     ae_vector_clear(w);
 | |
| 
 | |
|     *n = b->n;
 | |
|     ae_vector_set_length(x, *n, _state);
 | |
|     ae_vector_set_length(y, *n, _state);
 | |
|     ae_vector_set_length(w, *n, _state);
 | |
|     v = b->sy;
 | |
|     ae_v_move(&x->ptr.p_double[0], 1, &b->x.ptr.p_double[0], 1, ae_v_len(0,*n-1));
 | |
|     ae_v_moved(&y->ptr.p_double[0], 1, &b->y.ptr.p_double[0], 1, ae_v_len(0,*n-1), v);
 | |
|     ae_v_move(&w->ptr.p_double[0], 1, &b->w.ptr.p_double[0], 1, ae_v_len(0,*n-1));
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Rational interpolant from X/Y/W arrays
 | |
| 
 | |
| F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   interpolation nodes, array[0..N-1]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     W   -   barycentric weights, array[0..N-1]
 | |
|     N   -   nodes count, N>0
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     B   -   barycentric interpolant built from (X, Y, W)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricbuildxyw(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      barycentricinterpolant* b,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _barycentricinterpolant_clear(b);
 | |
| 
 | |
|     ae_assert(n>0, "BarycentricBuildXYW: incorrect N!", _state);
 | |
|     
 | |
|     /*
 | |
|      * fill X/Y/W
 | |
|      */
 | |
|     ae_vector_set_length(&b->x, n, _state);
 | |
|     ae_vector_set_length(&b->y, n, _state);
 | |
|     ae_vector_set_length(&b->w, n, _state);
 | |
|     ae_v_move(&b->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     ae_v_move(&b->y.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     ae_v_move(&b->w.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     b->n = n;
 | |
|     
 | |
|     /*
 | |
|      * Normalize
 | |
|      */
 | |
|     ratint_barycentricnormalize(b, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Rational interpolant without poles
 | |
| 
 | |
| The subroutine constructs the rational interpolating function without real
 | |
| poles  (see  'Barycentric rational interpolation with no  poles  and  high
 | |
| rates of approximation', Michael S. Floater. and  Kai  Hormann,  for  more
 | |
| information on this subject).
 | |
| 
 | |
| Input parameters:
 | |
|     X   -   interpolation nodes, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     N   -   number of nodes, N>0.
 | |
|     D   -   order of the interpolation scheme, 0 <= D <= N-1.
 | |
|             D<0 will cause an error.
 | |
|             D>=N it will be replaced with D=N-1.
 | |
|             if you don't know what D to choose, use small value about 3-5.
 | |
| 
 | |
| Output parameters:
 | |
|     B   -   barycentric interpolant.
 | |
| 
 | |
| Note:
 | |
|     this algorithm always succeeds and calculates the weights  with  close
 | |
|     to machine precision.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 17.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricbuildfloaterhormann(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t d,
 | |
|      barycentricinterpolant* b,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     double s0;
 | |
|     double s;
 | |
|     double v;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_vector perm;
 | |
|     ae_vector wtemp;
 | |
|     ae_vector sortrbuf;
 | |
|     ae_vector sortrbuf2;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&perm, 0, sizeof(perm));
 | |
|     memset(&wtemp, 0, sizeof(wtemp));
 | |
|     memset(&sortrbuf, 0, sizeof(sortrbuf));
 | |
|     memset(&sortrbuf2, 0, sizeof(sortrbuf2));
 | |
|     _barycentricinterpolant_clear(b);
 | |
|     ae_vector_init(&perm, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&wtemp, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sortrbuf, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sortrbuf2, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>0, "BarycentricFloaterHormann: N<=0!", _state);
 | |
|     ae_assert(d>=0, "BarycentricFloaterHormann: incorrect D!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare
 | |
|      */
 | |
|     if( d>n-1 )
 | |
|     {
 | |
|         d = n-1;
 | |
|     }
 | |
|     b->n = n;
 | |
|     
 | |
|     /*
 | |
|      * special case: N=1
 | |
|      */
 | |
|     if( n==1 )
 | |
|     {
 | |
|         ae_vector_set_length(&b->x, n, _state);
 | |
|         ae_vector_set_length(&b->y, n, _state);
 | |
|         ae_vector_set_length(&b->w, n, _state);
 | |
|         b->x.ptr.p_double[0] = x->ptr.p_double[0];
 | |
|         b->y.ptr.p_double[0] = y->ptr.p_double[0];
 | |
|         b->w.ptr.p_double[0] = (double)(1);
 | |
|         ratint_barycentricnormalize(b, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Fill X/Y
 | |
|      */
 | |
|     ae_vector_set_length(&b->x, n, _state);
 | |
|     ae_vector_set_length(&b->y, n, _state);
 | |
|     ae_v_move(&b->x.ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     ae_v_move(&b->y.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     tagsortfastr(&b->x, &b->y, &sortrbuf, &sortrbuf2, n, _state);
 | |
|     
 | |
|     /*
 | |
|      * Calculate Wk
 | |
|      */
 | |
|     ae_vector_set_length(&b->w, n, _state);
 | |
|     s0 = (double)(1);
 | |
|     for(k=1; k<=d; k++)
 | |
|     {
 | |
|         s0 = -s0;
 | |
|     }
 | |
|     for(k=0; k<=n-1; k++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Wk
 | |
|          */
 | |
|         s = (double)(0);
 | |
|         for(i=ae_maxint(k-d, 0, _state); i<=ae_minint(k, n-1-d, _state); i++)
 | |
|         {
 | |
|             v = (double)(1);
 | |
|             for(j=i; j<=i+d; j++)
 | |
|             {
 | |
|                 if( j!=k )
 | |
|                 {
 | |
|                     v = v/ae_fabs(b->x.ptr.p_double[k]-b->x.ptr.p_double[j], _state);
 | |
|                 }
 | |
|             }
 | |
|             s = s+v;
 | |
|         }
 | |
|         b->w.ptr.p_double[k] = s0*s;
 | |
|         
 | |
|         /*
 | |
|          * Next S0
 | |
|          */
 | |
|         s0 = -s0;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Normalize
 | |
|      */
 | |
|     ratint_barycentricnormalize(b, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Copying of the barycentric interpolant (for internal use only)
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     B   -   barycentric interpolant
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     B2  -   copy(B1)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentriccopy(barycentricinterpolant* b,
 | |
|      barycentricinterpolant* b2,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _barycentricinterpolant_clear(b2);
 | |
| 
 | |
|     b2->n = b->n;
 | |
|     b2->sy = b->sy;
 | |
|     ae_vector_set_length(&b2->x, b2->n, _state);
 | |
|     ae_vector_set_length(&b2->y, b2->n, _state);
 | |
|     ae_vector_set_length(&b2->w, b2->n, _state);
 | |
|     ae_v_move(&b2->x.ptr.p_double[0], 1, &b->x.ptr.p_double[0], 1, ae_v_len(0,b2->n-1));
 | |
|     ae_v_move(&b2->y.ptr.p_double[0], 1, &b->y.ptr.p_double[0], 1, ae_v_len(0,b2->n-1));
 | |
|     ae_v_move(&b2->w.ptr.p_double[0], 1, &b->w.ptr.p_double[0], 1, ae_v_len(0,b2->n-1));
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Normalization of barycentric interpolant:
 | |
| * B.N, B.X, B.Y and B.W are initialized
 | |
| * B.SY is NOT initialized
 | |
| * Y[] is normalized, scaling coefficient is stored in B.SY
 | |
| * W[] is normalized, no scaling coefficient is stored
 | |
| * X[] is sorted
 | |
| 
 | |
| Internal subroutine.
 | |
| *************************************************************************/
 | |
| static void ratint_barycentricnormalize(barycentricinterpolant* b,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector p1;
 | |
|     ae_vector p2;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t j2;
 | |
|     double v;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&p1, 0, sizeof(p1));
 | |
|     memset(&p2, 0, sizeof(p2));
 | |
|     ae_vector_init(&p1, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Normalize task: |Y|<=1, |W|<=1, sort X[]
 | |
|      */
 | |
|     b->sy = (double)(0);
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         b->sy = ae_maxreal(b->sy, ae_fabs(b->y.ptr.p_double[i], _state), _state);
 | |
|     }
 | |
|     if( ae_fp_greater(b->sy,(double)(0))&&ae_fp_greater(ae_fabs(b->sy-1, _state),10*ae_machineepsilon) )
 | |
|     {
 | |
|         v = 1/b->sy;
 | |
|         ae_v_muld(&b->y.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v);
 | |
|     }
 | |
|     v = (double)(0);
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         v = ae_maxreal(v, ae_fabs(b->w.ptr.p_double[i], _state), _state);
 | |
|     }
 | |
|     if( ae_fp_greater(v,(double)(0))&&ae_fp_greater(ae_fabs(v-1, _state),10*ae_machineepsilon) )
 | |
|     {
 | |
|         v = 1/v;
 | |
|         ae_v_muld(&b->w.ptr.p_double[0], 1, ae_v_len(0,b->n-1), v);
 | |
|     }
 | |
|     for(i=0; i<=b->n-2; i++)
 | |
|     {
 | |
|         if( ae_fp_less(b->x.ptr.p_double[i+1],b->x.ptr.p_double[i]) )
 | |
|         {
 | |
|             tagsort(&b->x, b->n, &p1, &p2, _state);
 | |
|             for(j=0; j<=b->n-1; j++)
 | |
|             {
 | |
|                 j2 = p2.ptr.p_int[j];
 | |
|                 v = b->y.ptr.p_double[j];
 | |
|                 b->y.ptr.p_double[j] = b->y.ptr.p_double[j2];
 | |
|                 b->y.ptr.p_double[j2] = v;
 | |
|                 v = b->w.ptr.p_double[j];
 | |
|                 b->w.ptr.p_double[j] = b->w.ptr.p_double[j2];
 | |
|                 b->w.ptr.p_double[j2] = v;
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _barycentricinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     barycentricinterpolant *p = (barycentricinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->w, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _barycentricinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     barycentricinterpolant *dst = (barycentricinterpolant*)_dst;
 | |
|     barycentricinterpolant *src = (barycentricinterpolant*)_src;
 | |
|     dst->n = src->n;
 | |
|     dst->sy = src->sy;
 | |
|     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->w, &src->w, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _barycentricinterpolant_clear(void* _p)
 | |
| {
 | |
|     barycentricinterpolant *p = (barycentricinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->x);
 | |
|     ae_vector_clear(&p->y);
 | |
|     ae_vector_clear(&p->w);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _barycentricinterpolant_destroy(void* _p)
 | |
| {
 | |
|     barycentricinterpolant *p = (barycentricinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->x);
 | |
|     ae_vector_destroy(&p->y);
 | |
|     ae_vector_destroy(&p->w);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_FITSPHERE) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fits least squares (LS) circle (or NX-dimensional sphere) to data  (a  set
 | |
| of points in NX-dimensional space).
 | |
| 
 | |
| Least squares circle minimizes sum of squared deviations between distances
 | |
| from points to the center and  some  "candidate"  radius,  which  is  also
 | |
| fitted to the data.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     R       -   radius
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 07.05.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitspherels(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t nx,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      double* r,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double dummy;
 | |
| 
 | |
|     ae_vector_clear(cx);
 | |
|     *r = 0;
 | |
| 
 | |
|     fitspherex(xy, npoints, nx, 0, 0.0, 0, 0.0, cx, &dummy, r, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fits minimum circumscribed (MC) circle (or NX-dimensional sphere) to  data
 | |
| (a set of points in NX-dimensional space).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     RHi     -   radius
 | |
| 
 | |
| NOTE: this function is an easy-to-use wrapper around more powerful "expert"
 | |
|       function fitspherex().
 | |
|       
 | |
|       This  wrapper  is optimized  for  ease of use and stability - at the
 | |
|       cost of somewhat lower  performance  (we  have  to  use  very  tight
 | |
|       stopping criteria for inner optimizer because we want to  make  sure
 | |
|       that it will converge on any dataset).
 | |
|       
 | |
|       If you are ready to experiment with settings of  "expert"  function,
 | |
|       you can achieve ~2-4x speedup over standard "bulletproof" settings.
 | |
| 
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitspheremc(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t nx,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      double* rhi,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double dummy;
 | |
| 
 | |
|     ae_vector_clear(cx);
 | |
|     *rhi = 0;
 | |
| 
 | |
|     fitspherex(xy, npoints, nx, 1, 0.0, 0, 0.0, cx, &dummy, rhi, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fits maximum inscribed circle (or NX-dimensional sphere) to data (a set of
 | |
| points in NX-dimensional space).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     RLo     -   radius
 | |
| 
 | |
| NOTE: this function is an easy-to-use wrapper around more powerful "expert"
 | |
|       function fitspherex().
 | |
|       
 | |
|       This  wrapper  is optimized  for  ease of use and stability - at the
 | |
|       cost of somewhat lower  performance  (we  have  to  use  very  tight
 | |
|       stopping criteria for inner optimizer because we want to  make  sure
 | |
|       that it will converge on any dataset).
 | |
|       
 | |
|       If you are ready to experiment with settings of  "expert"  function,
 | |
|       you can achieve ~2-4x speedup over standard "bulletproof" settings.
 | |
| 
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitspheremi(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t nx,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      double* rlo,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double dummy;
 | |
| 
 | |
|     ae_vector_clear(cx);
 | |
|     *rlo = 0;
 | |
| 
 | |
|     fitspherex(xy, npoints, nx, 2, 0.0, 0, 0.0, cx, rlo, &dummy, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fits minimum zone circle (or NX-dimensional sphere)  to  data  (a  set  of
 | |
| points in NX-dimensional space).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     RLo     -   radius of inscribed circle
 | |
|     RHo     -   radius of circumscribed circle
 | |
| 
 | |
| NOTE: this function is an easy-to-use wrapper around more powerful "expert"
 | |
|       function fitspherex().
 | |
|       
 | |
|       This  wrapper  is optimized  for  ease of use and stability - at the
 | |
|       cost of somewhat lower  performance  (we  have  to  use  very  tight
 | |
|       stopping criteria for inner optimizer because we want to  make  sure
 | |
|       that it will converge on any dataset).
 | |
|       
 | |
|       If you are ready to experiment with settings of  "expert"  function,
 | |
|       you can achieve ~2-4x speedup over standard "bulletproof" settings.
 | |
| 
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitspheremz(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t nx,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      double* rlo,
 | |
|      double* rhi,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     ae_vector_clear(cx);
 | |
|     *rlo = 0;
 | |
|     *rhi = 0;
 | |
| 
 | |
|     fitspherex(xy, npoints, nx, 3, 0.0, 0, 0.0, cx, rlo, rhi, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fitting minimum circumscribed, maximum inscribed or minimum  zone  circles
 | |
| (or NX-dimensional spheres)  to  data  (a  set of points in NX-dimensional
 | |
| space).
 | |
| 
 | |
| This  is  expert  function  which  allows  to  tweak  many  parameters  of
 | |
| underlying nonlinear solver:
 | |
| * stopping criteria for inner iterations
 | |
| * number of outer iterations
 | |
| * penalty coefficient used to handle  nonlinear  constraints  (we  convert
 | |
|   unconstrained nonsmooth optimization problem ivolving max() and/or min()
 | |
|   operations to quadratically constrained smooth one).
 | |
| 
 | |
| You may tweak all these parameters or only some  of  them,  leaving  other
 | |
| ones at their default state - just specify zero  value,  and  solver  will
 | |
| fill it with appropriate default one.
 | |
| 
 | |
| These comments also include some discussion of  approach  used  to  handle
 | |
| such unusual fitting problem,  its  stability,  drawbacks  of  alternative
 | |
| methods, and convergence properties.
 | |
|   
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
|     ProblemType-used to encode problem type:
 | |
|                 * 0 for least squares circle
 | |
|                 * 1 for minimum circumscribed circle/sphere fitting (MC)
 | |
|                 * 2 for  maximum inscribed circle/sphere fitting (MI)
 | |
|                 * 3 for minimum zone circle fitting (difference between
 | |
|                     Rhi and Rlo is minimized), denoted as MZ
 | |
|     EpsX    -   stopping condition for NLC optimizer:
 | |
|                 * must be non-negative
 | |
|                 * use 0 to choose default value (1.0E-12 is used by default)
 | |
|                 * you may specify larger values, up to 1.0E-6, if you want
 | |
|                   to   speed-up   solver;   NLC   solver  performs several
 | |
|                   preconditioned  outer  iterations,   so   final   result
 | |
|                   typically has precision much better than EpsX.
 | |
|     AULIts  -   number of outer iterations performed by NLC optimizer:
 | |
|                 * must be non-negative
 | |
|                 * use 0 to choose default value (20 is used by default)
 | |
|                 * you may specify values smaller than 20 if you want to
 | |
|                   speed up solver; 10 often results in good combination of
 | |
|                   precision and speed; sometimes you may get good results
 | |
|                   with just 6 outer iterations.
 | |
|                 Ignored for ProblemType=0.
 | |
|     Penalty -   penalty coefficient for NLC optimizer:
 | |
|                 * must be non-negative
 | |
|                 * use 0 to choose default value (1.0E6 in current version)
 | |
|                 * it should be really large, 1.0E6...1.0E7 is a good value
 | |
|                   to start from;
 | |
|                 * generally, default value is good enough
 | |
|                 Ignored for ProblemType=0.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     RLo     -   radius:
 | |
|                 * for ProblemType=2,3, radius of the inscribed sphere
 | |
|                 * for ProblemType=0 - radius of the least squares sphere
 | |
|                 * for ProblemType=1 - zero
 | |
|     RHo     -   radius:
 | |
|                 * for ProblemType=1,3, radius of the circumscribed sphere
 | |
|                 * for ProblemType=0 - radius of the least squares sphere
 | |
|                 * for ProblemType=2 - zero
 | |
| 
 | |
| NOTE: ON THE UNIQUENESS OF SOLUTIONS
 | |
| 
 | |
| ALGLIB provides solution to several related circle fitting  problems:   MC
 | |
| (minimum circumscribed), MI (maximum inscribed)   and   MZ  (minimum zone)
 | |
| fitting, LS (least squares) fitting.
 | |
| 
 | |
| It  is  important  to  note  that  among these problems only MC and LS are
 | |
| convex and have unique solution independently from starting point.
 | |
| 
 | |
| As  for MI,  it  may (or  may  not, depending on dataset properties)  have
 | |
| multiple solutions, and it always  has  one degenerate solution C=infinity
 | |
| which corresponds to infinitely large radius. Thus, there are no guarantees
 | |
| that solution to  MI returned by this solver will be the best one (and  no
 | |
| one can provide you with such guarantee because problem is  NP-hard).  The
 | |
| only guarantee you have is that this solution is locally optimal, i.e.  it
 | |
| can not be improved by infinitesimally small tweaks in the parameters.
 | |
| 
 | |
| It  is  also  possible  to "run away" to infinity when  started  from  bad
 | |
| initial point located outside of point cloud (or when point cloud does not
 | |
| span entire circumference/surface of the sphere).
 | |
| 
 | |
| Finally,  MZ (minimum zone circle) stands somewhere between MC  and  MI in
 | |
| stability. It is somewhat regularized by "circumscribed" term of the merit
 | |
| function; however, solutions to  MZ may be non-unique, and in some unlucky
 | |
| cases it is also possible to "run away to infinity".
 | |
| 
 | |
| 
 | |
| NOTE: ON THE NONLINEARLY CONSTRAINED PROGRAMMING APPROACH
 | |
| 
 | |
| The problem formulation for MC  (minimum circumscribed   circle;  for  the
 | |
| sake of simplicity we omit MZ and MI here) is:
 | |
| 
 | |
|         [     [         ]2 ]
 | |
|     min [ max [ XY[i]-C ]  ]
 | |
|      C  [  i  [         ]  ]
 | |
| 
 | |
| i.e. it is unconstrained nonsmooth optimization problem of finding  "best"
 | |
| central point, with radius R being unambiguously  determined  from  C.  In
 | |
| order to move away from non-smoothness we use following reformulation:
 | |
| 
 | |
|         [   ]                  [         ]2
 | |
|     min [ R ] subject to R>=0, [ XY[i]-C ]  <= R^2
 | |
|     C,R [   ]                  [         ]
 | |
|     
 | |
| i.e. it becomes smooth quadratically constrained optimization problem with
 | |
| linear target function. Such problem statement is 100% equivalent  to  the
 | |
| original nonsmooth one, but much easier  to  approach.  We solve  it  with
 | |
| MinNLC solver provided by ALGLIB.
 | |
| 
 | |
| 
 | |
| NOTE: ON INSTABILITY OF SEQUENTIAL LINEARIZATION APPROACH
 | |
| 
 | |
| ALGLIB  has  nonlinearly  constrained  solver which proved to be stable on
 | |
| such problems. However, some authors proposed to linearize constraints  in
 | |
| the vicinity of current approximation (Ci,Ri) and to get next  approximate
 | |
| solution (Ci+1,Ri+1) as solution to linear programming problem. Obviously,
 | |
| LP problems are easier than nonlinearly constrained ones.
 | |
| 
 | |
| Indeed,  such approach  to   MC/MI/MZ   resulted   in  ~10-20x increase in
 | |
| performance (when compared with NLC solver). However, it turned  out  that
 | |
| in some cases linearized model fails to predict correct direction for next
 | |
| step and tells us that we converged to solution even when we are still 2-4
 | |
| digits of precision away from it.
 | |
| 
 | |
| It is important that it is not failure of LP solver - it is failure of the
 | |
| linear model;  even  when  solved  exactly,  it  fails  to  handle  subtle
 | |
| nonlinearities which arise near the solution. We validated it by comparing
 | |
| results returned by ALGLIB linear solver with that of MATLAB.
 | |
| 
 | |
| In our experiments with linearization:
 | |
| * MC failed most often, at both realistic and synthetic datasets
 | |
| * MI sometimes failed, but sometimes succeeded
 | |
| * MZ often  succeeded; our guess is that presence of two independent  sets
 | |
|   of constraints (one set for Rlo and another one for Rhi) and  two  terms
 | |
|   in the target function (Rlo and Rhi) regularizes task,  so  when  linear
 | |
|   model fails to handle nonlinearities from Rlo, it uses  Rhi  as  a  hint
 | |
|   (and vice versa).
 | |
|   
 | |
| Because linearization approach failed to achieve stable results, we do not
 | |
| include it in ALGLIB.
 | |
| 
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitspherex(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t problemtype,
 | |
|      double epsx,
 | |
|      ae_int_t aulits,
 | |
|      double penalty,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      double* rlo,
 | |
|      double* rhi,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     fitsphereinternalreport rep;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&rep, 0, sizeof(rep));
 | |
|     ae_vector_clear(cx);
 | |
|     *rlo = 0;
 | |
|     *rhi = 0;
 | |
|     _fitsphereinternalreport_init(&rep, _state, ae_true);
 | |
| 
 | |
|     ae_assert(ae_isfinite(penalty, _state)&&ae_fp_greater_eq(penalty,(double)(0)), "FitSphereX: Penalty<0 or is not finite", _state);
 | |
|     ae_assert(ae_isfinite(epsx, _state)&&ae_fp_greater_eq(epsx,(double)(0)), "FitSphereX: EpsX<0 or is not finite", _state);
 | |
|     ae_assert(aulits>=0, "FitSphereX: AULIts<0", _state);
 | |
|     fitsphereinternal(xy, npoints, nx, problemtype, 0, epsx, aulits, penalty, cx, rlo, rhi, &rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fitting minimum circumscribed, maximum inscribed or minimum  zone  circles
 | |
| (or NX-dimensional spheres)  to  data  (a  set of points in NX-dimensional
 | |
| space).
 | |
| 
 | |
| Internal computational function.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   array[NPoints,NX] (or larger), contains dataset.
 | |
|                 One row = one point in NX-dimensional space.
 | |
|     NPoints -   dataset size, NPoints>0
 | |
|     NX      -   space dimensionality, NX>0 (1, 2, 3, 4, 5 and so on)
 | |
|     ProblemType-used to encode problem type:
 | |
|                 * 0 for least squares circle
 | |
|                 * 1 for minimum circumscribed circle/sphere fitting (MC)
 | |
|                 * 2 for  maximum inscribed circle/sphere fitting (MI)
 | |
|                 * 3 for minimum zone circle fitting (difference between
 | |
|                     Rhi and Rlo is minimized), denoted as MZ
 | |
|     SolverType- solver to use:
 | |
|                 * 0 use best solver available (1 in current version)
 | |
|                 * 1 use nonlinearly constrained optimization approach, AUL
 | |
|                     (it is roughly 10-20 times  slower  than  SPC-LIN, but
 | |
|                     much more stable)
 | |
|                 * 2 use special fast IMPRECISE solver, SPC-LIN  sequential
 | |
|                     linearization approach; SPC-LIN is fast, but sometimes
 | |
|                     fails to converge with more than 3 digits of precision;
 | |
|                     see comments below.
 | |
|                     NOT RECOMMENDED UNLESS YOU REALLY NEED HIGH PERFORMANCE
 | |
|                     AT THE COST OF SOME PRECISION.
 | |
|                 * 3 use nonlinearly constrained optimization approach, SLP
 | |
|                     (most robust one, but somewhat slower than AUL)
 | |
|                 Ignored for ProblemType=0.
 | |
|     EpsX    -   stopping criteria for SLP and NLC optimizers:
 | |
|                 * must be non-negative
 | |
|                 * use 0 to choose default value (1.0E-12 is used by default)
 | |
|                 * if you use SLP solver, you should use default values
 | |
|                 * if you use NLC solver, you may specify larger values, up
 | |
|                   to 1.0E-6, if you want to speed-up  solver;  NLC  solver
 | |
|                   performs several preconditioned outer iterations, so final
 | |
|                   result typically has precision much better than EpsX.
 | |
|     AULIts  -   number of iterations performed by NLC optimizer:
 | |
|                 * must be non-negative
 | |
|                 * use 0 to choose default value (20 is used by default)
 | |
|                 * you may specify values smaller than 20 if you want to
 | |
|                   speed up solver; 10 often results in good combination of
 | |
|                   precision and speed
 | |
|                 Ignored for ProblemType=0.
 | |
|     Penalty -   penalty coefficient for NLC optimizer (ignored  for  SLP):
 | |
|                 * must be non-negative
 | |
|                 * use 0 to choose default value (1.0E6 in current version)
 | |
|                 * it should be really large, 1.0E6...1.0E7 is a good value
 | |
|                   to start from;
 | |
|                 * generally, default value is good enough
 | |
|                 * ignored by SLP optimizer
 | |
|                 Ignored for ProblemType=0.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CX      -   central point for a sphere
 | |
|     RLo     -   radius:
 | |
|                 * for ProblemType=2,3, radius of the inscribed sphere
 | |
|                 * for ProblemType=0 - radius of the least squares sphere
 | |
|                 * for ProblemType=1 - zero
 | |
|     RHo     -   radius:
 | |
|                 * for ProblemType=1,3, radius of the circumscribed sphere
 | |
|                 * for ProblemType=0 - radius of the least squares sphere
 | |
|                 * for ProblemType=2 - zero
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void fitsphereinternal(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t problemtype,
 | |
|      ae_int_t solvertype,
 | |
|      double epsx,
 | |
|      ae_int_t aulits,
 | |
|      double penalty,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      double* rlo,
 | |
|      double* rhi,
 | |
|      fitsphereinternalreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double v;
 | |
|     double vv;
 | |
|     ae_int_t cpr;
 | |
|     ae_bool userlo;
 | |
|     ae_bool userhi;
 | |
|     double vlo;
 | |
|     double vhi;
 | |
|     ae_vector vmin;
 | |
|     ae_vector vmax;
 | |
|     double spread;
 | |
|     ae_vector pcr;
 | |
|     ae_vector scr;
 | |
|     ae_vector bl;
 | |
|     ae_vector bu;
 | |
|     ae_int_t suboffset;
 | |
|     ae_int_t dstrow;
 | |
|     minnlcstate nlcstate;
 | |
|     minnlcreport nlcrep;
 | |
|     ae_matrix cmatrix;
 | |
|     ae_vector ct;
 | |
|     ae_int_t outeridx;
 | |
|     ae_int_t maxouterits;
 | |
|     ae_int_t maxits;
 | |
|     double safeguard;
 | |
|     double bi;
 | |
|     minbleicstate blcstate;
 | |
|     minbleicreport blcrep;
 | |
|     ae_vector prevc;
 | |
|     minlmstate lmstate;
 | |
|     minlmreport lmrep;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&vmin, 0, sizeof(vmin));
 | |
|     memset(&vmax, 0, sizeof(vmax));
 | |
|     memset(&pcr, 0, sizeof(pcr));
 | |
|     memset(&scr, 0, sizeof(scr));
 | |
|     memset(&bl, 0, sizeof(bl));
 | |
|     memset(&bu, 0, sizeof(bu));
 | |
|     memset(&nlcstate, 0, sizeof(nlcstate));
 | |
|     memset(&nlcrep, 0, sizeof(nlcrep));
 | |
|     memset(&cmatrix, 0, sizeof(cmatrix));
 | |
|     memset(&ct, 0, sizeof(ct));
 | |
|     memset(&blcstate, 0, sizeof(blcstate));
 | |
|     memset(&blcrep, 0, sizeof(blcrep));
 | |
|     memset(&prevc, 0, sizeof(prevc));
 | |
|     memset(&lmstate, 0, sizeof(lmstate));
 | |
|     memset(&lmrep, 0, sizeof(lmrep));
 | |
|     ae_vector_clear(cx);
 | |
|     *rlo = 0;
 | |
|     *rhi = 0;
 | |
|     _fitsphereinternalreport_clear(rep);
 | |
|     ae_vector_init(&vmin, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&vmax, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&pcr, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&scr, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bl, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bu, 0, DT_REAL, _state, ae_true);
 | |
|     _minnlcstate_init(&nlcstate, _state, ae_true);
 | |
|     _minnlcreport_init(&nlcrep, _state, ae_true);
 | |
|     ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ct, 0, DT_INT, _state, ae_true);
 | |
|     _minbleicstate_init(&blcstate, _state, ae_true);
 | |
|     _minbleicreport_init(&blcrep, _state, ae_true);
 | |
|     ae_vector_init(&prevc, 0, DT_REAL, _state, ae_true);
 | |
|     _minlmstate_init(&lmstate, _state, ae_true);
 | |
|     _minlmreport_init(&lmrep, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Check input parameters
 | |
|      */
 | |
|     ae_assert(npoints>0, "FitSphereX: NPoints<=0", _state);
 | |
|     ae_assert(nx>0, "FitSphereX: NX<=0", _state);
 | |
|     ae_assert(apservisfinitematrix(xy, npoints, nx, _state), "FitSphereX: XY contains infinite or NAN values", _state);
 | |
|     ae_assert(problemtype>=0&&problemtype<=3, "FitSphereX: ProblemType is neither 0, 1, 2 or 3", _state);
 | |
|     ae_assert(solvertype>=0&&solvertype<=3, "FitSphereX: ProblemType is neither 1, 2 or 3", _state);
 | |
|     ae_assert(ae_isfinite(penalty, _state)&&ae_fp_greater_eq(penalty,(double)(0)), "FitSphereX: Penalty<0 or is not finite", _state);
 | |
|     ae_assert(ae_isfinite(epsx, _state)&&ae_fp_greater_eq(epsx,(double)(0)), "FitSphereX: EpsX<0 or is not finite", _state);
 | |
|     ae_assert(aulits>=0, "FitSphereX: AULIts<0", _state);
 | |
|     if( solvertype==0 )
 | |
|     {
 | |
|         solvertype = 1;
 | |
|     }
 | |
|     if( ae_fp_eq(penalty,(double)(0)) )
 | |
|     {
 | |
|         penalty = 1.0E6;
 | |
|     }
 | |
|     if( ae_fp_eq(epsx,(double)(0)) )
 | |
|     {
 | |
|         epsx = 1.0E-12;
 | |
|     }
 | |
|     if( aulits==0 )
 | |
|     {
 | |
|         aulits = 20;
 | |
|     }
 | |
|     safeguard = (double)(10);
 | |
|     maxouterits = 10;
 | |
|     maxits = 10000;
 | |
|     rep->nfev = 0;
 | |
|     rep->iterationscount = 0;
 | |
|     
 | |
|     /*
 | |
|      * Determine initial values, initial estimates and spread of the points
 | |
|      */
 | |
|     ae_vector_set_length(&vmin, nx, _state);
 | |
|     ae_vector_set_length(&vmax, nx, _state);
 | |
|     ae_vector_set_length(cx, nx, _state);
 | |
|     for(j=0; j<=nx-1; j++)
 | |
|     {
 | |
|         vmin.ptr.p_double[j] = xy->ptr.pp_double[0][j];
 | |
|         vmax.ptr.p_double[j] = xy->ptr.pp_double[0][j];
 | |
|         cx->ptr.p_double[j] = (double)(0);
 | |
|     }
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             cx->ptr.p_double[j] = cx->ptr.p_double[j]+xy->ptr.pp_double[i][j];
 | |
|             vmin.ptr.p_double[j] = ae_minreal(vmin.ptr.p_double[j], xy->ptr.pp_double[i][j], _state);
 | |
|             vmax.ptr.p_double[j] = ae_maxreal(vmax.ptr.p_double[j], xy->ptr.pp_double[i][j], _state);
 | |
|         }
 | |
|     }
 | |
|     spread = (double)(0);
 | |
|     for(j=0; j<=nx-1; j++)
 | |
|     {
 | |
|         cx->ptr.p_double[j] = cx->ptr.p_double[j]/npoints;
 | |
|         spread = ae_maxreal(spread, vmax.ptr.p_double[j]-vmin.ptr.p_double[j], _state);
 | |
|     }
 | |
|     *rlo = ae_maxrealnumber;
 | |
|     *rhi = (double)(0);
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         v = (double)(0);
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state);
 | |
|         }
 | |
|         v = ae_sqrt(v, _state);
 | |
|         *rhi = ae_maxreal(*rhi, v, _state);
 | |
|         *rlo = ae_minreal(*rlo, v, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Handle degenerate case of zero spread
 | |
|      */
 | |
|     if( ae_fp_eq(spread,(double)(0)) )
 | |
|     {
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             cx->ptr.p_double[j] = vmin.ptr.p_double[j];
 | |
|         }
 | |
|         *rhi = (double)(0);
 | |
|         *rlo = (double)(0);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare initial point for optimizer, scale vector and box constraints
 | |
|      */
 | |
|     ae_vector_set_length(&pcr, nx+2, _state);
 | |
|     ae_vector_set_length(&scr, nx+2, _state);
 | |
|     ae_vector_set_length(&bl, nx+2, _state);
 | |
|     ae_vector_set_length(&bu, nx+2, _state);
 | |
|     for(j=0; j<=nx-1; j++)
 | |
|     {
 | |
|         pcr.ptr.p_double[j] = cx->ptr.p_double[j];
 | |
|         scr.ptr.p_double[j] = 0.1*spread;
 | |
|         bl.ptr.p_double[j] = cx->ptr.p_double[j]-safeguard*spread;
 | |
|         bu.ptr.p_double[j] = cx->ptr.p_double[j]+safeguard*spread;
 | |
|     }
 | |
|     pcr.ptr.p_double[nx+0] = *rlo;
 | |
|     pcr.ptr.p_double[nx+1] = *rhi;
 | |
|     scr.ptr.p_double[nx+0] = 0.5*spread;
 | |
|     scr.ptr.p_double[nx+1] = 0.5*spread;
 | |
|     bl.ptr.p_double[nx+0] = (double)(0);
 | |
|     bl.ptr.p_double[nx+1] = (double)(0);
 | |
|     bu.ptr.p_double[nx+0] = safeguard*(*rhi);
 | |
|     bu.ptr.p_double[nx+1] = safeguard*(*rhi);
 | |
|     
 | |
|     /*
 | |
|      * First branch: least squares fitting vs MI/MC/MZ fitting
 | |
|      */
 | |
|     if( problemtype==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Solve problem with Levenberg-Marquardt algorithm
 | |
|          */
 | |
|         pcr.ptr.p_double[nx] = *rhi;
 | |
|         minlmcreatevj(nx+1, npoints, &pcr, &lmstate, _state);
 | |
|         minlmsetscale(&lmstate, &scr, _state);
 | |
|         minlmsetbc(&lmstate, &bl, &bu, _state);
 | |
|         minlmsetcond(&lmstate, epsx, maxits, _state);
 | |
|         while(minlmiteration(&lmstate, _state))
 | |
|         {
 | |
|             if( lmstate.needfij||lmstate.needfi )
 | |
|             {
 | |
|                 inc(&rep->nfev, _state);
 | |
|                 for(i=0; i<=npoints-1; i++)
 | |
|                 {
 | |
|                     v = (double)(0);
 | |
|                     for(j=0; j<=nx-1; j++)
 | |
|                     {
 | |
|                         v = v+ae_sqr(lmstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j], _state);
 | |
|                     }
 | |
|                     lmstate.fi.ptr.p_double[i] = ae_sqrt(v, _state)-lmstate.x.ptr.p_double[nx];
 | |
|                     if( lmstate.needfij )
 | |
|                     {
 | |
|                         for(j=0; j<=nx-1; j++)
 | |
|                         {
 | |
|                             lmstate.j.ptr.pp_double[i][j] = 0.5/(1.0E-9*spread+ae_sqrt(v, _state))*2*(lmstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j]);
 | |
|                         }
 | |
|                         lmstate.j.ptr.pp_double[i][nx] = (double)(-1);
 | |
|                     }
 | |
|                 }
 | |
|                 continue;
 | |
|             }
 | |
|             ae_assert(ae_false, "Assertion failed", _state);
 | |
|         }
 | |
|         minlmresults(&lmstate, &pcr, &lmrep, _state);
 | |
|         ae_assert(lmrep.terminationtype>0, "FitSphereX: unexpected failure of LM solver", _state);
 | |
|         rep->iterationscount = rep->iterationscount+lmrep.iterationscount;
 | |
|         
 | |
|         /*
 | |
|          * Offload center coordinates from PCR to CX,
 | |
|          * re-calculate exact value of RLo/RHi using CX.
 | |
|          */
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             cx->ptr.p_double[j] = pcr.ptr.p_double[j];
 | |
|         }
 | |
|         vv = (double)(0);
 | |
|         for(i=0; i<=npoints-1; i++)
 | |
|         {
 | |
|             v = (double)(0);
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state);
 | |
|             }
 | |
|             v = ae_sqrt(v, _state);
 | |
|             vv = vv+v/npoints;
 | |
|         }
 | |
|         *rlo = vv;
 | |
|         *rhi = vv;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * MI, MC, MZ fitting.
 | |
|          * Prepare problem metrics
 | |
|          */
 | |
|         userlo = problemtype==2||problemtype==3;
 | |
|         userhi = problemtype==1||problemtype==3;
 | |
|         if( userlo&&userhi )
 | |
|         {
 | |
|             cpr = 2;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             cpr = 1;
 | |
|         }
 | |
|         if( userlo )
 | |
|         {
 | |
|             vlo = (double)(1);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             vlo = (double)(0);
 | |
|         }
 | |
|         if( userhi )
 | |
|         {
 | |
|             vhi = (double)(1);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             vhi = (double)(0);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Solve with NLC solver; problem is treated as general nonlinearly constrained
 | |
|          * programming, with augmented Lagrangian solver or SLP being used.
 | |
|          */
 | |
|         if( solvertype==1||solvertype==3 )
 | |
|         {
 | |
|             minnlccreate(nx+2, &pcr, &nlcstate, _state);
 | |
|             minnlcsetscale(&nlcstate, &scr, _state);
 | |
|             minnlcsetbc(&nlcstate, &bl, &bu, _state);
 | |
|             minnlcsetnlc(&nlcstate, 0, cpr*npoints, _state);
 | |
|             minnlcsetcond(&nlcstate, epsx, maxits, _state);
 | |
|             minnlcsetprecexactrobust(&nlcstate, 5, _state);
 | |
|             minnlcsetstpmax(&nlcstate, 0.1, _state);
 | |
|             if( solvertype==1 )
 | |
|             {
 | |
|                 minnlcsetalgoaul(&nlcstate, penalty, aulits, _state);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 minnlcsetalgoslp(&nlcstate, _state);
 | |
|             }
 | |
|             minnlcrestartfrom(&nlcstate, &pcr, _state);
 | |
|             while(minnlciteration(&nlcstate, _state))
 | |
|             {
 | |
|                 if( nlcstate.needfij )
 | |
|                 {
 | |
|                     inc(&rep->nfev, _state);
 | |
|                     nlcstate.fi.ptr.p_double[0] = vhi*nlcstate.x.ptr.p_double[nx+1]-vlo*nlcstate.x.ptr.p_double[nx+0];
 | |
|                     for(j=0; j<=nx-1; j++)
 | |
|                     {
 | |
|                         nlcstate.j.ptr.pp_double[0][j] = (double)(0);
 | |
|                     }
 | |
|                     nlcstate.j.ptr.pp_double[0][nx+0] = -1*vlo;
 | |
|                     nlcstate.j.ptr.pp_double[0][nx+1] = 1*vhi;
 | |
|                     for(i=0; i<=npoints-1; i++)
 | |
|                     {
 | |
|                         suboffset = 0;
 | |
|                         if( userhi )
 | |
|                         {
 | |
|                             dstrow = 1+cpr*i+suboffset;
 | |
|                             v = (double)(0);
 | |
|                             for(j=0; j<=nx-1; j++)
 | |
|                             {
 | |
|                                 vv = nlcstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j];
 | |
|                                 v = v+vv*vv;
 | |
|                                 nlcstate.j.ptr.pp_double[dstrow][j] = 2*vv;
 | |
|                             }
 | |
|                             vv = nlcstate.x.ptr.p_double[nx+1];
 | |
|                             v = v-vv*vv;
 | |
|                             nlcstate.j.ptr.pp_double[dstrow][nx+0] = (double)(0);
 | |
|                             nlcstate.j.ptr.pp_double[dstrow][nx+1] = -2*vv;
 | |
|                             nlcstate.fi.ptr.p_double[dstrow] = v;
 | |
|                             inc(&suboffset, _state);
 | |
|                         }
 | |
|                         if( userlo )
 | |
|                         {
 | |
|                             dstrow = 1+cpr*i+suboffset;
 | |
|                             v = (double)(0);
 | |
|                             for(j=0; j<=nx-1; j++)
 | |
|                             {
 | |
|                                 vv = nlcstate.x.ptr.p_double[j]-xy->ptr.pp_double[i][j];
 | |
|                                 v = v-vv*vv;
 | |
|                                 nlcstate.j.ptr.pp_double[dstrow][j] = -2*vv;
 | |
|                             }
 | |
|                             vv = nlcstate.x.ptr.p_double[nx+0];
 | |
|                             v = v+vv*vv;
 | |
|                             nlcstate.j.ptr.pp_double[dstrow][nx+0] = 2*vv;
 | |
|                             nlcstate.j.ptr.pp_double[dstrow][nx+1] = (double)(0);
 | |
|                             nlcstate.fi.ptr.p_double[dstrow] = v;
 | |
|                             inc(&suboffset, _state);
 | |
|                         }
 | |
|                         ae_assert(suboffset==cpr, "Assertion failed", _state);
 | |
|                     }
 | |
|                     continue;
 | |
|                 }
 | |
|                 ae_assert(ae_false, "Assertion failed", _state);
 | |
|             }
 | |
|             minnlcresults(&nlcstate, &pcr, &nlcrep, _state);
 | |
|             ae_assert(nlcrep.terminationtype>0, "FitSphereX: unexpected failure of NLC solver", _state);
 | |
|             rep->iterationscount = rep->iterationscount+nlcrep.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Offload center coordinates from PCR to CX,
 | |
|              * re-calculate exact value of RLo/RHi using CX.
 | |
|              */
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 cx->ptr.p_double[j] = pcr.ptr.p_double[j];
 | |
|             }
 | |
|             *rlo = ae_maxrealnumber;
 | |
|             *rhi = (double)(0);
 | |
|             for(i=0; i<=npoints-1; i++)
 | |
|             {
 | |
|                 v = (double)(0);
 | |
|                 for(j=0; j<=nx-1; j++)
 | |
|                 {
 | |
|                     v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state);
 | |
|                 }
 | |
|                 v = ae_sqrt(v, _state);
 | |
|                 *rhi = ae_maxreal(*rhi, v, _state);
 | |
|                 *rlo = ae_minreal(*rlo, v, _state);
 | |
|             }
 | |
|             if( !userlo )
 | |
|             {
 | |
|                 *rlo = (double)(0);
 | |
|             }
 | |
|             if( !userhi )
 | |
|             {
 | |
|                 *rhi = (double)(0);
 | |
|             }
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Solve problem with SLP (sequential LP) approach; this approach
 | |
|          * is much faster than NLP, but often fails for MI and MC (for MZ
 | |
|          * it performs well enough).
 | |
|          *
 | |
|          * REFERENCE: "On a sequential linear programming approach to finding
 | |
|          *            the smallest circumscribed, largest inscribed, and minimum
 | |
|          *            zone circle or sphere", Helmuth Spath and G.A.Watson
 | |
|          */
 | |
|         if( solvertype==2 )
 | |
|         {
 | |
|             ae_matrix_set_length(&cmatrix, cpr*npoints, nx+3, _state);
 | |
|             ae_vector_set_length(&ct, cpr*npoints, _state);
 | |
|             ae_vector_set_length(&prevc, nx, _state);
 | |
|             minbleiccreate(nx+2, &pcr, &blcstate, _state);
 | |
|             minbleicsetscale(&blcstate, &scr, _state);
 | |
|             minbleicsetbc(&blcstate, &bl, &bu, _state);
 | |
|             minbleicsetcond(&blcstate, (double)(0), (double)(0), epsx, maxits, _state);
 | |
|             for(outeridx=0; outeridx<=maxouterits-1; outeridx++)
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * Prepare initial point for algorithm; center coordinates at
 | |
|                  * PCR are used to calculate RLo/RHi and update PCR with them.
 | |
|                  */
 | |
|                 *rlo = ae_maxrealnumber;
 | |
|                 *rhi = (double)(0);
 | |
|                 for(i=0; i<=npoints-1; i++)
 | |
|                 {
 | |
|                     v = (double)(0);
 | |
|                     for(j=0; j<=nx-1; j++)
 | |
|                     {
 | |
|                         v = v+ae_sqr(xy->ptr.pp_double[i][j]-pcr.ptr.p_double[j], _state);
 | |
|                     }
 | |
|                     v = ae_sqrt(v, _state);
 | |
|                     *rhi = ae_maxreal(*rhi, v, _state);
 | |
|                     *rlo = ae_minreal(*rlo, v, _state);
 | |
|                 }
 | |
|                 pcr.ptr.p_double[nx+0] = *rlo*0.99999;
 | |
|                 pcr.ptr.p_double[nx+1] = *rhi/0.99999;
 | |
|                 
 | |
|                 /*
 | |
|                  * Generate matrix of linear constraints
 | |
|                  */
 | |
|                 for(i=0; i<=npoints-1; i++)
 | |
|                 {
 | |
|                     v = (double)(0);
 | |
|                     for(j=0; j<=nx-1; j++)
 | |
|                     {
 | |
|                         v = v+ae_sqr(xy->ptr.pp_double[i][j], _state);
 | |
|                     }
 | |
|                     bi = -v/2;
 | |
|                     suboffset = 0;
 | |
|                     if( userhi )
 | |
|                     {
 | |
|                         dstrow = cpr*i+suboffset;
 | |
|                         for(j=0; j<=nx-1; j++)
 | |
|                         {
 | |
|                             cmatrix.ptr.pp_double[dstrow][j] = pcr.ptr.p_double[j]/2-xy->ptr.pp_double[i][j];
 | |
|                         }
 | |
|                         cmatrix.ptr.pp_double[dstrow][nx+0] = (double)(0);
 | |
|                         cmatrix.ptr.pp_double[dstrow][nx+1] = -*rhi/2;
 | |
|                         cmatrix.ptr.pp_double[dstrow][nx+2] = bi;
 | |
|                         ct.ptr.p_int[dstrow] = -1;
 | |
|                         inc(&suboffset, _state);
 | |
|                     }
 | |
|                     if( userlo )
 | |
|                     {
 | |
|                         dstrow = cpr*i+suboffset;
 | |
|                         for(j=0; j<=nx-1; j++)
 | |
|                         {
 | |
|                             cmatrix.ptr.pp_double[dstrow][j] = -(pcr.ptr.p_double[j]/2-xy->ptr.pp_double[i][j]);
 | |
|                         }
 | |
|                         cmatrix.ptr.pp_double[dstrow][nx+0] = *rlo/2;
 | |
|                         cmatrix.ptr.pp_double[dstrow][nx+1] = (double)(0);
 | |
|                         cmatrix.ptr.pp_double[dstrow][nx+2] = -bi;
 | |
|                         ct.ptr.p_int[dstrow] = -1;
 | |
|                         inc(&suboffset, _state);
 | |
|                     }
 | |
|                     ae_assert(suboffset==cpr, "Assertion failed", _state);
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * Solve LP subproblem with MinBLEIC
 | |
|                  */
 | |
|                 for(j=0; j<=nx-1; j++)
 | |
|                 {
 | |
|                     prevc.ptr.p_double[j] = pcr.ptr.p_double[j];
 | |
|                 }
 | |
|                 minbleicsetlc(&blcstate, &cmatrix, &ct, cpr*npoints, _state);
 | |
|                 minbleicrestartfrom(&blcstate, &pcr, _state);
 | |
|                 while(minbleiciteration(&blcstate, _state))
 | |
|                 {
 | |
|                     if( blcstate.needfg )
 | |
|                     {
 | |
|                         inc(&rep->nfev, _state);
 | |
|                         blcstate.f = vhi*blcstate.x.ptr.p_double[nx+1]-vlo*blcstate.x.ptr.p_double[nx+0];
 | |
|                         for(j=0; j<=nx-1; j++)
 | |
|                         {
 | |
|                             blcstate.g.ptr.p_double[j] = (double)(0);
 | |
|                         }
 | |
|                         blcstate.g.ptr.p_double[nx+0] = -1*vlo;
 | |
|                         blcstate.g.ptr.p_double[nx+1] = 1*vhi;
 | |
|                         continue;
 | |
|                     }
 | |
|                 }
 | |
|                 minbleicresults(&blcstate, &pcr, &blcrep, _state);
 | |
|                 ae_assert(blcrep.terminationtype>0, "FitSphereX: unexpected failure of BLEIC solver", _state);
 | |
|                 rep->iterationscount = rep->iterationscount+blcrep.iterationscount;
 | |
|                 
 | |
|                 /*
 | |
|                  * Terminate iterations early if we converged
 | |
|                  */
 | |
|                 v = (double)(0);
 | |
|                 for(j=0; j<=nx-1; j++)
 | |
|                 {
 | |
|                     v = v+ae_sqr(prevc.ptr.p_double[j]-pcr.ptr.p_double[j], _state);
 | |
|                 }
 | |
|                 v = ae_sqrt(v, _state);
 | |
|                 if( ae_fp_less_eq(v,epsx) )
 | |
|                 {
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Offload center coordinates from PCR to CX,
 | |
|              * re-calculate exact value of RLo/RHi using CX.
 | |
|              */
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 cx->ptr.p_double[j] = pcr.ptr.p_double[j];
 | |
|             }
 | |
|             *rlo = ae_maxrealnumber;
 | |
|             *rhi = (double)(0);
 | |
|             for(i=0; i<=npoints-1; i++)
 | |
|             {
 | |
|                 v = (double)(0);
 | |
|                 for(j=0; j<=nx-1; j++)
 | |
|                 {
 | |
|                     v = v+ae_sqr(xy->ptr.pp_double[i][j]-cx->ptr.p_double[j], _state);
 | |
|                 }
 | |
|                 v = ae_sqrt(v, _state);
 | |
|                 *rhi = ae_maxreal(*rhi, v, _state);
 | |
|                 *rlo = ae_minreal(*rlo, v, _state);
 | |
|             }
 | |
|             if( !userlo )
 | |
|             {
 | |
|                 *rlo = (double)(0);
 | |
|             }
 | |
|             if( !userhi )
 | |
|             {
 | |
|                 *rhi = (double)(0);
 | |
|             }
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Oooops...!
 | |
|          */
 | |
|         ae_assert(ae_false, "FitSphereX: integrity check failed", _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _fitsphereinternalreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     fitsphereinternalreport *p = (fitsphereinternalreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _fitsphereinternalreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     fitsphereinternalreport *dst = (fitsphereinternalreport*)_dst;
 | |
|     fitsphereinternalreport *src = (fitsphereinternalreport*)_src;
 | |
|     dst->nfev = src->nfev;
 | |
|     dst->iterationscount = src->iterationscount;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _fitsphereinternalreport_clear(void* _p)
 | |
| {
 | |
|     fitsphereinternalreport *p = (fitsphereinternalreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _fitsphereinternalreport_destroy(void* _p)
 | |
| {
 | |
|     fitsphereinternalreport *p = (fitsphereinternalreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_INTFITSERV) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal subroutine: automatic scaling for LLS tasks.
 | |
| NEVER CALL IT DIRECTLY!
 | |
| 
 | |
| Maps abscissas to [-1,1], standartizes ordinates and correspondingly scales
 | |
| constraints. It also scales weights so that max(W[i])=1
 | |
| 
 | |
| Transformations performed:
 | |
| * X, XC         [XA,XB] => [-1,+1]
 | |
|                 transformation makes min(X)=-1, max(X)=+1
 | |
| 
 | |
| * Y             [SA,SB] => [0,1]
 | |
|                 transformation makes mean(Y)=0, stddev(Y)=1
 | |
|                 
 | |
| * YC            transformed accordingly to SA, SB, DC[I]
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 08.09.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitscalexy(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      double* xa,
 | |
|      double* xb,
 | |
|      double* sa,
 | |
|      double* sb,
 | |
|      /* Real    */ ae_vector* xoriginal,
 | |
|      /* Real    */ ae_vector* yoriginal,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double xmin;
 | |
|     double xmax;
 | |
|     ae_int_t i;
 | |
|     double mx;
 | |
| 
 | |
|     *xa = 0;
 | |
|     *xb = 0;
 | |
|     *sa = 0;
 | |
|     *sb = 0;
 | |
|     ae_vector_clear(xoriginal);
 | |
|     ae_vector_clear(yoriginal);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitScaleXY: incorrect N", _state);
 | |
|     ae_assert(k>=0, "LSFitScaleXY: incorrect K", _state);
 | |
|     xmin = x->ptr.p_double[0];
 | |
|     xmax = x->ptr.p_double[0];
 | |
|     for(i=1; i<=n-1; i++)
 | |
|     {
 | |
|         xmin = ae_minreal(xmin, x->ptr.p_double[i], _state);
 | |
|         xmax = ae_maxreal(xmax, x->ptr.p_double[i], _state);
 | |
|     }
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         xmin = ae_minreal(xmin, xc->ptr.p_double[i], _state);
 | |
|         xmax = ae_maxreal(xmax, xc->ptr.p_double[i], _state);
 | |
|     }
 | |
|     if( ae_fp_eq(xmin,xmax) )
 | |
|     {
 | |
|         if( ae_fp_eq(xmin,(double)(0)) )
 | |
|         {
 | |
|             xmin = (double)(-1);
 | |
|             xmax = (double)(1);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if( ae_fp_greater(xmin,(double)(0)) )
 | |
|             {
 | |
|                 xmin = 0.5*xmin;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 xmax = 0.5*xmax;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     ae_vector_set_length(xoriginal, n, _state);
 | |
|     ae_v_move(&xoriginal->ptr.p_double[0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     *xa = xmin;
 | |
|     *xb = xmax;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         x->ptr.p_double[i] = 2*(x->ptr.p_double[i]-0.5*(*xa+(*xb)))/(*xb-(*xa));
 | |
|     }
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         ae_assert(dc->ptr.p_int[i]>=0, "LSFitScaleXY: internal error!", _state);
 | |
|         xc->ptr.p_double[i] = 2*(xc->ptr.p_double[i]-0.5*(*xa+(*xb)))/(*xb-(*xa));
 | |
|         yc->ptr.p_double[i] = yc->ptr.p_double[i]*ae_pow(0.5*(*xb-(*xa)), (double)(dc->ptr.p_int[i]), _state);
 | |
|     }
 | |
|     ae_vector_set_length(yoriginal, n, _state);
 | |
|     ae_v_move(&yoriginal->ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     *sa = (double)(0);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         *sa = *sa+y->ptr.p_double[i];
 | |
|     }
 | |
|     *sa = *sa/n;
 | |
|     *sb = (double)(0);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         *sb = *sb+ae_sqr(y->ptr.p_double[i]-(*sa), _state);
 | |
|     }
 | |
|     *sb = ae_sqrt(*sb/n, _state)+(*sa);
 | |
|     if( ae_fp_eq(*sb,*sa) )
 | |
|     {
 | |
|         *sb = 2*(*sa);
 | |
|     }
 | |
|     if( ae_fp_eq(*sb,*sa) )
 | |
|     {
 | |
|         *sb = *sa+1;
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[i] = (y->ptr.p_double[i]-(*sa))/(*sb-(*sa));
 | |
|     }
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         if( dc->ptr.p_int[i]==0 )
 | |
|         {
 | |
|             yc->ptr.p_double[i] = (yc->ptr.p_double[i]-(*sa))/(*sb-(*sa));
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             yc->ptr.p_double[i] = yc->ptr.p_double[i]/(*sb-(*sa));
 | |
|         }
 | |
|     }
 | |
|     mx = (double)(0);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         mx = ae_maxreal(mx, ae_fabs(w->ptr.p_double[i], _state), _state);
 | |
|     }
 | |
|     if( ae_fp_neq(mx,(double)(0)) )
 | |
|     {
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             w->ptr.p_double[i] = w->ptr.p_double[i]/mx;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void buildpriorterm(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t modeltype,
 | |
|      double priorval,
 | |
|      /* Real    */ ae_matrix* v,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t j0;
 | |
|     ae_int_t j1;
 | |
|     double rj;
 | |
|     ae_matrix araw;
 | |
|     ae_matrix amod;
 | |
|     ae_matrix braw;
 | |
|     ae_vector tmp0;
 | |
|     double lambdareg;
 | |
|     ae_int_t rfsits;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&araw, 0, sizeof(araw));
 | |
|     memset(&amod, 0, sizeof(amod));
 | |
|     memset(&braw, 0, sizeof(braw));
 | |
|     memset(&tmp0, 0, sizeof(tmp0));
 | |
|     ae_matrix_clear(v);
 | |
|     ae_matrix_init(&araw, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&amod, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&braw, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=0, "BuildPriorTerm: N<0", _state);
 | |
|     ae_assert(nx>0, "BuildPriorTerm: NX<=0", _state);
 | |
|     ae_assert(ny>0, "BuildPriorTerm: NY<=0", _state);
 | |
|     ae_matrix_set_length(v, ny, nx+1, _state);
 | |
|     for(i=0; i<=v->rows-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=v->cols-1; j++)
 | |
|         {
 | |
|             v->ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     if( n==0 )
 | |
|     {
 | |
|         if( modeltype==0 )
 | |
|         {
 | |
|             for(i=0; i<=ny-1; i++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][nx] = priorval;
 | |
|             }
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( modeltype==1 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( modeltype==2 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( modeltype==3 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         ae_assert(ae_false, "BuildPriorTerm: unexpected model type", _state);
 | |
|     }
 | |
|     if( modeltype==0 )
 | |
|     {
 | |
|         for(i=0; i<=ny-1; i++)
 | |
|         {
 | |
|             v->ptr.pp_double[i][nx] = priorval;
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 xy->ptr.pp_double[i][nx+j] = xy->ptr.pp_double[i][nx+j]-priorval;
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     if( modeltype==2 )
 | |
|     {
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]+xy->ptr.pp_double[i][nx+j];
 | |
|             }
 | |
|         }
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]/coalesce((double)(n), (double)(1), _state);
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 xy->ptr.pp_double[i][nx+j] = xy->ptr.pp_double[i][nx+j]-v->ptr.pp_double[j][nx];
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     if( modeltype==3 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(modeltype==1, "BuildPriorTerm: unexpected model type", _state);
 | |
|     lambdareg = 0.0;
 | |
|     ae_matrix_set_length(&araw, nx+1, nx+1, _state);
 | |
|     ae_matrix_set_length(&braw, nx+1, ny, _state);
 | |
|     ae_vector_set_length(&tmp0, nx+1, _state);
 | |
|     ae_matrix_set_length(&amod, nx+1, nx+1, _state);
 | |
|     for(i=0; i<=nx; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx; j++)
 | |
|         {
 | |
|             araw.ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             tmp0.ptr.p_double[j] = xy->ptr.pp_double[i][j];
 | |
|         }
 | |
|         tmp0.ptr.p_double[nx] = 1.0;
 | |
|         for(j0=0; j0<=nx; j0++)
 | |
|         {
 | |
|             for(j1=0; j1<=nx; j1++)
 | |
|             {
 | |
|                 araw.ptr.pp_double[j0][j1] = araw.ptr.pp_double[j0][j1]+tmp0.ptr.p_double[j0]*tmp0.ptr.p_double[j1];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     for(rfsits=1; rfsits<=3; rfsits++)
 | |
|     {
 | |
|         for(i=0; i<=nx; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 braw.ptr.pp_double[i][j] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 tmp0.ptr.p_double[j] = xy->ptr.pp_double[i][j];
 | |
|             }
 | |
|             tmp0.ptr.p_double[nx] = 1.0;
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 rj = xy->ptr.pp_double[i][nx+j];
 | |
|                 for(j0=0; j0<=nx; j0++)
 | |
|                 {
 | |
|                     rj = rj-tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0];
 | |
|                 }
 | |
|                 for(j0=0; j0<=nx; j0++)
 | |
|                 {
 | |
|                     braw.ptr.pp_double[j0][j] = braw.ptr.pp_double[j0][j]+rj*tmp0.ptr.p_double[j0];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         for(;;)
 | |
|         {
 | |
|             for(i=0; i<=nx; i++)
 | |
|             {
 | |
|                 for(j=0; j<=nx; j++)
 | |
|                 {
 | |
|                     amod.ptr.pp_double[i][j] = araw.ptr.pp_double[i][j];
 | |
|                 }
 | |
|                 amod.ptr.pp_double[i][i] = amod.ptr.pp_double[i][i]+lambdareg*coalesce(amod.ptr.pp_double[i][i], (double)(1), _state);
 | |
|             }
 | |
|             if( spdmatrixcholesky(&amod, nx+1, ae_true, _state) )
 | |
|             {
 | |
|                 break;
 | |
|             }
 | |
|             lambdareg = coalesce(10*lambdareg, 1.0E-12, _state);
 | |
|         }
 | |
|         rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 1, &braw, 0, 0, _state);
 | |
|         rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 0, &braw, 0, 0, _state);
 | |
|         for(i=0; i<=nx; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[j][i] = v->ptr.pp_double[j][i]+braw.ptr.pp_double[i][j];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             tmp0.ptr.p_double[j] = xy->ptr.pp_double[i][j];
 | |
|         }
 | |
|         tmp0.ptr.p_double[nx] = 1.0;
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             rj = 0.0;
 | |
|             for(j0=0; j0<=nx; j0++)
 | |
|             {
 | |
|                 rj = rj+tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0];
 | |
|             }
 | |
|             xy->ptr.pp_double[i][nx+j] = xy->ptr.pp_double[i][nx+j]-rj;
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| void buildpriorterm1(/* Real    */ ae_vector* xy1,
 | |
|      ae_int_t n,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t modeltype,
 | |
|      double priorval,
 | |
|      /* Real    */ ae_matrix* v,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t j0;
 | |
|     ae_int_t j1;
 | |
|     ae_int_t ew;
 | |
|     double rj;
 | |
|     ae_matrix araw;
 | |
|     ae_matrix amod;
 | |
|     ae_matrix braw;
 | |
|     ae_vector tmp0;
 | |
|     double lambdareg;
 | |
|     ae_int_t rfsits;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&araw, 0, sizeof(araw));
 | |
|     memset(&amod, 0, sizeof(amod));
 | |
|     memset(&braw, 0, sizeof(braw));
 | |
|     memset(&tmp0, 0, sizeof(tmp0));
 | |
|     ae_matrix_clear(v);
 | |
|     ae_matrix_init(&araw, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&amod, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&braw, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=0, "BuildPriorTerm: N<0", _state);
 | |
|     ae_assert(nx>0, "BuildPriorTerm: NX<=0", _state);
 | |
|     ae_assert(ny>0, "BuildPriorTerm: NY<=0", _state);
 | |
|     ew = nx+ny;
 | |
|     ae_matrix_set_length(v, ny, nx+1, _state);
 | |
|     for(i=0; i<=v->rows-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=v->cols-1; j++)
 | |
|         {
 | |
|             v->ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     if( n==0 )
 | |
|     {
 | |
|         if( modeltype==0 )
 | |
|         {
 | |
|             for(i=0; i<=ny-1; i++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][nx] = priorval;
 | |
|             }
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( modeltype==1 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( modeltype==2 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( modeltype==3 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         ae_assert(ae_false, "BuildPriorTerm: unexpected model type", _state);
 | |
|     }
 | |
|     if( modeltype==0 )
 | |
|     {
 | |
|         for(i=0; i<=ny-1; i++)
 | |
|         {
 | |
|             v->ptr.pp_double[i][nx] = priorval;
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 xy1->ptr.p_double[i*ew+nx+j] = xy1->ptr.p_double[i*ew+nx+j]-priorval;
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     if( modeltype==2 )
 | |
|     {
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]+xy1->ptr.p_double[i*ew+nx+j];
 | |
|             }
 | |
|         }
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             v->ptr.pp_double[j][nx] = v->ptr.pp_double[j][nx]/coalesce((double)(n), (double)(1), _state);
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 xy1->ptr.p_double[i*ew+nx+j] = xy1->ptr.p_double[i*ew+nx+j]-v->ptr.pp_double[j][nx];
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     if( modeltype==3 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(modeltype==1, "BuildPriorTerm: unexpected model type", _state);
 | |
|     lambdareg = 0.0;
 | |
|     ae_matrix_set_length(&araw, nx+1, nx+1, _state);
 | |
|     ae_matrix_set_length(&braw, nx+1, ny, _state);
 | |
|     ae_vector_set_length(&tmp0, nx+1, _state);
 | |
|     ae_matrix_set_length(&amod, nx+1, nx+1, _state);
 | |
|     for(i=0; i<=nx; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx; j++)
 | |
|         {
 | |
|             araw.ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             tmp0.ptr.p_double[j] = xy1->ptr.p_double[i*ew+j];
 | |
|         }
 | |
|         tmp0.ptr.p_double[nx] = 1.0;
 | |
|         for(j0=0; j0<=nx; j0++)
 | |
|         {
 | |
|             for(j1=0; j1<=nx; j1++)
 | |
|             {
 | |
|                 araw.ptr.pp_double[j0][j1] = araw.ptr.pp_double[j0][j1]+tmp0.ptr.p_double[j0]*tmp0.ptr.p_double[j1];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     for(rfsits=1; rfsits<=3; rfsits++)
 | |
|     {
 | |
|         for(i=0; i<=nx; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 braw.ptr.pp_double[i][j] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 tmp0.ptr.p_double[j] = xy1->ptr.p_double[i*ew+j];
 | |
|             }
 | |
|             tmp0.ptr.p_double[nx] = 1.0;
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 rj = xy1->ptr.p_double[i*ew+nx+j];
 | |
|                 for(j0=0; j0<=nx; j0++)
 | |
|                 {
 | |
|                     rj = rj-tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0];
 | |
|                 }
 | |
|                 for(j0=0; j0<=nx; j0++)
 | |
|                 {
 | |
|                     braw.ptr.pp_double[j0][j] = braw.ptr.pp_double[j0][j]+rj*tmp0.ptr.p_double[j0];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         for(;;)
 | |
|         {
 | |
|             for(i=0; i<=nx; i++)
 | |
|             {
 | |
|                 for(j=0; j<=nx; j++)
 | |
|                 {
 | |
|                     amod.ptr.pp_double[i][j] = araw.ptr.pp_double[i][j];
 | |
|                 }
 | |
|                 amod.ptr.pp_double[i][i] = amod.ptr.pp_double[i][i]+lambdareg*coalesce(amod.ptr.pp_double[i][i], (double)(1), _state);
 | |
|             }
 | |
|             if( spdmatrixcholesky(&amod, nx+1, ae_true, _state) )
 | |
|             {
 | |
|                 break;
 | |
|             }
 | |
|             lambdareg = coalesce(10*lambdareg, 1.0E-12, _state);
 | |
|         }
 | |
|         rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 1, &braw, 0, 0, _state);
 | |
|         rmatrixlefttrsm(nx+1, ny, &amod, 0, 0, ae_true, ae_false, 0, &braw, 0, 0, _state);
 | |
|         for(i=0; i<=nx; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[j][i] = v->ptr.pp_double[j][i]+braw.ptr.pp_double[i][j];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             tmp0.ptr.p_double[j] = xy1->ptr.p_double[i*ew+j];
 | |
|         }
 | |
|         tmp0.ptr.p_double[nx] = 1.0;
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             rj = 0.0;
 | |
|             for(j0=0; j0<=nx; j0++)
 | |
|             {
 | |
|                 rj = rj+tmp0.ptr.p_double[j0]*v->ptr.pp_double[j][j0];
 | |
|             }
 | |
|             xy1->ptr.p_double[i*ew+nx+j] = xy1->ptr.p_double[i*ew+nx+j]-rj;
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_SPLINE1D) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds linear spline interpolant
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   spline nodes, array[0..N-1]
 | |
|     Y   -   function values, array[0..N-1]
 | |
|     N   -   points count (optional):
 | |
|             * N>=2
 | |
|             * if given, only first N points are used to build spline
 | |
|             * if not given, automatically detected from X/Y sizes
 | |
|               (len(X) must be equal to len(Y))
 | |
|     
 | |
| OUTPUT PARAMETERS:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 24.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildlinear(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      spline1dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     _spline1dinterpolant_clear(c);
 | |
| 
 | |
|     ae_assert(n>1, "Spline1DBuildLinear: N<2!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DBuildLinear: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DBuildLinear: Length(Y)<N!", _state);
 | |
|     
 | |
|     /*
 | |
|      * check and sort points
 | |
|      */
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildLinear: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DBuildLinear: Y contains infinite or NAN values!", _state);
 | |
|     spline1d_heapsortpoints(x, y, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DBuildLinear: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Build
 | |
|      */
 | |
|     c->periodic = ae_false;
 | |
|     c->n = n;
 | |
|     c->k = 3;
 | |
|     c->continuity = 0;
 | |
|     ae_vector_set_length(&c->x, n, _state);
 | |
|     ae_vector_set_length(&c->c, 4*(n-1)+2, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         c->x.ptr.p_double[i] = x->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=n-2; i++)
 | |
|     {
 | |
|         c->c.ptr.p_double[4*i+0] = y->ptr.p_double[i];
 | |
|         c->c.ptr.p_double[4*i+1] = (y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i]);
 | |
|         c->c.ptr.p_double[4*i+2] = (double)(0);
 | |
|         c->c.ptr.p_double[4*i+3] = (double)(0);
 | |
|     }
 | |
|     c->c.ptr.p_double[4*(n-1)+0] = y->ptr.p_double[n-1];
 | |
|     c->c.ptr.p_double[4*(n-1)+1] = c->c.ptr.p_double[4*(n-2)+1];
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds cubic spline interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1].
 | |
|     Y           -   function values, array[0..N-1].
 | |
|     
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildcubic(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t boundltype,
 | |
|      double boundl,
 | |
|      ae_int_t boundrtype,
 | |
|      double boundr,
 | |
|      spline1dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector a1;
 | |
|     ae_vector a2;
 | |
|     ae_vector a3;
 | |
|     ae_vector b;
 | |
|     ae_vector dt;
 | |
|     ae_vector d;
 | |
|     ae_vector p;
 | |
|     ae_int_t ylen;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&a1, 0, sizeof(a1));
 | |
|     memset(&a2, 0, sizeof(a2));
 | |
|     memset(&a3, 0, sizeof(a3));
 | |
|     memset(&b, 0, sizeof(b));
 | |
|     memset(&dt, 0, sizeof(dt));
 | |
|     memset(&d, 0, sizeof(d));
 | |
|     memset(&p, 0, sizeof(p));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     _spline1dinterpolant_clear(c);
 | |
|     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * check correctness of boundary conditions
 | |
|      */
 | |
|     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DBuildCubic: incorrect BoundLType!", _state);
 | |
|     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DBuildCubic: incorrect BoundRType!", _state);
 | |
|     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DBuildCubic: incorrect BoundLType/BoundRType!", _state);
 | |
|     if( boundltype==1||boundltype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundl, _state), "Spline1DBuildCubic: BoundL is infinite or NAN!", _state);
 | |
|     }
 | |
|     if( boundrtype==1||boundrtype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundr, _state), "Spline1DBuildCubic: BoundR is infinite or NAN!", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * check lengths of arguments
 | |
|      */
 | |
|     ae_assert(n>=2, "Spline1DBuildCubic: N<2!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DBuildCubic: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DBuildCubic: Length(Y)<N!", _state);
 | |
|     
 | |
|     /*
 | |
|      * check and sort points
 | |
|      */
 | |
|     ylen = n;
 | |
|     if( boundltype==-1 )
 | |
|     {
 | |
|         ylen = n-1;
 | |
|     }
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildCubic: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, ylen, _state), "Spline1DBuildCubic: Y contains infinite or NAN values!", _state);
 | |
|     spline1d_heapsortppoints(x, y, &p, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DBuildCubic: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Now we've checked and preordered everything,
 | |
|      * so we can call internal function to calculate derivatives,
 | |
|      * and then build Hermite spline using these derivatives
 | |
|      */
 | |
|     if( boundltype==-1||boundrtype==-1 )
 | |
|     {
 | |
|         y->ptr.p_double[n-1] = y->ptr.p_double[0];
 | |
|     }
 | |
|     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state);
 | |
|     spline1dbuildhermite(x, y, &d, n, c, _state);
 | |
|     c->periodic = boundltype==-1||boundrtype==-1;
 | |
|     c->continuity = 2;
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at nodes x[], it calculates and returns table of function derivatives  d[]
 | |
| (calculated at the same nodes x[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes
 | |
|     Y           -   function values
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     D           -   derivative values at X[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| Derivative values are correctly reordered on return, so  D[I]  is  always
 | |
| equal to S'(X[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dgriddiffcubic(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t boundltype,
 | |
|      double boundl,
 | |
|      ae_int_t boundrtype,
 | |
|      double boundr,
 | |
|      /* Real    */ ae_vector* d,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector a1;
 | |
|     ae_vector a2;
 | |
|     ae_vector a3;
 | |
|     ae_vector b;
 | |
|     ae_vector dt;
 | |
|     ae_vector p;
 | |
|     ae_int_t i;
 | |
|     ae_int_t ylen;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&a1, 0, sizeof(a1));
 | |
|     memset(&a2, 0, sizeof(a2));
 | |
|     memset(&a3, 0, sizeof(a3));
 | |
|     memset(&b, 0, sizeof(b));
 | |
|     memset(&dt, 0, sizeof(dt));
 | |
|     memset(&p, 0, sizeof(p));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_clear(d);
 | |
|     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * check correctness of boundary conditions
 | |
|      */
 | |
|     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DGridDiffCubic: incorrect BoundLType!", _state);
 | |
|     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DGridDiffCubic: incorrect BoundRType!", _state);
 | |
|     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DGridDiffCubic: incorrect BoundLType/BoundRType!", _state);
 | |
|     if( boundltype==1||boundltype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundl, _state), "Spline1DGridDiffCubic: BoundL is infinite or NAN!", _state);
 | |
|     }
 | |
|     if( boundrtype==1||boundrtype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundr, _state), "Spline1DGridDiffCubic: BoundR is infinite or NAN!", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * check lengths of arguments
 | |
|      */
 | |
|     ae_assert(n>=2, "Spline1DGridDiffCubic: N<2!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DGridDiffCubic: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DGridDiffCubic: Length(Y)<N!", _state);
 | |
|     
 | |
|     /*
 | |
|      * check and sort points
 | |
|      */
 | |
|     ylen = n;
 | |
|     if( boundltype==-1 )
 | |
|     {
 | |
|         ylen = n-1;
 | |
|     }
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DGridDiffCubic: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, ylen, _state), "Spline1DGridDiffCubic: Y contains infinite or NAN values!", _state);
 | |
|     spline1d_heapsortppoints(x, y, &p, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DGridDiffCubic: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Now we've checked and preordered everything,
 | |
|      * so we can call internal function.
 | |
|      */
 | |
|     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, d, &a1, &a2, &a3, &b, &dt, _state);
 | |
|     
 | |
|     /*
 | |
|      * Remember that HeapSortPPoints() call?
 | |
|      * Now we have to reorder them back.
 | |
|      */
 | |
|     if( dt.cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(&dt, n, _state);
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         dt.ptr.p_double[p.ptr.p_int[i]] = d->ptr.p_double[i];
 | |
|     }
 | |
|     ae_v_move(&d->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at  nodes  x[],  it  calculates  and  returns  tables  of first and second
 | |
| function derivatives d1[] and d2[] (calculated at the same nodes x[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes
 | |
|     Y           -   function values
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     D1          -   S' values at X[]
 | |
|     D2          -   S'' values at X[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| Derivative values are correctly reordered on return, so  D[I]  is  always
 | |
| equal to S'(X[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dgriddiff2cubic(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t boundltype,
 | |
|      double boundl,
 | |
|      ae_int_t boundrtype,
 | |
|      double boundr,
 | |
|      /* Real    */ ae_vector* d1,
 | |
|      /* Real    */ ae_vector* d2,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector a1;
 | |
|     ae_vector a2;
 | |
|     ae_vector a3;
 | |
|     ae_vector b;
 | |
|     ae_vector dt;
 | |
|     ae_vector p;
 | |
|     ae_int_t i;
 | |
|     ae_int_t ylen;
 | |
|     double delta;
 | |
|     double delta2;
 | |
|     double delta3;
 | |
|     double s2;
 | |
|     double s3;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&a1, 0, sizeof(a1));
 | |
|     memset(&a2, 0, sizeof(a2));
 | |
|     memset(&a3, 0, sizeof(a3));
 | |
|     memset(&b, 0, sizeof(b));
 | |
|     memset(&dt, 0, sizeof(dt));
 | |
|     memset(&p, 0, sizeof(p));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_clear(d1);
 | |
|     ae_vector_clear(d2);
 | |
|     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * check correctness of boundary conditions
 | |
|      */
 | |
|     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DGridDiff2Cubic: incorrect BoundLType!", _state);
 | |
|     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DGridDiff2Cubic: incorrect BoundRType!", _state);
 | |
|     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DGridDiff2Cubic: incorrect BoundLType/BoundRType!", _state);
 | |
|     if( boundltype==1||boundltype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundl, _state), "Spline1DGridDiff2Cubic: BoundL is infinite or NAN!", _state);
 | |
|     }
 | |
|     if( boundrtype==1||boundrtype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundr, _state), "Spline1DGridDiff2Cubic: BoundR is infinite or NAN!", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * check lengths of arguments
 | |
|      */
 | |
|     ae_assert(n>=2, "Spline1DGridDiff2Cubic: N<2!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DGridDiff2Cubic: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DGridDiff2Cubic: Length(Y)<N!", _state);
 | |
|     
 | |
|     /*
 | |
|      * check and sort points
 | |
|      */
 | |
|     ylen = n;
 | |
|     if( boundltype==-1 )
 | |
|     {
 | |
|         ylen = n-1;
 | |
|     }
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DGridDiff2Cubic: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, ylen, _state), "Spline1DGridDiff2Cubic: Y contains infinite or NAN values!", _state);
 | |
|     spline1d_heapsortppoints(x, y, &p, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DGridDiff2Cubic: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Now we've checked and preordered everything,
 | |
|      * so we can call internal function.
 | |
|      *
 | |
|      * After this call we will calculate second derivatives
 | |
|      * (manually, by converting to the power basis)
 | |
|      */
 | |
|     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, d1, &a1, &a2, &a3, &b, &dt, _state);
 | |
|     ae_vector_set_length(d2, n, _state);
 | |
|     delta = (double)(0);
 | |
|     s2 = (double)(0);
 | |
|     s3 = (double)(0);
 | |
|     for(i=0; i<=n-2; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * We convert from Hermite basis to the power basis.
 | |
|          * Si is coefficient before x^i.
 | |
|          *
 | |
|          * Inside this cycle we need just S2,
 | |
|          * because we calculate S'' exactly at spline node,
 | |
|          * (only x^2 matters at x=0), but after iterations
 | |
|          * will be over, we will need other coefficients
 | |
|          * to calculate spline value at the last node.
 | |
|          */
 | |
|         delta = x->ptr.p_double[i+1]-x->ptr.p_double[i];
 | |
|         delta2 = ae_sqr(delta, _state);
 | |
|         delta3 = delta*delta2;
 | |
|         s2 = (3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])-2*d1->ptr.p_double[i]*delta-d1->ptr.p_double[i+1]*delta)/delta2;
 | |
|         s3 = (2*(y->ptr.p_double[i]-y->ptr.p_double[i+1])+d1->ptr.p_double[i]*delta+d1->ptr.p_double[i+1]*delta)/delta3;
 | |
|         d2->ptr.p_double[i] = 2*s2;
 | |
|     }
 | |
|     d2->ptr.p_double[n-1] = 2*s2+6*s3*delta;
 | |
|     
 | |
|     /*
 | |
|      * Remember that HeapSortPPoints() call?
 | |
|      * Now we have to reorder them back.
 | |
|      */
 | |
|     if( dt.cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(&dt, n, _state);
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         dt.ptr.p_double[p.ptr.p_int[i]] = d1->ptr.p_double[i];
 | |
|     }
 | |
|     ae_v_move(&d1->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         dt.ptr.p_double[p.ptr.p_int[i]] = d2->ptr.p_double[i];
 | |
|     }
 | |
|     ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
 | |
| function values y2[] (calculated at x2[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   old spline nodes
 | |
|     Y           -   function values
 | |
|     X2           -  new spline nodes
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points from X/Y are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
|     N2          -   new points count:
 | |
|                     * N2>=2
 | |
|                     * if given, only first N2 points from X2 are used
 | |
|                     * if not given, automatically detected from X2 size
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F2          -   function values at X2[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller  may pass unsorted array.
 | |
| Function  values  are correctly reordered on  return, so F2[I]  is  always
 | |
| equal to S(X2[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dconvcubic(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t boundltype,
 | |
|      double boundl,
 | |
|      ae_int_t boundrtype,
 | |
|      double boundr,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      ae_int_t n2,
 | |
|      /* Real    */ ae_vector* y2,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector _x2;
 | |
|     ae_vector a1;
 | |
|     ae_vector a2;
 | |
|     ae_vector a3;
 | |
|     ae_vector b;
 | |
|     ae_vector d;
 | |
|     ae_vector dt;
 | |
|     ae_vector d1;
 | |
|     ae_vector d2;
 | |
|     ae_vector p;
 | |
|     ae_vector p2;
 | |
|     ae_int_t i;
 | |
|     ae_int_t ylen;
 | |
|     double t;
 | |
|     double t2;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&_x2, 0, sizeof(_x2));
 | |
|     memset(&a1, 0, sizeof(a1));
 | |
|     memset(&a2, 0, sizeof(a2));
 | |
|     memset(&a3, 0, sizeof(a3));
 | |
|     memset(&b, 0, sizeof(b));
 | |
|     memset(&d, 0, sizeof(d));
 | |
|     memset(&dt, 0, sizeof(dt));
 | |
|     memset(&d1, 0, sizeof(d1));
 | |
|     memset(&d2, 0, sizeof(d2));
 | |
|     memset(&p, 0, sizeof(p));
 | |
|     memset(&p2, 0, sizeof(p2));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_init_copy(&_x2, x2, _state, ae_true);
 | |
|     x2 = &_x2;
 | |
|     ae_vector_clear(y2);
 | |
|     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&d1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&d2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * check correctness of boundary conditions
 | |
|      */
 | |
|     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvCubic: incorrect BoundLType!", _state);
 | |
|     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvCubic: incorrect BoundRType!", _state);
 | |
|     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvCubic: incorrect BoundLType/BoundRType!", _state);
 | |
|     if( boundltype==1||boundltype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundl, _state), "Spline1DConvCubic: BoundL is infinite or NAN!", _state);
 | |
|     }
 | |
|     if( boundrtype==1||boundrtype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundr, _state), "Spline1DConvCubic: BoundR is infinite or NAN!", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * check lengths of arguments
 | |
|      */
 | |
|     ae_assert(n>=2, "Spline1DConvCubic: N<2!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DConvCubic: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DConvCubic: Length(Y)<N!", _state);
 | |
|     ae_assert(n2>=2, "Spline1DConvCubic: N2<2!", _state);
 | |
|     ae_assert(x2->cnt>=n2, "Spline1DConvCubic: Length(X2)<N2!", _state);
 | |
|     
 | |
|     /*
 | |
|      * check and sort X/Y
 | |
|      */
 | |
|     ylen = n;
 | |
|     if( boundltype==-1 )
 | |
|     {
 | |
|         ylen = n-1;
 | |
|     }
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DConvCubic: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, ylen, _state), "Spline1DConvCubic: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(x2, n2, _state), "Spline1DConvCubic: X2 contains infinite or NAN values!", _state);
 | |
|     spline1d_heapsortppoints(x, y, &p, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DConvCubic: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * set up DT (we will need it below)
 | |
|      */
 | |
|     ae_vector_set_length(&dt, ae_maxint(n, n2, _state), _state);
 | |
|     
 | |
|     /*
 | |
|      * sort X2:
 | |
|      * * use fake array DT because HeapSortPPoints() needs both integer AND real arrays
 | |
|      * * if we have periodic problem, wrap points
 | |
|      * * sort them, store permutation at P2
 | |
|      */
 | |
|     if( boundrtype==-1&&boundltype==-1 )
 | |
|     {
 | |
|         for(i=0; i<=n2-1; i++)
 | |
|         {
 | |
|             t = x2->ptr.p_double[i];
 | |
|             apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state);
 | |
|             x2->ptr.p_double[i] = t;
 | |
|         }
 | |
|     }
 | |
|     spline1d_heapsortppoints(x2, &dt, &p2, n2, _state);
 | |
|     
 | |
|     /*
 | |
|      * Now we've checked and preordered everything, so we:
 | |
|      * * call internal GridDiff() function to get Hermite form of spline
 | |
|      * * convert using internal Conv() function
 | |
|      * * convert Y2 back to original order
 | |
|      */
 | |
|     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state);
 | |
|     spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, &d1, ae_false, &d2, ae_false, _state);
 | |
|     ae_assert(dt.cnt>=n2, "Spline1DConvCubic: internal error!", _state);
 | |
|     for(i=0; i<=n2-1; i++)
 | |
|     {
 | |
|         dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i];
 | |
|     }
 | |
|     ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
 | |
| function values y2[] and derivatives d2[] (calculated at x2[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   old spline nodes
 | |
|     Y           -   function values
 | |
|     X2           -  new spline nodes
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points from X/Y are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
|     N2          -   new points count:
 | |
|                     * N2>=2
 | |
|                     * if given, only first N2 points from X2 are used
 | |
|                     * if not given, automatically detected from X2 size
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F2          -   function values at X2[]
 | |
|     D2          -   first derivatives at X2[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller  may pass unsorted array.
 | |
| Function  values  are correctly reordered on  return, so F2[I]  is  always
 | |
| equal to S(X2[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dconvdiffcubic(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t boundltype,
 | |
|      double boundl,
 | |
|      ae_int_t boundrtype,
 | |
|      double boundr,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      ae_int_t n2,
 | |
|      /* Real    */ ae_vector* y2,
 | |
|      /* Real    */ ae_vector* d2,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector _x2;
 | |
|     ae_vector a1;
 | |
|     ae_vector a2;
 | |
|     ae_vector a3;
 | |
|     ae_vector b;
 | |
|     ae_vector d;
 | |
|     ae_vector dt;
 | |
|     ae_vector rt1;
 | |
|     ae_vector p;
 | |
|     ae_vector p2;
 | |
|     ae_int_t i;
 | |
|     ae_int_t ylen;
 | |
|     double t;
 | |
|     double t2;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&_x2, 0, sizeof(_x2));
 | |
|     memset(&a1, 0, sizeof(a1));
 | |
|     memset(&a2, 0, sizeof(a2));
 | |
|     memset(&a3, 0, sizeof(a3));
 | |
|     memset(&b, 0, sizeof(b));
 | |
|     memset(&d, 0, sizeof(d));
 | |
|     memset(&dt, 0, sizeof(dt));
 | |
|     memset(&rt1, 0, sizeof(rt1));
 | |
|     memset(&p, 0, sizeof(p));
 | |
|     memset(&p2, 0, sizeof(p2));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_init_copy(&_x2, x2, _state, ae_true);
 | |
|     x2 = &_x2;
 | |
|     ae_vector_clear(y2);
 | |
|     ae_vector_clear(d2);
 | |
|     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&rt1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * check correctness of boundary conditions
 | |
|      */
 | |
|     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvDiffCubic: incorrect BoundLType!", _state);
 | |
|     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvDiffCubic: incorrect BoundRType!", _state);
 | |
|     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvDiffCubic: incorrect BoundLType/BoundRType!", _state);
 | |
|     if( boundltype==1||boundltype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundl, _state), "Spline1DConvDiffCubic: BoundL is infinite or NAN!", _state);
 | |
|     }
 | |
|     if( boundrtype==1||boundrtype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundr, _state), "Spline1DConvDiffCubic: BoundR is infinite or NAN!", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * check lengths of arguments
 | |
|      */
 | |
|     ae_assert(n>=2, "Spline1DConvDiffCubic: N<2!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DConvDiffCubic: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DConvDiffCubic: Length(Y)<N!", _state);
 | |
|     ae_assert(n2>=2, "Spline1DConvDiffCubic: N2<2!", _state);
 | |
|     ae_assert(x2->cnt>=n2, "Spline1DConvDiffCubic: Length(X2)<N2!", _state);
 | |
|     
 | |
|     /*
 | |
|      * check and sort X/Y
 | |
|      */
 | |
|     ylen = n;
 | |
|     if( boundltype==-1 )
 | |
|     {
 | |
|         ylen = n-1;
 | |
|     }
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DConvDiffCubic: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, ylen, _state), "Spline1DConvDiffCubic: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(x2, n2, _state), "Spline1DConvDiffCubic: X2 contains infinite or NAN values!", _state);
 | |
|     spline1d_heapsortppoints(x, y, &p, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DConvDiffCubic: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * set up DT (we will need it below)
 | |
|      */
 | |
|     ae_vector_set_length(&dt, ae_maxint(n, n2, _state), _state);
 | |
|     
 | |
|     /*
 | |
|      * sort X2:
 | |
|      * * use fake array DT because HeapSortPPoints() needs both integer AND real arrays
 | |
|      * * if we have periodic problem, wrap points
 | |
|      * * sort them, store permutation at P2
 | |
|      */
 | |
|     if( boundrtype==-1&&boundltype==-1 )
 | |
|     {
 | |
|         for(i=0; i<=n2-1; i++)
 | |
|         {
 | |
|             t = x2->ptr.p_double[i];
 | |
|             apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state);
 | |
|             x2->ptr.p_double[i] = t;
 | |
|         }
 | |
|     }
 | |
|     spline1d_heapsortppoints(x2, &dt, &p2, n2, _state);
 | |
|     
 | |
|     /*
 | |
|      * Now we've checked and preordered everything, so we:
 | |
|      * * call internal GridDiff() function to get Hermite form of spline
 | |
|      * * convert using internal Conv() function
 | |
|      * * convert Y2 back to original order
 | |
|      */
 | |
|     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state);
 | |
|     spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, d2, ae_true, &rt1, ae_false, _state);
 | |
|     ae_assert(dt.cnt>=n2, "Spline1DConvDiffCubic: internal error!", _state);
 | |
|     for(i=0; i<=n2-1; i++)
 | |
|     {
 | |
|         dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i];
 | |
|     }
 | |
|     ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
 | |
|     for(i=0; i<=n2-1; i++)
 | |
|     {
 | |
|         dt.ptr.p_double[p2.ptr.p_int[i]] = d2->ptr.p_double[i];
 | |
|     }
 | |
|     ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function solves following problem: given table y[] of function values
 | |
| at old nodes x[]  and new nodes  x2[],  it calculates and returns table of
 | |
| function  values  y2[],  first  and  second  derivatives  d2[]  and  dd2[]
 | |
| (calculated at x2[]).
 | |
| 
 | |
| This function yields same result as Spline1DBuildCubic() call followed  by
 | |
| sequence of Spline1DDiff() calls, but it can be several times faster  when
 | |
| called for ordered X[] and X2[].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   old spline nodes
 | |
|     Y           -   function values
 | |
|     X2           -  new spline nodes
 | |
| 
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points from X/Y are used
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundLType  -   boundary condition type for the left boundary
 | |
|     BoundL      -   left boundary condition (first or second derivative,
 | |
|                     depending on the BoundLType)
 | |
|     BoundRType  -   boundary condition type for the right boundary
 | |
|     BoundR      -   right boundary condition (first or second derivative,
 | |
|                     depending on the BoundRType)
 | |
|     N2          -   new points count:
 | |
|                     * N2>=2
 | |
|                     * if given, only first N2 points from X2 are used
 | |
|                     * if not given, automatically detected from X2 size
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F2          -   function values at X2[]
 | |
|     D2          -   first derivatives at X2[]
 | |
|     DD2         -   second derivatives at X2[]
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller  may pass unsorted array.
 | |
| Function  values  are correctly reordered on  return, so F2[I]  is  always
 | |
| equal to S(X2[I]) independently of points order.
 | |
| 
 | |
| SETTING BOUNDARY VALUES:
 | |
| 
 | |
| The BoundLType/BoundRType parameters can have the following values:
 | |
|     * -1, which corresonds to the periodic (cyclic) boundary conditions.
 | |
|           In this case:
 | |
|           * both BoundLType and BoundRType must be equal to -1.
 | |
|           * BoundL/BoundR are ignored
 | |
|           * Y[last] is ignored (it is assumed to be equal to Y[first]).
 | |
|     *  0, which  corresponds  to  the  parabolically   terminated  spline
 | |
|           (BoundL and/or BoundR are ignored).
 | |
|     *  1, which corresponds to the first derivative boundary condition
 | |
|     *  2, which corresponds to the second derivative boundary condition
 | |
|     *  by default, BoundType=0 is used
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dconvdiff2cubic(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t boundltype,
 | |
|      double boundl,
 | |
|      ae_int_t boundrtype,
 | |
|      double boundr,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      ae_int_t n2,
 | |
|      /* Real    */ ae_vector* y2,
 | |
|      /* Real    */ ae_vector* d2,
 | |
|      /* Real    */ ae_vector* dd2,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector _x2;
 | |
|     ae_vector a1;
 | |
|     ae_vector a2;
 | |
|     ae_vector a3;
 | |
|     ae_vector b;
 | |
|     ae_vector d;
 | |
|     ae_vector dt;
 | |
|     ae_vector p;
 | |
|     ae_vector p2;
 | |
|     ae_int_t i;
 | |
|     ae_int_t ylen;
 | |
|     double t;
 | |
|     double t2;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&_x2, 0, sizeof(_x2));
 | |
|     memset(&a1, 0, sizeof(a1));
 | |
|     memset(&a2, 0, sizeof(a2));
 | |
|     memset(&a3, 0, sizeof(a3));
 | |
|     memset(&b, 0, sizeof(b));
 | |
|     memset(&d, 0, sizeof(d));
 | |
|     memset(&dt, 0, sizeof(dt));
 | |
|     memset(&p, 0, sizeof(p));
 | |
|     memset(&p2, 0, sizeof(p2));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_init_copy(&_x2, x2, _state, ae_true);
 | |
|     x2 = &_x2;
 | |
|     ae_vector_clear(y2);
 | |
|     ae_vector_clear(d2);
 | |
|     ae_vector_clear(dd2);
 | |
|     ae_vector_init(&a1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&a3, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dt, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * check correctness of boundary conditions
 | |
|      */
 | |
|     ae_assert(((boundltype==-1||boundltype==0)||boundltype==1)||boundltype==2, "Spline1DConvDiff2Cubic: incorrect BoundLType!", _state);
 | |
|     ae_assert(((boundrtype==-1||boundrtype==0)||boundrtype==1)||boundrtype==2, "Spline1DConvDiff2Cubic: incorrect BoundRType!", _state);
 | |
|     ae_assert((boundrtype==-1&&boundltype==-1)||(boundrtype!=-1&&boundltype!=-1), "Spline1DConvDiff2Cubic: incorrect BoundLType/BoundRType!", _state);
 | |
|     if( boundltype==1||boundltype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundl, _state), "Spline1DConvDiff2Cubic: BoundL is infinite or NAN!", _state);
 | |
|     }
 | |
|     if( boundrtype==1||boundrtype==2 )
 | |
|     {
 | |
|         ae_assert(ae_isfinite(boundr, _state), "Spline1DConvDiff2Cubic: BoundR is infinite or NAN!", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * check lengths of arguments
 | |
|      */
 | |
|     ae_assert(n>=2, "Spline1DConvDiff2Cubic: N<2!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DConvDiff2Cubic: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DConvDiff2Cubic: Length(Y)<N!", _state);
 | |
|     ae_assert(n2>=2, "Spline1DConvDiff2Cubic: N2<2!", _state);
 | |
|     ae_assert(x2->cnt>=n2, "Spline1DConvDiff2Cubic: Length(X2)<N2!", _state);
 | |
|     
 | |
|     /*
 | |
|      * check and sort X/Y
 | |
|      */
 | |
|     ylen = n;
 | |
|     if( boundltype==-1 )
 | |
|     {
 | |
|         ylen = n-1;
 | |
|     }
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DConvDiff2Cubic: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, ylen, _state), "Spline1DConvDiff2Cubic: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(x2, n2, _state), "Spline1DConvDiff2Cubic: X2 contains infinite or NAN values!", _state);
 | |
|     spline1d_heapsortppoints(x, y, &p, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DConvDiff2Cubic: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * set up DT (we will need it below)
 | |
|      */
 | |
|     ae_vector_set_length(&dt, ae_maxint(n, n2, _state), _state);
 | |
|     
 | |
|     /*
 | |
|      * sort X2:
 | |
|      * * use fake array DT because HeapSortPPoints() needs both integer AND real arrays
 | |
|      * * if we have periodic problem, wrap points
 | |
|      * * sort them, store permutation at P2
 | |
|      */
 | |
|     if( boundrtype==-1&&boundltype==-1 )
 | |
|     {
 | |
|         for(i=0; i<=n2-1; i++)
 | |
|         {
 | |
|             t = x2->ptr.p_double[i];
 | |
|             apperiodicmap(&t, x->ptr.p_double[0], x->ptr.p_double[n-1], &t2, _state);
 | |
|             x2->ptr.p_double[i] = t;
 | |
|         }
 | |
|     }
 | |
|     spline1d_heapsortppoints(x2, &dt, &p2, n2, _state);
 | |
|     
 | |
|     /*
 | |
|      * Now we've checked and preordered everything, so we:
 | |
|      * * call internal GridDiff() function to get Hermite form of spline
 | |
|      * * convert using internal Conv() function
 | |
|      * * convert Y2 back to original order
 | |
|      */
 | |
|     spline1d_spline1dgriddiffcubicinternal(x, y, n, boundltype, boundl, boundrtype, boundr, &d, &a1, &a2, &a3, &b, &dt, _state);
 | |
|     spline1dconvdiffinternal(x, y, &d, n, x2, n2, y2, ae_true, d2, ae_true, dd2, ae_true, _state);
 | |
|     ae_assert(dt.cnt>=n2, "Spline1DConvDiff2Cubic: internal error!", _state);
 | |
|     for(i=0; i<=n2-1; i++)
 | |
|     {
 | |
|         dt.ptr.p_double[p2.ptr.p_int[i]] = y2->ptr.p_double[i];
 | |
|     }
 | |
|     ae_v_move(&y2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
 | |
|     for(i=0; i<=n2-1; i++)
 | |
|     {
 | |
|         dt.ptr.p_double[p2.ptr.p_int[i]] = d2->ptr.p_double[i];
 | |
|     }
 | |
|     ae_v_move(&d2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
 | |
|     for(i=0; i<=n2-1; i++)
 | |
|     {
 | |
|         dt.ptr.p_double[p2.ptr.p_int[i]] = dd2->ptr.p_double[i];
 | |
|     }
 | |
|     ae_v_move(&dd2->ptr.p_double[0], 1, &dt.ptr.p_double[0], 1, ae_v_len(0,n2-1));
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds Catmull-Rom spline interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1].
 | |
|     Y           -   function values, array[0..N-1].
 | |
|     
 | |
| OPTIONAL PARAMETERS:
 | |
|     N           -   points count:
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
|     BoundType   -   boundary condition type:
 | |
|                     * -1 for periodic boundary condition
 | |
|                     *  0 for parabolically terminated spline (default)
 | |
|     Tension     -   tension parameter:
 | |
|                     * tension=0   corresponds to classic Catmull-Rom spline (default)
 | |
|                     * 0<tension<1 corresponds to more general form - cardinal spline
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| PROBLEMS WITH PERIODIC BOUNDARY CONDITIONS:
 | |
| 
 | |
| Problems with periodic boundary conditions have Y[first_point]=Y[last_point].
 | |
| However, this subroutine doesn't require you to specify equal  values  for
 | |
| the first and last points - it automatically forces them  to  be  equal by
 | |
| copying  Y[first_point]  (corresponds  to the leftmost,  minimal  X[])  to
 | |
| Y[last_point]. However it is recommended to pass consistent values of Y[],
 | |
| i.e. to make Y[first_point]=Y[last_point].
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildcatmullrom(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t boundtype,
 | |
|      double tension,
 | |
|      spline1dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector d;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&d, 0, sizeof(d));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     _spline1dinterpolant_clear(c);
 | |
|     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=2, "Spline1DBuildCatmullRom: N<2!", _state);
 | |
|     ae_assert(boundtype==-1||boundtype==0, "Spline1DBuildCatmullRom: incorrect BoundType!", _state);
 | |
|     ae_assert(ae_fp_greater_eq(tension,(double)(0)), "Spline1DBuildCatmullRom: Tension<0!", _state);
 | |
|     ae_assert(ae_fp_less_eq(tension,(double)(1)), "Spline1DBuildCatmullRom: Tension>1!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DBuildCatmullRom: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DBuildCatmullRom: Length(Y)<N!", _state);
 | |
|     
 | |
|     /*
 | |
|      * check and sort points
 | |
|      */
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildCatmullRom: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DBuildCatmullRom: Y contains infinite or NAN values!", _state);
 | |
|     spline1d_heapsortpoints(x, y, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DBuildCatmullRom: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Special cases:
 | |
|      * * N=2, parabolic terminated boundary condition on both ends
 | |
|      * * N=2, periodic boundary condition
 | |
|      */
 | |
|     if( n==2&&boundtype==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Just linear spline
 | |
|          */
 | |
|         spline1dbuildlinear(x, y, n, c, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     if( n==2&&boundtype==-1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Same as cubic spline with periodic conditions
 | |
|          */
 | |
|         spline1dbuildcubic(x, y, n, -1, 0.0, -1, 0.0, c, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Periodic or non-periodic boundary conditions
 | |
|      */
 | |
|     if( boundtype==-1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Periodic boundary conditions
 | |
|          */
 | |
|         y->ptr.p_double[n-1] = y->ptr.p_double[0];
 | |
|         ae_vector_set_length(&d, n, _state);
 | |
|         d.ptr.p_double[0] = (y->ptr.p_double[1]-y->ptr.p_double[n-2])/(2*(x->ptr.p_double[1]-x->ptr.p_double[0]+x->ptr.p_double[n-1]-x->ptr.p_double[n-2]));
 | |
|         for(i=1; i<=n-2; i++)
 | |
|         {
 | |
|             d.ptr.p_double[i] = (1-tension)*(y->ptr.p_double[i+1]-y->ptr.p_double[i-1])/(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]);
 | |
|         }
 | |
|         d.ptr.p_double[n-1] = d.ptr.p_double[0];
 | |
|         
 | |
|         /*
 | |
|          * Now problem is reduced to the cubic Hermite spline
 | |
|          */
 | |
|         spline1dbuildhermite(x, y, &d, n, c, _state);
 | |
|         c->periodic = ae_true;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Non-periodic boundary conditions
 | |
|          */
 | |
|         ae_vector_set_length(&d, n, _state);
 | |
|         for(i=1; i<=n-2; i++)
 | |
|         {
 | |
|             d.ptr.p_double[i] = (1-tension)*(y->ptr.p_double[i+1]-y->ptr.p_double[i-1])/(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]);
 | |
|         }
 | |
|         d.ptr.p_double[0] = 2*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])-d.ptr.p_double[1];
 | |
|         d.ptr.p_double[n-1] = 2*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])-d.ptr.p_double[n-2];
 | |
|         
 | |
|         /*
 | |
|          * Now problem is reduced to the cubic Hermite spline
 | |
|          */
 | |
|         spline1dbuildhermite(x, y, &d, n, c, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds Hermite spline interpolant.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1]
 | |
|     Y           -   function values, array[0..N-1]
 | |
|     D           -   derivatives, array[0..N-1]
 | |
|     N           -   points count (optional):
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant.
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildhermite(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* d,
 | |
|      ae_int_t n,
 | |
|      spline1dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector _d;
 | |
|     ae_int_t i;
 | |
|     double delta;
 | |
|     double delta2;
 | |
|     double delta3;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&_d, 0, sizeof(_d));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_init_copy(&_d, d, _state, ae_true);
 | |
|     d = &_d;
 | |
|     _spline1dinterpolant_clear(c);
 | |
| 
 | |
|     ae_assert(n>=2, "Spline1DBuildHermite: N<2!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DBuildHermite: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DBuildHermite: Length(Y)<N!", _state);
 | |
|     ae_assert(d->cnt>=n, "Spline1DBuildHermite: Length(D)<N!", _state);
 | |
|     
 | |
|     /*
 | |
|      * check and sort points
 | |
|      */
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildHermite: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DBuildHermite: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(d, n, _state), "Spline1DBuildHermite: D contains infinite or NAN values!", _state);
 | |
|     heapsortdpoints(x, y, d, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DBuildHermite: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Build
 | |
|      */
 | |
|     ae_vector_set_length(&c->x, n, _state);
 | |
|     ae_vector_set_length(&c->c, 4*(n-1)+2, _state);
 | |
|     c->periodic = ae_false;
 | |
|     c->k = 3;
 | |
|     c->n = n;
 | |
|     c->continuity = 1;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         c->x.ptr.p_double[i] = x->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=n-2; i++)
 | |
|     {
 | |
|         delta = x->ptr.p_double[i+1]-x->ptr.p_double[i];
 | |
|         delta2 = ae_sqr(delta, _state);
 | |
|         delta3 = delta*delta2;
 | |
|         c->c.ptr.p_double[4*i+0] = y->ptr.p_double[i];
 | |
|         c->c.ptr.p_double[4*i+1] = d->ptr.p_double[i];
 | |
|         c->c.ptr.p_double[4*i+2] = (3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])-2*d->ptr.p_double[i]*delta-d->ptr.p_double[i+1]*delta)/delta2;
 | |
|         c->c.ptr.p_double[4*i+3] = (2*(y->ptr.p_double[i]-y->ptr.p_double[i+1])+d->ptr.p_double[i]*delta+d->ptr.p_double[i+1]*delta)/delta3;
 | |
|     }
 | |
|     c->c.ptr.p_double[4*(n-1)+0] = y->ptr.p_double[n-1];
 | |
|     c->c.ptr.p_double[4*(n-1)+1] = d->ptr.p_double[n-1];
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds Akima spline interpolant
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1]
 | |
|     Y           -   function values, array[0..N-1]
 | |
|     N           -   points count (optional):
 | |
|                     * N>=2
 | |
|                     * if given, only first N points are used to build spline
 | |
|                     * if not given, automatically detected from X/Y sizes
 | |
|                       (len(X) must be equal to len(Y))
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 24.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildakima(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      spline1dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_int_t i;
 | |
|     ae_vector d;
 | |
|     ae_vector w;
 | |
|     ae_vector diff;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&d, 0, sizeof(d));
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     memset(&diff, 0, sizeof(diff));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     _spline1dinterpolant_clear(c);
 | |
|     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&diff, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=2, "Spline1DBuildAkima: N<2!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DBuildAkima: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DBuildAkima: Length(Y)<N!", _state);
 | |
|     
 | |
|     /*
 | |
|      * check and sort points
 | |
|      */
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildAkima: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DBuildAkima: Y contains infinite or NAN values!", _state);
 | |
|     spline1d_heapsortpoints(x, y, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DBuildAkima: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Handle special cases: N=2, N=3, N=4
 | |
|      */
 | |
|     if( n<=4 )
 | |
|     {
 | |
|         spline1dbuildcubic(x, y, n, 0, 0.0, 0, 0.0, c, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare W (weights), Diff (divided differences)
 | |
|      */
 | |
|     ae_vector_set_length(&w, n-1, _state);
 | |
|     ae_vector_set_length(&diff, n-1, _state);
 | |
|     for(i=0; i<=n-2; i++)
 | |
|     {
 | |
|         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]);
 | |
|     }
 | |
|     for(i=1; i<=n-2; i++)
 | |
|     {
 | |
|         w.ptr.p_double[i] = ae_fabs(diff.ptr.p_double[i]-diff.ptr.p_double[i-1], _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare Hermite interpolation scheme
 | |
|      */
 | |
|     ae_vector_set_length(&d, n, _state);
 | |
|     for(i=2; i<=n-3; i++)
 | |
|     {
 | |
|         if( ae_fp_neq(ae_fabs(w.ptr.p_double[i-1], _state)+ae_fabs(w.ptr.p_double[i+1], _state),(double)(0)) )
 | |
|         {
 | |
|             d.ptr.p_double[i] = (w.ptr.p_double[i+1]*diff.ptr.p_double[i-1]+w.ptr.p_double[i-1]*diff.ptr.p_double[i])/(w.ptr.p_double[i+1]+w.ptr.p_double[i-1]);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             d.ptr.p_double[i] = ((x->ptr.p_double[i+1]-x->ptr.p_double[i])*diff.ptr.p_double[i-1]+(x->ptr.p_double[i]-x->ptr.p_double[i-1])*diff.ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]);
 | |
|         }
 | |
|     }
 | |
|     d.ptr.p_double[0] = spline1d_diffthreepoint(x->ptr.p_double[0], x->ptr.p_double[0], y->ptr.p_double[0], x->ptr.p_double[1], y->ptr.p_double[1], x->ptr.p_double[2], y->ptr.p_double[2], _state);
 | |
|     d.ptr.p_double[1] = spline1d_diffthreepoint(x->ptr.p_double[1], x->ptr.p_double[0], y->ptr.p_double[0], x->ptr.p_double[1], y->ptr.p_double[1], x->ptr.p_double[2], y->ptr.p_double[2], _state);
 | |
|     d.ptr.p_double[n-2] = spline1d_diffthreepoint(x->ptr.p_double[n-2], x->ptr.p_double[n-3], y->ptr.p_double[n-3], x->ptr.p_double[n-2], y->ptr.p_double[n-2], x->ptr.p_double[n-1], y->ptr.p_double[n-1], _state);
 | |
|     d.ptr.p_double[n-1] = spline1d_diffthreepoint(x->ptr.p_double[n-1], x->ptr.p_double[n-3], y->ptr.p_double[n-3], x->ptr.p_double[n-2], y->ptr.p_double[n-2], x->ptr.p_double[n-1], y->ptr.p_double[n-1], _state);
 | |
|     
 | |
|     /*
 | |
|      * Build Akima spline using Hermite interpolation scheme
 | |
|      */
 | |
|     spline1dbuildhermite(x, y, &d, n, c, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates the value of the spline at the given point X.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant
 | |
|     X   -   point
 | |
| 
 | |
| Result:
 | |
|     S(x)
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double spline1dcalc(spline1dinterpolant* c, double x, ae_state *_state)
 | |
| {
 | |
|     ae_int_t l;
 | |
|     ae_int_t r;
 | |
|     ae_int_t m;
 | |
|     double t;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(c->k==3, "Spline1DCalc: internal error", _state);
 | |
|     ae_assert(!ae_isinf(x, _state), "Spline1DCalc: infinite X!", _state);
 | |
|     
 | |
|     /*
 | |
|      * special case: NaN
 | |
|      */
 | |
|     if( ae_isnan(x, _state) )
 | |
|     {
 | |
|         result = _state->v_nan;
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * correct if periodic
 | |
|      */
 | |
|     if( c->periodic )
 | |
|     {
 | |
|         apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->n-2+1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         m = (l+r)/2;
 | |
|         if( c->x.ptr.p_double[m]>=x )
 | |
|         {
 | |
|             r = m;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = m;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Interpolation
 | |
|      */
 | |
|     x = x-c->x.ptr.p_double[l];
 | |
|     m = 4*l;
 | |
|     result = c->c.ptr.p_double[m]+x*(c->c.ptr.p_double[m+1]+x*(c->c.ptr.p_double[m+2]+x*c->c.ptr.p_double[m+3]));
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine differentiates the spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X   -   point
 | |
| 
 | |
| Result:
 | |
|     S   -   S(x)
 | |
|     DS  -   S'(x)
 | |
|     D2S -   S''(x)
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 24.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1ddiff(spline1dinterpolant* c,
 | |
|      double x,
 | |
|      double* s,
 | |
|      double* ds,
 | |
|      double* d2s,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t l;
 | |
|     ae_int_t r;
 | |
|     ae_int_t m;
 | |
|     double t;
 | |
| 
 | |
|     *s = 0;
 | |
|     *ds = 0;
 | |
|     *d2s = 0;
 | |
| 
 | |
|     ae_assert(c->k==3, "Spline1DDiff: internal error", _state);
 | |
|     ae_assert(!ae_isinf(x, _state), "Spline1DDiff: infinite X!", _state);
 | |
|     
 | |
|     /*
 | |
|      * special case: NaN
 | |
|      */
 | |
|     if( ae_isnan(x, _state) )
 | |
|     {
 | |
|         *s = _state->v_nan;
 | |
|         *ds = _state->v_nan;
 | |
|         *d2s = _state->v_nan;
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * correct if periodic
 | |
|      */
 | |
|     if( c->periodic )
 | |
|     {
 | |
|         apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Binary search
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->n-2+1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         m = (l+r)/2;
 | |
|         if( c->x.ptr.p_double[m]>=x )
 | |
|         {
 | |
|             r = m;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = m;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Differentiation
 | |
|      */
 | |
|     x = x-c->x.ptr.p_double[l];
 | |
|     m = 4*l;
 | |
|     *s = c->c.ptr.p_double[m]+x*(c->c.ptr.p_double[m+1]+x*(c->c.ptr.p_double[m+2]+x*c->c.ptr.p_double[m+3]));
 | |
|     *ds = c->c.ptr.p_double[m+1]+2*x*c->c.ptr.p_double[m+2]+3*ae_sqr(x, _state)*c->c.ptr.p_double[m+3];
 | |
|     *d2s = 2*c->c.ptr.p_double[m+2]+6*x*c->c.ptr.p_double[m+3];
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine makes the copy of the spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
| 
 | |
| Result:
 | |
|     CC  -   spline copy
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 29.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dcopy(spline1dinterpolant* c,
 | |
|      spline1dinterpolant* cc,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t s;
 | |
| 
 | |
|     _spline1dinterpolant_clear(cc);
 | |
| 
 | |
|     cc->periodic = c->periodic;
 | |
|     cc->n = c->n;
 | |
|     cc->k = c->k;
 | |
|     cc->continuity = c->continuity;
 | |
|     ae_vector_set_length(&cc->x, cc->n, _state);
 | |
|     ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1));
 | |
|     s = c->c.cnt;
 | |
|     ae_vector_set_length(&cc->c, s, _state);
 | |
|     ae_v_move(&cc->c.ptr.p_double[0], 1, &c->c.ptr.p_double[0], 1, ae_v_len(0,s-1));
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine unpacks the spline into the coefficients table.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X   -   point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Tbl -   coefficients table, unpacked format, array[0..N-2, 0..5].
 | |
|             For I = 0...N-2:
 | |
|                 Tbl[I,0] = X[i]
 | |
|                 Tbl[I,1] = X[i+1]
 | |
|                 Tbl[I,2] = C0
 | |
|                 Tbl[I,3] = C1
 | |
|                 Tbl[I,4] = C2
 | |
|                 Tbl[I,5] = C3
 | |
|             On [x[i], x[i+1]] spline is equals to:
 | |
|                 S(x) = C0 + C1*t + C2*t^2 + C3*t^3
 | |
|                 t = x-x[i]
 | |
|                 
 | |
| NOTE:
 | |
|     You  can rebuild spline with  Spline1DBuildHermite()  function,  which
 | |
|     accepts as inputs function values and derivatives at nodes, which  are
 | |
|     easy to calculate when you have coefficients.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 29.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dunpack(spline1dinterpolant* c,
 | |
|      ae_int_t* n,
 | |
|      /* Real    */ ae_matrix* tbl,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     *n = 0;
 | |
|     ae_matrix_clear(tbl);
 | |
| 
 | |
|     ae_matrix_set_length(tbl, c->n-2+1, 2+c->k+1, _state);
 | |
|     *n = c->n;
 | |
|     
 | |
|     /*
 | |
|      * Fill
 | |
|      */
 | |
|     for(i=0; i<=*n-2; i++)
 | |
|     {
 | |
|         tbl->ptr.pp_double[i][0] = c->x.ptr.p_double[i];
 | |
|         tbl->ptr.pp_double[i][1] = c->x.ptr.p_double[i+1];
 | |
|         for(j=0; j<=c->k; j++)
 | |
|         {
 | |
|             tbl->ptr.pp_double[i][2+j] = c->c.ptr.p_double[(c->k+1)*i+j];
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline argument.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     A, B-   transformation coefficients: x = A*t + B
 | |
| Result:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dlintransx(spline1dinterpolant* c,
 | |
|      double a,
 | |
|      double b,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t n;
 | |
|     double v;
 | |
|     double dv;
 | |
|     double d2v;
 | |
|     ae_vector x;
 | |
|     ae_vector y;
 | |
|     ae_vector d;
 | |
|     ae_bool isperiodic;
 | |
|     ae_int_t contval;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&x, 0, sizeof(x));
 | |
|     memset(&y, 0, sizeof(y));
 | |
|     memset(&d, 0, sizeof(d));
 | |
|     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(c->k==3, "Spline1DLinTransX: internal error", _state);
 | |
|     n = c->n;
 | |
|     ae_vector_set_length(&x, n, _state);
 | |
|     ae_vector_set_length(&y, n, _state);
 | |
|     ae_vector_set_length(&d, n, _state);
 | |
|     
 | |
|     /*
 | |
|      * Unpack, X, Y, dY/dX.
 | |
|      * Scale and pack with Spline1DBuildHermite again.
 | |
|      */
 | |
|     if( ae_fp_eq(a,(double)(0)) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Special case: A=0
 | |
|          */
 | |
|         v = spline1dcalc(c, b, _state);
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             x.ptr.p_double[i] = c->x.ptr.p_double[i];
 | |
|             y.ptr.p_double[i] = v;
 | |
|             d.ptr.p_double[i] = 0.0;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * General case, A<>0
 | |
|          */
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             x.ptr.p_double[i] = c->x.ptr.p_double[i];
 | |
|             spline1ddiff(c, x.ptr.p_double[i], &v, &dv, &d2v, _state);
 | |
|             x.ptr.p_double[i] = (x.ptr.p_double[i]-b)/a;
 | |
|             y.ptr.p_double[i] = v;
 | |
|             d.ptr.p_double[i] = a*dv;
 | |
|         }
 | |
|     }
 | |
|     isperiodic = c->periodic;
 | |
|     contval = c->continuity;
 | |
|     if( contval>0 )
 | |
|     {
 | |
|         spline1dbuildhermite(&x, &y, &d, n, c, _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         spline1dbuildlinear(&x, &y, n, c, _state);
 | |
|     }
 | |
|     c->periodic = isperiodic;
 | |
|     c->continuity = contval;
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     A, B-   transformation coefficients: S2(x) = A*S(x) + B
 | |
| Result:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dlintransy(spline1dinterpolant* c,
 | |
|      double a,
 | |
|      double b,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t n;
 | |
| 
 | |
| 
 | |
|     ae_assert(c->k==3, "Spline1DLinTransX: internal error", _state);
 | |
|     n = c->n;
 | |
|     for(i=0; i<=n-2; i++)
 | |
|     {
 | |
|         c->c.ptr.p_double[4*i] = a*c->c.ptr.p_double[4*i]+b;
 | |
|         for(j=1; j<=3; j++)
 | |
|         {
 | |
|             c->c.ptr.p_double[4*i+j] = a*c->c.ptr.p_double[4*i+j];
 | |
|         }
 | |
|     }
 | |
|     c->c.ptr.p_double[4*(n-1)+0] = a*c->c.ptr.p_double[4*(n-1)+0]+b;
 | |
|     c->c.ptr.p_double[4*(n-1)+1] = a*c->c.ptr.p_double[4*(n-1)+1];
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine integrates the spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X   -   right bound of the integration interval [a, x],
 | |
|             here 'a' denotes min(x[])
 | |
| Result:
 | |
|     integral(S(t)dt,a,x)
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 23.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double spline1dintegrate(spline1dinterpolant* c,
 | |
|      double x,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t n;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t l;
 | |
|     ae_int_t r;
 | |
|     ae_int_t m;
 | |
|     double w;
 | |
|     double v;
 | |
|     double t;
 | |
|     double intab;
 | |
|     double additionalterm;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     n = c->n;
 | |
|     
 | |
|     /*
 | |
|      * Periodic splines require special treatment. We make
 | |
|      * following transformation:
 | |
|      *
 | |
|      *     integral(S(t)dt,A,X) = integral(S(t)dt,A,Z)+AdditionalTerm
 | |
|      *
 | |
|      * here X may lie outside of [A,B], Z lies strictly in [A,B],
 | |
|      * AdditionalTerm is equals to integral(S(t)dt,A,B) times some
 | |
|      * integer number (may be zero).
 | |
|      */
 | |
|     if( c->periodic&&(ae_fp_less(x,c->x.ptr.p_double[0])||ae_fp_greater(x,c->x.ptr.p_double[c->n-1])) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * compute integral(S(x)dx,A,B)
 | |
|          */
 | |
|         intab = (double)(0);
 | |
|         for(i=0; i<=c->n-2; i++)
 | |
|         {
 | |
|             w = c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i];
 | |
|             m = (c->k+1)*i;
 | |
|             intab = intab+c->c.ptr.p_double[m]*w;
 | |
|             v = w;
 | |
|             for(j=1; j<=c->k; j++)
 | |
|             {
 | |
|                 v = v*w;
 | |
|                 intab = intab+c->c.ptr.p_double[m+j]*v/(j+1);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * map X into [A,B]
 | |
|          */
 | |
|         apperiodicmap(&x, c->x.ptr.p_double[0], c->x.ptr.p_double[c->n-1], &t, _state);
 | |
|         additionalterm = t*intab;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         additionalterm = (double)(0);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = n-2+1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         m = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->x.ptr.p_double[m],x) )
 | |
|         {
 | |
|             r = m;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = m;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Integration
 | |
|      */
 | |
|     result = (double)(0);
 | |
|     for(i=0; i<=l-1; i++)
 | |
|     {
 | |
|         w = c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i];
 | |
|         m = (c->k+1)*i;
 | |
|         result = result+c->c.ptr.p_double[m]*w;
 | |
|         v = w;
 | |
|         for(j=1; j<=c->k; j++)
 | |
|         {
 | |
|             v = v*w;
 | |
|             result = result+c->c.ptr.p_double[m+j]*v/(j+1);
 | |
|         }
 | |
|     }
 | |
|     w = x-c->x.ptr.p_double[l];
 | |
|     m = (c->k+1)*l;
 | |
|     v = w;
 | |
|     result = result+c->c.ptr.p_double[m]*w;
 | |
|     for(j=1; j<=c->k; j++)
 | |
|     {
 | |
|         v = v*w;
 | |
|         result = result+c->c.ptr.p_double[m+j]*v/(j+1);
 | |
|     }
 | |
|     result = result+additionalterm;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fitting by smoothing (penalized) cubic spline.
 | |
| 
 | |
| This function approximates N scattered points (some of X[] may be equal to
 | |
| each other) by cubic spline with M  nodes  at  equidistant  grid  spanning
 | |
| interval [min(x,xc),max(x,xc)].
 | |
| 
 | |
| The problem is regularized by adding nonlinearity penalty to  usual  least
 | |
| squares penalty function:
 | |
| 
 | |
|     MERIT_FUNC = F_LS + F_NL
 | |
| 
 | |
| where F_LS is a least squares error  term,  and  F_NL  is  a  nonlinearity
 | |
| penalty which is roughly proportional to LambdaNS*integral{ S''(x)^2*dx }.
 | |
| Algorithm applies automatic renormalization of F_NL  which  makes  penalty
 | |
| term roughly invariant to scaling of X[] and changes in M.
 | |
| 
 | |
| This function is a new edition  of  penalized  regression  spline fitting,
 | |
| a fast and compact one which needs much less resources that  its  previous
 | |
| version: just O(maxMN) memory and O(maxMN*log(maxMN)) time.
 | |
| 
 | |
| NOTE: it is OK to run this function with both M<<N and M>>N;  say,  it  is
 | |
|       possible to process 100 points with 1000-node spline.
 | |
|            
 | |
| INPUT PARAMETERS:
 | |
|     X           -   points, array[0..N-1].
 | |
|     Y           -   function values, array[0..N-1].
 | |
|     N           -   number of points (optional):
 | |
|                     * N>0
 | |
|                     * if given, only first N elements of X/Y are processed
 | |
|                     * if not given, automatically determined from lengths
 | |
|     M           -   number of basis functions ( = number_of_nodes), M>=4.
 | |
|     LambdaNS    -   LambdaNS>=0, regularization  constant  passed by user.
 | |
|                     It penalizes nonlinearity in the regression spline.
 | |
|                     Possible values to start from are 0.00001, 0.1, 1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     S   -   spline interpolant.
 | |
|     Rep -   Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 27.08.2019 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfit(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      double lambdans,
 | |
|      spline1dinterpolant* s,
 | |
|      spline1dfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_int_t bfrad;
 | |
|     double xa;
 | |
|     double xb;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t k0;
 | |
|     ae_int_t k1;
 | |
|     double v;
 | |
|     double dv;
 | |
|     double d2v;
 | |
|     ae_int_t gridexpansion;
 | |
|     ae_vector xywork;
 | |
|     ae_matrix vterm;
 | |
|     ae_vector sx;
 | |
|     ae_vector sy;
 | |
|     ae_vector sdy;
 | |
|     ae_vector tmpx;
 | |
|     ae_vector tmpy;
 | |
|     spline1dinterpolant basis1;
 | |
|     sparsematrix av;
 | |
|     sparsematrix ah;
 | |
|     sparsematrix ata;
 | |
|     ae_vector targets;
 | |
|     double meany;
 | |
|     ae_int_t lsqrcnt;
 | |
|     ae_int_t nrel;
 | |
|     double rss;
 | |
|     double tss;
 | |
|     ae_int_t arows;
 | |
|     ae_vector tmp0;
 | |
|     ae_vector tmp1;
 | |
|     linlsqrstate solver;
 | |
|     linlsqrreport srep;
 | |
|     double creg;
 | |
|     double mxata;
 | |
|     ae_int_t bw;
 | |
|     ae_vector nzidx;
 | |
|     ae_vector nzval;
 | |
|     ae_int_t nzcnt;
 | |
|     double scaletargetsby;
 | |
|     double scalepenaltyby;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&xywork, 0, sizeof(xywork));
 | |
|     memset(&vterm, 0, sizeof(vterm));
 | |
|     memset(&sx, 0, sizeof(sx));
 | |
|     memset(&sy, 0, sizeof(sy));
 | |
|     memset(&sdy, 0, sizeof(sdy));
 | |
|     memset(&tmpx, 0, sizeof(tmpx));
 | |
|     memset(&tmpy, 0, sizeof(tmpy));
 | |
|     memset(&basis1, 0, sizeof(basis1));
 | |
|     memset(&av, 0, sizeof(av));
 | |
|     memset(&ah, 0, sizeof(ah));
 | |
|     memset(&ata, 0, sizeof(ata));
 | |
|     memset(&targets, 0, sizeof(targets));
 | |
|     memset(&tmp0, 0, sizeof(tmp0));
 | |
|     memset(&tmp1, 0, sizeof(tmp1));
 | |
|     memset(&solver, 0, sizeof(solver));
 | |
|     memset(&srep, 0, sizeof(srep));
 | |
|     memset(&nzidx, 0, sizeof(nzidx));
 | |
|     memset(&nzval, 0, sizeof(nzval));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     _spline1dinterpolant_clear(s);
 | |
|     _spline1dfitreport_clear(rep);
 | |
|     ae_vector_init(&xywork, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&vterm, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sy, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sdy, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
 | |
|     _spline1dinterpolant_init(&basis1, _state, ae_true);
 | |
|     _sparsematrix_init(&av, _state, ae_true);
 | |
|     _sparsematrix_init(&ah, _state, ae_true);
 | |
|     _sparsematrix_init(&ata, _state, ae_true);
 | |
|     ae_vector_init(&targets, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true);
 | |
|     _linlsqrstate_init(&solver, _state, ae_true);
 | |
|     _linlsqrreport_init(&srep, _state, ae_true);
 | |
|     ae_vector_init(&nzidx, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&nzval, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=1, "Spline1DFit: N<1!", _state);
 | |
|     ae_assert(m>=1, "Spline1DFit: M<1!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DFit: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DFit: Length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DFit: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DFit: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(ae_isfinite(lambdans, _state), "Spline1DFit: LambdaNS is infinite!", _state);
 | |
|     ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline1DFit: LambdaNS<0!", _state);
 | |
|     bfrad = 2;
 | |
|     lsqrcnt = 10;
 | |
|     
 | |
|     /*
 | |
|      * Sort points.
 | |
|      * Determine actual area size, make sure that XA<XB
 | |
|      */
 | |
|     tagsortfastr(x, y, &tmpx, &tmpy, n, _state);
 | |
|     xa = x->ptr.p_double[0];
 | |
|     xb = x->ptr.p_double[n-1];
 | |
|     if( ae_fp_eq(xa,xb) )
 | |
|     {
 | |
|         v = xa;
 | |
|         if( ae_fp_greater_eq(v,(double)(0)) )
 | |
|         {
 | |
|             xa = v/2-1;
 | |
|             xb = v*2+1;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             xa = v*2-1;
 | |
|             xb = v/2+1;
 | |
|         }
 | |
|     }
 | |
|     ae_assert(ae_fp_less(xa,xb), "Spline1DFit: integrity error", _state);
 | |
|     
 | |
|     /*
 | |
|      * Perform a grid correction according to current grid expansion size.
 | |
|      */
 | |
|     m = ae_maxint(m, 4, _state);
 | |
|     gridexpansion = 1;
 | |
|     v = (xb-xa)/m;
 | |
|     xa = xa-v*gridexpansion;
 | |
|     xb = xb+v*gridexpansion;
 | |
|     m = m+2*gridexpansion;
 | |
|     
 | |
|     /*
 | |
|      * Convert X/Y to work representation, remove linear trend (in
 | |
|      * order to improve condition number).
 | |
|      *
 | |
|      * Compute total-sum-of-squares (needed later for R2 coefficient).
 | |
|      */
 | |
|     ae_vector_set_length(&xywork, 2*n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         xywork.ptr.p_double[2*i+0] = (x->ptr.p_double[i]-xa)/(xb-xa);
 | |
|         xywork.ptr.p_double[2*i+1] = y->ptr.p_double[i];
 | |
|     }
 | |
|     buildpriorterm1(&xywork, n, 1, 1, 1, 0.0, &vterm, _state);
 | |
|     meany = (double)(0);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         meany = meany+y->ptr.p_double[i];
 | |
|     }
 | |
|     meany = meany/n;
 | |
|     tss = (double)(0);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         tss = tss+ae_sqr(y->ptr.p_double[i]-meany, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Build 1D compact basis function
 | |
|      * Generate design matrix AV ("vertical") and its transpose AH ("horizontal").
 | |
|      */
 | |
|     ae_vector_set_length(&tmpx, 7, _state);
 | |
|     ae_vector_set_length(&tmpy, 7, _state);
 | |
|     tmpx.ptr.p_double[0] = -(double)3/(double)(m-1);
 | |
|     tmpx.ptr.p_double[1] = -(double)2/(double)(m-1);
 | |
|     tmpx.ptr.p_double[2] = -(double)1/(double)(m-1);
 | |
|     tmpx.ptr.p_double[3] = (double)0/(double)(m-1);
 | |
|     tmpx.ptr.p_double[4] = (double)1/(double)(m-1);
 | |
|     tmpx.ptr.p_double[5] = (double)2/(double)(m-1);
 | |
|     tmpx.ptr.p_double[6] = (double)3/(double)(m-1);
 | |
|     tmpy.ptr.p_double[0] = (double)(0);
 | |
|     tmpy.ptr.p_double[1] = (double)(0);
 | |
|     tmpy.ptr.p_double[2] = (double)1/(double)12;
 | |
|     tmpy.ptr.p_double[3] = (double)2/(double)6;
 | |
|     tmpy.ptr.p_double[4] = (double)1/(double)12;
 | |
|     tmpy.ptr.p_double[5] = (double)(0);
 | |
|     tmpy.ptr.p_double[6] = (double)(0);
 | |
|     spline1dbuildcubic(&tmpx, &tmpy, tmpx.cnt, 2, 0.0, 2, 0.0, &basis1, _state);
 | |
|     arows = n+2*m;
 | |
|     sparsecreate(arows, m, 0, &av, _state);
 | |
|     setlengthzero(&targets, arows, _state);
 | |
|     scaletargetsby = 1/ae_sqrt((double)(n), _state);
 | |
|     scalepenaltyby = 1/ae_sqrt((double)(m), _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Generate design matrix row #I which corresponds to I-th dataset point
 | |
|          */
 | |
|         k = ae_ifloor(boundval(xywork.ptr.p_double[2*i+0]*(m-1), (double)(0), (double)(m-1), _state), _state);
 | |
|         k0 = ae_maxint(k-(bfrad-1), 0, _state);
 | |
|         k1 = ae_minint(k+bfrad, m-1, _state);
 | |
|         for(j=k0; j<=k1; j++)
 | |
|         {
 | |
|             sparseset(&av, i, j, spline1dcalc(&basis1, xywork.ptr.p_double[2*i+0]-(double)j/(double)(m-1), _state)*scaletargetsby, _state);
 | |
|         }
 | |
|         targets.ptr.p_double[i] = xywork.ptr.p_double[2*i+1]*scaletargetsby;
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Generate design matrix row #(I+N) which corresponds to nonlinearity penalty at I-th node
 | |
|          */
 | |
|         k0 = ae_maxint(i-(bfrad-1), 0, _state);
 | |
|         k1 = ae_minint(i+(bfrad-1), m-1, _state);
 | |
|         for(j=k0; j<=k1; j++)
 | |
|         {
 | |
|             spline1ddiff(&basis1, (double)i/(double)(m-1)-(double)j/(double)(m-1), &v, &dv, &d2v, _state);
 | |
|             sparseset(&av, n+i, j, lambdans*d2v*scalepenaltyby, _state);
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Generate design matrix row #(I+N+M) which corresponds to regularization for I-th coefficient
 | |
|          */
 | |
|         sparseset(&av, n+m+i, i, spline1d_lambdareg, _state);
 | |
|     }
 | |
|     sparseconverttocrs(&av, _state);
 | |
|     sparsecopytransposecrs(&av, &ah, _state);
 | |
|     
 | |
|     /*
 | |
|      * Build 7-diagonal (bandwidth=3) normal equations matrix and perform Cholesky
 | |
|      * decomposition (to be used later as preconditioner for LSQR iterations).
 | |
|      */
 | |
|     bw = 3;
 | |
|     sparsecreatesksband(m, m, bw, &ata, _state);
 | |
|     mxata = (double)(0);
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         for(j=i; j<=ae_minint(i+bw, m-1, _state); j++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Get pattern of nonzeros in one of the rows (let it be I-th one)
 | |
|              * and compute dot product only for nonzero entries.
 | |
|              */
 | |
|             sparsegetcompressedrow(&ah, i, &nzidx, &nzval, &nzcnt, _state);
 | |
|             v = (double)(0);
 | |
|             for(k=0; k<=nzcnt-1; k++)
 | |
|             {
 | |
|                 v = v+sparseget(&ah, i, nzidx.ptr.p_int[k], _state)*sparseget(&ah, j, nzidx.ptr.p_int[k], _state);
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Update ATA and max(ATA)
 | |
|              */
 | |
|             sparseset(&ata, i, j, v, _state);
 | |
|             if( i==j )
 | |
|             {
 | |
|                 mxata = ae_maxreal(mxata, ae_fabs(v, _state), _state);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     mxata = coalesce(mxata, 1.0, _state);
 | |
|     creg = spline1d_cholreg;
 | |
|     for(;;)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Regularization
 | |
|          */
 | |
|         for(i=0; i<=m-1; i++)
 | |
|         {
 | |
|             sparseset(&ata, i, i, sparseget(&ata, i, i, _state)+mxata*creg, _state);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Try Cholesky factorization.
 | |
|          */
 | |
|         if( !sparsecholeskyskyline(&ata, m, ae_true, _state) )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Factorization failed, increase regularizer and repeat
 | |
|              */
 | |
|             creg = coalesce(10*creg, 1.0E-12, _state);
 | |
|             continue;
 | |
|         }
 | |
|         break;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Solve with preconditioned LSQR:
 | |
|      *
 | |
|      * use Cholesky factor U of squared design matrix A'*A to
 | |
|      * transform min|A*x-b| to min|[A*inv(U)]*y-b| with y=U*x.
 | |
|      *
 | |
|      * Preconditioned problem is solved with LSQR solver, which
 | |
|      * gives superior results to normal equations approach. Due
 | |
|      * to Cholesky preconditioner being utilized we can solve
 | |
|      * problem in just a few iterations.
 | |
|      */
 | |
|     rvectorsetlengthatleast(&tmp0, arows, _state);
 | |
|     rvectorsetlengthatleast(&tmp1, m, _state);
 | |
|     linlsqrcreatebuf(arows, m, &solver, _state);
 | |
|     linlsqrsetb(&solver, &targets, _state);
 | |
|     linlsqrsetcond(&solver, 1.0E-14, 1.0E-14, lsqrcnt, _state);
 | |
|     while(linlsqriteration(&solver, _state))
 | |
|     {
 | |
|         if( solver.needmv )
 | |
|         {
 | |
|             for(i=0; i<=m-1; i++)
 | |
|             {
 | |
|                 tmp1.ptr.p_double[i] = solver.x.ptr.p_double[i];
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Use Cholesky factorization of the system matrix
 | |
|              * as preconditioner: solve TRSV(U,Solver.X)
 | |
|              */
 | |
|             sparsetrsv(&ata, ae_true, ae_false, 0, &tmp1, _state);
 | |
|             
 | |
|             /*
 | |
|              * After preconditioning is done, multiply by A
 | |
|              */
 | |
|             sparsemv(&av, &tmp1, &solver.mv, _state);
 | |
|         }
 | |
|         if( solver.needmtv )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Multiply by design matrix A
 | |
|              */
 | |
|             sparsemtv(&av, &solver.x, &solver.mtv, _state);
 | |
|             
 | |
|             /*
 | |
|              * Multiply by preconditioner: solve TRSV(U',A*Solver.X)
 | |
|              */
 | |
|             sparsetrsv(&ata, ae_true, ae_false, 1, &solver.mtv, _state);
 | |
|         }
 | |
|     }
 | |
|     linlsqrresults(&solver, &tmp1, &srep, _state);
 | |
|     sparsetrsv(&ata, ae_true, ae_false, 0, &tmp1, _state);
 | |
|     
 | |
|     /*
 | |
|      * Generate output spline as a table of spline valued and first
 | |
|      * derivatives at nodes (used to build Hermite spline)
 | |
|      */
 | |
|     ae_vector_set_length(&sx, m, _state);
 | |
|     ae_vector_set_length(&sy, m, _state);
 | |
|     ae_vector_set_length(&sdy, m, _state);
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         sx.ptr.p_double[i] = (double)i/(double)(m-1);
 | |
|         sy.ptr.p_double[i] = (double)(0);
 | |
|         sdy.ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         k0 = ae_maxint(i-(bfrad-1), 0, _state);
 | |
|         k1 = ae_minint(i+bfrad, m-1, _state);
 | |
|         for(j=k0; j<=k1; j++)
 | |
|         {
 | |
|             spline1ddiff(&basis1, (double)j/(double)(m-1)-(double)i/(double)(m-1), &v, &dv, &d2v, _state);
 | |
|             sy.ptr.p_double[j] = sy.ptr.p_double[j]+tmp1.ptr.p_double[i]*v;
 | |
|             sdy.ptr.p_double[j] = sdy.ptr.p_double[j]+tmp1.ptr.p_double[i]*dv;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Calculate model values
 | |
|      */
 | |
|     sparsemv(&av, &tmp1, &tmp0, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         tmp0.ptr.p_double[i] = tmp0.ptr.p_double[i]/scaletargetsby;
 | |
|     }
 | |
|     rss = 0.0;
 | |
|     nrel = 0;
 | |
|     rep->rmserror = (double)(0);
 | |
|     rep->maxerror = (double)(0);
 | |
|     rep->avgerror = (double)(0);
 | |
|     rep->avgrelerror = (double)(0);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         v = xywork.ptr.p_double[2*i+1]-tmp0.ptr.p_double[i];
 | |
|         rss = rss+v*v;
 | |
|         rep->rmserror = rep->rmserror+ae_sqr(v, _state);
 | |
|         rep->avgerror = rep->avgerror+ae_fabs(v, _state);
 | |
|         rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
 | |
|         if( ae_fp_neq(y->ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             rep->avgrelerror = rep->avgrelerror+ae_fabs(v/y->ptr.p_double[i], _state);
 | |
|             nrel = nrel+1;
 | |
|         }
 | |
|     }
 | |
|     rep->rmserror = ae_sqrt(rep->rmserror/n, _state);
 | |
|     rep->avgerror = rep->avgerror/n;
 | |
|     rep->avgrelerror = rep->avgrelerror/coalesce((double)(nrel), 1.0, _state);
 | |
|     
 | |
|     /*
 | |
|      * Append prior term.
 | |
|      * Transform spline to original coordinates.
 | |
|      * Output.
 | |
|      */
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         sy.ptr.p_double[i] = sy.ptr.p_double[i]+vterm.ptr.pp_double[0][0]*sx.ptr.p_double[i]+vterm.ptr.pp_double[0][1];
 | |
|         sdy.ptr.p_double[i] = sdy.ptr.p_double[i]+vterm.ptr.pp_double[0][0];
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         sx.ptr.p_double[i] = sx.ptr.p_double[i]*(xb-xa)+xa;
 | |
|         sdy.ptr.p_double[i] = sdy.ptr.p_double[i]/(xb-xa);
 | |
|     }
 | |
|     spline1dbuildhermite(&sx, &sy, &sdy, m, s, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal version of Spline1DConvDiff
 | |
| 
 | |
| Converts from Hermite spline given by grid XOld to new grid X2
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XOld    -   old grid
 | |
|     YOld    -   values at old grid
 | |
|     DOld    -   first derivative at old grid
 | |
|     N       -   grid size
 | |
|     X2      -   new grid
 | |
|     N2      -   new grid size
 | |
|     Y       -   possibly preallocated output array
 | |
|                 (reallocate if too small)
 | |
|     NeedY   -   do we need Y?
 | |
|     D1      -   possibly preallocated output array
 | |
|                 (reallocate if too small)
 | |
|     NeedD1  -   do we need D1?
 | |
|     D2      -   possibly preallocated output array
 | |
|                 (reallocate if too small)
 | |
|     NeedD2  -   do we need D1?
 | |
| 
 | |
| OUTPUT ARRAYS:
 | |
|     Y       -   values, if needed
 | |
|     D1      -   first derivative, if needed
 | |
|     D2      -   second derivative, if needed
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dconvdiffinternal(/* Real    */ ae_vector* xold,
 | |
|      /* Real    */ ae_vector* yold,
 | |
|      /* Real    */ ae_vector* dold,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      ae_int_t n2,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_bool needy,
 | |
|      /* Real    */ ae_vector* d1,
 | |
|      ae_bool needd1,
 | |
|      /* Real    */ ae_vector* d2,
 | |
|      ae_bool needd2,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t intervalindex;
 | |
|     ae_int_t pointindex;
 | |
|     ae_bool havetoadvance;
 | |
|     double c0;
 | |
|     double c1;
 | |
|     double c2;
 | |
|     double c3;
 | |
|     double a;
 | |
|     double b;
 | |
|     double w;
 | |
|     double w2;
 | |
|     double w3;
 | |
|     double fa;
 | |
|     double fb;
 | |
|     double da;
 | |
|     double db;
 | |
|     double t;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Prepare space
 | |
|      */
 | |
|     if( needy&&y->cnt<n2 )
 | |
|     {
 | |
|         ae_vector_set_length(y, n2, _state);
 | |
|     }
 | |
|     if( needd1&&d1->cnt<n2 )
 | |
|     {
 | |
|         ae_vector_set_length(d1, n2, _state);
 | |
|     }
 | |
|     if( needd2&&d2->cnt<n2 )
 | |
|     {
 | |
|         ae_vector_set_length(d2, n2, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * These assignments aren't actually needed
 | |
|      * (variables are initialized in the loop below),
 | |
|      * but without them compiler will complain about uninitialized locals
 | |
|      */
 | |
|     c0 = (double)(0);
 | |
|     c1 = (double)(0);
 | |
|     c2 = (double)(0);
 | |
|     c3 = (double)(0);
 | |
|     a = (double)(0);
 | |
|     b = (double)(0);
 | |
|     
 | |
|     /*
 | |
|      * Cycle
 | |
|      */
 | |
|     intervalindex = -1;
 | |
|     pointindex = 0;
 | |
|     for(;;)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * are we ready to exit?
 | |
|          */
 | |
|         if( pointindex>=n2 )
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
|         t = x2->ptr.p_double[pointindex];
 | |
|         
 | |
|         /*
 | |
|          * do we need to advance interval?
 | |
|          */
 | |
|         havetoadvance = ae_false;
 | |
|         if( intervalindex==-1 )
 | |
|         {
 | |
|             havetoadvance = ae_true;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if( intervalindex<n-2 )
 | |
|             {
 | |
|                 havetoadvance = ae_fp_greater_eq(t,b);
 | |
|             }
 | |
|         }
 | |
|         if( havetoadvance )
 | |
|         {
 | |
|             intervalindex = intervalindex+1;
 | |
|             a = xold->ptr.p_double[intervalindex];
 | |
|             b = xold->ptr.p_double[intervalindex+1];
 | |
|             w = b-a;
 | |
|             w2 = w*w;
 | |
|             w3 = w*w2;
 | |
|             fa = yold->ptr.p_double[intervalindex];
 | |
|             fb = yold->ptr.p_double[intervalindex+1];
 | |
|             da = dold->ptr.p_double[intervalindex];
 | |
|             db = dold->ptr.p_double[intervalindex+1];
 | |
|             c0 = fa;
 | |
|             c1 = da;
 | |
|             c2 = (3*(fb-fa)-2*da*w-db*w)/w2;
 | |
|             c3 = (2*(fa-fb)+da*w+db*w)/w3;
 | |
|             continue;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Calculate spline and its derivatives using power basis
 | |
|          */
 | |
|         t = t-a;
 | |
|         if( needy )
 | |
|         {
 | |
|             y->ptr.p_double[pointindex] = c0+t*(c1+t*(c2+t*c3));
 | |
|         }
 | |
|         if( needd1 )
 | |
|         {
 | |
|             d1->ptr.p_double[pointindex] = c1+2*t*c2+3*t*t*c3;
 | |
|         }
 | |
|         if( needd2 )
 | |
|         {
 | |
|             d2->ptr.p_double[pointindex] = 2*c2+6*t*c3;
 | |
|         }
 | |
|         pointindex = pointindex+1;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function finds all roots and extrema of the spline S(x)  defined  at
 | |
| [A,B] (interval which contains spline nodes).
 | |
| 
 | |
| It  does not extrapolates function, so roots and extrema located  outside 
 | |
| of [A,B] will not be found. It returns all isolated (including  multiple)
 | |
| roots and extrema.
 | |
| 
 | |
| INPUT PARAMETERS
 | |
|     C           -   spline interpolant
 | |
|     
 | |
| OUTPUT PARAMETERS
 | |
|     R           -   array[NR], contains roots of the spline. 
 | |
|                     In case there is no roots, this array has zero length.
 | |
|     NR          -   number of roots, >=0
 | |
|     DR          -   is set to True in case there is at least one interval
 | |
|                     where spline is just a zero constant. Such degenerate
 | |
|                     cases are not reported in the R/NR
 | |
|     E           -   array[NE], contains  extrema  (maximums/minimums)  of 
 | |
|                     the spline. In case there is no extrema,  this  array 
 | |
|                     has zero length.
 | |
|     ET          -   array[NE], extrema types:
 | |
|                     * ET[i]>0 in case I-th extrema is a minimum
 | |
|                     * ET[i]<0 in case I-th extrema is a maximum
 | |
|     NE          -   number of extrema, >=0
 | |
|     DE          -   is set to True in case there is at least one interval
 | |
|                     where spline is a constant. Such degenerate cases are  
 | |
|                     not reported in the E/NE.
 | |
|                     
 | |
| NOTES:
 | |
| 
 | |
| 1. This function does NOT report following kinds of roots:
 | |
|    * intervals where function is constantly zero
 | |
|    * roots which are outside of [A,B] (note: it CAN return A or B)
 | |
| 
 | |
| 2. This function does NOT report following kinds of extrema:
 | |
|    * intervals where function is a constant
 | |
|    * extrema which are outside of (A,B) (note: it WON'T return A or B)
 | |
|    
 | |
|  -- ALGLIB PROJECT --
 | |
|      Copyright 26.09.2011 by Bochkanov Sergey   
 | |
| *************************************************************************/
 | |
| void spline1drootsandextrema(spline1dinterpolant* c,
 | |
|      /* Real    */ ae_vector* r,
 | |
|      ae_int_t* nr,
 | |
|      ae_bool* dr,
 | |
|      /* Real    */ ae_vector* e,
 | |
|      /* Integer */ ae_vector* et,
 | |
|      ae_int_t* ne,
 | |
|      ae_bool* de,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     double pl;
 | |
|     double ml;
 | |
|     double pll;
 | |
|     double pr;
 | |
|     double mr;
 | |
|     ae_vector tr;
 | |
|     ae_vector tmpr;
 | |
|     ae_vector tmpe;
 | |
|     ae_vector tmpet;
 | |
|     ae_vector tmpc;
 | |
|     double x0;
 | |
|     double x1;
 | |
|     double x2;
 | |
|     double ex0;
 | |
|     double ex1;
 | |
|     ae_int_t tne;
 | |
|     ae_int_t tnr;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_bool nstep;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&tr, 0, sizeof(tr));
 | |
|     memset(&tmpr, 0, sizeof(tmpr));
 | |
|     memset(&tmpe, 0, sizeof(tmpe));
 | |
|     memset(&tmpet, 0, sizeof(tmpet));
 | |
|     memset(&tmpc, 0, sizeof(tmpc));
 | |
|     ae_vector_clear(r);
 | |
|     *nr = 0;
 | |
|     *dr = ae_false;
 | |
|     ae_vector_clear(e);
 | |
|     ae_vector_clear(et);
 | |
|     *ne = 0;
 | |
|     *de = ae_false;
 | |
|     ae_vector_init(&tr, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpr, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpe, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpet, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&tmpc, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      *exception handling
 | |
|      */
 | |
|     ae_assert(c->k==3, "Spline1DRootsAndExtrema : incorrect parameter C.K!", _state);
 | |
|     ae_assert(c->continuity>=0, "Spline1DRootsAndExtrema : parameter C.Continuity must not be less than 0!", _state);
 | |
|     
 | |
|     /*
 | |
|      *initialization of variable
 | |
|      */
 | |
|     *nr = 0;
 | |
|     *ne = 0;
 | |
|     *dr = ae_false;
 | |
|     *de = ae_false;
 | |
|     nstep = ae_true;
 | |
|     
 | |
|     /*
 | |
|      *consider case, when C.Continuty=0
 | |
|      */
 | |
|     if( c->continuity==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          *allocation for auxiliary arrays 
 | |
|          *'TmpR ' - it stores a time value for roots
 | |
|          *'TmpE ' - it stores a time value for extremums
 | |
|          *'TmpET '- it stores a time value for extremums type
 | |
|          */
 | |
|         rvectorsetlengthatleast(&tmpr, 3*(c->n-1), _state);
 | |
|         rvectorsetlengthatleast(&tmpe, 2*(c->n-1), _state);
 | |
|         ivectorsetlengthatleast(&tmpet, 2*(c->n-1), _state);
 | |
|         
 | |
|         /*
 | |
|          *start calculating
 | |
|          */
 | |
|         for(i=0; i<=c->n-2; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              *initialization pL, mL, pR, mR
 | |
|              */
 | |
|             pl = c->c.ptr.p_double[4*i];
 | |
|             ml = c->c.ptr.p_double[4*i+1];
 | |
|             pr = c->c.ptr.p_double[4*(i+1)];
 | |
|             mr = c->c.ptr.p_double[4*i+1]+2*c->c.ptr.p_double[4*i+2]*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i])+3*c->c.ptr.p_double[4*i+3]*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i])*(c->x.ptr.p_double[i+1]-c->x.ptr.p_double[i]);
 | |
|             
 | |
|             /*
 | |
|              *pre-searching roots and extremums
 | |
|              */
 | |
|             solvecubicpolinom(pl, ml, pr, mr, c->x.ptr.p_double[i], c->x.ptr.p_double[i+1], &x0, &x1, &x2, &ex0, &ex1, &tnr, &tne, &tr, _state);
 | |
|             *dr = *dr||tnr==-1;
 | |
|             *de = *de||tne==-1;
 | |
|             
 | |
|             /*
 | |
|              *searching of roots
 | |
|              */
 | |
|             if( tnr==1&&nstep )
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  *is there roots?
 | |
|                  */
 | |
|                 if( *nr>0 )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      *is a next root equal a previous root?
 | |
|                      *if is't, then write new root
 | |
|                      */
 | |
|                     if( ae_fp_neq(x0,tmpr.ptr.p_double[*nr-1]) )
 | |
|                     {
 | |
|                         tmpr.ptr.p_double[*nr] = x0;
 | |
|                         *nr = *nr+1;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      *write a first root
 | |
|                      */
 | |
|                     tmpr.ptr.p_double[*nr] = x0;
 | |
|                     *nr = *nr+1;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  *case when function at a segment identically to zero
 | |
|                  *then we have to clear a root, if the one located on a 
 | |
|                  *constant segment
 | |
|                  */
 | |
|                 if( tnr==-1 )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      *safe state variable as constant
 | |
|                      */
 | |
|                     if( nstep )
 | |
|                     {
 | |
|                         nstep = ae_false;
 | |
|                     }
 | |
|                     
 | |
|                     /*
 | |
|                      *clear the root, if there is
 | |
|                      */
 | |
|                     if( *nr>0 )
 | |
|                     {
 | |
|                         if( ae_fp_eq(c->x.ptr.p_double[i],tmpr.ptr.p_double[*nr-1]) )
 | |
|                         {
 | |
|                             *nr = *nr-1;
 | |
|                         }
 | |
|                     }
 | |
|                     
 | |
|                     /*
 | |
|                      *change state for 'DR'
 | |
|                      */
 | |
|                     if( !*dr )
 | |
|                     {
 | |
|                         *dr = ae_true;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     nstep = ae_true;
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              *searching of extremums
 | |
|              */
 | |
|             if( i>0 )
 | |
|             {
 | |
|                 pll = c->c.ptr.p_double[4*(i-1)];
 | |
|                 
 | |
|                 /*
 | |
|                  *if pL=pLL or pL=pR then
 | |
|                  */
 | |
|                 if( tne==-1 )
 | |
|                 {
 | |
|                     if( !*de )
 | |
|                     {
 | |
|                         *de = ae_true;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if( ae_fp_greater(pl,pll)&&ae_fp_greater(pl,pr) )
 | |
|                     {
 | |
|                         
 | |
|                         /*
 | |
|                          *maximum
 | |
|                          */
 | |
|                         tmpet.ptr.p_int[*ne] = -1;
 | |
|                         tmpe.ptr.p_double[*ne] = c->x.ptr.p_double[i];
 | |
|                         *ne = *ne+1;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         if( ae_fp_less(pl,pll)&&ae_fp_less(pl,pr) )
 | |
|                         {
 | |
|                             
 | |
|                             /*
 | |
|                              *minimum
 | |
|                              */
 | |
|                             tmpet.ptr.p_int[*ne] = 1;
 | |
|                             tmpe.ptr.p_double[*ne] = c->x.ptr.p_double[i];
 | |
|                             *ne = *ne+1;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          *write final result
 | |
|          */
 | |
|         rvectorsetlengthatleast(r, *nr, _state);
 | |
|         rvectorsetlengthatleast(e, *ne, _state);
 | |
|         ivectorsetlengthatleast(et, *ne, _state);
 | |
|         
 | |
|         /*
 | |
|          *write roots
 | |
|          */
 | |
|         for(i=0; i<=*nr-1; i++)
 | |
|         {
 | |
|             r->ptr.p_double[i] = tmpr.ptr.p_double[i];
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          *write extremums and their types
 | |
|          */
 | |
|         for(i=0; i<=*ne-1; i++)
 | |
|         {
 | |
|             e->ptr.p_double[i] = tmpe.ptr.p_double[i];
 | |
|             et->ptr.p_int[i] = tmpet.ptr.p_int[i];
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          *case, when C.Continuity>=1 
 | |
|          *'TmpR ' - it stores a time value for roots
 | |
|          *'TmpC' - it stores a time value for extremums and 
 | |
|          *their function value (TmpC={EX0,F(EX0), EX1,F(EX1), ..., EXn,F(EXn)};)
 | |
|          *'TmpE' - it stores a time value for extremums only
 | |
|          *'TmpET'- it stores a time value for extremums type
 | |
|          */
 | |
|         rvectorsetlengthatleast(&tmpr, 2*c->n-1, _state);
 | |
|         rvectorsetlengthatleast(&tmpc, 4*c->n, _state);
 | |
|         rvectorsetlengthatleast(&tmpe, 2*c->n, _state);
 | |
|         ivectorsetlengthatleast(&tmpet, 2*c->n, _state);
 | |
|         
 | |
|         /*
 | |
|          *start calculating
 | |
|          */
 | |
|         for(i=0; i<=c->n-2; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              *we calculate pL,mL, pR,mR as Fi+1(F'i+1) at left border
 | |
|              */
 | |
|             pl = c->c.ptr.p_double[4*i];
 | |
|             ml = c->c.ptr.p_double[4*i+1];
 | |
|             pr = c->c.ptr.p_double[4*(i+1)];
 | |
|             mr = c->c.ptr.p_double[4*(i+1)+1];
 | |
|             
 | |
|             /*
 | |
|              *calculating roots and extremums at [X[i],X[i+1]]
 | |
|              */
 | |
|             solvecubicpolinom(pl, ml, pr, mr, c->x.ptr.p_double[i], c->x.ptr.p_double[i+1], &x0, &x1, &x2, &ex0, &ex1, &tnr, &tne, &tr, _state);
 | |
|             
 | |
|             /*
 | |
|              *searching roots
 | |
|              */
 | |
|             if( tnr>0 )
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  *re-init tR
 | |
|                  */
 | |
|                 if( tnr>=1 )
 | |
|                 {
 | |
|                     tr.ptr.p_double[0] = x0;
 | |
|                 }
 | |
|                 if( tnr>=2 )
 | |
|                 {
 | |
|                     tr.ptr.p_double[1] = x1;
 | |
|                 }
 | |
|                 if( tnr==3 )
 | |
|                 {
 | |
|                     tr.ptr.p_double[2] = x2;
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  *start root selection
 | |
|                  */
 | |
|                 if( *nr>0 )
 | |
|                 {
 | |
|                     if( ae_fp_neq(tmpr.ptr.p_double[*nr-1],x0) )
 | |
|                     {
 | |
|                         
 | |
|                         /*
 | |
|                          *previous segment was't constant identical zero
 | |
|                          */
 | |
|                         if( nstep )
 | |
|                         {
 | |
|                             for(j=0; j<=tnr-1; j++)
 | |
|                             {
 | |
|                                 tmpr.ptr.p_double[*nr+j] = tr.ptr.p_double[j];
 | |
|                             }
 | |
|                             *nr = *nr+tnr;
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             
 | |
|                             /*
 | |
|                              *previous segment was constant identical zero
 | |
|                              *and we must ignore [NR+j-1] root
 | |
|                              */
 | |
|                             for(j=1; j<=tnr-1; j++)
 | |
|                             {
 | |
|                                 tmpr.ptr.p_double[*nr+j-1] = tr.ptr.p_double[j];
 | |
|                             }
 | |
|                             *nr = *nr+tnr-1;
 | |
|                             nstep = ae_true;
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         for(j=1; j<=tnr-1; j++)
 | |
|                         {
 | |
|                             tmpr.ptr.p_double[*nr+j-1] = tr.ptr.p_double[j];
 | |
|                         }
 | |
|                         *nr = *nr+tnr-1;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      *write first root
 | |
|                      */
 | |
|                     for(j=0; j<=tnr-1; j++)
 | |
|                     {
 | |
|                         tmpr.ptr.p_double[*nr+j] = tr.ptr.p_double[j];
 | |
|                     }
 | |
|                     *nr = *nr+tnr;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( tnr==-1 )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      *decrement 'NR' if at previous step was writen a root
 | |
|                      *(previous segment identical zero)
 | |
|                      */
 | |
|                     if( *nr>0&&nstep )
 | |
|                     {
 | |
|                         *nr = *nr-1;
 | |
|                     }
 | |
|                     
 | |
|                     /*
 | |
|                      *previous segment is't constant
 | |
|                      */
 | |
|                     if( nstep )
 | |
|                     {
 | |
|                         nstep = ae_false;
 | |
|                     }
 | |
|                     
 | |
|                     /*
 | |
|                      *rewrite 'DR'
 | |
|                      */
 | |
|                     if( !*dr )
 | |
|                     {
 | |
|                         *dr = ae_true;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              *searching extremums
 | |
|              *write all term like extremums
 | |
|              */
 | |
|             if( tne==1 )
 | |
|             {
 | |
|                 if( *ne>0 )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      *just ignore identical extremums
 | |
|                      *because he must be one
 | |
|                      */
 | |
|                     if( ae_fp_neq(tmpc.ptr.p_double[*ne-2],ex0) )
 | |
|                     {
 | |
|                         tmpc.ptr.p_double[*ne] = ex0;
 | |
|                         tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]);
 | |
|                         *ne = *ne+2;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      *write first extremum and it function value
 | |
|                      */
 | |
|                     tmpc.ptr.p_double[*ne] = ex0;
 | |
|                     tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]);
 | |
|                     *ne = *ne+2;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( tne==2 )
 | |
|                 {
 | |
|                     if( *ne>0 )
 | |
|                     {
 | |
|                         
 | |
|                         /*
 | |
|                          *ignore identical extremum
 | |
|                          */
 | |
|                         if( ae_fp_neq(tmpc.ptr.p_double[*ne-2],ex0) )
 | |
|                         {
 | |
|                             tmpc.ptr.p_double[*ne] = ex0;
 | |
|                             tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]);
 | |
|                             *ne = *ne+2;
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         
 | |
|                         /*
 | |
|                          *write first extremum
 | |
|                          */
 | |
|                         tmpc.ptr.p_double[*ne] = ex0;
 | |
|                         tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i])*(ex0-c->x.ptr.p_double[i]);
 | |
|                         *ne = *ne+2;
 | |
|                     }
 | |
|                     
 | |
|                     /*
 | |
|                      *write second extremum
 | |
|                      */
 | |
|                     tmpc.ptr.p_double[*ne] = ex1;
 | |
|                     tmpc.ptr.p_double[*ne+1] = c->c.ptr.p_double[4*i]+c->c.ptr.p_double[4*i+1]*(ex1-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+2]*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i])+c->c.ptr.p_double[4*i+3]*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i])*(ex1-c->x.ptr.p_double[i]);
 | |
|                     *ne = *ne+2;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if( tne==-1 )
 | |
|                     {
 | |
|                         if( !*de )
 | |
|                         {
 | |
|                             *de = ae_true;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          *checking of arrays
 | |
|          *get number of extremums (tNe=NE/2)
 | |
|          *initialize pL as value F0(X[0]) and
 | |
|          *initialize pR as value Fn-1(X[N])
 | |
|          */
 | |
|         tne = *ne/2;
 | |
|         *ne = 0;
 | |
|         pl = c->c.ptr.p_double[0];
 | |
|         pr = c->c.ptr.p_double[4*(c->n-1)];
 | |
|         for(i=0; i<=tne-1; i++)
 | |
|         {
 | |
|             if( i>0&&i<tne-1 )
 | |
|             {
 | |
|                 if( ae_fp_greater(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i-1)+1])&&ae_fp_greater(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i+1)+1]) )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      *maximum
 | |
|                      */
 | |
|                     tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
 | |
|                     tmpet.ptr.p_int[*ne] = -1;
 | |
|                     *ne = *ne+1;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if( ae_fp_less(tmpc.ptr.p_double[2*i+1],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]) )
 | |
|                     {
 | |
|                         
 | |
|                         /*
 | |
|                          *minimum
 | |
|                          */
 | |
|                         tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
 | |
|                         tmpet.ptr.p_int[*ne] = 1;
 | |
|                         *ne = *ne+1;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( i==0 )
 | |
|                 {
 | |
|                     if( ae_fp_neq(tmpc.ptr.p_double[2*i],c->x.ptr.p_double[0]) )
 | |
|                     {
 | |
|                         if( ae_fp_greater(tmpc.ptr.p_double[2*i+1],pl)&&ae_fp_greater(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i+1)+1]) )
 | |
|                         {
 | |
|                             
 | |
|                             /*
 | |
|                              *maximum
 | |
|                              */
 | |
|                             tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
 | |
|                             tmpet.ptr.p_int[*ne] = -1;
 | |
|                             *ne = *ne+1;
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             if( ae_fp_less(tmpc.ptr.p_double[2*i+1],pl)&&ae_fp_less(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i+1)+1]) )
 | |
|                             {
 | |
|                                 
 | |
|                                 /*
 | |
|                                  *minimum
 | |
|                                  */
 | |
|                                 tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
 | |
|                                 tmpet.ptr.p_int[*ne] = 1;
 | |
|                                 *ne = *ne+1;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if( i==tne-1 )
 | |
|                     {
 | |
|                         if( ae_fp_neq(tmpc.ptr.p_double[2*i],c->x.ptr.p_double[c->n-1]) )
 | |
|                         {
 | |
|                             if( ae_fp_greater(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i-1)+1])&&ae_fp_greater(tmpc.ptr.p_double[2*i+1],pr) )
 | |
|                             {
 | |
|                                 
 | |
|                                 /*
 | |
|                                  *maximum
 | |
|                                  */
 | |
|                                 tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
 | |
|                                 tmpet.ptr.p_int[*ne] = -1;
 | |
|                                 *ne = *ne+1;
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 if( ae_fp_less(tmpc.ptr.p_double[2*i+1],tmpc.ptr.p_double[2*(i-1)+1])&&ae_fp_less(tmpc.ptr.p_double[2*i+1],pr) )
 | |
|                                 {
 | |
|                                     
 | |
|                                     /*
 | |
|                                      *minimum
 | |
|                                      */
 | |
|                                     tmpe.ptr.p_double[*ne] = tmpc.ptr.p_double[2*i];
 | |
|                                     tmpet.ptr.p_int[*ne] = 1;
 | |
|                                     *ne = *ne+1;
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          *final results
 | |
|          *allocate R, E, ET
 | |
|          */
 | |
|         rvectorsetlengthatleast(r, *nr, _state);
 | |
|         rvectorsetlengthatleast(e, *ne, _state);
 | |
|         ivectorsetlengthatleast(et, *ne, _state);
 | |
|         
 | |
|         /*
 | |
|          *write result for extremus and their types
 | |
|          */
 | |
|         for(i=0; i<=*ne-1; i++)
 | |
|         {
 | |
|             e->ptr.p_double[i] = tmpe.ptr.p_double[i];
 | |
|             et->ptr.p_int[i] = tmpet.ptr.p_int[i];
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          *write result for roots
 | |
|          */
 | |
|         for(i=0; i<=*nr-1; i++)
 | |
|         {
 | |
|             r->ptr.p_double[i] = tmpr.ptr.p_double[i];
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal subroutine. Heap sort.
 | |
| *************************************************************************/
 | |
| void heapsortdpoints(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* d,
 | |
|      ae_int_t n,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector rbuf;
 | |
|     ae_vector ibuf;
 | |
|     ae_vector rbuf2;
 | |
|     ae_vector ibuf2;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&rbuf, 0, sizeof(rbuf));
 | |
|     memset(&ibuf, 0, sizeof(ibuf));
 | |
|     memset(&rbuf2, 0, sizeof(rbuf2));
 | |
|     memset(&ibuf2, 0, sizeof(ibuf2));
 | |
|     ae_vector_init(&rbuf, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ibuf, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&rbuf2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ibuf2, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     ae_vector_set_length(&ibuf, n, _state);
 | |
|     ae_vector_set_length(&rbuf, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         ibuf.ptr.p_int[i] = i;
 | |
|     }
 | |
|     tagsortfasti(x, &ibuf, &rbuf2, &ibuf2, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         rbuf.ptr.p_double[i] = y->ptr.p_double[ibuf.ptr.p_int[i]];
 | |
|     }
 | |
|     ae_v_move(&y->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         rbuf.ptr.p_double[i] = d->ptr.p_double[ibuf.ptr.p_int[i]];
 | |
|     }
 | |
|     ae_v_move(&d->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This procedure search roots of an quadratic equation inside [0;1] and it number of roots.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P0   -   value of a function at 0
 | |
|     M0   -   value of a derivative at 0
 | |
|     P1   -   value of a function at 1
 | |
|     M1   -   value of a derivative at 1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X0   -  first root of an equation
 | |
|     X1   -  second root of an equation
 | |
|     NR   -  number of roots
 | |
|     
 | |
| RESTRICTIONS OF PARAMETERS:
 | |
| 
 | |
| Parameters for this procedure has't to be zero simultaneously. Is expected, 
 | |
| that input polinom is't degenerate or constant identicaly ZERO.
 | |
| 
 | |
| 
 | |
| REMARK:
 | |
| 
 | |
| The procedure always fill value for X1 and X2, even if it is't belongs to [0;1].
 | |
| But first true root(even if existing one) is in X1.
 | |
| Number of roots is NR.
 | |
| 
 | |
|  -- ALGLIB PROJECT --
 | |
|      Copyright 26.09.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void solvepolinom2(double p0,
 | |
|      double m0,
 | |
|      double p1,
 | |
|      double m1,
 | |
|      double* x0,
 | |
|      double* x1,
 | |
|      ae_int_t* nr,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double a;
 | |
|     double b;
 | |
|     double c;
 | |
|     double dd;
 | |
|     double tmp;
 | |
|     double exf;
 | |
|     double extr;
 | |
| 
 | |
|     *x0 = 0;
 | |
|     *x1 = 0;
 | |
|     *nr = 0;
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      *calculate parameters for equation: A, B  and C
 | |
|      */
 | |
|     a = 6*p0+3*m0-6*p1+3*m1;
 | |
|     b = -6*p0-4*m0+6*p1-2*m1;
 | |
|     c = m0;
 | |
|     
 | |
|     /*
 | |
|      *check case, when A=0
 | |
|      *we are considering the linear equation
 | |
|      */
 | |
|     if( ae_fp_eq(a,(double)(0)) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          *B<>0 and root inside [0;1]
 | |
|          *one root
 | |
|          */
 | |
|         if( (ae_fp_neq(b,(double)(0))&&ae_sign(c, _state)*ae_sign(b, _state)<=0)&&ae_fp_greater_eq(ae_fabs(b, _state),ae_fabs(c, _state)) )
 | |
|         {
 | |
|             *x0 = -c/b;
 | |
|             *nr = 1;
 | |
|             return;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             *nr = 0;
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      *consider case, when extremumu outside (0;1)
 | |
|      *exist one root only
 | |
|      */
 | |
|     if( ae_fp_less_eq(ae_fabs(2*a, _state),ae_fabs(b, _state))||ae_sign(b, _state)*ae_sign(a, _state)>=0 )
 | |
|     {
 | |
|         if( ae_sign(m0, _state)*ae_sign(m1, _state)>0 )
 | |
|         {
 | |
|             *nr = 0;
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          *consider case, when the one exist
 | |
|          *same sign of derivative
 | |
|          */
 | |
|         if( ae_sign(m0, _state)*ae_sign(m1, _state)<0 )
 | |
|         {
 | |
|             *nr = 1;
 | |
|             extr = -b/(2*a);
 | |
|             dd = b*b-4*a*c;
 | |
|             if( ae_fp_less(dd,(double)(0)) )
 | |
|             {
 | |
|                 return;
 | |
|             }
 | |
|             *x0 = (-b-ae_sqrt(dd, _state))/(2*a);
 | |
|             *x1 = (-b+ae_sqrt(dd, _state))/(2*a);
 | |
|             if( (ae_fp_greater_eq(extr,(double)(1))&&ae_fp_less_eq(*x1,extr))||(ae_fp_less_eq(extr,(double)(0))&&ae_fp_greater_eq(*x1,extr)) )
 | |
|             {
 | |
|                 *x0 = *x1;
 | |
|             }
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          *consider case, when the one is 0
 | |
|          */
 | |
|         if( ae_fp_eq(m0,(double)(0)) )
 | |
|         {
 | |
|             *x0 = (double)(0);
 | |
|             *nr = 1;
 | |
|             return;
 | |
|         }
 | |
|         if( ae_fp_eq(m1,(double)(0)) )
 | |
|         {
 | |
|             *x0 = (double)(1);
 | |
|             *nr = 1;
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          *consider case, when both of derivatives is 0
 | |
|          */
 | |
|         if( ae_fp_eq(m0,(double)(0))&&ae_fp_eq(m1,(double)(0)) )
 | |
|         {
 | |
|             *x0 = (double)(0);
 | |
|             *x1 = (double)(1);
 | |
|             *nr = 2;
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          *consider case, when derivative at 0 is 0, and derivative at 1 is't 0
 | |
|          */
 | |
|         if( ae_fp_eq(m0,(double)(0))&&ae_fp_neq(m1,(double)(0)) )
 | |
|         {
 | |
|             dd = b*b-4*a*c;
 | |
|             if( ae_fp_less(dd,(double)(0)) )
 | |
|             {
 | |
|                 *x0 = (double)(0);
 | |
|                 *nr = 1;
 | |
|                 return;
 | |
|             }
 | |
|             *x0 = (-b-ae_sqrt(dd, _state))/(2*a);
 | |
|             *x1 = (-b+ae_sqrt(dd, _state))/(2*a);
 | |
|             extr = -b/(2*a);
 | |
|             exf = a*extr*extr+b*extr+c;
 | |
|             if( ae_sign(exf, _state)*ae_sign(m1, _state)>0 )
 | |
|             {
 | |
|                 *x0 = (double)(0);
 | |
|                 *nr = 1;
 | |
|                 return;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( ae_fp_greater(extr,*x0) )
 | |
|                 {
 | |
|                     *x0 = (double)(0);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     *x1 = (double)(0);
 | |
|                 }
 | |
|                 *nr = 2;
 | |
|                 
 | |
|                 /*
 | |
|                  *roots must placed ascending
 | |
|                  */
 | |
|                 if( ae_fp_greater(*x0,*x1) )
 | |
|                 {
 | |
|                     tmp = *x0;
 | |
|                     *x0 = *x1;
 | |
|                     *x1 = tmp;
 | |
|                 }
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
|         if( ae_fp_eq(m1,(double)(0))&&ae_fp_neq(m0,(double)(0)) )
 | |
|         {
 | |
|             dd = b*b-4*a*c;
 | |
|             if( ae_fp_less(dd,(double)(0)) )
 | |
|             {
 | |
|                 *x0 = (double)(1);
 | |
|                 *nr = 1;
 | |
|                 return;
 | |
|             }
 | |
|             *x0 = (-b-ae_sqrt(dd, _state))/(2*a);
 | |
|             *x1 = (-b+ae_sqrt(dd, _state))/(2*a);
 | |
|             extr = -b/(2*a);
 | |
|             exf = a*extr*extr+b*extr+c;
 | |
|             if( ae_sign(exf, _state)*ae_sign(m0, _state)>0 )
 | |
|             {
 | |
|                 *x0 = (double)(1);
 | |
|                 *nr = 1;
 | |
|                 return;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( ae_fp_less(extr,*x0) )
 | |
|                 {
 | |
|                     *x0 = (double)(1);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     *x1 = (double)(1);
 | |
|                 }
 | |
|                 *nr = 2;
 | |
|                 
 | |
|                 /*
 | |
|                  *roots must placed ascending
 | |
|                  */
 | |
|                 if( ae_fp_greater(*x0,*x1) )
 | |
|                 {
 | |
|                     tmp = *x0;
 | |
|                     *x0 = *x1;
 | |
|                     *x1 = tmp;
 | |
|                 }
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             extr = -b/(2*a);
 | |
|             exf = a*extr*extr+b*extr+c;
 | |
|             if( ae_sign(exf, _state)*ae_sign(m0, _state)>0&&ae_sign(exf, _state)*ae_sign(m1, _state)>0 )
 | |
|             {
 | |
|                 *nr = 0;
 | |
|                 return;
 | |
|             }
 | |
|             dd = b*b-4*a*c;
 | |
|             if( ae_fp_less(dd,(double)(0)) )
 | |
|             {
 | |
|                 *nr = 0;
 | |
|                 return;
 | |
|             }
 | |
|             *x0 = (-b-ae_sqrt(dd, _state))/(2*a);
 | |
|             *x1 = (-b+ae_sqrt(dd, _state))/(2*a);
 | |
|             
 | |
|             /*
 | |
|              *if EXF and m0, EXF and m1 has different signs, then equation has two roots              
 | |
|              */
 | |
|             if( ae_sign(exf, _state)*ae_sign(m0, _state)<0&&ae_sign(exf, _state)*ae_sign(m1, _state)<0 )
 | |
|             {
 | |
|                 *nr = 2;
 | |
|                 
 | |
|                 /*
 | |
|                  *roots must placed ascending
 | |
|                  */
 | |
|                 if( ae_fp_greater(*x0,*x1) )
 | |
|                 {
 | |
|                     tmp = *x0;
 | |
|                     *x0 = *x1;
 | |
|                     *x1 = tmp;
 | |
|                 }
 | |
|                 return;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 *nr = 1;
 | |
|                 if( ae_sign(exf, _state)*ae_sign(m0, _state)<0 )
 | |
|                 {
 | |
|                     if( ae_fp_less(*x1,extr) )
 | |
|                     {
 | |
|                         *x0 = *x1;
 | |
|                     }
 | |
|                     return;
 | |
|                 }
 | |
|                 if( ae_sign(exf, _state)*ae_sign(m1, _state)<0 )
 | |
|                 {
 | |
|                     if( ae_fp_greater(*x1,extr) )
 | |
|                     {
 | |
|                         *x0 = *x1;
 | |
|                     }
 | |
|                     return;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This procedure search roots of an cubic equation inside [A;B], it number of roots 
 | |
| and number of extremums.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     pA   -   value of a function at A
 | |
|     mA   -   value of a derivative at A
 | |
|     pB   -   value of a function at B
 | |
|     mB   -   value of a derivative at B
 | |
|     A0   -   left border [A0;B0]
 | |
|     B0   -   right border [A0;B0]
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X0   -  first root of an equation
 | |
|     X1   -  second root of an equation
 | |
|     X2   -  third root of an equation
 | |
|     EX0  -  first extremum of a function
 | |
|     EX0  -  second extremum of a function
 | |
|     NR   -  number of roots
 | |
|     NR   -  number of extrmums
 | |
|     
 | |
| RESTRICTIONS OF PARAMETERS:
 | |
| 
 | |
| Length of [A;B] must be positive and is't zero, i.e. A<>B and A<B.
 | |
| 
 | |
| 
 | |
| REMARK:
 | |
| 
 | |
| If 'NR' is -1 it's mean, than polinom has infiniti roots.
 | |
| If 'NE' is -1 it's mean, than polinom has infiniti extremums.
 | |
| 
 | |
|  -- ALGLIB PROJECT --
 | |
|      Copyright 26.09.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void solvecubicpolinom(double pa,
 | |
|      double ma,
 | |
|      double pb,
 | |
|      double mb,
 | |
|      double a,
 | |
|      double b,
 | |
|      double* x0,
 | |
|      double* x1,
 | |
|      double* x2,
 | |
|      double* ex0,
 | |
|      double* ex1,
 | |
|      ae_int_t* nr,
 | |
|      ae_int_t* ne,
 | |
|      /* Real    */ ae_vector* tempdata,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     double tmpma;
 | |
|     double tmpmb;
 | |
|     double tex0;
 | |
|     double tex1;
 | |
| 
 | |
|     *x0 = 0;
 | |
|     *x1 = 0;
 | |
|     *x2 = 0;
 | |
|     *ex0 = 0;
 | |
|     *ex1 = 0;
 | |
|     *nr = 0;
 | |
|     *ne = 0;
 | |
| 
 | |
|     rvectorsetlengthatleast(tempdata, 3, _state);
 | |
|     
 | |
|     /*
 | |
|      *case, when A>B
 | |
|      */
 | |
|     ae_assert(ae_fp_less(a,b), "\nSolveCubicPolinom: incorrect borders for [A;B]!\n", _state);
 | |
|     
 | |
|     /*
 | |
|      *case 1    
 | |
|      *function can be identicaly to ZERO
 | |
|      */
 | |
|     if( ((ae_fp_eq(ma,(double)(0))&&ae_fp_eq(mb,(double)(0)))&&ae_fp_eq(pa,pb))&&ae_fp_eq(pa,(double)(0)) )
 | |
|     {
 | |
|         *nr = -1;
 | |
|         *ne = -1;
 | |
|         return;
 | |
|     }
 | |
|     if( (ae_fp_eq(ma,(double)(0))&&ae_fp_eq(mb,(double)(0)))&&ae_fp_eq(pa,pb) )
 | |
|     {
 | |
|         *nr = 0;
 | |
|         *ne = -1;
 | |
|         return;
 | |
|     }
 | |
|     tmpma = ma*(b-a);
 | |
|     tmpmb = mb*(b-a);
 | |
|     solvepolinom2(pa, tmpma, pb, tmpmb, ex0, ex1, ne, _state);
 | |
|     *ex0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *ex0, _state);
 | |
|     *ex1 = spline1d_rescaleval((double)(0), (double)(1), a, b, *ex1, _state);
 | |
|     
 | |
|     /*
 | |
|      *case 3.1
 | |
|      *no extremums at [A;B]
 | |
|      */
 | |
|     if( *ne==0 )
 | |
|     {
 | |
|         *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state);
 | |
|         if( *nr==1 )
 | |
|         {
 | |
|             *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state);
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      *case 3.2
 | |
|      *one extremum
 | |
|      */
 | |
|     if( *ne==1 )
 | |
|     {
 | |
|         if( ae_fp_eq(*ex0,a)||ae_fp_eq(*ex0,b) )
 | |
|         {
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state);
 | |
|             if( *nr==1 )
 | |
|             {
 | |
|                 *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state);
 | |
|             }
 | |
|             return;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             *nr = 0;
 | |
|             i = 0;
 | |
|             tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state);
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr);
 | |
|             if( *nr>i )
 | |
|             {
 | |
|                 tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state);
 | |
|                 i = i+1;
 | |
|             }
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, (double)(1), x0, _state)+(*nr);
 | |
|             if( *nr>i )
 | |
|             {
 | |
|                 *x0 = spline1d_rescaleval(tex0, (double)(1), *ex0, b, *x0, _state);
 | |
|                 if( i>0 )
 | |
|                 {
 | |
|                     if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) )
 | |
|                     {
 | |
|                         tempdata->ptr.p_double[i] = *x0;
 | |
|                         i = i+1;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         *nr = *nr-1;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     tempdata->ptr.p_double[i] = *x0;
 | |
|                     i = i+1;
 | |
|                 }
 | |
|             }
 | |
|             if( *nr>0 )
 | |
|             {
 | |
|                 *x0 = tempdata->ptr.p_double[0];
 | |
|                 if( *nr>1 )
 | |
|                 {
 | |
|                     *x1 = tempdata->ptr.p_double[1];
 | |
|                 }
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          *case 3.3
 | |
|          *two extremums(or more, but it's impossible)
 | |
|          *
 | |
|          *
 | |
|          *case 3.3.0
 | |
|          *both extremums at the border
 | |
|          */
 | |
|         if( ae_fp_eq(*ex0,a)&&ae_fp_eq(*ex1,b) )
 | |
|         {
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), (double)(1), x0, _state);
 | |
|             if( *nr==1 )
 | |
|             {
 | |
|                 *x0 = spline1d_rescaleval((double)(0), (double)(1), a, b, *x0, _state);
 | |
|             }
 | |
|             return;
 | |
|         }
 | |
|         if( ae_fp_eq(*ex0,a)&&ae_fp_neq(*ex1,b) )
 | |
|         {
 | |
|             *nr = 0;
 | |
|             i = 0;
 | |
|             tex1 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex1, _state);
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex1, x0, _state)+(*nr);
 | |
|             if( *nr>i )
 | |
|             {
 | |
|                 tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex1, a, *ex1, *x0, _state);
 | |
|                 i = i+1;
 | |
|             }
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex1, (double)(1), x0, _state)+(*nr);
 | |
|             if( *nr>i )
 | |
|             {
 | |
|                 *x0 = spline1d_rescaleval(tex1, (double)(1), *ex1, b, *x0, _state);
 | |
|                 if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) )
 | |
|                 {
 | |
|                     tempdata->ptr.p_double[i] = *x0;
 | |
|                     i = i+1;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     *nr = *nr-1;
 | |
|                 }
 | |
|             }
 | |
|             if( *nr>0 )
 | |
|             {
 | |
|                 *x0 = tempdata->ptr.p_double[0];
 | |
|                 if( *nr>1 )
 | |
|                 {
 | |
|                     *x1 = tempdata->ptr.p_double[1];
 | |
|                 }
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
|         if( ae_fp_eq(*ex1,b)&&ae_fp_neq(*ex0,a) )
 | |
|         {
 | |
|             *nr = 0;
 | |
|             i = 0;
 | |
|             tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state);
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr);
 | |
|             if( *nr>i )
 | |
|             {
 | |
|                 tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state);
 | |
|                 i = i+1;
 | |
|             }
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, (double)(1), x0, _state)+(*nr);
 | |
|             if( *nr>i )
 | |
|             {
 | |
|                 *x0 = spline1d_rescaleval(tex0, (double)(1), *ex0, b, *x0, _state);
 | |
|                 if( i>0 )
 | |
|                 {
 | |
|                     if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) )
 | |
|                     {
 | |
|                         tempdata->ptr.p_double[i] = *x0;
 | |
|                         i = i+1;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         *nr = *nr-1;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     tempdata->ptr.p_double[i] = *x0;
 | |
|                     i = i+1;
 | |
|                 }
 | |
|             }
 | |
|             if( *nr>0 )
 | |
|             {
 | |
|                 *x0 = tempdata->ptr.p_double[0];
 | |
|                 if( *nr>1 )
 | |
|                 {
 | |
|                     *x1 = tempdata->ptr.p_double[1];
 | |
|                 }
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              *case 3.3.2
 | |
|              *both extremums inside (0;1)
 | |
|              */
 | |
|             *nr = 0;
 | |
|             i = 0;
 | |
|             tex0 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex0, _state);
 | |
|             tex1 = spline1d_rescaleval(a, b, (double)(0), (double)(1), *ex1, _state);
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, (double)(0), tex0, x0, _state)+(*nr);
 | |
|             if( *nr>i )
 | |
|             {
 | |
|                 tempdata->ptr.p_double[i] = spline1d_rescaleval((double)(0), tex0, a, *ex0, *x0, _state);
 | |
|                 i = i+1;
 | |
|             }
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex0, tex1, x0, _state)+(*nr);
 | |
|             if( *nr>i )
 | |
|             {
 | |
|                 *x0 = spline1d_rescaleval(tex0, tex1, *ex0, *ex1, *x0, _state);
 | |
|                 if( i>0 )
 | |
|                 {
 | |
|                     if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) )
 | |
|                     {
 | |
|                         tempdata->ptr.p_double[i] = *x0;
 | |
|                         i = i+1;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         *nr = *nr-1;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     tempdata->ptr.p_double[i] = *x0;
 | |
|                     i = i+1;
 | |
|                 }
 | |
|             }
 | |
|             *nr = bisectmethod(pa, tmpma, pb, tmpmb, tex1, (double)(1), x0, _state)+(*nr);
 | |
|             if( *nr>i )
 | |
|             {
 | |
|                 *x0 = spline1d_rescaleval(tex1, (double)(1), *ex1, b, *x0, _state);
 | |
|                 if( i>0 )
 | |
|                 {
 | |
|                     if( ae_fp_neq(*x0,tempdata->ptr.p_double[i-1]) )
 | |
|                     {
 | |
|                         tempdata->ptr.p_double[i] = *x0;
 | |
|                         i = i+1;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         *nr = *nr-1;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     tempdata->ptr.p_double[i] = *x0;
 | |
|                     i = i+1;
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              *write are found roots
 | |
|              */
 | |
|             if( *nr>0 )
 | |
|             {
 | |
|                 *x0 = tempdata->ptr.p_double[0];
 | |
|                 if( *nr>1 )
 | |
|                 {
 | |
|                     *x1 = tempdata->ptr.p_double[1];
 | |
|                 }
 | |
|                 if( *nr>2 )
 | |
|                 {
 | |
|                     *x2 = tempdata->ptr.p_double[2];
 | |
|                 }
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Function for searching a root at [A;B] by bisection method and return number of roots
 | |
| (0 or 1)
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     pA   -   value of a function at A
 | |
|     mA   -   value of a derivative at A
 | |
|     pB   -   value of a function at B
 | |
|     mB   -   value of a derivative at B
 | |
|     A0   -   left border [A0;B0] 
 | |
|     B0   -   right border [A0;B0]
 | |
|     
 | |
| RESTRICTIONS OF PARAMETERS:
 | |
| 
 | |
| We assume, that B0>A0.
 | |
| 
 | |
| 
 | |
| REMARK:
 | |
| 
 | |
| Assume, that exist one root only at [A;B], else 
 | |
| function may be work incorrectly.
 | |
| The function dont check value A0,B0!
 | |
| 
 | |
|  -- ALGLIB PROJECT --
 | |
|      Copyright 26.09.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| ae_int_t bisectmethod(double pa,
 | |
|      double ma,
 | |
|      double pb,
 | |
|      double mb,
 | |
|      double a,
 | |
|      double b,
 | |
|      double* x,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double vacuum;
 | |
|     double eps;
 | |
|     double a0;
 | |
|     double b0;
 | |
|     double m;
 | |
|     double lf;
 | |
|     double rf;
 | |
|     double mf;
 | |
|     ae_int_t result;
 | |
| 
 | |
|     *x = 0;
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      *accuracy
 | |
|      */
 | |
|     eps = 1000*(b-a)*ae_machineepsilon;
 | |
|     
 | |
|     /*
 | |
|      *initialization left and right borders
 | |
|      */
 | |
|     a0 = a;
 | |
|     b0 = b;
 | |
|     
 | |
|     /*
 | |
|      *initialize function value at 'A' and 'B'
 | |
|      */
 | |
|     spline1d_hermitecalc(pa, ma, pb, mb, a, &lf, &vacuum, _state);
 | |
|     spline1d_hermitecalc(pa, ma, pb, mb, b, &rf, &vacuum, _state);
 | |
|     
 | |
|     /*
 | |
|      *check, that 'A' and 'B' are't roots,
 | |
|      *and that root exist
 | |
|      */
 | |
|     if( ae_sign(lf, _state)*ae_sign(rf, _state)>0 )
 | |
|     {
 | |
|         result = 0;
 | |
|         return result;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         if( ae_fp_eq(lf,(double)(0)) )
 | |
|         {
 | |
|             *x = a;
 | |
|             result = 1;
 | |
|             return result;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if( ae_fp_eq(rf,(double)(0)) )
 | |
|             {
 | |
|                 *x = b;
 | |
|                 result = 1;
 | |
|                 return result;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      *searching a root
 | |
|      */
 | |
|     do
 | |
|     {
 | |
|         m = (b0+a0)/2;
 | |
|         spline1d_hermitecalc(pa, ma, pb, mb, a0, &lf, &vacuum, _state);
 | |
|         spline1d_hermitecalc(pa, ma, pb, mb, b0, &rf, &vacuum, _state);
 | |
|         spline1d_hermitecalc(pa, ma, pb, mb, m, &mf, &vacuum, _state);
 | |
|         if( ae_sign(mf, _state)*ae_sign(lf, _state)<0 )
 | |
|         {
 | |
|             b0 = m;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if( ae_sign(mf, _state)*ae_sign(rf, _state)<0 )
 | |
|             {
 | |
|                 a0 = m;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( ae_fp_eq(lf,(double)(0)) )
 | |
|                 {
 | |
|                     *x = a0;
 | |
|                     result = 1;
 | |
|                     return result;
 | |
|                 }
 | |
|                 if( ae_fp_eq(rf,(double)(0)) )
 | |
|                 {
 | |
|                     *x = b0;
 | |
|                     result = 1;
 | |
|                     return result;
 | |
|                 }
 | |
|                 if( ae_fp_eq(mf,(double)(0)) )
 | |
|                 {
 | |
|                     *x = m;
 | |
|                     result = 1;
 | |
|                     return result;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     while(ae_fp_greater_eq(ae_fabs(b0-a0, _state),eps));
 | |
|     *x = m;
 | |
|     result = 1;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function builds monotone cubic Hermite interpolant. This interpolant
 | |
| is monotonic in [x(0),x(n-1)] and is constant outside of this interval.
 | |
| 
 | |
| In  case  y[]  form  non-monotonic  sequence,  interpolant  is  piecewise
 | |
| monotonic.  Say, for x=(0,1,2,3,4)  and  y=(0,1,2,1,0)  interpolant  will
 | |
| monotonically grow at [0..2] and monotonically decrease at [2..4].
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X           -   spline nodes, array[0..N-1]. Subroutine automatically
 | |
|                     sorts points, so caller may pass unsorted array.
 | |
|     Y           -   function values, array[0..N-1]
 | |
|     N           -   the number of points(N>=2).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C           -   spline interpolant.
 | |
| 
 | |
|  -- ALGLIB PROJECT --
 | |
|      Copyright 21.06.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dbuildmonotone(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      spline1dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector d;
 | |
|     ae_vector ex;
 | |
|     ae_vector ey;
 | |
|     ae_vector p;
 | |
|     double delta;
 | |
|     double alpha;
 | |
|     double beta;
 | |
|     ae_int_t tmpn;
 | |
|     ae_int_t sn;
 | |
|     double ca;
 | |
|     double cb;
 | |
|     double epsilon;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&d, 0, sizeof(d));
 | |
|     memset(&ex, 0, sizeof(ex));
 | |
|     memset(&ey, 0, sizeof(ey));
 | |
|     memset(&p, 0, sizeof(p));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     _spline1dinterpolant_clear(c);
 | |
|     ae_vector_init(&d, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ex, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ey, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Check lengths of arguments
 | |
|      */
 | |
|     ae_assert(n>=2, "Spline1DBuildMonotone: N<2", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DBuildMonotone: Length(X)<N", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DBuildMonotone: Length(Y)<N", _state);
 | |
|     
 | |
|     /*
 | |
|      * Check and sort points
 | |
|      */
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DBuildMonotone: X contains infinite or NAN values", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DBuildMonotone: Y contains infinite or NAN values", _state);
 | |
|     spline1d_heapsortppoints(x, y, &p, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "Spline1DBuildMonotone: at least two consequent points are too close", _state);
 | |
|     epsilon = ae_machineepsilon;
 | |
|     n = n+2;
 | |
|     ae_vector_set_length(&d, n, _state);
 | |
|     ae_vector_set_length(&ex, n, _state);
 | |
|     ae_vector_set_length(&ey, n, _state);
 | |
|     ex.ptr.p_double[0] = x->ptr.p_double[0]-ae_fabs(x->ptr.p_double[1]-x->ptr.p_double[0], _state);
 | |
|     ex.ptr.p_double[n-1] = x->ptr.p_double[n-3]+ae_fabs(x->ptr.p_double[n-3]-x->ptr.p_double[n-4], _state);
 | |
|     ey.ptr.p_double[0] = y->ptr.p_double[0];
 | |
|     ey.ptr.p_double[n-1] = y->ptr.p_double[n-3];
 | |
|     for(i=1; i<=n-2; i++)
 | |
|     {
 | |
|         ex.ptr.p_double[i] = x->ptr.p_double[i-1];
 | |
|         ey.ptr.p_double[i] = y->ptr.p_double[i-1];
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Init sign of the function for first segment
 | |
|      */
 | |
|     i = 0;
 | |
|     ca = (double)(0);
 | |
|     do
 | |
|     {
 | |
|         ca = ey.ptr.p_double[i+1]-ey.ptr.p_double[i];
 | |
|         i = i+1;
 | |
|     }
 | |
|     while(!(ae_fp_neq(ca,(double)(0))||i>n-2));
 | |
|     if( ae_fp_neq(ca,(double)(0)) )
 | |
|     {
 | |
|         ca = ca/ae_fabs(ca, _state);
 | |
|     }
 | |
|     i = 0;
 | |
|     while(i<n-1)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Partition of the segment [X0;Xn]
 | |
|          */
 | |
|         tmpn = 1;
 | |
|         for(j=i; j<=n-2; j++)
 | |
|         {
 | |
|             cb = ey.ptr.p_double[j+1]-ey.ptr.p_double[j];
 | |
|             if( ae_fp_greater_eq(ca*cb,(double)(0)) )
 | |
|             {
 | |
|                 tmpn = tmpn+1;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ca = cb/ae_fabs(cb, _state);
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         sn = i+tmpn;
 | |
|         ae_assert(tmpn>=2, "Spline1DBuildMonotone: internal error", _state);
 | |
|         
 | |
|         /*
 | |
|          * Calculate derivatives for current segment
 | |
|          */
 | |
|         d.ptr.p_double[i] = (double)(0);
 | |
|         d.ptr.p_double[sn-1] = (double)(0);
 | |
|         for(j=i+1; j<=sn-2; j++)
 | |
|         {
 | |
|             d.ptr.p_double[j] = ((ey.ptr.p_double[j]-ey.ptr.p_double[j-1])/(ex.ptr.p_double[j]-ex.ptr.p_double[j-1])+(ey.ptr.p_double[j+1]-ey.ptr.p_double[j])/(ex.ptr.p_double[j+1]-ex.ptr.p_double[j]))/2;
 | |
|         }
 | |
|         for(j=i; j<=sn-2; j++)
 | |
|         {
 | |
|             delta = (ey.ptr.p_double[j+1]-ey.ptr.p_double[j])/(ex.ptr.p_double[j+1]-ex.ptr.p_double[j]);
 | |
|             if( ae_fp_less_eq(ae_fabs(delta, _state),epsilon) )
 | |
|             {
 | |
|                 d.ptr.p_double[j] = (double)(0);
 | |
|                 d.ptr.p_double[j+1] = (double)(0);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 alpha = d.ptr.p_double[j]/delta;
 | |
|                 beta = d.ptr.p_double[j+1]/delta;
 | |
|                 if( ae_fp_neq(alpha,(double)(0)) )
 | |
|                 {
 | |
|                     cb = alpha*ae_sqrt(1+ae_sqr(beta/alpha, _state), _state);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if( ae_fp_neq(beta,(double)(0)) )
 | |
|                     {
 | |
|                         cb = beta;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                 }
 | |
|                 if( ae_fp_greater(cb,(double)(3)) )
 | |
|                 {
 | |
|                     d.ptr.p_double[j] = 3*alpha*delta/cb;
 | |
|                     d.ptr.p_double[j+1] = 3*beta*delta/cb;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Transition to next segment
 | |
|          */
 | |
|         i = sn-1;
 | |
|     }
 | |
|     spline1dbuildhermite(&ex, &ey, &d, n, c, _state);
 | |
|     c->continuity = 2;
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal version of Spline1DGridDiffCubic.
 | |
| 
 | |
| Accepts pre-ordered X/Y, temporary arrays (which may be  preallocated,  if
 | |
| you want to save time, or not) and output array (which may be preallocated
 | |
| too).
 | |
| 
 | |
| Y is passed as var-parameter because we may need to force last element  to
 | |
| be equal to the first one (if periodic boundary conditions are specified).
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 03.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline1d_spline1dgriddiffcubicinternal(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t boundltype,
 | |
|      double boundl,
 | |
|      ae_int_t boundrtype,
 | |
|      double boundr,
 | |
|      /* Real    */ ae_vector* d,
 | |
|      /* Real    */ ae_vector* a1,
 | |
|      /* Real    */ ae_vector* a2,
 | |
|      /* Real    */ ae_vector* a3,
 | |
|      /* Real    */ ae_vector* b,
 | |
|      /* Real    */ ae_vector* dt,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * allocate arrays
 | |
|      */
 | |
|     if( d->cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(d, n, _state);
 | |
|     }
 | |
|     if( a1->cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(a1, n, _state);
 | |
|     }
 | |
|     if( a2->cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(a2, n, _state);
 | |
|     }
 | |
|     if( a3->cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(a3, n, _state);
 | |
|     }
 | |
|     if( b->cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(b, n, _state);
 | |
|     }
 | |
|     if( dt->cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(dt, n, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Special cases:
 | |
|      * * N=2, parabolic terminated boundary condition on both ends
 | |
|      * * N=2, periodic boundary condition
 | |
|      */
 | |
|     if( (n==2&&boundltype==0)&&boundrtype==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]);
 | |
|         d->ptr.p_double[1] = d->ptr.p_double[0];
 | |
|         return;
 | |
|     }
 | |
|     if( (n==2&&boundltype==-1)&&boundrtype==-1 )
 | |
|     {
 | |
|         d->ptr.p_double[0] = (double)(0);
 | |
|         d->ptr.p_double[1] = (double)(0);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Periodic and non-periodic boundary conditions are
 | |
|      * two separate classes
 | |
|      */
 | |
|     if( boundrtype==-1&&boundltype==-1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Periodic boundary conditions
 | |
|          */
 | |
|         y->ptr.p_double[n-1] = y->ptr.p_double[0];
 | |
|         
 | |
|         /*
 | |
|          * Boundary conditions at N-1 points
 | |
|          * (one point less because last point is the same as first point).
 | |
|          */
 | |
|         a1->ptr.p_double[0] = x->ptr.p_double[1]-x->ptr.p_double[0];
 | |
|         a2->ptr.p_double[0] = 2*(x->ptr.p_double[1]-x->ptr.p_double[0]+x->ptr.p_double[n-1]-x->ptr.p_double[n-2]);
 | |
|         a3->ptr.p_double[0] = x->ptr.p_double[n-1]-x->ptr.p_double[n-2];
 | |
|         b->ptr.p_double[0] = 3*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])*(x->ptr.p_double[1]-x->ptr.p_double[0])+3*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])*(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]);
 | |
|         for(i=1; i<=n-2; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Altough last point is [N-2], we use X[N-1] and Y[N-1]
 | |
|              * (because of periodicity)
 | |
|              */
 | |
|             a1->ptr.p_double[i] = x->ptr.p_double[i+1]-x->ptr.p_double[i];
 | |
|             a2->ptr.p_double[i] = 2*(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]);
 | |
|             a3->ptr.p_double[i] = x->ptr.p_double[i]-x->ptr.p_double[i-1];
 | |
|             b->ptr.p_double[i] = 3*(y->ptr.p_double[i]-y->ptr.p_double[i-1])/(x->ptr.p_double[i]-x->ptr.p_double[i-1])*(x->ptr.p_double[i+1]-x->ptr.p_double[i])+3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i])*(x->ptr.p_double[i]-x->ptr.p_double[i-1]);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Solve, add last point (with index N-1)
 | |
|          */
 | |
|         spline1d_solvecyclictridiagonal(a1, a2, a3, b, n-1, dt, _state);
 | |
|         ae_v_move(&d->ptr.p_double[0], 1, &dt->ptr.p_double[0], 1, ae_v_len(0,n-2));
 | |
|         d->ptr.p_double[n-1] = d->ptr.p_double[0];
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Non-periodic boundary condition.
 | |
|          * Left boundary conditions.
 | |
|          */
 | |
|         if( boundltype==0 )
 | |
|         {
 | |
|             a1->ptr.p_double[0] = (double)(0);
 | |
|             a2->ptr.p_double[0] = (double)(1);
 | |
|             a3->ptr.p_double[0] = (double)(1);
 | |
|             b->ptr.p_double[0] = 2*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0]);
 | |
|         }
 | |
|         if( boundltype==1 )
 | |
|         {
 | |
|             a1->ptr.p_double[0] = (double)(0);
 | |
|             a2->ptr.p_double[0] = (double)(1);
 | |
|             a3->ptr.p_double[0] = (double)(0);
 | |
|             b->ptr.p_double[0] = boundl;
 | |
|         }
 | |
|         if( boundltype==2 )
 | |
|         {
 | |
|             a1->ptr.p_double[0] = (double)(0);
 | |
|             a2->ptr.p_double[0] = (double)(2);
 | |
|             a3->ptr.p_double[0] = (double)(1);
 | |
|             b->ptr.p_double[0] = 3*(y->ptr.p_double[1]-y->ptr.p_double[0])/(x->ptr.p_double[1]-x->ptr.p_double[0])-0.5*boundl*(x->ptr.p_double[1]-x->ptr.p_double[0]);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Central conditions
 | |
|          */
 | |
|         for(i=1; i<=n-2; i++)
 | |
|         {
 | |
|             a1->ptr.p_double[i] = x->ptr.p_double[i+1]-x->ptr.p_double[i];
 | |
|             a2->ptr.p_double[i] = 2*(x->ptr.p_double[i+1]-x->ptr.p_double[i-1]);
 | |
|             a3->ptr.p_double[i] = x->ptr.p_double[i]-x->ptr.p_double[i-1];
 | |
|             b->ptr.p_double[i] = 3*(y->ptr.p_double[i]-y->ptr.p_double[i-1])/(x->ptr.p_double[i]-x->ptr.p_double[i-1])*(x->ptr.p_double[i+1]-x->ptr.p_double[i])+3*(y->ptr.p_double[i+1]-y->ptr.p_double[i])/(x->ptr.p_double[i+1]-x->ptr.p_double[i])*(x->ptr.p_double[i]-x->ptr.p_double[i-1]);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Right boundary conditions
 | |
|          */
 | |
|         if( boundrtype==0 )
 | |
|         {
 | |
|             a1->ptr.p_double[n-1] = (double)(1);
 | |
|             a2->ptr.p_double[n-1] = (double)(1);
 | |
|             a3->ptr.p_double[n-1] = (double)(0);
 | |
|             b->ptr.p_double[n-1] = 2*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]);
 | |
|         }
 | |
|         if( boundrtype==1 )
 | |
|         {
 | |
|             a1->ptr.p_double[n-1] = (double)(0);
 | |
|             a2->ptr.p_double[n-1] = (double)(1);
 | |
|             a3->ptr.p_double[n-1] = (double)(0);
 | |
|             b->ptr.p_double[n-1] = boundr;
 | |
|         }
 | |
|         if( boundrtype==2 )
 | |
|         {
 | |
|             a1->ptr.p_double[n-1] = (double)(1);
 | |
|             a2->ptr.p_double[n-1] = (double)(2);
 | |
|             a3->ptr.p_double[n-1] = (double)(0);
 | |
|             b->ptr.p_double[n-1] = 3*(y->ptr.p_double[n-1]-y->ptr.p_double[n-2])/(x->ptr.p_double[n-1]-x->ptr.p_double[n-2])+0.5*boundr*(x->ptr.p_double[n-1]-x->ptr.p_double[n-2]);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Solve
 | |
|          */
 | |
|         spline1d_solvetridiagonal(a1, a2, a3, b, n, d, _state);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal subroutine. Heap sort.
 | |
| *************************************************************************/
 | |
| static void spline1d_heapsortpoints(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector bufx;
 | |
|     ae_vector bufy;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&bufx, 0, sizeof(bufx));
 | |
|     memset(&bufy, 0, sizeof(bufy));
 | |
|     ae_vector_init(&bufx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bufy, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     tagsortfastr(x, y, &bufx, &bufy, n, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal subroutine. Heap sort.
 | |
| 
 | |
| Accepts:
 | |
|     X, Y    -   points
 | |
|     P       -   empty or preallocated array
 | |
|     
 | |
| Returns:
 | |
|     X, Y    -   sorted by X
 | |
|     P       -   array of permutations; I-th position of output
 | |
|                 arrays X/Y contains (X[P[I]],Y[P[I]])
 | |
| *************************************************************************/
 | |
| static void spline1d_heapsortppoints(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Integer */ ae_vector* p,
 | |
|      ae_int_t n,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector rbuf;
 | |
|     ae_vector ibuf;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&rbuf, 0, sizeof(rbuf));
 | |
|     memset(&ibuf, 0, sizeof(ibuf));
 | |
|     ae_vector_init(&rbuf, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ibuf, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     if( p->cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(p, n, _state);
 | |
|     }
 | |
|     ae_vector_set_length(&rbuf, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         p->ptr.p_int[i] = i;
 | |
|     }
 | |
|     tagsortfasti(x, p, &rbuf, &ibuf, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         rbuf.ptr.p_double[i] = y->ptr.p_double[p->ptr.p_int[i]];
 | |
|     }
 | |
|     ae_v_move(&y->ptr.p_double[0], 1, &rbuf.ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal subroutine. Tridiagonal solver. Solves
 | |
| 
 | |
| ( B[0] C[0]                      
 | |
| ( A[1] B[1] C[1]                 )
 | |
| (      A[2] B[2] C[2]            )
 | |
| (            ..........          ) * X = D
 | |
| (            ..........          )
 | |
| (           A[N-2] B[N-2] C[N-2] )
 | |
| (                  A[N-1] B[N-1] )
 | |
| 
 | |
| *************************************************************************/
 | |
| static void spline1d_solvetridiagonal(/* Real    */ ae_vector* a,
 | |
|      /* Real    */ ae_vector* b,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      /* Real    */ ae_vector* d,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _b;
 | |
|     ae_vector _d;
 | |
|     ae_int_t k;
 | |
|     double t;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_b, 0, sizeof(_b));
 | |
|     memset(&_d, 0, sizeof(_d));
 | |
|     ae_vector_init_copy(&_b, b, _state, ae_true);
 | |
|     b = &_b;
 | |
|     ae_vector_init_copy(&_d, d, _state, ae_true);
 | |
|     d = &_d;
 | |
| 
 | |
|     if( x->cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(x, n, _state);
 | |
|     }
 | |
|     for(k=1; k<=n-1; k++)
 | |
|     {
 | |
|         t = a->ptr.p_double[k]/b->ptr.p_double[k-1];
 | |
|         b->ptr.p_double[k] = b->ptr.p_double[k]-t*c->ptr.p_double[k-1];
 | |
|         d->ptr.p_double[k] = d->ptr.p_double[k]-t*d->ptr.p_double[k-1];
 | |
|     }
 | |
|     x->ptr.p_double[n-1] = d->ptr.p_double[n-1]/b->ptr.p_double[n-1];
 | |
|     for(k=n-2; k>=0; k--)
 | |
|     {
 | |
|         x->ptr.p_double[k] = (d->ptr.p_double[k]-c->ptr.p_double[k]*x->ptr.p_double[k+1])/b->ptr.p_double[k];
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal subroutine. Cyclic tridiagonal solver. Solves
 | |
| 
 | |
| ( B[0] C[0]                 A[0] )
 | |
| ( A[1] B[1] C[1]                 )
 | |
| (      A[2] B[2] C[2]            )
 | |
| (            ..........          ) * X = D
 | |
| (            ..........          )
 | |
| (           A[N-2] B[N-2] C[N-2] )
 | |
| ( C[N-1]           A[N-1] B[N-1] )
 | |
| *************************************************************************/
 | |
| static void spline1d_solvecyclictridiagonal(/* Real    */ ae_vector* a,
 | |
|      /* Real    */ ae_vector* b,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      /* Real    */ ae_vector* d,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _b;
 | |
|     ae_int_t k;
 | |
|     double alpha;
 | |
|     double beta;
 | |
|     double gamma;
 | |
|     ae_vector y;
 | |
|     ae_vector z;
 | |
|     ae_vector u;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_b, 0, sizeof(_b));
 | |
|     memset(&y, 0, sizeof(y));
 | |
|     memset(&z, 0, sizeof(z));
 | |
|     memset(&u, 0, sizeof(u));
 | |
|     ae_vector_init_copy(&_b, b, _state, ae_true);
 | |
|     b = &_b;
 | |
|     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&z, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&u, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     if( x->cnt<n )
 | |
|     {
 | |
|         ae_vector_set_length(x, n, _state);
 | |
|     }
 | |
|     beta = a->ptr.p_double[0];
 | |
|     alpha = c->ptr.p_double[n-1];
 | |
|     gamma = -b->ptr.p_double[0];
 | |
|     b->ptr.p_double[0] = 2*b->ptr.p_double[0];
 | |
|     b->ptr.p_double[n-1] = b->ptr.p_double[n-1]-alpha*beta/gamma;
 | |
|     ae_vector_set_length(&u, n, _state);
 | |
|     for(k=0; k<=n-1; k++)
 | |
|     {
 | |
|         u.ptr.p_double[k] = (double)(0);
 | |
|     }
 | |
|     u.ptr.p_double[0] = gamma;
 | |
|     u.ptr.p_double[n-1] = alpha;
 | |
|     spline1d_solvetridiagonal(a, b, c, d, n, &y, _state);
 | |
|     spline1d_solvetridiagonal(a, b, c, &u, n, &z, _state);
 | |
|     for(k=0; k<=n-1; k++)
 | |
|     {
 | |
|         x->ptr.p_double[k] = y.ptr.p_double[k]-(y.ptr.p_double[0]+beta/gamma*y.ptr.p_double[n-1])/(1+z.ptr.p_double[0]+beta/gamma*z.ptr.p_double[n-1])*z.ptr.p_double[k];
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal subroutine. Three-point differentiation
 | |
| *************************************************************************/
 | |
| static double spline1d_diffthreepoint(double t,
 | |
|      double x0,
 | |
|      double f0,
 | |
|      double x1,
 | |
|      double f1,
 | |
|      double x2,
 | |
|      double f2,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double a;
 | |
|     double b;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     t = t-x0;
 | |
|     x1 = x1-x0;
 | |
|     x2 = x2-x0;
 | |
|     a = (f2-f0-x2/x1*(f1-f0))/(ae_sqr(x2, _state)-x1*x2);
 | |
|     b = (f1-f0-a*ae_sqr(x1, _state))/x1;
 | |
|     result = 2*a*t+b;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Procedure for calculating value of a function is providet in the form of
 | |
| Hermite polinom  
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P0   -   value of a function at 0
 | |
|     M0   -   value of a derivative at 0
 | |
|     P1   -   value of a function at 1
 | |
|     M1   -   value of a derivative at 1
 | |
|     T    -   point inside [0;1]
 | |
|     
 | |
| OUTPUT PARAMETERS:
 | |
|     S    -   value of a function at T
 | |
|     B0   -   value of a derivative function at T
 | |
|     
 | |
|  -- ALGLIB PROJECT --
 | |
|      Copyright 26.09.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline1d_hermitecalc(double p0,
 | |
|      double m0,
 | |
|      double p1,
 | |
|      double m1,
 | |
|      double t,
 | |
|      double* s,
 | |
|      double* ds,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     *s = 0;
 | |
|     *ds = 0;
 | |
| 
 | |
|     *s = p0*(1+2*t)*(1-t)*(1-t)+m0*t*(1-t)*(1-t)+p1*(3-2*t)*t*t+m1*t*t*(t-1);
 | |
|     *ds = -p0*6*t*(1-t)+m0*(1-t)*(1-3*t)+p1*6*t*(1-t)+m1*t*(3*t-2);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Function for mapping from [A0;B0] to [A1;B1]
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A0   -   left border [A0;B0]
 | |
|     B0   -   right border [A0;B0]
 | |
|     A1   -   left border [A1;B1]
 | |
|     B1   -   right border [A1;B1]
 | |
|     T    -   value inside [A0;B0]  
 | |
|     
 | |
| RESTRICTIONS OF PARAMETERS:
 | |
| 
 | |
| We assume, that B0>A0 and B1>A1. But we chech, that T is inside [A0;B0], 
 | |
| and if T<A0 then T become A1, if T>B0 then T - B1. 
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|         A0   -   left border for segment [A0;B0] from 'T' is converted to [A1;B1] 
 | |
|         B0   -   right border for segment [A0;B0] from 'T' is converted to [A1;B1] 
 | |
|         A1   -   left border for segment [A1;B1] to 'T' is converted from [A0;B0] 
 | |
|         B1   -   right border for segment [A1;B1] to 'T' is converted from [A0;B0] 
 | |
|         T    -   the parameter is mapped from [A0;B0] to [A1;B1] 
 | |
| 
 | |
| Result:
 | |
|     is converted value for 'T' from [A0;B0] to [A1;B1]
 | |
|          
 | |
| REMARK:
 | |
| 
 | |
| The function dont check value A0,B0 and A1,B1!
 | |
| 
 | |
|  -- ALGLIB PROJECT --
 | |
|      Copyright 26.09.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static double spline1d_rescaleval(double a0,
 | |
|      double b0,
 | |
|      double a1,
 | |
|      double b1,
 | |
|      double t,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      *return left border
 | |
|      */
 | |
|     if( ae_fp_less_eq(t,a0) )
 | |
|     {
 | |
|         result = a1;
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      *return right border
 | |
|      */
 | |
|     if( ae_fp_greater_eq(t,b0) )
 | |
|     {
 | |
|         result = b1;
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      *return value between left and right borders
 | |
|      */
 | |
|     result = (b1-a1)*(t-a0)/(b0-a0)+a1;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline1dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline1dinterpolant *p = (spline1dinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline1dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline1dinterpolant *dst = (spline1dinterpolant*)_dst;
 | |
|     spline1dinterpolant *src = (spline1dinterpolant*)_src;
 | |
|     dst->periodic = src->periodic;
 | |
|     dst->n = src->n;
 | |
|     dst->k = src->k;
 | |
|     dst->continuity = src->continuity;
 | |
|     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline1dinterpolant_clear(void* _p)
 | |
| {
 | |
|     spline1dinterpolant *p = (spline1dinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->x);
 | |
|     ae_vector_clear(&p->c);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline1dinterpolant_destroy(void* _p)
 | |
| {
 | |
|     spline1dinterpolant *p = (spline1dinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->x);
 | |
|     ae_vector_destroy(&p->c);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline1dfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline1dfitreport *p = (spline1dfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline1dfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline1dfitreport *dst = (spline1dfitreport*)_dst;
 | |
|     spline1dfitreport *src = (spline1dfitreport*)_src;
 | |
|     dst->taskrcond = src->taskrcond;
 | |
|     dst->rmserror = src->rmserror;
 | |
|     dst->avgerror = src->avgerror;
 | |
|     dst->avgrelerror = src->avgrelerror;
 | |
|     dst->maxerror = src->maxerror;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline1dfitreport_clear(void* _p)
 | |
| {
 | |
|     spline1dfitreport *p = (spline1dfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline1dfitreport_destroy(void* _p)
 | |
| {
 | |
|     spline1dfitreport *p = (spline1dfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_PARAMETRIC) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  builds  non-periodic 2-dimensional parametric spline  which
 | |
| starts at (X[0],Y[0]) and ends at (X[N-1],Y[N-1]).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY  -   points, array[0..N-1,0..1].
 | |
|             XY[I,0:1] corresponds to the Ith point.
 | |
|             Order of points is important!
 | |
|     N   -   points count, N>=5 for Akima splines, N>=2 for other types  of
 | |
|             splines.
 | |
|     ST  -   spline type:
 | |
|             * 0     Akima spline
 | |
|             * 1     parabolically terminated Catmull-Rom spline (Tension=0)
 | |
|             * 2     parabolically terminated cubic spline
 | |
|     PT  -   parameterization type:
 | |
|             * 0     uniform
 | |
|             * 1     chord length
 | |
|             * 2     centripetal
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
| 
 | |
| 
 | |
| NOTES:
 | |
| * this function  assumes  that  there all consequent points  are distinct.
 | |
|   I.e. (x0,y0)<>(x1,y1),  (x1,y1)<>(x2,y2),  (x2,y2)<>(x3,y3)  and  so on.
 | |
|   However, non-consequent points may coincide, i.e. we can  have  (x0,y0)=
 | |
|   =(x2,y2).
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2build(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_int_t st,
 | |
|      ae_int_t pt,
 | |
|      pspline2interpolant* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_matrix _xy;
 | |
|     ae_vector tmp;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_xy, 0, sizeof(_xy));
 | |
|     memset(&tmp, 0, sizeof(tmp));
 | |
|     ae_matrix_init_copy(&_xy, xy, _state, ae_true);
 | |
|     xy = &_xy;
 | |
|     _pspline2interpolant_clear(p);
 | |
|     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(st>=0&&st<=2, "PSpline2Build: incorrect spline type!", _state);
 | |
|     ae_assert(pt>=0&&pt<=2, "PSpline2Build: incorrect parameterization type!", _state);
 | |
|     if( st==0 )
 | |
|     {
 | |
|         ae_assert(n>=5, "PSpline2Build: N<5 (minimum value for Akima splines)!", _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         ae_assert(n>=2, "PSpline2Build: N<2!", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare
 | |
|      */
 | |
|     p->n = n;
 | |
|     p->periodic = ae_false;
 | |
|     ae_vector_set_length(&tmp, n, _state);
 | |
|     
 | |
|     /*
 | |
|      * Build parameterization, check that all parameters are distinct
 | |
|      */
 | |
|     parametric_pspline2par(xy, n, pt, &p->p, _state);
 | |
|     ae_assert(aredistinct(&p->p, n, _state), "PSpline2Build: consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Build splines
 | |
|      */
 | |
|     if( st==0 )
 | |
|     {
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildakima(&p->p, &tmp, n, &p->x, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildakima(&p->p, &tmp, n, &p->y, _state);
 | |
|     }
 | |
|     if( st==1 )
 | |
|     {
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->x, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->y, _state);
 | |
|     }
 | |
|     if( st==2 )
 | |
|     {
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->x, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->y, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  builds  non-periodic 3-dimensional parametric spline  which
 | |
| starts at (X[0],Y[0],Z[0]) and ends at (X[N-1],Y[N-1],Z[N-1]).
 | |
| 
 | |
| Same as PSpline2Build() function, but for 3D, so we  won't  duplicate  its
 | |
| description here.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3build(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_int_t st,
 | |
|      ae_int_t pt,
 | |
|      pspline3interpolant* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_matrix _xy;
 | |
|     ae_vector tmp;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_xy, 0, sizeof(_xy));
 | |
|     memset(&tmp, 0, sizeof(tmp));
 | |
|     ae_matrix_init_copy(&_xy, xy, _state, ae_true);
 | |
|     xy = &_xy;
 | |
|     _pspline3interpolant_clear(p);
 | |
|     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(st>=0&&st<=2, "PSpline3Build: incorrect spline type!", _state);
 | |
|     ae_assert(pt>=0&&pt<=2, "PSpline3Build: incorrect parameterization type!", _state);
 | |
|     if( st==0 )
 | |
|     {
 | |
|         ae_assert(n>=5, "PSpline3Build: N<5 (minimum value for Akima splines)!", _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         ae_assert(n>=2, "PSpline3Build: N<2!", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare
 | |
|      */
 | |
|     p->n = n;
 | |
|     p->periodic = ae_false;
 | |
|     ae_vector_set_length(&tmp, n, _state);
 | |
|     
 | |
|     /*
 | |
|      * Build parameterization, check that all parameters are distinct
 | |
|      */
 | |
|     parametric_pspline3par(xy, n, pt, &p->p, _state);
 | |
|     ae_assert(aredistinct(&p->p, n, _state), "PSpline3Build: consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Build splines
 | |
|      */
 | |
|     if( st==0 )
 | |
|     {
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildakima(&p->p, &tmp, n, &p->x, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildakima(&p->p, &tmp, n, &p->y, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildakima(&p->p, &tmp, n, &p->z, _state);
 | |
|     }
 | |
|     if( st==1 )
 | |
|     {
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->x, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->y, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildcatmullrom(&p->p, &tmp, n, 0, 0.0, &p->z, _state);
 | |
|     }
 | |
|     if( st==2 )
 | |
|     {
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->x, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->y, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1));
 | |
|         spline1dbuildcubic(&p->p, &tmp, n, 0, 0.0, 0, 0.0, &p->z, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  builds  periodic  2-dimensional  parametric  spline  which
 | |
| starts at (X[0],Y[0]), goes through all points to (X[N-1],Y[N-1]) and then
 | |
| back to (X[0],Y[0]).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY  -   points, array[0..N-1,0..1].
 | |
|             XY[I,0:1] corresponds to the Ith point.
 | |
|             XY[N-1,0:1] must be different from XY[0,0:1].
 | |
|             Order of points is important!
 | |
|     N   -   points count, N>=3 for other types of splines.
 | |
|     ST  -   spline type:
 | |
|             * 1     Catmull-Rom spline (Tension=0) with cyclic boundary conditions
 | |
|             * 2     cubic spline with cyclic boundary conditions
 | |
|     PT  -   parameterization type:
 | |
|             * 0     uniform
 | |
|             * 1     chord length
 | |
|             * 2     centripetal
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
| 
 | |
| 
 | |
| NOTES:
 | |
| * this function  assumes  that there all consequent points  are  distinct.
 | |
|   I.e. (x0,y0)<>(x1,y1), (x1,y1)<>(x2,y2),  (x2,y2)<>(x3,y3)  and  so  on.
 | |
|   However, non-consequent points may coincide, i.e. we can  have  (x0,y0)=
 | |
|   =(x2,y2).
 | |
| * last point of sequence is NOT equal to the first  point.  You  shouldn't
 | |
|   make curve "explicitly periodic" by making them equal.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2buildperiodic(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_int_t st,
 | |
|      ae_int_t pt,
 | |
|      pspline2interpolant* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_matrix _xy;
 | |
|     ae_matrix xyp;
 | |
|     ae_vector tmp;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_xy, 0, sizeof(_xy));
 | |
|     memset(&xyp, 0, sizeof(xyp));
 | |
|     memset(&tmp, 0, sizeof(tmp));
 | |
|     ae_matrix_init_copy(&_xy, xy, _state, ae_true);
 | |
|     xy = &_xy;
 | |
|     _pspline2interpolant_clear(p);
 | |
|     ae_matrix_init(&xyp, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(st>=1&&st<=2, "PSpline2BuildPeriodic: incorrect spline type!", _state);
 | |
|     ae_assert(pt>=0&&pt<=2, "PSpline2BuildPeriodic: incorrect parameterization type!", _state);
 | |
|     ae_assert(n>=3, "PSpline2BuildPeriodic: N<3!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare
 | |
|      */
 | |
|     p->n = n;
 | |
|     p->periodic = ae_true;
 | |
|     ae_vector_set_length(&tmp, n+1, _state);
 | |
|     ae_matrix_set_length(&xyp, n+1, 2, _state);
 | |
|     ae_v_move(&xyp.ptr.pp_double[0][0], xyp.stride, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
 | |
|     ae_v_move(&xyp.ptr.pp_double[0][1], xyp.stride, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
 | |
|     ae_v_move(&xyp.ptr.pp_double[n][0], 1, &xy->ptr.pp_double[0][0], 1, ae_v_len(0,1));
 | |
|     
 | |
|     /*
 | |
|      * Build parameterization, check that all parameters are distinct
 | |
|      */
 | |
|     parametric_pspline2par(&xyp, n+1, pt, &p->p, _state);
 | |
|     ae_assert(aredistinct(&p->p, n+1, _state), "PSpline2BuildPeriodic: consequent (or first and last) points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Build splines
 | |
|      */
 | |
|     if( st==1 )
 | |
|     {
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n));
 | |
|         spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->x, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n));
 | |
|         spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->y, _state);
 | |
|     }
 | |
|     if( st==2 )
 | |
|     {
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n));
 | |
|         spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->x, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n));
 | |
|         spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->y, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  builds  periodic  3-dimensional  parametric  spline  which
 | |
| starts at (X[0],Y[0],Z[0]), goes through all points to (X[N-1],Y[N-1],Z[N-1])
 | |
| and then back to (X[0],Y[0],Z[0]).
 | |
| 
 | |
| Same as PSpline2Build() function, but for 3D, so we  won't  duplicate  its
 | |
| description here.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3buildperiodic(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_int_t st,
 | |
|      ae_int_t pt,
 | |
|      pspline3interpolant* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_matrix _xy;
 | |
|     ae_matrix xyp;
 | |
|     ae_vector tmp;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_xy, 0, sizeof(_xy));
 | |
|     memset(&xyp, 0, sizeof(xyp));
 | |
|     memset(&tmp, 0, sizeof(tmp));
 | |
|     ae_matrix_init_copy(&_xy, xy, _state, ae_true);
 | |
|     xy = &_xy;
 | |
|     _pspline3interpolant_clear(p);
 | |
|     ae_matrix_init(&xyp, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(st>=1&&st<=2, "PSpline3BuildPeriodic: incorrect spline type!", _state);
 | |
|     ae_assert(pt>=0&&pt<=2, "PSpline3BuildPeriodic: incorrect parameterization type!", _state);
 | |
|     ae_assert(n>=3, "PSpline3BuildPeriodic: N<3!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare
 | |
|      */
 | |
|     p->n = n;
 | |
|     p->periodic = ae_true;
 | |
|     ae_vector_set_length(&tmp, n+1, _state);
 | |
|     ae_matrix_set_length(&xyp, n+1, 3, _state);
 | |
|     ae_v_move(&xyp.ptr.pp_double[0][0], xyp.stride, &xy->ptr.pp_double[0][0], xy->stride, ae_v_len(0,n-1));
 | |
|     ae_v_move(&xyp.ptr.pp_double[0][1], xyp.stride, &xy->ptr.pp_double[0][1], xy->stride, ae_v_len(0,n-1));
 | |
|     ae_v_move(&xyp.ptr.pp_double[0][2], xyp.stride, &xy->ptr.pp_double[0][2], xy->stride, ae_v_len(0,n-1));
 | |
|     ae_v_move(&xyp.ptr.pp_double[n][0], 1, &xy->ptr.pp_double[0][0], 1, ae_v_len(0,2));
 | |
|     
 | |
|     /*
 | |
|      * Build parameterization, check that all parameters are distinct
 | |
|      */
 | |
|     parametric_pspline3par(&xyp, n+1, pt, &p->p, _state);
 | |
|     ae_assert(aredistinct(&p->p, n+1, _state), "PSplineBuild2Periodic: consequent (or first and last) points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Build splines
 | |
|      */
 | |
|     if( st==1 )
 | |
|     {
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n));
 | |
|         spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->x, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n));
 | |
|         spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->y, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][2], xyp.stride, ae_v_len(0,n));
 | |
|         spline1dbuildcatmullrom(&p->p, &tmp, n+1, -1, 0.0, &p->z, _state);
 | |
|     }
 | |
|     if( st==2 )
 | |
|     {
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][0], xyp.stride, ae_v_len(0,n));
 | |
|         spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->x, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][1], xyp.stride, ae_v_len(0,n));
 | |
|         spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->y, _state);
 | |
|         ae_v_move(&tmp.ptr.p_double[0], 1, &xyp.ptr.pp_double[0][2], xyp.stride, ae_v_len(0,n));
 | |
|         spline1dbuildcubic(&p->p, &tmp, n+1, -1, 0.0, -1, 0.0, &p->z, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function returns vector of parameter values correspoding to points.
 | |
| 
 | |
| I.e. for P created from (X[0],Y[0])...(X[N-1],Y[N-1]) and U=TValues(P)  we
 | |
| have
 | |
|     (X[0],Y[0]) = PSpline2Calc(P,U[0]),
 | |
|     (X[1],Y[1]) = PSpline2Calc(P,U[1]),
 | |
|     (X[2],Y[2]) = PSpline2Calc(P,U[2]),
 | |
|     ...
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     N   -   array size
 | |
|     T   -   array[0..N-1]
 | |
| 
 | |
| 
 | |
| NOTES:
 | |
| * for non-periodic splines U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]=1
 | |
| * for periodic splines     U[0]=0, U[0]<U[1]<...<U[N-1], U[N-1]<1
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2parametervalues(pspline2interpolant* p,
 | |
|      ae_int_t* n,
 | |
|      /* Real    */ ae_vector* t,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     *n = 0;
 | |
|     ae_vector_clear(t);
 | |
| 
 | |
|     ae_assert(p->n>=2, "PSpline2ParameterValues: internal error!", _state);
 | |
|     *n = p->n;
 | |
|     ae_vector_set_length(t, *n, _state);
 | |
|     ae_v_move(&t->ptr.p_double[0], 1, &p->p.ptr.p_double[0], 1, ae_v_len(0,*n-1));
 | |
|     t->ptr.p_double[0] = (double)(0);
 | |
|     if( !p->periodic )
 | |
|     {
 | |
|         t->ptr.p_double[*n-1] = (double)(1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function returns vector of parameter values correspoding to points.
 | |
| 
 | |
| Same as PSpline2ParameterValues(), but for 3D.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3parametervalues(pspline3interpolant* p,
 | |
|      ae_int_t* n,
 | |
|      /* Real    */ ae_vector* t,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     *n = 0;
 | |
|     ae_vector_clear(t);
 | |
| 
 | |
|     ae_assert(p->n>=2, "PSpline3ParameterValues: internal error!", _state);
 | |
|     *n = p->n;
 | |
|     ae_vector_set_length(t, *n, _state);
 | |
|     ae_v_move(&t->ptr.p_double[0], 1, &p->p.ptr.p_double[0], 1, ae_v_len(0,*n-1));
 | |
|     t->ptr.p_double[0] = (double)(0);
 | |
|     if( !p->periodic )
 | |
|     {
 | |
|         t->ptr.p_double[*n-1] = (double)(1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  the value of the parametric spline for a  given
 | |
| value of parameter T
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-position
 | |
|     Y   -   Y-position
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2calc(pspline2interpolant* p,
 | |
|      double t,
 | |
|      double* x,
 | |
|      double* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     *x = 0;
 | |
|     *y = 0;
 | |
| 
 | |
|     if( p->periodic )
 | |
|     {
 | |
|         t = t-ae_ifloor(t, _state);
 | |
|     }
 | |
|     *x = spline1dcalc(&p->x, t, _state);
 | |
|     *y = spline1dcalc(&p->y, t, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  the value of the parametric spline for a  given
 | |
| value of parameter T.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-position
 | |
|     Y   -   Y-position
 | |
|     Z   -   Z-position
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3calc(pspline3interpolant* p,
 | |
|      double t,
 | |
|      double* x,
 | |
|      double* y,
 | |
|      double* z,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     *x = 0;
 | |
|     *y = 0;
 | |
|     *z = 0;
 | |
| 
 | |
|     if( p->periodic )
 | |
|     {
 | |
|         t = t-ae_ifloor(t, _state);
 | |
|     }
 | |
|     *x = spline1dcalc(&p->x, t, _state);
 | |
|     *y = spline1dcalc(&p->y, t, _state);
 | |
|     *z = spline1dcalc(&p->z, t, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  tangent vector for a given value of parameter T
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X    -   X-component of tangent vector (normalized)
 | |
|     Y    -   Y-component of tangent vector (normalized)
 | |
|     
 | |
| NOTE:
 | |
|     X^2+Y^2 is either 1 (for non-zero tangent vector) or 0.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2tangent(pspline2interpolant* p,
 | |
|      double t,
 | |
|      double* x,
 | |
|      double* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double v;
 | |
|     double v0;
 | |
|     double v1;
 | |
| 
 | |
|     *x = 0;
 | |
|     *y = 0;
 | |
| 
 | |
|     if( p->periodic )
 | |
|     {
 | |
|         t = t-ae_ifloor(t, _state);
 | |
|     }
 | |
|     pspline2diff(p, t, &v0, x, &v1, y, _state);
 | |
|     if( ae_fp_neq(*x,(double)(0))||ae_fp_neq(*y,(double)(0)) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * this code is a bit more complex than X^2+Y^2 to avoid
 | |
|          * overflow for large values of X and Y.
 | |
|          */
 | |
|         v = safepythag2(*x, *y, _state);
 | |
|         *x = *x/v;
 | |
|         *y = *y/v;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  tangent vector for a given value of parameter T
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X    -   X-component of tangent vector (normalized)
 | |
|     Y    -   Y-component of tangent vector (normalized)
 | |
|     Z    -   Z-component of tangent vector (normalized)
 | |
| 
 | |
| NOTE:
 | |
|     X^2+Y^2+Z^2 is either 1 (for non-zero tangent vector) or 0.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3tangent(pspline3interpolant* p,
 | |
|      double t,
 | |
|      double* x,
 | |
|      double* y,
 | |
|      double* z,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double v;
 | |
|     double v0;
 | |
|     double v1;
 | |
|     double v2;
 | |
| 
 | |
|     *x = 0;
 | |
|     *y = 0;
 | |
|     *z = 0;
 | |
| 
 | |
|     if( p->periodic )
 | |
|     {
 | |
|         t = t-ae_ifloor(t, _state);
 | |
|     }
 | |
|     pspline3diff(p, t, &v0, x, &v1, y, &v2, z, _state);
 | |
|     if( (ae_fp_neq(*x,(double)(0))||ae_fp_neq(*y,(double)(0)))||ae_fp_neq(*z,(double)(0)) )
 | |
|     {
 | |
|         v = safepythag3(*x, *y, *z, _state);
 | |
|         *x = *x/v;
 | |
|         *y = *y/v;
 | |
|         *z = *z/v;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates derivative, i.e. it returns (dX/dT,dY/dT).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-value
 | |
|     DX  -   X-derivative
 | |
|     Y   -   Y-value
 | |
|     DY  -   Y-derivative
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2diff(pspline2interpolant* p,
 | |
|      double t,
 | |
|      double* x,
 | |
|      double* dx,
 | |
|      double* y,
 | |
|      double* dy,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double d2s;
 | |
| 
 | |
|     *x = 0;
 | |
|     *dx = 0;
 | |
|     *y = 0;
 | |
|     *dy = 0;
 | |
| 
 | |
|     if( p->periodic )
 | |
|     {
 | |
|         t = t-ae_ifloor(t, _state);
 | |
|     }
 | |
|     spline1ddiff(&p->x, t, x, dx, &d2s, _state);
 | |
|     spline1ddiff(&p->y, t, y, dy, &d2s, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates derivative, i.e. it returns (dX/dT,dY/dT,dZ/dT).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-value
 | |
|     DX  -   X-derivative
 | |
|     Y   -   Y-value
 | |
|     DY  -   Y-derivative
 | |
|     Z   -   Z-value
 | |
|     DZ  -   Z-derivative
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3diff(pspline3interpolant* p,
 | |
|      double t,
 | |
|      double* x,
 | |
|      double* dx,
 | |
|      double* y,
 | |
|      double* dy,
 | |
|      double* z,
 | |
|      double* dz,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double d2s;
 | |
| 
 | |
|     *x = 0;
 | |
|     *dx = 0;
 | |
|     *y = 0;
 | |
|     *dy = 0;
 | |
|     *z = 0;
 | |
|     *dz = 0;
 | |
| 
 | |
|     if( p->periodic )
 | |
|     {
 | |
|         t = t-ae_ifloor(t, _state);
 | |
|     }
 | |
|     spline1ddiff(&p->x, t, x, dx, &d2s, _state);
 | |
|     spline1ddiff(&p->y, t, y, dy, &d2s, _state);
 | |
|     spline1ddiff(&p->z, t, z, dz, &d2s, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates first and second derivative with respect to T.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-value
 | |
|     DX  -   derivative
 | |
|     D2X -   second derivative
 | |
|     Y   -   Y-value
 | |
|     DY  -   derivative
 | |
|     D2Y -   second derivative
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline2diff2(pspline2interpolant* p,
 | |
|      double t,
 | |
|      double* x,
 | |
|      double* dx,
 | |
|      double* d2x,
 | |
|      double* y,
 | |
|      double* dy,
 | |
|      double* d2y,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     *x = 0;
 | |
|     *dx = 0;
 | |
|     *d2x = 0;
 | |
|     *y = 0;
 | |
|     *dy = 0;
 | |
|     *d2y = 0;
 | |
| 
 | |
|     if( p->periodic )
 | |
|     {
 | |
|         t = t-ae_ifloor(t, _state);
 | |
|     }
 | |
|     spline1ddiff(&p->x, t, x, dx, d2x, _state);
 | |
|     spline1ddiff(&p->y, t, y, dy, d2y, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates first and second derivative with respect to T.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     T   -   point:
 | |
|             * T in [0,1] corresponds to interval spanned by points
 | |
|             * for non-periodic splines T<0 (or T>1) correspond to parts of
 | |
|               the curve before the first (after the last) point
 | |
|             * for periodic splines T<0 (or T>1) are projected  into  [0,1]
 | |
|               by making T=T-floor(T).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X   -   X-value
 | |
|     DX  -   derivative
 | |
|     D2X -   second derivative
 | |
|     Y   -   Y-value
 | |
|     DY  -   derivative
 | |
|     D2Y -   second derivative
 | |
|     Z   -   Z-value
 | |
|     DZ  -   derivative
 | |
|     D2Z -   second derivative
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void pspline3diff2(pspline3interpolant* p,
 | |
|      double t,
 | |
|      double* x,
 | |
|      double* dx,
 | |
|      double* d2x,
 | |
|      double* y,
 | |
|      double* dy,
 | |
|      double* d2y,
 | |
|      double* z,
 | |
|      double* dz,
 | |
|      double* d2z,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     *x = 0;
 | |
|     *dx = 0;
 | |
|     *d2x = 0;
 | |
|     *y = 0;
 | |
|     *dy = 0;
 | |
|     *d2y = 0;
 | |
|     *z = 0;
 | |
|     *dz = 0;
 | |
|     *d2z = 0;
 | |
| 
 | |
|     if( p->periodic )
 | |
|     {
 | |
|         t = t-ae_ifloor(t, _state);
 | |
|     }
 | |
|     spline1ddiff(&p->x, t, x, dx, d2x, _state);
 | |
|     spline1ddiff(&p->y, t, y, dy, d2y, _state);
 | |
|     spline1ddiff(&p->z, t, z, dz, d2z, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  arc length, i.e. length of  curve  between  t=a
 | |
| and t=b.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     A,B -   parameter values corresponding to arc ends:
 | |
|             * B>A will result in positive length returned
 | |
|             * B<A will result in negative length returned
 | |
| 
 | |
| RESULT:
 | |
|     length of arc starting at T=A and ending at T=B.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double pspline2arclength(pspline2interpolant* p,
 | |
|      double a,
 | |
|      double b,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     autogkstate state;
 | |
|     autogkreport rep;
 | |
|     double sx;
 | |
|     double dsx;
 | |
|     double d2sx;
 | |
|     double sy;
 | |
|     double dsy;
 | |
|     double d2sy;
 | |
|     double result;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&state, 0, sizeof(state));
 | |
|     memset(&rep, 0, sizeof(rep));
 | |
|     _autogkstate_init(&state, _state, ae_true);
 | |
|     _autogkreport_init(&rep, _state, ae_true);
 | |
| 
 | |
|     autogksmooth(a, b, &state, _state);
 | |
|     while(autogkiteration(&state, _state))
 | |
|     {
 | |
|         spline1ddiff(&p->x, state.x, &sx, &dsx, &d2sx, _state);
 | |
|         spline1ddiff(&p->y, state.x, &sy, &dsy, &d2sy, _state);
 | |
|         state.f = safepythag2(dsx, dsy, _state);
 | |
|     }
 | |
|     autogkresults(&state, &result, &rep, _state);
 | |
|     ae_assert(rep.terminationtype>0, "PSpline2ArcLength: internal error!", _state);
 | |
|     ae_frame_leave(_state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  calculates  arc length, i.e. length of  curve  between  t=a
 | |
| and t=b.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   parametric spline interpolant
 | |
|     A,B -   parameter values corresponding to arc ends:
 | |
|             * B>A will result in positive length returned
 | |
|             * B<A will result in negative length returned
 | |
| 
 | |
| RESULT:
 | |
|     length of arc starting at T=A and ending at T=B.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.05.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double pspline3arclength(pspline3interpolant* p,
 | |
|      double a,
 | |
|      double b,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     autogkstate state;
 | |
|     autogkreport rep;
 | |
|     double sx;
 | |
|     double dsx;
 | |
|     double d2sx;
 | |
|     double sy;
 | |
|     double dsy;
 | |
|     double d2sy;
 | |
|     double sz;
 | |
|     double dsz;
 | |
|     double d2sz;
 | |
|     double result;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&state, 0, sizeof(state));
 | |
|     memset(&rep, 0, sizeof(rep));
 | |
|     _autogkstate_init(&state, _state, ae_true);
 | |
|     _autogkreport_init(&rep, _state, ae_true);
 | |
| 
 | |
|     autogksmooth(a, b, &state, _state);
 | |
|     while(autogkiteration(&state, _state))
 | |
|     {
 | |
|         spline1ddiff(&p->x, state.x, &sx, &dsx, &d2sx, _state);
 | |
|         spline1ddiff(&p->y, state.x, &sy, &dsy, &d2sy, _state);
 | |
|         spline1ddiff(&p->z, state.x, &sz, &dsz, &d2sz, _state);
 | |
|         state.f = safepythag3(dsx, dsy, dsz, _state);
 | |
|     }
 | |
|     autogkresults(&state, &result, &rep, _state);
 | |
|     ae_assert(rep.terminationtype>0, "PSpline3ArcLength: internal error!", _state);
 | |
|     ae_frame_leave(_state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
 | |
| Peucker algorithm. This  function  performs PARAMETRIC fit, i.e. it can be
 | |
| used to fit curves like circles.
 | |
| 
 | |
| On  input  it  accepts dataset which describes parametric multidimensional
 | |
| curve X(t), with X being vector, and t taking values in [0,N), where N  is
 | |
| a number of points in dataset. As result, it returns reduced  dataset  X2,
 | |
| which can be used to build  parametric  curve  X2(t),  which  approximates
 | |
| X(t) with desired precision (or has specified number of sections).
 | |
| 
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array of multidimensional points:
 | |
|                 * at least N elements, leading N elements are used if more
 | |
|                   than N elements were specified
 | |
|                 * order of points is IMPORTANT because  it  is  parametric
 | |
|                   fit
 | |
|                 * each row of array is one point which has D coordinates
 | |
|     N       -   number of elements in X
 | |
|     D       -   number of dimensions (elements per row of X)
 | |
|     StopM   -   stopping condition - desired number of sections:
 | |
|                 * at most M sections are generated by this function
 | |
|                 * less than M sections can be generated if we have N<M
 | |
|                   (or some X are non-distinct).
 | |
|                 * zero StopM means that algorithm does not stop after
 | |
|                   achieving some pre-specified section count
 | |
|     StopEps -   stopping condition - desired precision:
 | |
|                 * algorithm stops after error in each section is at most Eps
 | |
|                 * zero Eps means that algorithm does not stop after
 | |
|                   achieving some pre-specified precision
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X2      -   array of corner points for piecewise approximation,
 | |
|                 has length NSections+1 or zero (for NSections=0).
 | |
|     Idx2    -   array of indexes (parameter values):
 | |
|                 * has length NSections+1 or zero (for NSections=0).
 | |
|                 * each element of Idx2 corresponds to same-numbered
 | |
|                   element of X2
 | |
|                 * each element of Idx2 is index of  corresponding  element
 | |
|                   of X2 at original array X, i.e. I-th  row  of  X2  is
 | |
|                   Idx2[I]-th row of X.
 | |
|                 * elements of Idx2 can be treated as parameter values
 | |
|                   which should be used when building new parametric curve
 | |
|                 * Idx2[0]=0, Idx2[NSections]=N-1
 | |
|     NSections-  number of sections found by algorithm, NSections<=M,
 | |
|                 NSections can be zero for degenerate datasets
 | |
|                 (N<=1 or all X[] are non-distinct).
 | |
| 
 | |
| NOTE: algorithm stops after:
 | |
|       a) dividing curve into StopM sections 
 | |
|       b) achieving required precision StopEps
 | |
|       c) dividing curve into N-1 sections
 | |
|       If both StopM and StopEps are non-zero, algorithm is stopped by  the
 | |
|       FIRST criterion which is satisfied. In case both StopM  and  StopEps
 | |
|       are zero, algorithm stops because of (c).
 | |
|                 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.10.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void parametricrdpfixed(/* Real    */ ae_matrix* x,
 | |
|      ae_int_t n,
 | |
|      ae_int_t d,
 | |
|      ae_int_t stopm,
 | |
|      double stopeps,
 | |
|      /* Real    */ ae_matrix* x2,
 | |
|      /* Integer */ ae_vector* idx2,
 | |
|      ae_int_t* nsections,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_bool allsame;
 | |
|     ae_int_t k0;
 | |
|     ae_int_t k1;
 | |
|     ae_int_t k2;
 | |
|     double e0;
 | |
|     double e1;
 | |
|     ae_int_t idx0;
 | |
|     ae_int_t idx1;
 | |
|     ae_int_t worstidx;
 | |
|     double worsterror;
 | |
|     ae_matrix sections;
 | |
|     ae_vector heaperrors;
 | |
|     ae_vector heaptags;
 | |
|     ae_vector buf0;
 | |
|     ae_vector buf1;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(§ions, 0, sizeof(sections));
 | |
|     memset(&heaperrors, 0, sizeof(heaperrors));
 | |
|     memset(&heaptags, 0, sizeof(heaptags));
 | |
|     memset(&buf0, 0, sizeof(buf0));
 | |
|     memset(&buf1, 0, sizeof(buf1));
 | |
|     ae_matrix_clear(x2);
 | |
|     ae_vector_clear(idx2);
 | |
|     *nsections = 0;
 | |
|     ae_matrix_init(§ions, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&heaperrors, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&heaptags, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&buf0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&buf1, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=0, "LSTFitPiecewiseLinearParametricRDP: N<0", _state);
 | |
|     ae_assert(d>=1, "LSTFitPiecewiseLinearParametricRDP: D<=0", _state);
 | |
|     ae_assert(stopm>=0, "LSTFitPiecewiseLinearParametricRDP: StopM<1", _state);
 | |
|     ae_assert(ae_isfinite(stopeps, _state)&&ae_fp_greater_eq(stopeps,(double)(0)), "LSTFitPiecewiseLinearParametricRDP: StopEps<0 or is infinite", _state);
 | |
|     ae_assert(x->rows>=n, "LSTFitPiecewiseLinearParametricRDP: Rows(X)<N", _state);
 | |
|     ae_assert(x->cols>=d, "LSTFitPiecewiseLinearParametricRDP: Cols(X)<D", _state);
 | |
|     ae_assert(apservisfinitematrix(x, n, d, _state), "LSTFitPiecewiseLinearParametricRDP: X contains infinite/NAN values", _state);
 | |
|     
 | |
|     /*
 | |
|      * Handle degenerate cases
 | |
|      */
 | |
|     if( n<=1 )
 | |
|     {
 | |
|         *nsections = 0;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     allsame = ae_true;
 | |
|     for(i=1; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=d-1; j++)
 | |
|         {
 | |
|             allsame = allsame&&ae_fp_eq(x->ptr.pp_double[i][j],x->ptr.pp_double[0][j]);
 | |
|         }
 | |
|     }
 | |
|     if( allsame )
 | |
|     {
 | |
|         *nsections = 0;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare first section
 | |
|      */
 | |
|     parametric_rdpanalyzesectionpar(x, 0, n-1, d, &worstidx, &worsterror, _state);
 | |
|     ae_matrix_set_length(§ions, n, 4, _state);
 | |
|     ae_vector_set_length(&heaperrors, n, _state);
 | |
|     ae_vector_set_length(&heaptags, n, _state);
 | |
|     *nsections = 1;
 | |
|     sections.ptr.pp_double[0][0] = (double)(0);
 | |
|     sections.ptr.pp_double[0][1] = (double)(n-1);
 | |
|     sections.ptr.pp_double[0][2] = (double)(worstidx);
 | |
|     sections.ptr.pp_double[0][3] = worsterror;
 | |
|     heaperrors.ptr.p_double[0] = worsterror;
 | |
|     heaptags.ptr.p_int[0] = 0;
 | |
|     ae_assert(ae_fp_eq(sections.ptr.pp_double[0][1],(double)(n-1)), "RDP algorithm: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Main loop.
 | |
|      * Repeatedly find section with worst error and divide it.
 | |
|      * Terminate after M-th section, or because of other reasons (see loop internals).
 | |
|      */
 | |
|     for(;;)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Break loop if one of the stopping conditions was met.
 | |
|          * Store index of worst section to K.
 | |
|          */
 | |
|         if( ae_fp_eq(heaperrors.ptr.p_double[0],(double)(0)) )
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
|         if( ae_fp_greater(stopeps,(double)(0))&&ae_fp_less_eq(heaperrors.ptr.p_double[0],stopeps) )
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
|         if( stopm>0&&*nsections>=stopm )
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
|         k = heaptags.ptr.p_int[0];
 | |
|         
 | |
|         /*
 | |
|          * K-th section is divided in two:
 | |
|          * * first  one spans interval from X[Sections[K,0]] to X[Sections[K,2]]
 | |
|          * * second one spans interval from X[Sections[K,2]] to X[Sections[K,1]]
 | |
|          *
 | |
|          * First section is stored at K-th position, second one is appended to the table.
 | |
|          * Then we update heap which stores pairs of (error,section_index)
 | |
|          */
 | |
|         k0 = ae_round(sections.ptr.pp_double[k][0], _state);
 | |
|         k1 = ae_round(sections.ptr.pp_double[k][1], _state);
 | |
|         k2 = ae_round(sections.ptr.pp_double[k][2], _state);
 | |
|         parametric_rdpanalyzesectionpar(x, k0, k2, d, &idx0, &e0, _state);
 | |
|         parametric_rdpanalyzesectionpar(x, k2, k1, d, &idx1, &e1, _state);
 | |
|         sections.ptr.pp_double[k][0] = (double)(k0);
 | |
|         sections.ptr.pp_double[k][1] = (double)(k2);
 | |
|         sections.ptr.pp_double[k][2] = (double)(idx0);
 | |
|         sections.ptr.pp_double[k][3] = e0;
 | |
|         tagheapreplacetopi(&heaperrors, &heaptags, *nsections, e0, k, _state);
 | |
|         sections.ptr.pp_double[*nsections][0] = (double)(k2);
 | |
|         sections.ptr.pp_double[*nsections][1] = (double)(k1);
 | |
|         sections.ptr.pp_double[*nsections][2] = (double)(idx1);
 | |
|         sections.ptr.pp_double[*nsections][3] = e1;
 | |
|         tagheappushi(&heaperrors, &heaptags, nsections, e1, *nsections, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Convert from sections to indexes
 | |
|      */
 | |
|     ae_vector_set_length(&buf0, *nsections+1, _state);
 | |
|     for(i=0; i<=*nsections-1; i++)
 | |
|     {
 | |
|         buf0.ptr.p_double[i] = (double)(ae_round(sections.ptr.pp_double[i][0], _state));
 | |
|     }
 | |
|     buf0.ptr.p_double[*nsections] = (double)(n-1);
 | |
|     tagsortfast(&buf0, &buf1, *nsections+1, _state);
 | |
|     ae_vector_set_length(idx2, *nsections+1, _state);
 | |
|     for(i=0; i<=*nsections; i++)
 | |
|     {
 | |
|         idx2->ptr.p_int[i] = ae_round(buf0.ptr.p_double[i], _state);
 | |
|     }
 | |
|     ae_assert(idx2->ptr.p_int[0]==0, "RDP algorithm: integrity check failed", _state);
 | |
|     ae_assert(idx2->ptr.p_int[*nsections]==n-1, "RDP algorithm: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Output sections:
 | |
|      * * first NSection elements of X2/Y2 are filled by x/y at left boundaries of sections
 | |
|      * * last element of X2/Y2 is filled by right boundary of rightmost section
 | |
|      * * X2/Y2 is sorted by ascending of X2
 | |
|      */
 | |
|     ae_matrix_set_length(x2, *nsections+1, d, _state);
 | |
|     for(i=0; i<=*nsections; i++)
 | |
|     {
 | |
|         for(j=0; j<=d-1; j++)
 | |
|         {
 | |
|             x2->ptr.pp_double[i][j] = x->ptr.pp_double[idx2->ptr.p_int[i]][j];
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Builds non-periodic parameterization for 2-dimensional spline
 | |
| *************************************************************************/
 | |
| static void parametric_pspline2par(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_int_t pt,
 | |
|      /* Real    */ ae_vector* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double v;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_vector_clear(p);
 | |
| 
 | |
|     ae_assert(pt>=0&&pt<=2, "PSpline2Par: internal error!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Build parameterization:
 | |
|      * * fill by non-normalized values
 | |
|      * * normalize them so we have P[0]=0, P[N-1]=1.
 | |
|      */
 | |
|     ae_vector_set_length(p, n, _state);
 | |
|     if( pt==0 )
 | |
|     {
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             p->ptr.p_double[i] = (double)(i);
 | |
|         }
 | |
|     }
 | |
|     if( pt==1 )
 | |
|     {
 | |
|         p->ptr.p_double[0] = (double)(0);
 | |
|         for(i=1; i<=n-1; i++)
 | |
|         {
 | |
|             p->ptr.p_double[i] = p->ptr.p_double[i-1]+safepythag2(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], _state);
 | |
|         }
 | |
|     }
 | |
|     if( pt==2 )
 | |
|     {
 | |
|         p->ptr.p_double[0] = (double)(0);
 | |
|         for(i=1; i<=n-1; i++)
 | |
|         {
 | |
|             p->ptr.p_double[i] = p->ptr.p_double[i-1]+ae_sqrt(safepythag2(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], _state), _state);
 | |
|         }
 | |
|     }
 | |
|     v = 1/p->ptr.p_double[n-1];
 | |
|     ae_v_muld(&p->ptr.p_double[0], 1, ae_v_len(0,n-1), v);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Builds non-periodic parameterization for 3-dimensional spline
 | |
| *************************************************************************/
 | |
| static void parametric_pspline3par(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_int_t pt,
 | |
|      /* Real    */ ae_vector* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double v;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_vector_clear(p);
 | |
| 
 | |
|     ae_assert(pt>=0&&pt<=2, "PSpline3Par: internal error!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Build parameterization:
 | |
|      * * fill by non-normalized values
 | |
|      * * normalize them so we have P[0]=0, P[N-1]=1.
 | |
|      */
 | |
|     ae_vector_set_length(p, n, _state);
 | |
|     if( pt==0 )
 | |
|     {
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             p->ptr.p_double[i] = (double)(i);
 | |
|         }
 | |
|     }
 | |
|     if( pt==1 )
 | |
|     {
 | |
|         p->ptr.p_double[0] = (double)(0);
 | |
|         for(i=1; i<=n-1; i++)
 | |
|         {
 | |
|             p->ptr.p_double[i] = p->ptr.p_double[i-1]+safepythag3(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], xy->ptr.pp_double[i][2]-xy->ptr.pp_double[i-1][2], _state);
 | |
|         }
 | |
|     }
 | |
|     if( pt==2 )
 | |
|     {
 | |
|         p->ptr.p_double[0] = (double)(0);
 | |
|         for(i=1; i<=n-1; i++)
 | |
|         {
 | |
|             p->ptr.p_double[i] = p->ptr.p_double[i-1]+ae_sqrt(safepythag3(xy->ptr.pp_double[i][0]-xy->ptr.pp_double[i-1][0], xy->ptr.pp_double[i][1]-xy->ptr.pp_double[i-1][1], xy->ptr.pp_double[i][2]-xy->ptr.pp_double[i-1][2], _state), _state);
 | |
|         }
 | |
|     }
 | |
|     v = 1/p->ptr.p_double[n-1];
 | |
|     ae_v_muld(&p->ptr.p_double[0], 1, ae_v_len(0,n-1), v);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function analyzes section of curve for processing by RDP algorithm:
 | |
| given set of points X,Y with indexes [I0,I1] it returns point with
 | |
| worst deviation from linear model (PARAMETRIC version which sees curve
 | |
| as X(t) with vector X).
 | |
| 
 | |
| Input parameters:
 | |
|     XY          -   array
 | |
|     I0,I1       -   interval (boundaries included) to process
 | |
|     D           -   number of dimensions
 | |
|     
 | |
| OUTPUT PARAMETERS:
 | |
|     WorstIdx    -   index of worst point
 | |
|     WorstError  -   error at worst point
 | |
|     
 | |
| NOTE: this function guarantees that it returns exactly zero for a section
 | |
|       with less than 3 points.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 02.10.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void parametric_rdpanalyzesectionpar(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t i0,
 | |
|      ae_int_t i1,
 | |
|      ae_int_t d,
 | |
|      ae_int_t* worstidx,
 | |
|      double* worsterror,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double v;
 | |
|     double d2;
 | |
|     double ts;
 | |
|     double vv;
 | |
| 
 | |
|     *worstidx = 0;
 | |
|     *worsterror = 0;
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Quick exit for 0, 1, 2 points
 | |
|      */
 | |
|     if( i1-i0+1<3 )
 | |
|     {
 | |
|         *worstidx = i0;
 | |
|         *worsterror = 0.0;
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Estimate D2 - squared distance between XY[I1] and XY[I0].
 | |
|      * In case D2=0 handle it as special case.
 | |
|      */
 | |
|     d2 = 0.0;
 | |
|     for(j=0; j<=d-1; j++)
 | |
|     {
 | |
|         d2 = d2+ae_sqr(xy->ptr.pp_double[i1][j]-xy->ptr.pp_double[i0][j], _state);
 | |
|     }
 | |
|     if( ae_fp_eq(d2,(double)(0)) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * First and last points are equal, interval evaluation is
 | |
|          * trivial - we just calculate distance from all points to
 | |
|          * the first/last one.
 | |
|          */
 | |
|         *worstidx = i0;
 | |
|         *worsterror = 0.0;
 | |
|         for(i=i0+1; i<=i1-1; i++)
 | |
|         {
 | |
|             vv = 0.0;
 | |
|             for(j=0; j<=d-1; j++)
 | |
|             {
 | |
|                 v = xy->ptr.pp_double[i][j]-xy->ptr.pp_double[i0][j];
 | |
|                 vv = vv+v*v;
 | |
|             }
 | |
|             vv = ae_sqrt(vv, _state);
 | |
|             if( ae_fp_greater(vv,*worsterror) )
 | |
|             {
 | |
|                 *worsterror = vv;
 | |
|                 *worstidx = i;
 | |
|             }
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * General case
 | |
|      *
 | |
|      * Current section of curve is modeled as x(t) = d*t+c, where
 | |
|      *     d = XY[I1]-XY[I0]
 | |
|      *     c = XY[I0]
 | |
|      *     t is in [0,1]
 | |
|      */
 | |
|     *worstidx = i0;
 | |
|     *worsterror = 0.0;
 | |
|     for(i=i0+1; i<=i1-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Determine t_s - parameter value for projected point.
 | |
|          */
 | |
|         ts = (double)(i-i0)/(double)(i1-i0);
 | |
|         
 | |
|         /*
 | |
|          * Estimate error norm
 | |
|          */
 | |
|         vv = 0.0;
 | |
|         for(j=0; j<=d-1; j++)
 | |
|         {
 | |
|             v = (xy->ptr.pp_double[i1][j]-xy->ptr.pp_double[i0][j])*ts-(xy->ptr.pp_double[i][j]-xy->ptr.pp_double[i0][j]);
 | |
|             vv = vv+ae_sqr(v, _state);
 | |
|         }
 | |
|         vv = ae_sqrt(vv, _state);
 | |
|         if( ae_fp_greater(vv,*worsterror) )
 | |
|         {
 | |
|             *worsterror = vv;
 | |
|             *worstidx = i;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void _pspline2interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     pspline2interpolant *p = (pspline2interpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic);
 | |
|     _spline1dinterpolant_init(&p->x, _state, make_automatic);
 | |
|     _spline1dinterpolant_init(&p->y, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _pspline2interpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     pspline2interpolant *dst = (pspline2interpolant*)_dst;
 | |
|     pspline2interpolant *src = (pspline2interpolant*)_src;
 | |
|     dst->n = src->n;
 | |
|     dst->periodic = src->periodic;
 | |
|     ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic);
 | |
|     _spline1dinterpolant_init_copy(&dst->x, &src->x, _state, make_automatic);
 | |
|     _spline1dinterpolant_init_copy(&dst->y, &src->y, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _pspline2interpolant_clear(void* _p)
 | |
| {
 | |
|     pspline2interpolant *p = (pspline2interpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->p);
 | |
|     _spline1dinterpolant_clear(&p->x);
 | |
|     _spline1dinterpolant_clear(&p->y);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _pspline2interpolant_destroy(void* _p)
 | |
| {
 | |
|     pspline2interpolant *p = (pspline2interpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->p);
 | |
|     _spline1dinterpolant_destroy(&p->x);
 | |
|     _spline1dinterpolant_destroy(&p->y);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _pspline3interpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     pspline3interpolant *p = (pspline3interpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->p, 0, DT_REAL, _state, make_automatic);
 | |
|     _spline1dinterpolant_init(&p->x, _state, make_automatic);
 | |
|     _spline1dinterpolant_init(&p->y, _state, make_automatic);
 | |
|     _spline1dinterpolant_init(&p->z, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _pspline3interpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     pspline3interpolant *dst = (pspline3interpolant*)_dst;
 | |
|     pspline3interpolant *src = (pspline3interpolant*)_src;
 | |
|     dst->n = src->n;
 | |
|     dst->periodic = src->periodic;
 | |
|     ae_vector_init_copy(&dst->p, &src->p, _state, make_automatic);
 | |
|     _spline1dinterpolant_init_copy(&dst->x, &src->x, _state, make_automatic);
 | |
|     _spline1dinterpolant_init_copy(&dst->y, &src->y, _state, make_automatic);
 | |
|     _spline1dinterpolant_init_copy(&dst->z, &src->z, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _pspline3interpolant_clear(void* _p)
 | |
| {
 | |
|     pspline3interpolant *p = (pspline3interpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->p);
 | |
|     _spline1dinterpolant_clear(&p->x);
 | |
|     _spline1dinterpolant_clear(&p->y);
 | |
|     _spline1dinterpolant_clear(&p->z);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _pspline3interpolant_destroy(void* _p)
 | |
| {
 | |
|     pspline3interpolant *p = (pspline3interpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->p);
 | |
|     _spline1dinterpolant_destroy(&p->x);
 | |
|     _spline1dinterpolant_destroy(&p->y);
 | |
|     _spline1dinterpolant_destroy(&p->z);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_SPLINE3D) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates the value of the trilinear or tricubic spline at
 | |
| the given point (X,Y,Z).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   coefficients table.
 | |
|             Built by BuildBilinearSpline or BuildBicubicSpline.
 | |
|     X, Y,
 | |
|     Z   -   point
 | |
| 
 | |
| Result:
 | |
|     S(x,y,z)
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double spline3dcalc(spline3dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      double z,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double v;
 | |
|     double vx;
 | |
|     double vy;
 | |
|     double vxy;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalc: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalc: X=NaN/Infinite, Y=NaN/Infinite or Z=NaN/Infinite", _state);
 | |
|     if( c->d!=1 )
 | |
|     {
 | |
|         result = (double)(0);
 | |
|         return result;
 | |
|     }
 | |
|     spline3d_spline3ddiff(c, x, y, z, &v, &vx, &vy, &vxy, _state);
 | |
|     result = v;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline argument.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C       -   spline interpolant
 | |
|     AX, BX  -   transformation coefficients: x = A*u + B
 | |
|     AY, BY  -   transformation coefficients: y = A*v + B
 | |
|     AZ, BZ  -   transformation coefficients: z = A*w + B
 | |
|     
 | |
| OUTPUT PARAMETERS:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dlintransxyz(spline3dinterpolant* c,
 | |
|      double ax,
 | |
|      double bx,
 | |
|      double ay,
 | |
|      double by,
 | |
|      double az,
 | |
|      double bz,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector x;
 | |
|     ae_vector y;
 | |
|     ae_vector z;
 | |
|     ae_vector f;
 | |
|     ae_vector v;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t di;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&x, 0, sizeof(x));
 | |
|     memset(&y, 0, sizeof(y));
 | |
|     memset(&z, 0, sizeof(z));
 | |
|     memset(&f, 0, sizeof(f));
 | |
|     memset(&v, 0, sizeof(v));
 | |
|     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&z, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&f, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&v, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(c->stype==-3||c->stype==-1, "Spline3DLinTransXYZ: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_vector_set_length(&x, c->n, _state);
 | |
|     ae_vector_set_length(&y, c->m, _state);
 | |
|     ae_vector_set_length(&z, c->l, _state);
 | |
|     ae_vector_set_length(&f, c->m*c->n*c->l*c->d, _state);
 | |
|     for(j=0; j<=c->n-1; j++)
 | |
|     {
 | |
|         x.ptr.p_double[j] = c->x.ptr.p_double[j];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         y.ptr.p_double[i] = c->y.ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->l-1; i++)
 | |
|     {
 | |
|         z.ptr.p_double[i] = c->z.ptr.p_double[i];
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Handle different combinations of zero/nonzero AX/AY/AZ
 | |
|      */
 | |
|     if( (ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) )
 | |
|     {
 | |
|         ae_v_move(&f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,c->m*c->n*c->l*c->d-1));
 | |
|     }
 | |
|     if( (ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) )
 | |
|     {
 | |
|         for(i=0; i<=c->m-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=c->l-1; j++)
 | |
|             {
 | |
|                 spline3dcalcv(c, bx, y.ptr.p_double[i], z.ptr.p_double[j], &v, _state);
 | |
|                 for(k=0; k<=c->n-1; k++)
 | |
|                 {
 | |
|                     for(di=0; di<=c->d-1; di++)
 | |
|                     {
 | |
|                         f.ptr.p_double[c->d*(c->n*(c->m*j+i)+k)+di] = v.ptr.p_double[di];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         ax = (double)(1);
 | |
|         bx = (double)(0);
 | |
|     }
 | |
|     if( (ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) )
 | |
|     {
 | |
|         for(i=0; i<=c->n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=c->l-1; j++)
 | |
|             {
 | |
|                 spline3dcalcv(c, x.ptr.p_double[i], by, z.ptr.p_double[j], &v, _state);
 | |
|                 for(k=0; k<=c->m-1; k++)
 | |
|                 {
 | |
|                     for(di=0; di<=c->d-1; di++)
 | |
|                     {
 | |
|                         f.ptr.p_double[c->d*(c->n*(c->m*j+k)+i)+di] = v.ptr.p_double[di];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         ay = (double)(1);
 | |
|         by = (double)(0);
 | |
|     }
 | |
|     if( (ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) )
 | |
|     {
 | |
|         for(i=0; i<=c->n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=c->m-1; j++)
 | |
|             {
 | |
|                 spline3dcalcv(c, x.ptr.p_double[i], y.ptr.p_double[j], bz, &v, _state);
 | |
|                 for(k=0; k<=c->l-1; k++)
 | |
|                 {
 | |
|                     for(di=0; di<=c->d-1; di++)
 | |
|                     {
 | |
|                         f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         az = (double)(1);
 | |
|         bz = (double)(0);
 | |
|     }
 | |
|     if( (ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_neq(az,(double)(0)) )
 | |
|     {
 | |
|         for(i=0; i<=c->l-1; i++)
 | |
|         {
 | |
|             spline3dcalcv(c, bx, by, z.ptr.p_double[i], &v, _state);
 | |
|             for(k=0; k<=c->m-1; k++)
 | |
|             {
 | |
|                 for(j=0; j<=c->n-1; j++)
 | |
|                 {
 | |
|                     for(di=0; di<=c->d-1; di++)
 | |
|                     {
 | |
|                         f.ptr.p_double[c->d*(c->n*(c->m*i+k)+j)+di] = v.ptr.p_double[di];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         ax = (double)(1);
 | |
|         bx = (double)(0);
 | |
|         ay = (double)(1);
 | |
|         by = (double)(0);
 | |
|     }
 | |
|     if( (ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) )
 | |
|     {
 | |
|         for(i=0; i<=c->m-1; i++)
 | |
|         {
 | |
|             spline3dcalcv(c, bx, y.ptr.p_double[i], bz, &v, _state);
 | |
|             for(k=0; k<=c->l-1; k++)
 | |
|             {
 | |
|                 for(j=0; j<=c->n-1; j++)
 | |
|                 {
 | |
|                     for(di=0; di<=c->d-1; di++)
 | |
|                     {
 | |
|                         f.ptr.p_double[c->d*(c->n*(c->m*k+i)+j)+di] = v.ptr.p_double[di];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         ax = (double)(1);
 | |
|         bx = (double)(0);
 | |
|         az = (double)(1);
 | |
|         bz = (double)(0);
 | |
|     }
 | |
|     if( (ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) )
 | |
|     {
 | |
|         for(i=0; i<=c->n-1; i++)
 | |
|         {
 | |
|             spline3dcalcv(c, x.ptr.p_double[i], by, bz, &v, _state);
 | |
|             for(k=0; k<=c->l-1; k++)
 | |
|             {
 | |
|                 for(j=0; j<=c->m-1; j++)
 | |
|                 {
 | |
|                     for(di=0; di<=c->d-1; di++)
 | |
|                     {
 | |
|                         f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         ay = (double)(1);
 | |
|         by = (double)(0);
 | |
|         az = (double)(1);
 | |
|         bz = (double)(0);
 | |
|     }
 | |
|     if( (ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)))&&ae_fp_eq(az,(double)(0)) )
 | |
|     {
 | |
|         spline3dcalcv(c, bx, by, bz, &v, _state);
 | |
|         for(k=0; k<=c->l-1; k++)
 | |
|         {
 | |
|             for(j=0; j<=c->m-1; j++)
 | |
|             {
 | |
|                 for(i=0; i<=c->n-1; i++)
 | |
|                 {
 | |
|                     for(di=0; di<=c->d-1; di++)
 | |
|                     {
 | |
|                         f.ptr.p_double[c->d*(c->n*(c->m*k+j)+i)+di] = v.ptr.p_double[di];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         ax = (double)(1);
 | |
|         bx = (double)(0);
 | |
|         ay = (double)(1);
 | |
|         by = (double)(0);
 | |
|         az = (double)(1);
 | |
|         bz = (double)(0);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * General case: AX<>0, AY<>0, AZ<>0
 | |
|      * Unpack, scale and pack again.
 | |
|      */
 | |
|     for(i=0; i<=c->n-1; i++)
 | |
|     {
 | |
|         x.ptr.p_double[i] = (x.ptr.p_double[i]-bx)/ax;
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay;
 | |
|     }
 | |
|     for(i=0; i<=c->l-1; i++)
 | |
|     {
 | |
|         z.ptr.p_double[i] = (z.ptr.p_double[i]-bz)/az;
 | |
|     }
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         spline3dbuildtrilinearv(&x, c->n, &y, c->m, &z, c->l, &f, c->d, c, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     A, B-   transformation coefficients: S2(x,y) = A*S(x,y,z) + B
 | |
|     
 | |
| OUTPUT PARAMETERS:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dlintransf(spline3dinterpolant* c,
 | |
|      double a,
 | |
|      double b,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector x;
 | |
|     ae_vector y;
 | |
|     ae_vector z;
 | |
|     ae_vector f;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&x, 0, sizeof(x));
 | |
|     memset(&y, 0, sizeof(y));
 | |
|     memset(&z, 0, sizeof(z));
 | |
|     memset(&f, 0, sizeof(f));
 | |
|     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&z, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&f, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(c->stype==-3||c->stype==-1, "Spline3DLinTransF: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_vector_set_length(&x, c->n, _state);
 | |
|     ae_vector_set_length(&y, c->m, _state);
 | |
|     ae_vector_set_length(&z, c->l, _state);
 | |
|     ae_vector_set_length(&f, c->m*c->n*c->l*c->d, _state);
 | |
|     for(j=0; j<=c->n-1; j++)
 | |
|     {
 | |
|         x.ptr.p_double[j] = c->x.ptr.p_double[j];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         y.ptr.p_double[i] = c->y.ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->l-1; i++)
 | |
|     {
 | |
|         z.ptr.p_double[i] = c->z.ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->m*c->n*c->l*c->d-1; i++)
 | |
|     {
 | |
|         f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b;
 | |
|     }
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         spline3dbuildtrilinearv(&x, c->n, &y, c->m, &z, c->l, &f, c->d, c, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine makes the copy of the spline model.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     CC  -   spline copy
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dcopy(spline3dinterpolant* c,
 | |
|      spline3dinterpolant* cc,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t tblsize;
 | |
| 
 | |
|     _spline3dinterpolant_clear(cc);
 | |
| 
 | |
|     ae_assert(c->k==1||c->k==3, "Spline3DCopy: incorrect C (incorrect parameter C.K)", _state);
 | |
|     cc->k = c->k;
 | |
|     cc->n = c->n;
 | |
|     cc->m = c->m;
 | |
|     cc->l = c->l;
 | |
|     cc->d = c->d;
 | |
|     tblsize = c->n*c->m*c->l*c->d;
 | |
|     cc->stype = c->stype;
 | |
|     ae_vector_set_length(&cc->x, cc->n, _state);
 | |
|     ae_vector_set_length(&cc->y, cc->m, _state);
 | |
|     ae_vector_set_length(&cc->z, cc->l, _state);
 | |
|     ae_vector_set_length(&cc->f, tblsize, _state);
 | |
|     ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1));
 | |
|     ae_v_move(&cc->y.ptr.p_double[0], 1, &c->y.ptr.p_double[0], 1, ae_v_len(0,cc->m-1));
 | |
|     ae_v_move(&cc->z.ptr.p_double[0], 1, &c->z.ptr.p_double[0], 1, ae_v_len(0,cc->l-1));
 | |
|     ae_v_move(&cc->f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,tblsize-1));
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Trilinear spline resampling
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A           -   array[0..OldXCount*OldYCount*OldZCount-1], function
 | |
|                     values at the old grid, :
 | |
|                         A[0]        x=0,y=0,z=0
 | |
|                         A[1]        x=1,y=0,z=0
 | |
|                         A[..]       ...
 | |
|                         A[..]       x=oldxcount-1,y=0,z=0
 | |
|                         A[..]       x=0,y=1,z=0
 | |
|                         A[..]       ...
 | |
|                         ...
 | |
|     OldZCount   -   old Z-count, OldZCount>1
 | |
|     OldYCount   -   old Y-count, OldYCount>1
 | |
|     OldXCount   -   old X-count, OldXCount>1
 | |
|     NewZCount   -   new Z-count, NewZCount>1
 | |
|     NewYCount   -   new Y-count, NewYCount>1
 | |
|     NewXCount   -   new X-count, NewXCount>1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     B           -   array[0..NewXCount*NewYCount*NewZCount-1], function
 | |
|                     values at the new grid:
 | |
|                         B[0]        x=0,y=0,z=0
 | |
|                         B[1]        x=1,y=0,z=0
 | |
|                         B[..]       ...
 | |
|                         B[..]       x=newxcount-1,y=0,z=0
 | |
|                         B[..]       x=0,y=1,z=0
 | |
|                         B[..]       ...
 | |
|                         ...
 | |
| 
 | |
|   -- ALGLIB routine --
 | |
|      26.04.2012
 | |
|      Copyright by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dresampletrilinear(/* Real    */ ae_vector* a,
 | |
|      ae_int_t oldzcount,
 | |
|      ae_int_t oldycount,
 | |
|      ae_int_t oldxcount,
 | |
|      ae_int_t newzcount,
 | |
|      ae_int_t newycount,
 | |
|      ae_int_t newxcount,
 | |
|      /* Real    */ ae_vector* b,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double xd;
 | |
|     double yd;
 | |
|     double zd;
 | |
|     double c0;
 | |
|     double c1;
 | |
|     double c2;
 | |
|     double c3;
 | |
|     ae_int_t ix;
 | |
|     ae_int_t iy;
 | |
|     ae_int_t iz;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
| 
 | |
|     ae_vector_clear(b);
 | |
| 
 | |
|     ae_assert((oldycount>1&&oldzcount>1)&&oldxcount>1, "Spline3DResampleTrilinear: length/width/height less than 1", _state);
 | |
|     ae_assert((newycount>1&&newzcount>1)&&newxcount>1, "Spline3DResampleTrilinear: length/width/height less than 1", _state);
 | |
|     ae_assert(a->cnt>=oldycount*oldzcount*oldxcount, "Spline3DResampleTrilinear: length/width/height less than 1", _state);
 | |
|     ae_vector_set_length(b, newxcount*newycount*newzcount, _state);
 | |
|     for(i=0; i<=newxcount-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=newycount-1; j++)
 | |
|         {
 | |
|             for(k=0; k<=newzcount-1; k++)
 | |
|             {
 | |
|                 ix = i*(oldxcount-1)/(newxcount-1);
 | |
|                 if( ix==oldxcount-1 )
 | |
|                 {
 | |
|                     ix = oldxcount-2;
 | |
|                 }
 | |
|                 xd = (double)(i*(oldxcount-1))/(double)(newxcount-1)-ix;
 | |
|                 iy = j*(oldycount-1)/(newycount-1);
 | |
|                 if( iy==oldycount-1 )
 | |
|                 {
 | |
|                     iy = oldycount-2;
 | |
|                 }
 | |
|                 yd = (double)(j*(oldycount-1))/(double)(newycount-1)-iy;
 | |
|                 iz = k*(oldzcount-1)/(newzcount-1);
 | |
|                 if( iz==oldzcount-1 )
 | |
|                 {
 | |
|                     iz = oldzcount-2;
 | |
|                 }
 | |
|                 zd = (double)(k*(oldzcount-1))/(double)(newzcount-1)-iz;
 | |
|                 c0 = a->ptr.p_double[oldxcount*(oldycount*iz+iy)+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*iz+iy)+(ix+1)]*xd;
 | |
|                 c1 = a->ptr.p_double[oldxcount*(oldycount*iz+(iy+1))+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*iz+(iy+1))+(ix+1)]*xd;
 | |
|                 c2 = a->ptr.p_double[oldxcount*(oldycount*(iz+1)+iy)+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*(iz+1)+iy)+(ix+1)]*xd;
 | |
|                 c3 = a->ptr.p_double[oldxcount*(oldycount*(iz+1)+(iy+1))+ix]*(1-xd)+a->ptr.p_double[oldxcount*(oldycount*(iz+1)+(iy+1))+(ix+1)]*xd;
 | |
|                 c0 = c0*(1-yd)+c1*yd;
 | |
|                 c1 = c2*(1-yd)+c3*yd;
 | |
|                 b->ptr.p_double[newxcount*(newycount*k+j)+i] = c0*(1-zd)+c1*zd;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds trilinear vector-valued spline.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   spline abscissas,  array[0..N-1]
 | |
|     Y   -   spline ordinates,  array[0..M-1]
 | |
|     Z   -   spline applicates, array[0..L-1] 
 | |
|     F   -   function values, array[0..M*N*L*D-1]:
 | |
|             * first D elements store D values at (X[0],Y[0],Z[0])
 | |
|             * next D elements store D values at (X[1],Y[0],Z[0])
 | |
|             * next D elements store D values at (X[2],Y[0],Z[0])
 | |
|             * ...
 | |
|             * next D elements store D values at (X[0],Y[1],Z[0])
 | |
|             * next D elements store D values at (X[1],Y[1],Z[0])
 | |
|             * next D elements store D values at (X[2],Y[1],Z[0])
 | |
|             * ...
 | |
|             * next D elements store D values at (X[0],Y[0],Z[1])
 | |
|             * next D elements store D values at (X[1],Y[0],Z[1])
 | |
|             * next D elements store D values at (X[2],Y[0],Z[1])
 | |
|             * ...
 | |
|             * general form - D function values at (X[i],Y[j]) are stored
 | |
|               at F[D*(N*(M*K+J)+I)...D*(N*(M*K+J)+I)+D-1].
 | |
|     M,N,
 | |
|     L   -   grid size, M>=2, N>=2, L>=2
 | |
|     D   -   vector dimension, D>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dbuildtrilinearv(/* Real    */ ae_vector* x,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t m,
 | |
|      /* Real    */ ae_vector* z,
 | |
|      ae_int_t l,
 | |
|      /* Real    */ ae_vector* f,
 | |
|      ae_int_t d,
 | |
|      spline3dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double t;
 | |
|     ae_int_t tblsize;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t j0;
 | |
| 
 | |
|     _spline3dinterpolant_clear(c);
 | |
| 
 | |
|     ae_assert(m>=2, "Spline3DBuildTrilinearV: M<2", _state);
 | |
|     ae_assert(n>=2, "Spline3DBuildTrilinearV: N<2", _state);
 | |
|     ae_assert(l>=2, "Spline3DBuildTrilinearV: L<2", _state);
 | |
|     ae_assert(d>=1, "Spline3DBuildTrilinearV: D<1", _state);
 | |
|     ae_assert((x->cnt>=n&&y->cnt>=m)&&z->cnt>=l, "Spline3DBuildTrilinearV: length of X, Y or Z is too short (Length(X/Y/Z)<N/M/L)", _state);
 | |
|     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);
 | |
|     tblsize = n*m*l*d;
 | |
|     ae_assert(f->cnt>=tblsize, "Spline3DBuildTrilinearV: length of F is too short (Length(F)<N*M*L*D)", _state);
 | |
|     ae_assert(isfinitevector(f, tblsize, _state), "Spline3DBuildTrilinearV: F contains NaN or Infinite value", _state);
 | |
|     
 | |
|     /*
 | |
|      * Fill interpolant
 | |
|      */
 | |
|     c->k = 1;
 | |
|     c->n = n;
 | |
|     c->m = m;
 | |
|     c->l = l;
 | |
|     c->d = d;
 | |
|     c->stype = -1;
 | |
|     ae_vector_set_length(&c->x, c->n, _state);
 | |
|     ae_vector_set_length(&c->y, c->m, _state);
 | |
|     ae_vector_set_length(&c->z, c->l, _state);
 | |
|     ae_vector_set_length(&c->f, tblsize, _state);
 | |
|     for(i=0; i<=c->n-1; i++)
 | |
|     {
 | |
|         c->x.ptr.p_double[i] = x->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         c->y.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->l-1; i++)
 | |
|     {
 | |
|         c->z.ptr.p_double[i] = z->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=tblsize-1; i++)
 | |
|     {
 | |
|         c->f.ptr.p_double[i] = f->ptr.p_double[i];
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Sort points:
 | |
|      *  * sort x;
 | |
|      *  * sort y;
 | |
|      *  * sort z.
 | |
|      */
 | |
|     for(j=0; j<=c->n-1; j++)
 | |
|     {
 | |
|         k = j;
 | |
|         for(i=j+1; i<=c->n-1; i++)
 | |
|         {
 | |
|             if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) )
 | |
|             {
 | |
|                 k = i;
 | |
|             }
 | |
|         }
 | |
|         if( k!=j )
 | |
|         {
 | |
|             for(i=0; i<=c->m-1; i++)
 | |
|             {
 | |
|                 for(j0=0; j0<=c->l-1; j0++)
 | |
|                 {
 | |
|                     for(i0=0; i0<=c->d-1; i0++)
 | |
|                     {
 | |
|                         t = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0];
 | |
|                         c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+k)+i0];
 | |
|                         c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+k)+i0] = t;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             t = c->x.ptr.p_double[j];
 | |
|             c->x.ptr.p_double[j] = c->x.ptr.p_double[k];
 | |
|             c->x.ptr.p_double[k] = t;
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         k = i;
 | |
|         for(j=i+1; j<=c->m-1; j++)
 | |
|         {
 | |
|             if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) )
 | |
|             {
 | |
|                 k = j;
 | |
|             }
 | |
|         }
 | |
|         if( k!=i )
 | |
|         {
 | |
|             for(j=0; j<=c->n-1; j++)
 | |
|             {
 | |
|                 for(j0=0; j0<=c->l-1; j0++)
 | |
|                 {
 | |
|                     for(i0=0; i0<=c->d-1; i0++)
 | |
|                     {
 | |
|                         t = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0];
 | |
|                         c->f.ptr.p_double[c->d*(c->n*(c->m*j0+i)+j)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*j0+k)+j)+i0];
 | |
|                         c->f.ptr.p_double[c->d*(c->n*(c->m*j0+k)+j)+i0] = t;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             t = c->y.ptr.p_double[i];
 | |
|             c->y.ptr.p_double[i] = c->y.ptr.p_double[k];
 | |
|             c->y.ptr.p_double[k] = t;
 | |
|         }
 | |
|     }
 | |
|     for(k=0; k<=c->l-1; k++)
 | |
|     {
 | |
|         i = k;
 | |
|         for(j=i+1; j<=c->l-1; j++)
 | |
|         {
 | |
|             if( ae_fp_less(c->z.ptr.p_double[j],c->z.ptr.p_double[i]) )
 | |
|             {
 | |
|                 i = j;
 | |
|             }
 | |
|         }
 | |
|         if( i!=k )
 | |
|         {
 | |
|             for(j=0; j<=c->m-1; j++)
 | |
|             {
 | |
|                 for(j0=0; j0<=c->n-1; j0++)
 | |
|                 {
 | |
|                     for(i0=0; i0<=c->d-1; i0++)
 | |
|                     {
 | |
|                         t = c->f.ptr.p_double[c->d*(c->n*(c->m*k+j)+j0)+i0];
 | |
|                         c->f.ptr.p_double[c->d*(c->n*(c->m*k+j)+j0)+i0] = c->f.ptr.p_double[c->d*(c->n*(c->m*i+j)+j0)+i0];
 | |
|                         c->f.ptr.p_double[c->d*(c->n*(c->m*i+j)+j0)+i0] = t;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             t = c->z.ptr.p_double[k];
 | |
|             c->z.ptr.p_double[k] = c->z.ptr.p_double[i];
 | |
|             c->z.ptr.p_double[i] = t;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates bilinear or bicubic vector-valued spline at the
 | |
| given point (X,Y,Z).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y,
 | |
|     Z   -   point
 | |
|     F   -   output buffer, possibly preallocated array. In case array size
 | |
|             is large enough to store result, it is not reallocated.  Array
 | |
|             which is too short will be reallocated
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   array[D] (or larger) which stores function values
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dcalcvbuf(spline3dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      double z,
 | |
|      /* Real    */ ae_vector* f,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double xd;
 | |
|     double yd;
 | |
|     double zd;
 | |
|     double c0;
 | |
|     double c1;
 | |
|     double c2;
 | |
|     double c3;
 | |
|     ae_int_t ix;
 | |
|     ae_int_t iy;
 | |
|     ae_int_t iz;
 | |
|     ae_int_t l;
 | |
|     ae_int_t r;
 | |
|     ae_int_t h;
 | |
|     ae_int_t i;
 | |
| 
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalcVBuf: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalcVBuf: X, Y or Z contains NaN/Infinite", _state);
 | |
|     rvectorsetlengthatleast(f, c->d, _state);
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->n-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     ix = l;
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ y[0], ..., y[n-2] ] (y[n-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->m-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     iy = l;
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ z[0], ..., z[n-2] ] (z[n-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->l-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->z.ptr.p_double[h],z) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     iz = l;
 | |
|     xd = (x-c->x.ptr.p_double[ix])/(c->x.ptr.p_double[ix+1]-c->x.ptr.p_double[ix]);
 | |
|     yd = (y-c->y.ptr.p_double[iy])/(c->y.ptr.p_double[iy+1]-c->y.ptr.p_double[iy]);
 | |
|     zd = (z-c->z.ptr.p_double[iz])/(c->z.ptr.p_double[iz+1]-c->z.ptr.p_double[iz]);
 | |
|     for(i=0; i<=c->d-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Trilinear interpolation
 | |
|          */
 | |
|         if( c->stype==-1 )
 | |
|         {
 | |
|             c0 = c->f.ptr.p_double[c->d*(c->n*(c->m*iz+iy)+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*iz+iy)+(ix+1))+i]*xd;
 | |
|             c1 = c->f.ptr.p_double[c->d*(c->n*(c->m*iz+(iy+1))+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*iz+(iy+1))+(ix+1))+i]*xd;
 | |
|             c2 = c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+iy)+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+iy)+(ix+1))+i]*xd;
 | |
|             c3 = c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+(iy+1))+ix)+i]*(1-xd)+c->f.ptr.p_double[c->d*(c->n*(c->m*(iz+1)+(iy+1))+(ix+1))+i]*xd;
 | |
|             c0 = c0*(1-yd)+c1*yd;
 | |
|             c1 = c2*(1-yd)+c3*yd;
 | |
|             f->ptr.p_double[i] = c0*(1-zd)+c1*zd;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates trilinear or tricubic vector-valued spline at the
 | |
| given point (X,Y,Z).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y,
 | |
|     Z   -   point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   array[D] which stores function values.  F is out-parameter and
 | |
|             it  is  reallocated  after  call to this function. In case you
 | |
|             want  to    reuse  previously  allocated  F,   you   may   use
 | |
|             Spline2DCalcVBuf(),  which  reallocates  F only when it is too
 | |
|             small.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dcalcv(spline3dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      double z,
 | |
|      /* Real    */ ae_vector* f,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     ae_vector_clear(f);
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline3DCalcV: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert((ae_isfinite(x, _state)&&ae_isfinite(y, _state))&&ae_isfinite(z, _state), "Spline3DCalcV: X=NaN/Infinite, Y=NaN/Infinite or Z=NaN/Infinite", _state);
 | |
|     ae_vector_set_length(f, c->d, _state);
 | |
|     spline3dcalcvbuf(c, x, y, z, f, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine unpacks tri-dimensional spline into the coefficients table
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
| 
 | |
| Result:
 | |
|     N   -   grid size (X)
 | |
|     M   -   grid size (Y)
 | |
|     L   -   grid size (Z)
 | |
|     D   -   number of components
 | |
|     SType-  spline type. Currently, only one spline type is supported:
 | |
|             trilinear spline, as indicated by SType=1.
 | |
|     Tbl -   spline coefficients: [0..(N-1)*(M-1)*(L-1)*D-1, 0..13].
 | |
|             For T=0..D-1 (component index), I = 0...N-2 (x index),
 | |
|             J=0..M-2 (y index), K=0..L-2 (z index):
 | |
|                 Q := T + I*D + J*D*(N-1) + K*D*(N-1)*(M-1),
 | |
|                 
 | |
|                 Q-th row stores decomposition for T-th component of the
 | |
|                 vector-valued function
 | |
|                 
 | |
|                 Tbl[Q,0] = X[i]
 | |
|                 Tbl[Q,1] = X[i+1]
 | |
|                 Tbl[Q,2] = Y[j]
 | |
|                 Tbl[Q,3] = Y[j+1]
 | |
|                 Tbl[Q,4] = Z[k]
 | |
|                 Tbl[Q,5] = Z[k+1]
 | |
|                 
 | |
|                 Tbl[Q,6] = C000
 | |
|                 Tbl[Q,7] = C100
 | |
|                 Tbl[Q,8] = C010
 | |
|                 Tbl[Q,9] = C110
 | |
|                 Tbl[Q,10]= C001
 | |
|                 Tbl[Q,11]= C101
 | |
|                 Tbl[Q,12]= C011
 | |
|                 Tbl[Q,13]= C111
 | |
|             On each grid square spline is equals to:
 | |
|                 S(x) = SUM(c[i,j,k]*(x^i)*(y^j)*(z^k), i=0..1, j=0..1, k=0..1)
 | |
|                 t = x-x[j]
 | |
|                 u = y-y[i]
 | |
|                 v = z-z[k]
 | |
|             
 | |
|             NOTE: format of Tbl is given for SType=1. Future versions of
 | |
|                   ALGLIB can use different formats for different values of
 | |
|                   SType.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline3dunpackv(spline3dinterpolant* c,
 | |
|      ae_int_t* n,
 | |
|      ae_int_t* m,
 | |
|      ae_int_t* l,
 | |
|      ae_int_t* d,
 | |
|      ae_int_t* stype,
 | |
|      /* Real    */ ae_matrix* tbl,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t p;
 | |
|     ae_int_t ci;
 | |
|     ae_int_t cj;
 | |
|     ae_int_t ck;
 | |
|     double du;
 | |
|     double dv;
 | |
|     double dw;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t di;
 | |
|     ae_int_t i0;
 | |
| 
 | |
|     *n = 0;
 | |
|     *m = 0;
 | |
|     *l = 0;
 | |
|     *d = 0;
 | |
|     *stype = 0;
 | |
|     ae_matrix_clear(tbl);
 | |
| 
 | |
|     ae_assert(c->stype==-1, "Spline3DUnpackV: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     *n = c->n;
 | |
|     *m = c->m;
 | |
|     *l = c->l;
 | |
|     *d = c->d;
 | |
|     *stype = ae_iabs(c->stype, _state);
 | |
|     ae_matrix_set_length(tbl, (*n-1)*(*m-1)*(*l-1)*(*d), 14, _state);
 | |
|     
 | |
|     /*
 | |
|      * Fill
 | |
|      */
 | |
|     for(i=0; i<=*n-2; i++)
 | |
|     {
 | |
|         for(j=0; j<=*m-2; j++)
 | |
|         {
 | |
|             for(k=0; k<=*l-2; k++)
 | |
|             {
 | |
|                 for(di=0; di<=*d-1; di++)
 | |
|                 {
 | |
|                     p = *d*((*n-1)*((*m-1)*k+j)+i)+di;
 | |
|                     tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[i];
 | |
|                     tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[i+1];
 | |
|                     tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[j];
 | |
|                     tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[j+1];
 | |
|                     tbl->ptr.pp_double[p][4] = c->z.ptr.p_double[k];
 | |
|                     tbl->ptr.pp_double[p][5] = c->z.ptr.p_double[k+1];
 | |
|                     du = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]);
 | |
|                     dv = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]);
 | |
|                     dw = 1/(tbl->ptr.pp_double[p][5]-tbl->ptr.pp_double[p][4]);
 | |
|                     
 | |
|                     /*
 | |
|                      * Trilinear interpolation
 | |
|                      */
 | |
|                     if( c->stype==-1 )
 | |
|                     {
 | |
|                         for(i0=6; i0<=13; i0++)
 | |
|                         {
 | |
|                             tbl->ptr.pp_double[p][i0] = (double)(0);
 | |
|                         }
 | |
|                         tbl->ptr.pp_double[p][6+2*(2*0+0)+0] = c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di];
 | |
|                         tbl->ptr.pp_double[p][6+2*(2*0+0)+1] = c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di];
 | |
|                         tbl->ptr.pp_double[p][6+2*(2*0+1)+0] = c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di];
 | |
|                         tbl->ptr.pp_double[p][6+2*(2*0+1)+1] = c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di];
 | |
|                         tbl->ptr.pp_double[p][6+2*(2*1+0)+0] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di];
 | |
|                         tbl->ptr.pp_double[p][6+2*(2*1+0)+1] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di];
 | |
|                         tbl->ptr.pp_double[p][6+2*(2*1+1)+0] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di];
 | |
|                         tbl->ptr.pp_double[p][6+2*(2*1+1)+1] = c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+(j+1))+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*(k+1)+j)+i)+di]-c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+(i+1))+di]+c->f.ptr.p_double[*d*(*n*(*m*k+(j+1))+i)+di]+c->f.ptr.p_double[*d*(*n*(*m*k+j)+(i+1))+di]-c->f.ptr.p_double[*d*(*n*(*m*k+j)+i)+di];
 | |
|                     }
 | |
|                     
 | |
|                     /*
 | |
|                      * Rescale Cij
 | |
|                      */
 | |
|                     for(ci=0; ci<=1; ci++)
 | |
|                     {
 | |
|                         for(cj=0; cj<=1; cj++)
 | |
|                         {
 | |
|                             for(ck=0; ck<=1; ck++)
 | |
|                             {
 | |
|                                 tbl->ptr.pp_double[p][6+2*(2*ck+cj)+ci] = tbl->ptr.pp_double[p][6+2*(2*ck+cj)+ci]*ae_pow(du, (double)(ci), _state)*ae_pow(dv, (double)(cj), _state)*ae_pow(dw, (double)(ck), _state);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates the value of the trilinear(or tricubic;possible
 | |
| will be later) spline  at the given point X(and its derivatives; possible
 | |
| will be later).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C       -   spline interpolant.
 | |
|     X, Y, Z -   point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   S(x,y,z)
 | |
|     FX  -   dS(x,y,z)/dX
 | |
|     FY  -   dS(x,y,z)/dY
 | |
|     FXY -   d2S(x,y,z)/dXdY
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 26.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline3d_spline3ddiff(spline3dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      double z,
 | |
|      double* f,
 | |
|      double* fx,
 | |
|      double* fy,
 | |
|      double* fxy,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double xd;
 | |
|     double yd;
 | |
|     double zd;
 | |
|     double c0;
 | |
|     double c1;
 | |
|     double c2;
 | |
|     double c3;
 | |
|     ae_int_t ix;
 | |
|     ae_int_t iy;
 | |
|     ae_int_t iz;
 | |
|     ae_int_t l;
 | |
|     ae_int_t r;
 | |
|     ae_int_t h;
 | |
| 
 | |
|     *f = 0;
 | |
|     *fx = 0;
 | |
|     *fy = 0;
 | |
|     *fxy = 0;
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline3DDiff: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline3DDiff: X or Y contains NaN or Infinite value", _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare F, dF/dX, dF/dY, d2F/dXdY
 | |
|      */
 | |
|     *f = (double)(0);
 | |
|     *fx = (double)(0);
 | |
|     *fy = (double)(0);
 | |
|     *fxy = (double)(0);
 | |
|     if( c->d!=1 )
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->n-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     ix = l;
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ y[0], ..., y[n-2] ] (y[n-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->m-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     iy = l;
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ z[0], ..., z[n-2] ] (z[n-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->l-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->z.ptr.p_double[h],z) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     iz = l;
 | |
|     xd = (x-c->x.ptr.p_double[ix])/(c->x.ptr.p_double[ix+1]-c->x.ptr.p_double[ix]);
 | |
|     yd = (y-c->y.ptr.p_double[iy])/(c->y.ptr.p_double[iy+1]-c->y.ptr.p_double[iy]);
 | |
|     zd = (z-c->z.ptr.p_double[iz])/(c->z.ptr.p_double[iz+1]-c->z.ptr.p_double[iz]);
 | |
|     
 | |
|     /*
 | |
|      * Trilinear interpolation
 | |
|      */
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         c0 = c->f.ptr.p_double[c->n*(c->m*iz+iy)+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*iz+iy)+(ix+1)]*xd;
 | |
|         c1 = c->f.ptr.p_double[c->n*(c->m*iz+(iy+1))+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*iz+(iy+1))+(ix+1)]*xd;
 | |
|         c2 = c->f.ptr.p_double[c->n*(c->m*(iz+1)+iy)+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*(iz+1)+iy)+(ix+1)]*xd;
 | |
|         c3 = c->f.ptr.p_double[c->n*(c->m*(iz+1)+(iy+1))+ix]*(1-xd)+c->f.ptr.p_double[c->n*(c->m*(iz+1)+(iy+1))+(ix+1)]*xd;
 | |
|         c0 = c0*(1-yd)+c1*yd;
 | |
|         c1 = c2*(1-yd)+c3*yd;
 | |
|         *f = c0*(1-zd)+c1*zd;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline3dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline3dinterpolant *p = (spline3dinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->z, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline3dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline3dinterpolant *dst = (spline3dinterpolant*)_dst;
 | |
|     spline3dinterpolant *src = (spline3dinterpolant*)_src;
 | |
|     dst->k = src->k;
 | |
|     dst->stype = src->stype;
 | |
|     dst->n = src->n;
 | |
|     dst->m = src->m;
 | |
|     dst->l = src->l;
 | |
|     dst->d = src->d;
 | |
|     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->z, &src->z, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline3dinterpolant_clear(void* _p)
 | |
| {
 | |
|     spline3dinterpolant *p = (spline3dinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->x);
 | |
|     ae_vector_clear(&p->y);
 | |
|     ae_vector_clear(&p->z);
 | |
|     ae_vector_clear(&p->f);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline3dinterpolant_destroy(void* _p)
 | |
| {
 | |
|     spline3dinterpolant *p = (spline3dinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->x);
 | |
|     ae_vector_destroy(&p->y);
 | |
|     ae_vector_destroy(&p->z);
 | |
|     ae_vector_destroy(&p->f);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_POLINT) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Conversion from barycentric representation to Chebyshev basis.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   polynomial in barycentric form
 | |
|     A,B -   base interval for Chebyshev polynomials (see below)
 | |
|             A<>B
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     T   -   coefficients of Chebyshev representation;
 | |
|             P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N-1 },
 | |
|             where Ti - I-th Chebyshev polynomial.
 | |
| 
 | |
| NOTES:
 | |
|     barycentric interpolant passed as P may be either polynomial  obtained
 | |
|     from  polynomial  interpolation/ fitting or rational function which is
 | |
|     NOT polynomial. We can't distinguish between these two cases, and this
 | |
|     algorithm just tries to work assuming that P IS a polynomial.  If not,
 | |
|     algorithm will return results, but they won't have any meaning.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbar2cheb(barycentricinterpolant* p,
 | |
|      double a,
 | |
|      double b,
 | |
|      /* Real    */ ae_vector* t,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t k;
 | |
|     ae_vector vp;
 | |
|     ae_vector vx;
 | |
|     ae_vector tk;
 | |
|     ae_vector tk1;
 | |
|     double v;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&vp, 0, sizeof(vp));
 | |
|     memset(&vx, 0, sizeof(vx));
 | |
|     memset(&tk, 0, sizeof(tk));
 | |
|     memset(&tk1, 0, sizeof(tk1));
 | |
|     ae_vector_clear(t);
 | |
|     ae_vector_init(&vp, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&vx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tk, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tk1, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(ae_isfinite(a, _state), "PolynomialBar2Cheb: A is not finite!", _state);
 | |
|     ae_assert(ae_isfinite(b, _state), "PolynomialBar2Cheb: B is not finite!", _state);
 | |
|     ae_assert(ae_fp_neq(a,b), "PolynomialBar2Cheb: A=B!", _state);
 | |
|     ae_assert(p->n>0, "PolynomialBar2Cheb: P is not correctly initialized barycentric interpolant!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Calculate function values on a Chebyshev grid
 | |
|      */
 | |
|     ae_vector_set_length(&vp, p->n, _state);
 | |
|     ae_vector_set_length(&vx, p->n, _state);
 | |
|     for(i=0; i<=p->n-1; i++)
 | |
|     {
 | |
|         vx.ptr.p_double[i] = ae_cos(ae_pi*(i+0.5)/p->n, _state);
 | |
|         vp.ptr.p_double[i] = barycentriccalc(p, 0.5*(vx.ptr.p_double[i]+1)*(b-a)+a, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * T[0]
 | |
|      */
 | |
|     ae_vector_set_length(t, p->n, _state);
 | |
|     v = (double)(0);
 | |
|     for(i=0; i<=p->n-1; i++)
 | |
|     {
 | |
|         v = v+vp.ptr.p_double[i];
 | |
|     }
 | |
|     t->ptr.p_double[0] = v/p->n;
 | |
|     
 | |
|     /*
 | |
|      * other T's.
 | |
|      *
 | |
|      * NOTES:
 | |
|      * 1. TK stores T{k} on VX, TK1 stores T{k-1} on VX
 | |
|      * 2. we can do same calculations with fast DCT, but it
 | |
|      *    * adds dependencies
 | |
|      *    * still leaves us with O(N^2) algorithm because
 | |
|      *      preparation of function values is O(N^2) process
 | |
|      */
 | |
|     if( p->n>1 )
 | |
|     {
 | |
|         ae_vector_set_length(&tk, p->n, _state);
 | |
|         ae_vector_set_length(&tk1, p->n, _state);
 | |
|         for(i=0; i<=p->n-1; i++)
 | |
|         {
 | |
|             tk.ptr.p_double[i] = vx.ptr.p_double[i];
 | |
|             tk1.ptr.p_double[i] = (double)(1);
 | |
|         }
 | |
|         for(k=1; k<=p->n-1; k++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * calculate discrete product of function vector and TK
 | |
|              */
 | |
|             v = ae_v_dotproduct(&tk.ptr.p_double[0], 1, &vp.ptr.p_double[0], 1, ae_v_len(0,p->n-1));
 | |
|             t->ptr.p_double[k] = v/(0.5*p->n);
 | |
|             
 | |
|             /*
 | |
|              * Update TK and TK1
 | |
|              */
 | |
|             for(i=0; i<=p->n-1; i++)
 | |
|             {
 | |
|                 v = 2*vx.ptr.p_double[i]*tk.ptr.p_double[i]-tk1.ptr.p_double[i];
 | |
|                 tk1.ptr.p_double[i] = tk.ptr.p_double[i];
 | |
|                 tk.ptr.p_double[i] = v;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Conversion from Chebyshev basis to barycentric representation.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     T   -   coefficients of Chebyshev representation;
 | |
|             P(x) = sum { T[i]*Ti(2*(x-A)/(B-A)-1), i=0..N },
 | |
|             where Ti - I-th Chebyshev polynomial.
 | |
|     N   -   number of coefficients:
 | |
|             * if given, only leading N elements of T are used
 | |
|             * if not given, automatically determined from size of T
 | |
|     A,B -   base interval for Chebyshev polynomials (see above)
 | |
|             A<B
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   polynomial in barycentric form
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialcheb2bar(/* Real    */ ae_vector* t,
 | |
|      ae_int_t n,
 | |
|      double a,
 | |
|      double b,
 | |
|      barycentricinterpolant* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t k;
 | |
|     ae_vector y;
 | |
|     double tk;
 | |
|     double tk1;
 | |
|     double vx;
 | |
|     double vy;
 | |
|     double v;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&y, 0, sizeof(y));
 | |
|     _barycentricinterpolant_clear(p);
 | |
|     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(ae_isfinite(a, _state), "PolynomialBar2Cheb: A is not finite!", _state);
 | |
|     ae_assert(ae_isfinite(b, _state), "PolynomialBar2Cheb: B is not finite!", _state);
 | |
|     ae_assert(ae_fp_neq(a,b), "PolynomialBar2Cheb: A=B!", _state);
 | |
|     ae_assert(n>=1, "PolynomialBar2Cheb: N<1", _state);
 | |
|     ae_assert(t->cnt>=n, "PolynomialBar2Cheb: Length(T)<N", _state);
 | |
|     ae_assert(isfinitevector(t, n, _state), "PolynomialBar2Cheb: T[] contains INF or NAN", _state);
 | |
|     
 | |
|     /*
 | |
|      * Calculate function values on a Chebyshev grid spanning [-1,+1]
 | |
|      */
 | |
|     ae_vector_set_length(&y, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Calculate value on a grid spanning [-1,+1]
 | |
|          */
 | |
|         vx = ae_cos(ae_pi*(i+0.5)/n, _state);
 | |
|         vy = t->ptr.p_double[0];
 | |
|         tk1 = (double)(1);
 | |
|         tk = vx;
 | |
|         for(k=1; k<=n-1; k++)
 | |
|         {
 | |
|             vy = vy+t->ptr.p_double[k]*tk;
 | |
|             v = 2*vx*tk-tk1;
 | |
|             tk1 = tk;
 | |
|             tk = v;
 | |
|         }
 | |
|         y.ptr.p_double[i] = vy;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Build barycentric interpolant, map grid from [-1,+1] to [A,B]
 | |
|      */
 | |
|     polynomialbuildcheb1(a, b, &y, n, p, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Conversion from barycentric representation to power basis.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     P   -   polynomial in barycentric form
 | |
|     C   -   offset (see below); 0.0 is used as default value.
 | |
|     S   -   scale (see below);  1.0 is used as default value. S<>0.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
 | |
|     N   -   number of coefficients (polynomial degree plus 1)
 | |
| 
 | |
| NOTES:
 | |
| 1.  this function accepts offset and scale, which can be  set  to  improve
 | |
|     numerical properties of polynomial. For example, if P was obtained  as
 | |
|     result of interpolation on [-1,+1],  you  can  set  C=0  and  S=1  and
 | |
|     represent  P  as sum of 1, x, x^2, x^3 and so on. In most cases you it
 | |
|     is exactly what you need.
 | |
| 
 | |
|     However, if your interpolation model was built on [999,1001], you will
 | |
|     see significant growth of numerical errors when using {1, x, x^2, x^3}
 | |
|     as basis. Representing P as sum of 1, (x-1000), (x-1000)^2, (x-1000)^3
 | |
|     will be better option. Such representation can be  obtained  by  using
 | |
|     1000.0 as offset C and 1.0 as scale S.
 | |
| 
 | |
| 2.  power basis is ill-conditioned and tricks described above can't  solve
 | |
|     this problem completely. This function  will  return  coefficients  in
 | |
|     any  case,  but  for  N>8  they  will  become unreliable. However, N's
 | |
|     less than 5 are pretty safe.
 | |
|     
 | |
| 3.  barycentric interpolant passed as P may be either polynomial  obtained
 | |
|     from  polynomial  interpolation/ fitting or rational function which is
 | |
|     NOT polynomial. We can't distinguish between these two cases, and this
 | |
|     algorithm just tries to work assuming that P IS a polynomial.  If not,
 | |
|     algorithm will return results, but they won't have any meaning.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbar2pow(barycentricinterpolant* p,
 | |
|      double c,
 | |
|      double s,
 | |
|      /* Real    */ ae_vector* a,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t k;
 | |
|     double e;
 | |
|     double d;
 | |
|     ae_vector vp;
 | |
|     ae_vector vx;
 | |
|     ae_vector tk;
 | |
|     ae_vector tk1;
 | |
|     ae_vector t;
 | |
|     double v;
 | |
|     double c0;
 | |
|     double s0;
 | |
|     double va;
 | |
|     double vb;
 | |
|     ae_vector vai;
 | |
|     ae_vector vbi;
 | |
|     double minx;
 | |
|     double maxx;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&vp, 0, sizeof(vp));
 | |
|     memset(&vx, 0, sizeof(vx));
 | |
|     memset(&tk, 0, sizeof(tk));
 | |
|     memset(&tk1, 0, sizeof(tk1));
 | |
|     memset(&t, 0, sizeof(t));
 | |
|     memset(&vai, 0, sizeof(vai));
 | |
|     memset(&vbi, 0, sizeof(vbi));
 | |
|     ae_vector_clear(a);
 | |
|     ae_vector_init(&vp, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&vx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tk, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tk1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&t, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&vai, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&vbi, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * We have barycentric model built using set of points X[], and we
 | |
|      * want to convert it to power basis centered about point  C  with
 | |
|      * scale S: I-th basis function is ((X-C)/S)^i.
 | |
|      *
 | |
|      * We use following three-stage algorithm:
 | |
|      *
 | |
|      * 1. we build Chebyshev representation of polynomial using
 | |
|      *    intermediate center C0 and scale S0, which are derived from X[]:
 | |
|      *    C0 = 0.5*(min(X)+max(X)), S0 = 0.5*(max(X)-min(X)). Chebyshev
 | |
|      *    representation is built by sampling points around center C0,
 | |
|      *    with typical distance between them proportional to S0.
 | |
|      * 2. then we transform form Chebyshev basis to intermediate power
 | |
|      *    basis, using same center/scale C0/S0.
 | |
|      * 3. after that, we apply linear transformation to intermediate
 | |
|      *    power basis which moves it to final center/scale C/S.
 | |
|      *
 | |
|      * The idea of such multi-stage algorithm is that it is much easier to
 | |
|      * transform barycentric model to Chebyshev basis, and only later to
 | |
|      * power basis, than transforming it directly to power basis. It is
 | |
|      * also more numerically stable to sample points using intermediate C0/S0,
 | |
|      * which are derived from user-supplied model, than using "final" C/S,
 | |
|      * which may be unsuitable for sampling (say, if S=1, we may have stability
 | |
|      * problems when working with models built from dataset with non-unit
 | |
|      * scale of abscissas).
 | |
|      */
 | |
|     ae_assert(ae_isfinite(c, _state), "PolynomialBar2Pow: C is not finite!", _state);
 | |
|     ae_assert(ae_isfinite(s, _state), "PolynomialBar2Pow: S is not finite!", _state);
 | |
|     ae_assert(ae_fp_neq(s,(double)(0)), "PolynomialBar2Pow: S=0!", _state);
 | |
|     ae_assert(p->n>0, "PolynomialBar2Pow: P is not correctly initialized barycentric interpolant!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Select intermediate center/scale
 | |
|      */
 | |
|     minx = p->x.ptr.p_double[0];
 | |
|     maxx = p->x.ptr.p_double[0];
 | |
|     for(i=1; i<=p->n-1; i++)
 | |
|     {
 | |
|         minx = ae_minreal(minx, p->x.ptr.p_double[i], _state);
 | |
|         maxx = ae_maxreal(maxx, p->x.ptr.p_double[i], _state);
 | |
|     }
 | |
|     if( ae_fp_eq(minx,maxx) )
 | |
|     {
 | |
|         c0 = minx;
 | |
|         s0 = 1.0;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         c0 = 0.5*(maxx+minx);
 | |
|         s0 = 0.5*(maxx-minx);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Calculate function values on a Chebyshev grid using intermediate C0/S0
 | |
|      */
 | |
|     ae_vector_set_length(&vp, p->n+1, _state);
 | |
|     ae_vector_set_length(&vx, p->n, _state);
 | |
|     for(i=0; i<=p->n-1; i++)
 | |
|     {
 | |
|         vx.ptr.p_double[i] = ae_cos(ae_pi*(i+0.5)/p->n, _state);
 | |
|         vp.ptr.p_double[i] = barycentriccalc(p, s0*vx.ptr.p_double[i]+c0, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * T[0]
 | |
|      */
 | |
|     ae_vector_set_length(&t, p->n, _state);
 | |
|     v = (double)(0);
 | |
|     for(i=0; i<=p->n-1; i++)
 | |
|     {
 | |
|         v = v+vp.ptr.p_double[i];
 | |
|     }
 | |
|     t.ptr.p_double[0] = v/p->n;
 | |
|     
 | |
|     /*
 | |
|      * other T's.
 | |
|      *
 | |
|      * NOTES:
 | |
|      * 1. TK stores T{k} on VX, TK1 stores T{k-1} on VX
 | |
|      * 2. we can do same calculations with fast DCT, but it
 | |
|      *    * adds dependencies
 | |
|      *    * still leaves us with O(N^2) algorithm because
 | |
|      *      preparation of function values is O(N^2) process
 | |
|      */
 | |
|     if( p->n>1 )
 | |
|     {
 | |
|         ae_vector_set_length(&tk, p->n, _state);
 | |
|         ae_vector_set_length(&tk1, p->n, _state);
 | |
|         for(i=0; i<=p->n-1; i++)
 | |
|         {
 | |
|             tk.ptr.p_double[i] = vx.ptr.p_double[i];
 | |
|             tk1.ptr.p_double[i] = (double)(1);
 | |
|         }
 | |
|         for(k=1; k<=p->n-1; k++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * calculate discrete product of function vector and TK
 | |
|              */
 | |
|             v = ae_v_dotproduct(&tk.ptr.p_double[0], 1, &vp.ptr.p_double[0], 1, ae_v_len(0,p->n-1));
 | |
|             t.ptr.p_double[k] = v/(0.5*p->n);
 | |
|             
 | |
|             /*
 | |
|              * Update TK and TK1
 | |
|              */
 | |
|             for(i=0; i<=p->n-1; i++)
 | |
|             {
 | |
|                 v = 2*vx.ptr.p_double[i]*tk.ptr.p_double[i]-tk1.ptr.p_double[i];
 | |
|                 tk1.ptr.p_double[i] = tk.ptr.p_double[i];
 | |
|                 tk.ptr.p_double[i] = v;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Convert from Chebyshev basis to power basis
 | |
|      */
 | |
|     ae_vector_set_length(a, p->n, _state);
 | |
|     for(i=0; i<=p->n-1; i++)
 | |
|     {
 | |
|         a->ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     d = (double)(0);
 | |
|     for(i=0; i<=p->n-1; i++)
 | |
|     {
 | |
|         for(k=i; k<=p->n-1; k++)
 | |
|         {
 | |
|             e = a->ptr.p_double[k];
 | |
|             a->ptr.p_double[k] = (double)(0);
 | |
|             if( i<=1&&k==i )
 | |
|             {
 | |
|                 a->ptr.p_double[k] = (double)(1);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( i!=0 )
 | |
|                 {
 | |
|                     a->ptr.p_double[k] = 2*d;
 | |
|                 }
 | |
|                 if( k>i+1 )
 | |
|                 {
 | |
|                     a->ptr.p_double[k] = a->ptr.p_double[k]-a->ptr.p_double[k-2];
 | |
|                 }
 | |
|             }
 | |
|             d = e;
 | |
|         }
 | |
|         d = a->ptr.p_double[i];
 | |
|         e = (double)(0);
 | |
|         k = i;
 | |
|         while(k<=p->n-1)
 | |
|         {
 | |
|             e = e+a->ptr.p_double[k]*t.ptr.p_double[k];
 | |
|             k = k+2;
 | |
|         }
 | |
|         a->ptr.p_double[i] = e;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Apply linear transformation which converts basis from intermediate
 | |
|      * one Fi=((x-C0)/S0)^i to final one Fi=((x-C)/S)^i.
 | |
|      *
 | |
|      * We have y=(x-C0)/S0, z=(x-C)/S, and coefficients A[] for basis Fi(y).
 | |
|      * Because we have y=A*z+B, for A=s/s0 and B=c/s0-c0/s0, we can perform
 | |
|      * substitution and get coefficients A_new[] in basis Fi(z).
 | |
|      */
 | |
|     ae_assert(vp.cnt>=p->n+1, "PolynomialBar2Pow: internal error", _state);
 | |
|     ae_assert(t.cnt>=p->n, "PolynomialBar2Pow: internal error", _state);
 | |
|     for(i=0; i<=p->n-1; i++)
 | |
|     {
 | |
|         t.ptr.p_double[i] = 0.0;
 | |
|     }
 | |
|     va = s/s0;
 | |
|     vb = c/s0-c0/s0;
 | |
|     ae_vector_set_length(&vai, p->n, _state);
 | |
|     ae_vector_set_length(&vbi, p->n, _state);
 | |
|     vai.ptr.p_double[0] = (double)(1);
 | |
|     vbi.ptr.p_double[0] = (double)(1);
 | |
|     for(k=1; k<=p->n-1; k++)
 | |
|     {
 | |
|         vai.ptr.p_double[k] = vai.ptr.p_double[k-1]*va;
 | |
|         vbi.ptr.p_double[k] = vbi.ptr.p_double[k-1]*vb;
 | |
|     }
 | |
|     for(k=0; k<=p->n-1; k++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Generate set of binomial coefficients in VP[]
 | |
|          */
 | |
|         if( k>0 )
 | |
|         {
 | |
|             vp.ptr.p_double[k] = (double)(1);
 | |
|             for(i=k-1; i>=1; i--)
 | |
|             {
 | |
|                 vp.ptr.p_double[i] = vp.ptr.p_double[i]+vp.ptr.p_double[i-1];
 | |
|             }
 | |
|             vp.ptr.p_double[0] = (double)(1);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             vp.ptr.p_double[0] = (double)(1);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Update T[] with expansion of K-th basis function
 | |
|          */
 | |
|         for(i=0; i<=k; i++)
 | |
|         {
 | |
|             t.ptr.p_double[i] = t.ptr.p_double[i]+a->ptr.p_double[k]*vai.ptr.p_double[i]*vbi.ptr.p_double[k-i]*vp.ptr.p_double[i];
 | |
|         }
 | |
|     }
 | |
|     for(k=0; k<=p->n-1; k++)
 | |
|     {
 | |
|         a->ptr.p_double[k] = t.ptr.p_double[k];
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Conversion from power basis to barycentric representation.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   coefficients, P(x) = sum { A[i]*((X-C)/S)^i, i=0..N-1 }
 | |
|     N   -   number of coefficients (polynomial degree plus 1)
 | |
|             * if given, only leading N elements of A are used
 | |
|             * if not given, automatically determined from size of A
 | |
|     C   -   offset (see below); 0.0 is used as default value.
 | |
|     S   -   scale (see below);  1.0 is used as default value. S<>0.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   polynomial in barycentric form
 | |
| 
 | |
| 
 | |
| NOTES:
 | |
| 1.  this function accepts offset and scale, which can be  set  to  improve
 | |
|     numerical properties of polynomial. For example, if you interpolate on
 | |
|     [-1,+1],  you  can  set C=0 and S=1 and convert from sum of 1, x, x^2,
 | |
|     x^3 and so on. In most cases you it is exactly what you need.
 | |
| 
 | |
|     However, if your interpolation model was built on [999,1001], you will
 | |
|     see significant growth of numerical errors when using {1, x, x^2, x^3}
 | |
|     as  input  basis.  Converting  from  sum  of  1, (x-1000), (x-1000)^2,
 | |
|     (x-1000)^3 will be better option (you have to specify 1000.0 as offset
 | |
|     C and 1.0 as scale S).
 | |
| 
 | |
| 2.  power basis is ill-conditioned and tricks described above can't  solve
 | |
|     this problem completely. This function  will  return barycentric model
 | |
|     in any case, but for N>8 accuracy well degrade. However, N's less than
 | |
|     5 are pretty safe.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 30.09.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialpow2bar(/* Real    */ ae_vector* a,
 | |
|      ae_int_t n,
 | |
|      double c,
 | |
|      double s,
 | |
|      barycentricinterpolant* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t k;
 | |
|     ae_vector y;
 | |
|     double vx;
 | |
|     double vy;
 | |
|     double px;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&y, 0, sizeof(y));
 | |
|     _barycentricinterpolant_clear(p);
 | |
|     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(ae_isfinite(c, _state), "PolynomialPow2Bar: C is not finite!", _state);
 | |
|     ae_assert(ae_isfinite(s, _state), "PolynomialPow2Bar: S is not finite!", _state);
 | |
|     ae_assert(ae_fp_neq(s,(double)(0)), "PolynomialPow2Bar: S is zero!", _state);
 | |
|     ae_assert(n>=1, "PolynomialPow2Bar: N<1", _state);
 | |
|     ae_assert(a->cnt>=n, "PolynomialPow2Bar: Length(A)<N", _state);
 | |
|     ae_assert(isfinitevector(a, n, _state), "PolynomialPow2Bar: A[] contains INF or NAN", _state);
 | |
|     
 | |
|     /*
 | |
|      * Calculate function values on a Chebyshev grid spanning [-1,+1]
 | |
|      */
 | |
|     ae_vector_set_length(&y, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Calculate value on a grid spanning [-1,+1]
 | |
|          */
 | |
|         vx = ae_cos(ae_pi*(i+0.5)/n, _state);
 | |
|         vy = a->ptr.p_double[0];
 | |
|         px = vx;
 | |
|         for(k=1; k<=n-1; k++)
 | |
|         {
 | |
|             vy = vy+px*a->ptr.p_double[k];
 | |
|             px = px*vx;
 | |
|         }
 | |
|         y.ptr.p_double[i] = vy;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Build barycentric interpolant, map grid from [-1,+1] to [A,B]
 | |
|      */
 | |
|     polynomialbuildcheb1(c-s, c+s, &y, n, p, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant: generation of the model on the general grid.
 | |
| This function has O(N^2) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   abscissas, array[0..N-1]
 | |
|     Y   -   function values, array[0..N-1]
 | |
|     N   -   number of points, N>=1
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbuild(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      barycentricinterpolant* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_vector w;
 | |
|     double b;
 | |
|     double a;
 | |
|     double v;
 | |
|     double mx;
 | |
|     ae_vector sortrbuf;
 | |
|     ae_vector sortrbuf2;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     memset(&sortrbuf, 0, sizeof(sortrbuf));
 | |
|     memset(&sortrbuf2, 0, sizeof(sortrbuf2));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     _barycentricinterpolant_clear(p);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sortrbuf, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sortrbuf2, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>0, "PolynomialBuild: N<=0!", _state);
 | |
|     ae_assert(x->cnt>=n, "PolynomialBuild: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "PolynomialBuild: Length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "PolynomialBuild: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "PolynomialBuild: Y contains infinite or NaN values!", _state);
 | |
|     tagsortfastr(x, y, &sortrbuf, &sortrbuf2, n, _state);
 | |
|     ae_assert(aredistinct(x, n, _state), "PolynomialBuild: at least two consequent points are too close!", _state);
 | |
|     
 | |
|     /*
 | |
|      * calculate W[j]
 | |
|      * multi-pass algorithm is used to avoid overflow
 | |
|      */
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     a = x->ptr.p_double[0];
 | |
|     b = x->ptr.p_double[0];
 | |
|     for(j=0; j<=n-1; j++)
 | |
|     {
 | |
|         w.ptr.p_double[j] = (double)(1);
 | |
|         a = ae_minreal(a, x->ptr.p_double[j], _state);
 | |
|         b = ae_maxreal(b, x->ptr.p_double[j], _state);
 | |
|     }
 | |
|     for(k=0; k<=n-1; k++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * W[K] is used instead of 0.0 because
 | |
|          * cycle on J does not touch K-th element
 | |
|          * and we MUST get maximum from ALL elements
 | |
|          */
 | |
|         mx = ae_fabs(w.ptr.p_double[k], _state);
 | |
|         for(j=0; j<=n-1; j++)
 | |
|         {
 | |
|             if( j!=k )
 | |
|             {
 | |
|                 v = (b-a)/(x->ptr.p_double[j]-x->ptr.p_double[k]);
 | |
|                 w.ptr.p_double[j] = w.ptr.p_double[j]*v;
 | |
|                 mx = ae_maxreal(mx, ae_fabs(w.ptr.p_double[j], _state), _state);
 | |
|             }
 | |
|         }
 | |
|         if( k%5==0 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * every 5-th run we renormalize W[]
 | |
|              */
 | |
|             v = 1/mx;
 | |
|             ae_v_muld(&w.ptr.p_double[0], 1, ae_v_len(0,n-1), v);
 | |
|         }
 | |
|     }
 | |
|     barycentricbuildxyw(x, y, &w, n, p, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant: generation of the model on equidistant grid.
 | |
| This function has O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     Y   -   function values at the nodes, array[0..N-1]
 | |
|     N   -   number of points, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 03.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbuildeqdist(double a,
 | |
|      double b,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      barycentricinterpolant* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_vector w;
 | |
|     ae_vector x;
 | |
|     double v;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     memset(&x, 0, sizeof(x));
 | |
|     _barycentricinterpolant_clear(p);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>0, "PolynomialBuildEqDist: N<=0!", _state);
 | |
|     ae_assert(y->cnt>=n, "PolynomialBuildEqDist: Length(Y)<N!", _state);
 | |
|     ae_assert(ae_isfinite(a, _state), "PolynomialBuildEqDist: A is infinite or NaN!", _state);
 | |
|     ae_assert(ae_isfinite(b, _state), "PolynomialBuildEqDist: B is infinite or NaN!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "PolynomialBuildEqDist: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(ae_fp_neq(b,a), "PolynomialBuildEqDist: B=A!", _state);
 | |
|     ae_assert(ae_fp_neq(a+(b-a)/n,a), "PolynomialBuildEqDist: B is too close to A!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Special case: N=1
 | |
|      */
 | |
|     if( n==1 )
 | |
|     {
 | |
|         ae_vector_set_length(&x, 1, _state);
 | |
|         ae_vector_set_length(&w, 1, _state);
 | |
|         x.ptr.p_double[0] = 0.5*(b+a);
 | |
|         w.ptr.p_double[0] = (double)(1);
 | |
|         barycentricbuildxyw(&x, y, &w, 1, p, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * general case
 | |
|      */
 | |
|     ae_vector_set_length(&x, n, _state);
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     v = (double)(1);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         w.ptr.p_double[i] = v;
 | |
|         x.ptr.p_double[i] = a+(b-a)*i/(n-1);
 | |
|         v = -v*(n-1-i);
 | |
|         v = v/(i+1);
 | |
|     }
 | |
|     barycentricbuildxyw(&x, y, &w, n, p, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant on Chebyshev grid (first kind).
 | |
| This function has O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     Y   -   function values at the nodes, array[0..N-1],
 | |
|             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n)))
 | |
|     N   -   number of points, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 03.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbuildcheb1(double a,
 | |
|      double b,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      barycentricinterpolant* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_vector w;
 | |
|     ae_vector x;
 | |
|     double v;
 | |
|     double t;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     memset(&x, 0, sizeof(x));
 | |
|     _barycentricinterpolant_clear(p);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>0, "PolynomialBuildCheb1: N<=0!", _state);
 | |
|     ae_assert(y->cnt>=n, "PolynomialBuildCheb1: Length(Y)<N!", _state);
 | |
|     ae_assert(ae_isfinite(a, _state), "PolynomialBuildCheb1: A is infinite or NaN!", _state);
 | |
|     ae_assert(ae_isfinite(b, _state), "PolynomialBuildCheb1: B is infinite or NaN!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "PolynomialBuildCheb1: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(ae_fp_neq(b,a), "PolynomialBuildCheb1: B=A!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Special case: N=1
 | |
|      */
 | |
|     if( n==1 )
 | |
|     {
 | |
|         ae_vector_set_length(&x, 1, _state);
 | |
|         ae_vector_set_length(&w, 1, _state);
 | |
|         x.ptr.p_double[0] = 0.5*(b+a);
 | |
|         w.ptr.p_double[0] = (double)(1);
 | |
|         barycentricbuildxyw(&x, y, &w, 1, p, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * general case
 | |
|      */
 | |
|     ae_vector_set_length(&x, n, _state);
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     v = (double)(1);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         t = ae_tan(0.5*ae_pi*(2*i+1)/(2*n), _state);
 | |
|         w.ptr.p_double[i] = 2*v*t/(1+ae_sqr(t, _state));
 | |
|         x.ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*(1-ae_sqr(t, _state))/(1+ae_sqr(t, _state));
 | |
|         v = -v;
 | |
|     }
 | |
|     barycentricbuildxyw(&x, y, &w, n, p, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Lagrange intepolant on Chebyshev grid (second kind).
 | |
| This function has O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     Y   -   function values at the nodes, array[0..N-1],
 | |
|             Y[I] = Y(0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1)))
 | |
|     N   -   number of points, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     P   -   barycentric model which represents Lagrange interpolant
 | |
|             (see ratint unit info and BarycentricCalc() description for
 | |
|             more information).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 03.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialbuildcheb2(double a,
 | |
|      double b,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      barycentricinterpolant* p,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_vector w;
 | |
|     ae_vector x;
 | |
|     double v;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     memset(&x, 0, sizeof(x));
 | |
|     _barycentricinterpolant_clear(p);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>0, "PolynomialBuildCheb2: N<=0!", _state);
 | |
|     ae_assert(y->cnt>=n, "PolynomialBuildCheb2: Length(Y)<N!", _state);
 | |
|     ae_assert(ae_isfinite(a, _state), "PolynomialBuildCheb2: A is infinite or NaN!", _state);
 | |
|     ae_assert(ae_isfinite(b, _state), "PolynomialBuildCheb2: B is infinite or NaN!", _state);
 | |
|     ae_assert(ae_fp_neq(b,a), "PolynomialBuildCheb2: B=A!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "PolynomialBuildCheb2: Y contains infinite or NaN values!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Special case: N=1
 | |
|      */
 | |
|     if( n==1 )
 | |
|     {
 | |
|         ae_vector_set_length(&x, 1, _state);
 | |
|         ae_vector_set_length(&w, 1, _state);
 | |
|         x.ptr.p_double[0] = 0.5*(b+a);
 | |
|         w.ptr.p_double[0] = (double)(1);
 | |
|         barycentricbuildxyw(&x, y, &w, 1, p, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * general case
 | |
|      */
 | |
|     ae_vector_set_length(&x, n, _state);
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     v = (double)(1);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         if( i==0||i==n-1 )
 | |
|         {
 | |
|             w.ptr.p_double[i] = v*0.5;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             w.ptr.p_double[i] = v;
 | |
|         }
 | |
|         x.ptr.p_double[i] = 0.5*(b+a)+0.5*(b-a)*ae_cos(ae_pi*i/(n-1), _state);
 | |
|         v = -v;
 | |
|     }
 | |
|     barycentricbuildxyw(&x, y, &w, n, p, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fast equidistant polynomial interpolation function with O(N) complexity
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     N   -   number of points on equidistant grid, N>=1
 | |
|             for N=1 a constant model is constructed.
 | |
|     T   -   position where P(x) is calculated
 | |
| 
 | |
| RESULT
 | |
|     value of the Lagrange interpolant at T
 | |
|     
 | |
| IMPORTANT
 | |
|     this function provides fast interface which is not overflow-safe
 | |
|     nor it is very precise.
 | |
|     the best option is to use  PolynomialBuildEqDist()/BarycentricCalc()
 | |
|     subroutines unless you are pretty sure that your data will not result
 | |
|     in overflow.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double polynomialcalceqdist(double a,
 | |
|      double b,
 | |
|      /* Real    */ ae_vector* f,
 | |
|      ae_int_t n,
 | |
|      double t,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double s1;
 | |
|     double s2;
 | |
|     double v;
 | |
|     double threshold;
 | |
|     double s;
 | |
|     double h;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double w;
 | |
|     double x;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(n>0, "PolynomialCalcEqDist: N<=0!", _state);
 | |
|     ae_assert(f->cnt>=n, "PolynomialCalcEqDist: Length(F)<N!", _state);
 | |
|     ae_assert(ae_isfinite(a, _state), "PolynomialCalcEqDist: A is infinite or NaN!", _state);
 | |
|     ae_assert(ae_isfinite(b, _state), "PolynomialCalcEqDist: B is infinite or NaN!", _state);
 | |
|     ae_assert(isfinitevector(f, n, _state), "PolynomialCalcEqDist: F contains infinite or NaN values!", _state);
 | |
|     ae_assert(ae_fp_neq(b,a), "PolynomialCalcEqDist: B=A!", _state);
 | |
|     ae_assert(!ae_isinf(t, _state), "PolynomialCalcEqDist: T is infinite!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Special case: T is NAN
 | |
|      */
 | |
|     if( ae_isnan(t, _state) )
 | |
|     {
 | |
|         result = _state->v_nan;
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Special case: N=1
 | |
|      */
 | |
|     if( n==1 )
 | |
|     {
 | |
|         result = f->ptr.p_double[0];
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * First, decide: should we use "safe" formula (guarded
 | |
|      * against overflow) or fast one?
 | |
|      */
 | |
|     threshold = ae_sqrt(ae_minrealnumber, _state);
 | |
|     j = 0;
 | |
|     s = t-a;
 | |
|     for(i=1; i<=n-1; i++)
 | |
|     {
 | |
|         x = a+(double)i/(double)(n-1)*(b-a);
 | |
|         if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) )
 | |
|         {
 | |
|             s = t-x;
 | |
|             j = i;
 | |
|         }
 | |
|     }
 | |
|     if( ae_fp_eq(s,(double)(0)) )
 | |
|     {
 | |
|         result = f->ptr.p_double[j];
 | |
|         return result;
 | |
|     }
 | |
|     if( ae_fp_greater(ae_fabs(s, _state),threshold) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * use fast formula
 | |
|          */
 | |
|         j = -1;
 | |
|         s = 1.0;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Calculate using safe or fast barycentric formula
 | |
|      */
 | |
|     s1 = (double)(0);
 | |
|     s2 = (double)(0);
 | |
|     w = 1.0;
 | |
|     h = (b-a)/(n-1);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         if( i!=j )
 | |
|         {
 | |
|             v = s*w/(t-(a+i*h));
 | |
|             s1 = s1+v*f->ptr.p_double[i];
 | |
|             s2 = s2+v;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             v = w;
 | |
|             s1 = s1+v*f->ptr.p_double[i];
 | |
|             s2 = s2+v;
 | |
|         }
 | |
|         w = -w*(n-1-i);
 | |
|         w = w/(i+1);
 | |
|     }
 | |
|     result = s1/s2;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fast polynomial interpolation function on Chebyshev points (first kind)
 | |
| with O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     N   -   number of points on Chebyshev grid (first kind),
 | |
|             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*(2*i+1)/(2*n))
 | |
|             for N=1 a constant model is constructed.
 | |
|     T   -   position where P(x) is calculated
 | |
| 
 | |
| RESULT
 | |
|     value of the Lagrange interpolant at T
 | |
| 
 | |
| IMPORTANT
 | |
|     this function provides fast interface which is not overflow-safe
 | |
|     nor it is very precise.
 | |
|     the best option is to use  PolIntBuildCheb1()/BarycentricCalc()
 | |
|     subroutines unless you are pretty sure that your data will not result
 | |
|     in overflow.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double polynomialcalccheb1(double a,
 | |
|      double b,
 | |
|      /* Real    */ ae_vector* f,
 | |
|      ae_int_t n,
 | |
|      double t,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double s1;
 | |
|     double s2;
 | |
|     double v;
 | |
|     double threshold;
 | |
|     double s;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double a0;
 | |
|     double delta;
 | |
|     double alpha;
 | |
|     double beta;
 | |
|     double ca;
 | |
|     double sa;
 | |
|     double tempc;
 | |
|     double temps;
 | |
|     double x;
 | |
|     double w;
 | |
|     double p1;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(n>0, "PolynomialCalcCheb1: N<=0!", _state);
 | |
|     ae_assert(f->cnt>=n, "PolynomialCalcCheb1: Length(F)<N!", _state);
 | |
|     ae_assert(ae_isfinite(a, _state), "PolynomialCalcCheb1: A is infinite or NaN!", _state);
 | |
|     ae_assert(ae_isfinite(b, _state), "PolynomialCalcCheb1: B is infinite or NaN!", _state);
 | |
|     ae_assert(isfinitevector(f, n, _state), "PolynomialCalcCheb1: F contains infinite or NaN values!", _state);
 | |
|     ae_assert(ae_fp_neq(b,a), "PolynomialCalcCheb1: B=A!", _state);
 | |
|     ae_assert(!ae_isinf(t, _state), "PolynomialCalcCheb1: T is infinite!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Special case: T is NAN
 | |
|      */
 | |
|     if( ae_isnan(t, _state) )
 | |
|     {
 | |
|         result = _state->v_nan;
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Special case: N=1
 | |
|      */
 | |
|     if( n==1 )
 | |
|     {
 | |
|         result = f->ptr.p_double[0];
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare information for the recurrence formula
 | |
|      * used to calculate sin(pi*(2j+1)/(2n+2)) and
 | |
|      * cos(pi*(2j+1)/(2n+2)):
 | |
|      *
 | |
|      * A0    = pi/(2n+2)
 | |
|      * Delta = pi/(n+1)
 | |
|      * Alpha = 2 sin^2 (Delta/2)
 | |
|      * Beta  = sin(Delta)
 | |
|      *
 | |
|      * so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta).
 | |
|      * Then we use
 | |
|      *
 | |
|      * sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x))
 | |
|      * cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x))
 | |
|      *
 | |
|      * to repeatedly calculate sin(..) and cos(..).
 | |
|      */
 | |
|     threshold = ae_sqrt(ae_minrealnumber, _state);
 | |
|     t = (t-0.5*(a+b))/(0.5*(b-a));
 | |
|     a0 = ae_pi/(2*(n-1)+2);
 | |
|     delta = 2*ae_pi/(2*(n-1)+2);
 | |
|     alpha = 2*ae_sqr(ae_sin(delta/2, _state), _state);
 | |
|     beta = ae_sin(delta, _state);
 | |
|     
 | |
|     /*
 | |
|      * First, decide: should we use "safe" formula (guarded
 | |
|      * against overflow) or fast one?
 | |
|      */
 | |
|     ca = ae_cos(a0, _state);
 | |
|     sa = ae_sin(a0, _state);
 | |
|     j = 0;
 | |
|     x = ca;
 | |
|     s = t-x;
 | |
|     for(i=1; i<=n-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Next X[i]
 | |
|          */
 | |
|         temps = sa-(alpha*sa-beta*ca);
 | |
|         tempc = ca-(alpha*ca+beta*sa);
 | |
|         sa = temps;
 | |
|         ca = tempc;
 | |
|         x = ca;
 | |
|         
 | |
|         /*
 | |
|          * Use X[i]
 | |
|          */
 | |
|         if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) )
 | |
|         {
 | |
|             s = t-x;
 | |
|             j = i;
 | |
|         }
 | |
|     }
 | |
|     if( ae_fp_eq(s,(double)(0)) )
 | |
|     {
 | |
|         result = f->ptr.p_double[j];
 | |
|         return result;
 | |
|     }
 | |
|     if( ae_fp_greater(ae_fabs(s, _state),threshold) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * use fast formula
 | |
|          */
 | |
|         j = -1;
 | |
|         s = 1.0;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Calculate using safe or fast barycentric formula
 | |
|      */
 | |
|     s1 = (double)(0);
 | |
|     s2 = (double)(0);
 | |
|     ca = ae_cos(a0, _state);
 | |
|     sa = ae_sin(a0, _state);
 | |
|     p1 = 1.0;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Calculate X[i], W[i]
 | |
|          */
 | |
|         x = ca;
 | |
|         w = p1*sa;
 | |
|         
 | |
|         /*
 | |
|          * Proceed
 | |
|          */
 | |
|         if( i!=j )
 | |
|         {
 | |
|             v = s*w/(t-x);
 | |
|             s1 = s1+v*f->ptr.p_double[i];
 | |
|             s2 = s2+v;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             v = w;
 | |
|             s1 = s1+v*f->ptr.p_double[i];
 | |
|             s2 = s2+v;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Next CA, SA, P1
 | |
|          */
 | |
|         temps = sa-(alpha*sa-beta*ca);
 | |
|         tempc = ca-(alpha*ca+beta*sa);
 | |
|         sa = temps;
 | |
|         ca = tempc;
 | |
|         p1 = -p1;
 | |
|     }
 | |
|     result = s1/s2;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fast polynomial interpolation function on Chebyshev points (second kind)
 | |
| with O(N) complexity.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A   -   left boundary of [A,B]
 | |
|     B   -   right boundary of [A,B]
 | |
|     F   -   function values, array[0..N-1]
 | |
|     N   -   number of points on Chebyshev grid (second kind),
 | |
|             X[i] = 0.5*(B+A) + 0.5*(B-A)*Cos(PI*i/(n-1))
 | |
|             for N=1 a constant model is constructed.
 | |
|     T   -   position where P(x) is calculated
 | |
| 
 | |
| RESULT
 | |
|     value of the Lagrange interpolant at T
 | |
| 
 | |
| IMPORTANT
 | |
|     this function provides fast interface which is not overflow-safe
 | |
|     nor it is very precise.
 | |
|     the best option is to use PolIntBuildCheb2()/BarycentricCalc()
 | |
|     subroutines unless you are pretty sure that your data will not result
 | |
|     in overflow.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double polynomialcalccheb2(double a,
 | |
|      double b,
 | |
|      /* Real    */ ae_vector* f,
 | |
|      ae_int_t n,
 | |
|      double t,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double s1;
 | |
|     double s2;
 | |
|     double v;
 | |
|     double threshold;
 | |
|     double s;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double a0;
 | |
|     double delta;
 | |
|     double alpha;
 | |
|     double beta;
 | |
|     double ca;
 | |
|     double sa;
 | |
|     double tempc;
 | |
|     double temps;
 | |
|     double x;
 | |
|     double w;
 | |
|     double p1;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(n>0, "PolynomialCalcCheb2: N<=0!", _state);
 | |
|     ae_assert(f->cnt>=n, "PolynomialCalcCheb2: Length(F)<N!", _state);
 | |
|     ae_assert(ae_isfinite(a, _state), "PolynomialCalcCheb2: A is infinite or NaN!", _state);
 | |
|     ae_assert(ae_isfinite(b, _state), "PolynomialCalcCheb2: B is infinite or NaN!", _state);
 | |
|     ae_assert(ae_fp_neq(b,a), "PolynomialCalcCheb2: B=A!", _state);
 | |
|     ae_assert(isfinitevector(f, n, _state), "PolynomialCalcCheb2: F contains infinite or NaN values!", _state);
 | |
|     ae_assert(!ae_isinf(t, _state), "PolynomialCalcEqDist: T is infinite!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Special case: T is NAN
 | |
|      */
 | |
|     if( ae_isnan(t, _state) )
 | |
|     {
 | |
|         result = _state->v_nan;
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Special case: N=1
 | |
|      */
 | |
|     if( n==1 )
 | |
|     {
 | |
|         result = f->ptr.p_double[0];
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare information for the recurrence formula
 | |
|      * used to calculate sin(pi*i/n) and
 | |
|      * cos(pi*i/n):
 | |
|      *
 | |
|      * A0    = 0
 | |
|      * Delta = pi/n
 | |
|      * Alpha = 2 sin^2 (Delta/2)
 | |
|      * Beta  = sin(Delta)
 | |
|      *
 | |
|      * so that sin(..) = sin(A0+j*delta) and cos(..) = cos(A0+j*delta).
 | |
|      * Then we use
 | |
|      *
 | |
|      * sin(x+delta) = sin(x) - (alpha*sin(x) - beta*cos(x))
 | |
|      * cos(x+delta) = cos(x) - (alpha*cos(x) - beta*sin(x))
 | |
|      *
 | |
|      * to repeatedly calculate sin(..) and cos(..).
 | |
|      */
 | |
|     threshold = ae_sqrt(ae_minrealnumber, _state);
 | |
|     t = (t-0.5*(a+b))/(0.5*(b-a));
 | |
|     a0 = 0.0;
 | |
|     delta = ae_pi/(n-1);
 | |
|     alpha = 2*ae_sqr(ae_sin(delta/2, _state), _state);
 | |
|     beta = ae_sin(delta, _state);
 | |
|     
 | |
|     /*
 | |
|      * First, decide: should we use "safe" formula (guarded
 | |
|      * against overflow) or fast one?
 | |
|      */
 | |
|     ca = ae_cos(a0, _state);
 | |
|     sa = ae_sin(a0, _state);
 | |
|     j = 0;
 | |
|     x = ca;
 | |
|     s = t-x;
 | |
|     for(i=1; i<=n-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Next X[i]
 | |
|          */
 | |
|         temps = sa-(alpha*sa-beta*ca);
 | |
|         tempc = ca-(alpha*ca+beta*sa);
 | |
|         sa = temps;
 | |
|         ca = tempc;
 | |
|         x = ca;
 | |
|         
 | |
|         /*
 | |
|          * Use X[i]
 | |
|          */
 | |
|         if( ae_fp_less(ae_fabs(t-x, _state),ae_fabs(s, _state)) )
 | |
|         {
 | |
|             s = t-x;
 | |
|             j = i;
 | |
|         }
 | |
|     }
 | |
|     if( ae_fp_eq(s,(double)(0)) )
 | |
|     {
 | |
|         result = f->ptr.p_double[j];
 | |
|         return result;
 | |
|     }
 | |
|     if( ae_fp_greater(ae_fabs(s, _state),threshold) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * use fast formula
 | |
|          */
 | |
|         j = -1;
 | |
|         s = 1.0;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Calculate using safe or fast barycentric formula
 | |
|      */
 | |
|     s1 = (double)(0);
 | |
|     s2 = (double)(0);
 | |
|     ca = ae_cos(a0, _state);
 | |
|     sa = ae_sin(a0, _state);
 | |
|     p1 = 1.0;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Calculate X[i], W[i]
 | |
|          */
 | |
|         x = ca;
 | |
|         if( i==0||i==n-1 )
 | |
|         {
 | |
|             w = 0.5*p1;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             w = 1.0*p1;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Proceed
 | |
|          */
 | |
|         if( i!=j )
 | |
|         {
 | |
|             v = s*w/(t-x);
 | |
|             s1 = s1+v*f->ptr.p_double[i];
 | |
|             s2 = s2+v;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             v = w;
 | |
|             s1 = s1+v*f->ptr.p_double[i];
 | |
|             s2 = s2+v;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Next CA, SA, P1
 | |
|          */
 | |
|         temps = sa-(alpha*sa-beta*ca);
 | |
|         tempc = ca-(alpha*ca+beta*sa);
 | |
|         sa = temps;
 | |
|         ca = tempc;
 | |
|         p1 = -p1;
 | |
|     }
 | |
|     result = s1/s2;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_LSFIT) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
 | |
| Peucker algorithm, which stops after generating specified number of linear
 | |
| sections.
 | |
| 
 | |
| IMPORTANT:
 | |
| * it does NOT perform least-squares fitting; it  builds  curve,  but  this
 | |
|   curve does not minimize some least squares metric.  See  description  of
 | |
|   RDP algorithm (say, in Wikipedia) for more details on WHAT is performed.
 | |
| * this function does NOT work with parametric curves  (i.e.  curves  which
 | |
|   can be represented as {X(t),Y(t)}. It works with curves   which  can  be
 | |
|   represented as Y(X). Thus,  it  is  impossible  to  model  figures  like
 | |
|   circles  with  this  functions.
 | |
|   If  you  want  to  work  with  parametric   curves,   you   should   use
 | |
|   ParametricRDPFixed() function provided  by  "Parametric"  subpackage  of
 | |
|   "Interpolation" package.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array of X-coordinates:
 | |
|                 * at least N elements
 | |
|                 * can be unordered (points are automatically sorted)
 | |
|                 * this function may accept non-distinct X (see below for
 | |
|                   more information on handling of such inputs)
 | |
|     Y       -   array of Y-coordinates:
 | |
|                 * at least N elements
 | |
|     N       -   number of elements in X/Y
 | |
|     M       -   desired number of sections:
 | |
|                 * at most M sections are generated by this function
 | |
|                 * less than M sections can be generated if we have N<M
 | |
|                   (or some X are non-distinct).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X2      -   X-values of corner points for piecewise approximation,
 | |
|                 has length NSections+1 or zero (for NSections=0).
 | |
|     Y2      -   Y-values of corner points,
 | |
|                 has length NSections+1 or zero (for NSections=0).
 | |
|     NSections-  number of sections found by algorithm, NSections<=M,
 | |
|                 NSections can be zero for degenerate datasets
 | |
|                 (N<=1 or all X[] are non-distinct).
 | |
| 
 | |
| NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is  a  first  point  of
 | |
|       curve, (X2[NSection-1],Y2[NSection-1]) is the last point.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.10.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lstfitpiecewiselinearrdpfixed(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      /* Real    */ ae_vector* y2,
 | |
|      ae_int_t* nsections,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t k0;
 | |
|     ae_int_t k1;
 | |
|     ae_int_t k2;
 | |
|     ae_vector buf0;
 | |
|     ae_vector buf1;
 | |
|     ae_matrix sections;
 | |
|     ae_vector points;
 | |
|     double v;
 | |
|     ae_int_t worstidx;
 | |
|     double worsterror;
 | |
|     ae_int_t idx0;
 | |
|     ae_int_t idx1;
 | |
|     double e0;
 | |
|     double e1;
 | |
|     ae_vector heaperrors;
 | |
|     ae_vector heaptags;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&buf0, 0, sizeof(buf0));
 | |
|     memset(&buf1, 0, sizeof(buf1));
 | |
|     memset(§ions, 0, sizeof(sections));
 | |
|     memset(&points, 0, sizeof(points));
 | |
|     memset(&heaperrors, 0, sizeof(heaperrors));
 | |
|     memset(&heaptags, 0, sizeof(heaptags));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_clear(x2);
 | |
|     ae_vector_clear(y2);
 | |
|     *nsections = 0;
 | |
|     ae_vector_init(&buf0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&buf1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(§ions, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&points, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&heaperrors, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&heaptags, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=0, "LSTFitPiecewiseLinearRDPFixed: N<0", _state);
 | |
|     ae_assert(m>=1, "LSTFitPiecewiseLinearRDPFixed: M<1", _state);
 | |
|     ae_assert(x->cnt>=n, "LSTFitPiecewiseLinearRDPFixed: Length(X)<N", _state);
 | |
|     ae_assert(y->cnt>=n, "LSTFitPiecewiseLinearRDPFixed: Length(Y)<N", _state);
 | |
|     if( n<=1 )
 | |
|     {
 | |
|         *nsections = 0;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Sort points.
 | |
|      * Handle possible ties (tied values are replaced by their mean)
 | |
|      */
 | |
|     tagsortfastr(x, y, &buf0, &buf1, n, _state);
 | |
|     i = 0;
 | |
|     while(i<=n-1)
 | |
|     {
 | |
|         j = i+1;
 | |
|         v = y->ptr.p_double[i];
 | |
|         while(j<=n-1&&ae_fp_eq(x->ptr.p_double[j],x->ptr.p_double[i]))
 | |
|         {
 | |
|             v = v+y->ptr.p_double[j];
 | |
|             j = j+1;
 | |
|         }
 | |
|         v = v/(j-i);
 | |
|         for(k=i; k<=j-1; k++)
 | |
|         {
 | |
|             y->ptr.p_double[k] = v;
 | |
|         }
 | |
|         i = j;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Handle degenerate case x[0]=x[N-1]
 | |
|      */
 | |
|     if( ae_fp_eq(x->ptr.p_double[n-1],x->ptr.p_double[0]) )
 | |
|     {
 | |
|         *nsections = 0;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare first section
 | |
|      */
 | |
|     lsfit_rdpanalyzesection(x, y, 0, n-1, &worstidx, &worsterror, _state);
 | |
|     ae_matrix_set_length(§ions, m, 4, _state);
 | |
|     ae_vector_set_length(&heaperrors, m, _state);
 | |
|     ae_vector_set_length(&heaptags, m, _state);
 | |
|     *nsections = 1;
 | |
|     sections.ptr.pp_double[0][0] = (double)(0);
 | |
|     sections.ptr.pp_double[0][1] = (double)(n-1);
 | |
|     sections.ptr.pp_double[0][2] = (double)(worstidx);
 | |
|     sections.ptr.pp_double[0][3] = worsterror;
 | |
|     heaperrors.ptr.p_double[0] = worsterror;
 | |
|     heaptags.ptr.p_int[0] = 0;
 | |
|     ae_assert(ae_fp_eq(sections.ptr.pp_double[0][1],(double)(n-1)), "RDP algorithm: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Main loop.
 | |
|      * Repeatedly find section with worst error and divide it.
 | |
|      * Terminate after M-th section, or because of other reasons (see loop internals).
 | |
|      */
 | |
|     while(*nsections<m)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Break if worst section has zero error.
 | |
|          * Store index of worst section to K.
 | |
|          */
 | |
|         if( ae_fp_eq(heaperrors.ptr.p_double[0],(double)(0)) )
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
|         k = heaptags.ptr.p_int[0];
 | |
|         
 | |
|         /*
 | |
|          * K-th section is divided in two:
 | |
|          * * first  one spans interval from X[Sections[K,0]] to X[Sections[K,2]]
 | |
|          * * second one spans interval from X[Sections[K,2]] to X[Sections[K,1]]
 | |
|          *
 | |
|          * First section is stored at K-th position, second one is appended to the table.
 | |
|          * Then we update heap which stores pairs of (error,section_index)
 | |
|          */
 | |
|         k0 = ae_round(sections.ptr.pp_double[k][0], _state);
 | |
|         k1 = ae_round(sections.ptr.pp_double[k][1], _state);
 | |
|         k2 = ae_round(sections.ptr.pp_double[k][2], _state);
 | |
|         lsfit_rdpanalyzesection(x, y, k0, k2, &idx0, &e0, _state);
 | |
|         lsfit_rdpanalyzesection(x, y, k2, k1, &idx1, &e1, _state);
 | |
|         sections.ptr.pp_double[k][0] = (double)(k0);
 | |
|         sections.ptr.pp_double[k][1] = (double)(k2);
 | |
|         sections.ptr.pp_double[k][2] = (double)(idx0);
 | |
|         sections.ptr.pp_double[k][3] = e0;
 | |
|         tagheapreplacetopi(&heaperrors, &heaptags, *nsections, e0, k, _state);
 | |
|         sections.ptr.pp_double[*nsections][0] = (double)(k2);
 | |
|         sections.ptr.pp_double[*nsections][1] = (double)(k1);
 | |
|         sections.ptr.pp_double[*nsections][2] = (double)(idx1);
 | |
|         sections.ptr.pp_double[*nsections][3] = e1;
 | |
|         tagheappushi(&heaperrors, &heaptags, nsections, e1, *nsections, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Convert from sections to points
 | |
|      */
 | |
|     ae_vector_set_length(&points, *nsections+1, _state);
 | |
|     k = ae_round(sections.ptr.pp_double[0][1], _state);
 | |
|     for(i=0; i<=*nsections-1; i++)
 | |
|     {
 | |
|         points.ptr.p_double[i] = (double)(ae_round(sections.ptr.pp_double[i][0], _state));
 | |
|         if( ae_fp_greater(x->ptr.p_double[ae_round(sections.ptr.pp_double[i][1], _state)],x->ptr.p_double[k]) )
 | |
|         {
 | |
|             k = ae_round(sections.ptr.pp_double[i][1], _state);
 | |
|         }
 | |
|     }
 | |
|     points.ptr.p_double[*nsections] = (double)(k);
 | |
|     tagsortfast(&points, &buf0, *nsections+1, _state);
 | |
|     
 | |
|     /*
 | |
|      * Output sections:
 | |
|      * * first NSection elements of X2/Y2 are filled by x/y at left boundaries of sections
 | |
|      * * last element of X2/Y2 is filled by right boundary of rightmost section
 | |
|      * * X2/Y2 is sorted by ascending of X2
 | |
|      */
 | |
|     ae_vector_set_length(x2, *nsections+1, _state);
 | |
|     ae_vector_set_length(y2, *nsections+1, _state);
 | |
|     for(i=0; i<=*nsections; i++)
 | |
|     {
 | |
|         x2->ptr.p_double[i] = x->ptr.p_double[ae_round(points.ptr.p_double[i], _state)];
 | |
|         y2->ptr.p_double[i] = y->ptr.p_double[ae_round(points.ptr.p_double[i], _state)];
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  subroutine fits piecewise linear curve to points with Ramer-Douglas-
 | |
| Peucker algorithm, which stops after achieving desired precision.
 | |
| 
 | |
| IMPORTANT:
 | |
| * it performs non-least-squares fitting; it builds curve, but  this  curve
 | |
|   does not minimize some least squares  metric.  See  description  of  RDP
 | |
|   algorithm (say, in Wikipedia) for more details on WHAT is performed.
 | |
| * this function does NOT work with parametric curves  (i.e.  curves  which
 | |
|   can be represented as {X(t),Y(t)}. It works with curves   which  can  be
 | |
|   represented as Y(X). Thus, it is impossible to model figures like circles
 | |
|   with this functions.
 | |
|   If  you  want  to  work  with  parametric   curves,   you   should   use
 | |
|   ParametricRDPFixed() function provided  by  "Parametric"  subpackage  of
 | |
|   "Interpolation" package.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array of X-coordinates:
 | |
|                 * at least N elements
 | |
|                 * can be unordered (points are automatically sorted)
 | |
|                 * this function may accept non-distinct X (see below for
 | |
|                   more information on handling of such inputs)
 | |
|     Y       -   array of Y-coordinates:
 | |
|                 * at least N elements
 | |
|     N       -   number of elements in X/Y
 | |
|     Eps     -   positive number, desired precision.
 | |
|     
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     X2      -   X-values of corner points for piecewise approximation,
 | |
|                 has length NSections+1 or zero (for NSections=0).
 | |
|     Y2      -   Y-values of corner points,
 | |
|                 has length NSections+1 or zero (for NSections=0).
 | |
|     NSections-  number of sections found by algorithm,
 | |
|                 NSections can be zero for degenerate datasets
 | |
|                 (N<=1 or all X[] are non-distinct).
 | |
| 
 | |
| NOTE: X2/Y2 are ordered arrays, i.e. (X2[0],Y2[0]) is  a  first  point  of
 | |
|       curve, (X2[NSection-1],Y2[NSection-1]) is the last point.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.10.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lstfitpiecewiselinearrdp(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      double eps,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      /* Real    */ ae_vector* y2,
 | |
|      ae_int_t* nsections,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_vector buf0;
 | |
|     ae_vector buf1;
 | |
|     ae_vector xtmp;
 | |
|     ae_vector ytmp;
 | |
|     double v;
 | |
|     ae_int_t npts;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&buf0, 0, sizeof(buf0));
 | |
|     memset(&buf1, 0, sizeof(buf1));
 | |
|     memset(&xtmp, 0, sizeof(xtmp));
 | |
|     memset(&ytmp, 0, sizeof(ytmp));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_clear(x2);
 | |
|     ae_vector_clear(y2);
 | |
|     *nsections = 0;
 | |
|     ae_vector_init(&buf0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&buf1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xtmp, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ytmp, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=0, "LSTFitPiecewiseLinearRDP: N<0", _state);
 | |
|     ae_assert(ae_fp_greater(eps,(double)(0)), "LSTFitPiecewiseLinearRDP: Eps<=0", _state);
 | |
|     ae_assert(x->cnt>=n, "LSTFitPiecewiseLinearRDP: Length(X)<N", _state);
 | |
|     ae_assert(y->cnt>=n, "LSTFitPiecewiseLinearRDP: Length(Y)<N", _state);
 | |
|     if( n<=1 )
 | |
|     {
 | |
|         *nsections = 0;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Sort points.
 | |
|      * Handle possible ties (tied values are replaced by their mean)
 | |
|      */
 | |
|     tagsortfastr(x, y, &buf0, &buf1, n, _state);
 | |
|     i = 0;
 | |
|     while(i<=n-1)
 | |
|     {
 | |
|         j = i+1;
 | |
|         v = y->ptr.p_double[i];
 | |
|         while(j<=n-1&&ae_fp_eq(x->ptr.p_double[j],x->ptr.p_double[i]))
 | |
|         {
 | |
|             v = v+y->ptr.p_double[j];
 | |
|             j = j+1;
 | |
|         }
 | |
|         v = v/(j-i);
 | |
|         for(k=i; k<=j-1; k++)
 | |
|         {
 | |
|             y->ptr.p_double[k] = v;
 | |
|         }
 | |
|         i = j;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Handle degenerate case x[0]=x[N-1]
 | |
|      */
 | |
|     if( ae_fp_eq(x->ptr.p_double[n-1],x->ptr.p_double[0]) )
 | |
|     {
 | |
|         *nsections = 0;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare data for recursive algorithm
 | |
|      */
 | |
|     ae_vector_set_length(&xtmp, n, _state);
 | |
|     ae_vector_set_length(&ytmp, n, _state);
 | |
|     npts = 2;
 | |
|     xtmp.ptr.p_double[0] = x->ptr.p_double[0];
 | |
|     ytmp.ptr.p_double[0] = y->ptr.p_double[0];
 | |
|     xtmp.ptr.p_double[1] = x->ptr.p_double[n-1];
 | |
|     ytmp.ptr.p_double[1] = y->ptr.p_double[n-1];
 | |
|     lsfit_rdprecursive(x, y, 0, n-1, eps, &xtmp, &ytmp, &npts, _state);
 | |
|     
 | |
|     /*
 | |
|      * Output sections:
 | |
|      * * first NSection elements of X2/Y2 are filled by x/y at left boundaries of sections
 | |
|      * * last element of X2/Y2 is filled by right boundary of rightmost section
 | |
|      * * X2/Y2 is sorted by ascending of X2
 | |
|      */
 | |
|     *nsections = npts-1;
 | |
|     ae_vector_set_length(x2, npts, _state);
 | |
|     ae_vector_set_length(y2, npts, _state);
 | |
|     for(i=0; i<=*nsections; i++)
 | |
|     {
 | |
|         x2->ptr.p_double[i] = xtmp.ptr.p_double[i];
 | |
|         y2->ptr.p_double[i] = ytmp.ptr.p_double[i];
 | |
|     }
 | |
|     tagsortfastr(x2, y2, &buf0, &buf1, npts, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Fitting by polynomials in barycentric form. This function provides  simple
 | |
| unterface for unconstrained unweighted fitting. See  PolynomialFitWC()  if
 | |
| you need constrained fitting.
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO:
 | |
|     PolynomialFitWC()
 | |
| 
 | |
| NOTES:
 | |
|     you can convert P from barycentric form  to  the  power  or  Chebyshev
 | |
|     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
 | |
|     POLINT subpackage.
 | |
|     
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     N   -   number of points, N>0
 | |
|             * if given, only leading N elements of X/Y are used
 | |
|             * if not given, automatically determined from sizes of X/Y
 | |
|     M   -   number of basis functions (= polynomial_degree + 1), M>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearW() subroutine:
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|     P   -   interpolant in barycentric form.
 | |
|     Rep -   report, same format as in LSFitLinearW() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 10.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialfit(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      barycentricinterpolant* p,
 | |
|      polynomialfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_vector w;
 | |
|     ae_vector xc;
 | |
|     ae_vector yc;
 | |
|     ae_vector dc;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     memset(&xc, 0, sizeof(xc));
 | |
|     memset(&yc, 0, sizeof(yc));
 | |
|     memset(&dc, 0, sizeof(dc));
 | |
|     *info = 0;
 | |
|     _barycentricinterpolant_clear(p);
 | |
|     _polynomialfitreport_clear(rep);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&yc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dc, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>0, "PolynomialFit: N<=0!", _state);
 | |
|     ae_assert(m>0, "PolynomialFit: M<=0!", _state);
 | |
|     ae_assert(x->cnt>=n, "PolynomialFit: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "PolynomialFit: Length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "PolynomialFit: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "PolynomialFit: Y contains infinite or NaN values!", _state);
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         w.ptr.p_double[i] = (double)(1);
 | |
|     }
 | |
|     polynomialfitwc(x, y, &w, n, &xc, &yc, &dc, 0, m, info, p, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted  fitting by polynomials in barycentric form, with constraints  on
 | |
| function values or first derivatives.
 | |
| 
 | |
| Small regularizing term is used when solving constrained tasks (to improve
 | |
| stability).
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO:
 | |
|     PolynomialFit()
 | |
| 
 | |
| NOTES:
 | |
|     you can convert P from barycentric form  to  the  power  or  Chebyshev
 | |
|     basis with PolynomialBar2Pow() or PolynomialBar2Cheb() functions  from
 | |
|     POLINT subpackage.
 | |
|     
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points, N>0.
 | |
|             * if given, only leading N elements of X/Y/W are used
 | |
|             * if not given, automatically determined from sizes of X/Y/W
 | |
|     XC  -   points where polynomial values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that P(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that P'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints, 0<=K<M.
 | |
|             K=0 means no constraints (XC/YC/DC are not used in such cases)
 | |
|     M   -   number of basis functions (= polynomial_degree + 1), M>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearW() subroutine:
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|     P   -   interpolant in barycentric form.
 | |
|     Rep -   report, same format as in LSFitLinearW() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained regression splines:
 | |
| * even simple constraints can be inconsistent, see  Wikipedia  article  on
 | |
|   this subject: http://en.wikipedia.org/wiki/Birkhoff_interpolation
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints is NOT GUARANTEED.
 | |
| * in the one special cases, however, we can  guarantee  consistency.  This
 | |
|   case  is:  M>1  and constraints on the function values (NOT DERIVATIVES)
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 10.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void polynomialfitwc(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      barycentricinterpolant* p,
 | |
|      polynomialfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector _w;
 | |
|     ae_vector _xc;
 | |
|     ae_vector _yc;
 | |
|     double xa;
 | |
|     double xb;
 | |
|     double sa;
 | |
|     double sb;
 | |
|     ae_vector xoriginal;
 | |
|     ae_vector yoriginal;
 | |
|     ae_vector y2;
 | |
|     ae_vector w2;
 | |
|     ae_vector tmp;
 | |
|     ae_vector tmp2;
 | |
|     ae_vector bx;
 | |
|     ae_vector by;
 | |
|     ae_vector bw;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double u;
 | |
|     double v;
 | |
|     double s;
 | |
|     ae_int_t relcnt;
 | |
|     lsfitreport lrep;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&_w, 0, sizeof(_w));
 | |
|     memset(&_xc, 0, sizeof(_xc));
 | |
|     memset(&_yc, 0, sizeof(_yc));
 | |
|     memset(&xoriginal, 0, sizeof(xoriginal));
 | |
|     memset(&yoriginal, 0, sizeof(yoriginal));
 | |
|     memset(&y2, 0, sizeof(y2));
 | |
|     memset(&w2, 0, sizeof(w2));
 | |
|     memset(&tmp, 0, sizeof(tmp));
 | |
|     memset(&tmp2, 0, sizeof(tmp2));
 | |
|     memset(&bx, 0, sizeof(bx));
 | |
|     memset(&by, 0, sizeof(by));
 | |
|     memset(&bw, 0, sizeof(bw));
 | |
|     memset(&lrep, 0, sizeof(lrep));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_init_copy(&_w, w, _state, ae_true);
 | |
|     w = &_w;
 | |
|     ae_vector_init_copy(&_xc, xc, _state, ae_true);
 | |
|     xc = &_xc;
 | |
|     ae_vector_init_copy(&_yc, yc, _state, ae_true);
 | |
|     yc = &_yc;
 | |
|     *info = 0;
 | |
|     _barycentricinterpolant_clear(p);
 | |
|     _polynomialfitreport_clear(rep);
 | |
|     ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&y2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&w2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&by, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bw, 0, DT_REAL, _state, ae_true);
 | |
|     _lsfitreport_init(&lrep, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>0, "PolynomialFitWC: N<=0!", _state);
 | |
|     ae_assert(m>0, "PolynomialFitWC: M<=0!", _state);
 | |
|     ae_assert(k>=0, "PolynomialFitWC: K<0!", _state);
 | |
|     ae_assert(k<m, "PolynomialFitWC: K>=M!", _state);
 | |
|     ae_assert(x->cnt>=n, "PolynomialFitWC: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "PolynomialFitWC: Length(Y)<N!", _state);
 | |
|     ae_assert(w->cnt>=n, "PolynomialFitWC: Length(W)<N!", _state);
 | |
|     ae_assert(xc->cnt>=k, "PolynomialFitWC: Length(XC)<K!", _state);
 | |
|     ae_assert(yc->cnt>=k, "PolynomialFitWC: Length(YC)<K!", _state);
 | |
|     ae_assert(dc->cnt>=k, "PolynomialFitWC: Length(DC)<K!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "PolynomialFitWC: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "PolynomialFitWC: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(w, n, _state), "PolynomialFitWC: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(xc, k, _state), "PolynomialFitWC: XC contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(yc, k, _state), "PolynomialFitWC: YC contains infinite or NaN values!", _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         ae_assert(dc->ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "PolynomialFitWC: one of DC[] is not 0 or 1!", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Scale X, Y, XC, YC.
 | |
|      * Solve scaled problem using internal Chebyshev fitting function.
 | |
|      */
 | |
|     lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state);
 | |
|     lsfit_internalchebyshevfit(x, y, w, n, xc, yc, dc, k, m, info, &tmp, &lrep, _state);
 | |
|     if( *info<0 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Generate barycentric model and scale it
 | |
|      * * BX, BY store barycentric model nodes
 | |
|      * * FMatrix is reused (remember - it is at least MxM, what we need)
 | |
|      *
 | |
|      * Model intialization is done in O(M^2). In principle, it can be
 | |
|      * done in O(M*log(M)), but before it we solved task with O(N*M^2)
 | |
|      * complexity, so it is only a small amount of total time spent.
 | |
|      */
 | |
|     ae_vector_set_length(&bx, m, _state);
 | |
|     ae_vector_set_length(&by, m, _state);
 | |
|     ae_vector_set_length(&bw, m, _state);
 | |
|     ae_vector_set_length(&tmp2, m, _state);
 | |
|     s = (double)(1);
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         if( m!=1 )
 | |
|         {
 | |
|             u = ae_cos(ae_pi*i/(m-1), _state);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             u = (double)(0);
 | |
|         }
 | |
|         v = (double)(0);
 | |
|         for(j=0; j<=m-1; j++)
 | |
|         {
 | |
|             if( j==0 )
 | |
|             {
 | |
|                 tmp2.ptr.p_double[j] = (double)(1);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( j==1 )
 | |
|                 {
 | |
|                     tmp2.ptr.p_double[j] = u;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     tmp2.ptr.p_double[j] = 2*u*tmp2.ptr.p_double[j-1]-tmp2.ptr.p_double[j-2];
 | |
|                 }
 | |
|             }
 | |
|             v = v+tmp.ptr.p_double[j]*tmp2.ptr.p_double[j];
 | |
|         }
 | |
|         bx.ptr.p_double[i] = u;
 | |
|         by.ptr.p_double[i] = v;
 | |
|         bw.ptr.p_double[i] = s;
 | |
|         if( i==0||i==m-1 )
 | |
|         {
 | |
|             bw.ptr.p_double[i] = 0.5*bw.ptr.p_double[i];
 | |
|         }
 | |
|         s = -s;
 | |
|     }
 | |
|     barycentricbuildxyw(&bx, &by, &bw, m, p, _state);
 | |
|     barycentriclintransx(p, 2/(xb-xa), -(xa+xb)/(xb-xa), _state);
 | |
|     barycentriclintransy(p, sb-sa, sa, _state);
 | |
|     
 | |
|     /*
 | |
|      * Scale absolute errors obtained from LSFitLinearW.
 | |
|      * Relative error should be calculated separately
 | |
|      * (because of shifting/scaling of the task)
 | |
|      */
 | |
|     rep->taskrcond = lrep.taskrcond;
 | |
|     rep->rmserror = lrep.rmserror*(sb-sa);
 | |
|     rep->avgerror = lrep.avgerror*(sb-sa);
 | |
|     rep->maxerror = lrep.maxerror*(sb-sa);
 | |
|     rep->avgrelerror = (double)(0);
 | |
|     relcnt = 0;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             rep->avgrelerror = rep->avgrelerror+ae_fabs(barycentriccalc(p, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state);
 | |
|             relcnt = relcnt+1;
 | |
|         }
 | |
|     }
 | |
|     if( relcnt!=0 )
 | |
|     {
 | |
|         rep->avgrelerror = rep->avgrelerror/relcnt;
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates value of four-parameter logistic (4PL)  model  at
 | |
| specified point X. 4PL model has following form:
 | |
| 
 | |
|     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   current point, X>=0:
 | |
|                 * zero X is correctly handled even for B<=0
 | |
|                 * negative X results in exception.
 | |
|     A, B, C, D- parameters of 4PL model:
 | |
|                 * A is unconstrained
 | |
|                 * B is unconstrained; zero or negative values are handled
 | |
|                   correctly.
 | |
|                 * C>0, non-positive value results in exception
 | |
|                 * D is unconstrained
 | |
|                 
 | |
| RESULT:
 | |
|     model value at X
 | |
| 
 | |
| NOTE: if B=0, denominator is assumed to be equal to 2.0 even  for  zero  X
 | |
|       (strictly speaking, 0^0 is undefined).
 | |
| 
 | |
| NOTE: this function also throws exception  if  all  input  parameters  are
 | |
|       correct, but overflow was detected during calculations.
 | |
|       
 | |
| NOTE: this function performs a lot of checks;  if  you  need  really  high
 | |
|       performance, consider evaluating model  yourself,  without  checking
 | |
|       for degenerate cases.
 | |
|       
 | |
|     
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.05.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double logisticcalc4(double x,
 | |
|      double a,
 | |
|      double b,
 | |
|      double c,
 | |
|      double d,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(x, _state), "LogisticCalc4: X is not finite", _state);
 | |
|     ae_assert(ae_isfinite(a, _state), "LogisticCalc4: A is not finite", _state);
 | |
|     ae_assert(ae_isfinite(b, _state), "LogisticCalc4: B is not finite", _state);
 | |
|     ae_assert(ae_isfinite(c, _state), "LogisticCalc4: C is not finite", _state);
 | |
|     ae_assert(ae_isfinite(d, _state), "LogisticCalc4: D is not finite", _state);
 | |
|     ae_assert(ae_fp_greater_eq(x,(double)(0)), "LogisticCalc4: X is negative", _state);
 | |
|     ae_assert(ae_fp_greater(c,(double)(0)), "LogisticCalc4: C is non-positive", _state);
 | |
|     
 | |
|     /*
 | |
|      * Check for degenerate cases
 | |
|      */
 | |
|     if( ae_fp_eq(b,(double)(0)) )
 | |
|     {
 | |
|         result = 0.5*(a+d);
 | |
|         return result;
 | |
|     }
 | |
|     if( ae_fp_eq(x,(double)(0)) )
 | |
|     {
 | |
|         if( ae_fp_greater(b,(double)(0)) )
 | |
|         {
 | |
|             result = a;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             result = d;
 | |
|         }
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * General case
 | |
|      */
 | |
|     result = d+(a-d)/(1.0+ae_pow(x/c, b, _state));
 | |
|     ae_assert(ae_isfinite(result, _state), "LogisticCalc4: overflow during calculations", _state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates value of five-parameter logistic (5PL)  model  at
 | |
| specified point X. 5PL model has following form:
 | |
| 
 | |
|     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   current point, X>=0:
 | |
|                 * zero X is correctly handled even for B<=0
 | |
|                 * negative X results in exception.
 | |
|     A, B, C, D, G- parameters of 5PL model:
 | |
|                 * A is unconstrained
 | |
|                 * B is unconstrained; zero or negative values are handled
 | |
|                   correctly.
 | |
|                 * C>0, non-positive value results in exception
 | |
|                 * D is unconstrained
 | |
|                 * G>0, non-positive value results in exception
 | |
|                 
 | |
| RESULT:
 | |
|     model value at X
 | |
| 
 | |
| NOTE: if B=0, denominator is assumed to be equal to Power(2.0,G) even  for
 | |
|       zero X (strictly speaking, 0^0 is undefined).
 | |
| 
 | |
| NOTE: this function also throws exception  if  all  input  parameters  are
 | |
|       correct, but overflow was detected during calculations.
 | |
|       
 | |
| NOTE: this function performs a lot of checks;  if  you  need  really  high
 | |
|       performance, consider evaluating model  yourself,  without  checking
 | |
|       for degenerate cases.
 | |
|       
 | |
|     
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.05.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double logisticcalc5(double x,
 | |
|      double a,
 | |
|      double b,
 | |
|      double c,
 | |
|      double d,
 | |
|      double g,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(x, _state), "LogisticCalc5: X is not finite", _state);
 | |
|     ae_assert(ae_isfinite(a, _state), "LogisticCalc5: A is not finite", _state);
 | |
|     ae_assert(ae_isfinite(b, _state), "LogisticCalc5: B is not finite", _state);
 | |
|     ae_assert(ae_isfinite(c, _state), "LogisticCalc5: C is not finite", _state);
 | |
|     ae_assert(ae_isfinite(d, _state), "LogisticCalc5: D is not finite", _state);
 | |
|     ae_assert(ae_isfinite(g, _state), "LogisticCalc5: G is not finite", _state);
 | |
|     ae_assert(ae_fp_greater_eq(x,(double)(0)), "LogisticCalc5: X is negative", _state);
 | |
|     ae_assert(ae_fp_greater(c,(double)(0)), "LogisticCalc5: C is non-positive", _state);
 | |
|     ae_assert(ae_fp_greater(g,(double)(0)), "LogisticCalc5: G is non-positive", _state);
 | |
|     
 | |
|     /*
 | |
|      * Check for degenerate cases
 | |
|      */
 | |
|     if( ae_fp_eq(b,(double)(0)) )
 | |
|     {
 | |
|         result = d+(a-d)/ae_pow(2.0, g, _state);
 | |
|         return result;
 | |
|     }
 | |
|     if( ae_fp_eq(x,(double)(0)) )
 | |
|     {
 | |
|         if( ae_fp_greater(b,(double)(0)) )
 | |
|         {
 | |
|             result = a;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             result = d;
 | |
|         }
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * General case
 | |
|      */
 | |
|     result = d+(a-d)/ae_pow(1.0+ae_pow(x/c, b, _state), g, _state);
 | |
|     ae_assert(ae_isfinite(result, _state), "LogisticCalc5: overflow during calculations", _state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits four-parameter logistic (4PL) model  to  data  provided
 | |
| by user. 4PL model has following form:
 | |
| 
 | |
|     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
 | |
| 
 | |
| Here:
 | |
|     * A, D - unconstrained (see LogisticFit4EC() for constrained 4PL)
 | |
|     * B>=0
 | |
|     * C>0
 | |
|     
 | |
| IMPORTANT: output of this function is constrained in  such  way that  B>0.
 | |
|            Because 4PL model is symmetric with respect to B, there  is  no
 | |
|            need to explore  B<0.  Constraining  B  makes  algorithm easier
 | |
|            to stabilize and debug.
 | |
|            Users  who  for  some  reason  prefer to work with negative B's
 | |
|            should transform output themselves (swap A and D, replace B  by
 | |
|            -B).
 | |
|            
 | |
| 4PL fitting is implemented as follows:
 | |
| * we perform small number of restarts from random locations which helps to
 | |
|   solve problem of bad local extrema. Locations are only partially  random
 | |
|   - we use input data to determine good  initial  guess,  but  we  include
 | |
|   controlled amount of randomness.
 | |
| * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
 | |
|   parameters B and C - it allows us to find good  initial  guess  for  the
 | |
|   second stage without risk of running into "flat spot".
 | |
| * second  Levenberg-Marquardt  round  is   performed   without   excessive
 | |
|   constraints. Results from the previous round are used as initial guess.
 | |
| * after fitting is done, we compare results with best values found so far,
 | |
|   rewrite "best solution" if needed, and move to next random location.
 | |
|   
 | |
| Overall algorithm is very stable and is not prone to  bad  local  extrema.
 | |
| Furthermore, it automatically scales when input data have  very  large  or
 | |
| very small range.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N], stores X-values.
 | |
|                 MUST include only non-negative numbers  (but  may  include
 | |
|                 zero values). Can be unsorted.
 | |
|     Y       -   array[N], values to fit.
 | |
|     N       -   number of points. If N is less than  length  of  X/Y, only
 | |
|                 leading N elements are used.
 | |
|                 
 | |
| OUTPUT PARAMETERS:
 | |
|     A, B, C, D- parameters of 4PL model
 | |
|     Rep     -   fitting report. This structure has many fields,  but  ONLY
 | |
|                 ONES LISTED BELOW ARE SET:
 | |
|                 * Rep.IterationsCount - number of iterations performed
 | |
|                 * Rep.RMSError - root-mean-square error
 | |
|                 * Rep.AvgError - average absolute error
 | |
|                 * Rep.AvgRelError - average relative error (calculated for
 | |
|                   non-zero Y-values)
 | |
|                 * Rep.MaxError - maximum absolute error
 | |
|                 * Rep.R2 - coefficient of determination,  R-squared.  This
 | |
|                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
 | |
|                   of nonlinear  regression  there  are  multiple  ways  to
 | |
|                   define R2, each of them giving different results).
 | |
| 
 | |
| NOTE: for stability reasons the B parameter is restricted by [1/1000,1000]
 | |
|       range. It prevents  algorithm from making trial steps  deep into the
 | |
|       area of bad parameters.
 | |
| 
 | |
| NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
 | |
|       LogisticCalc4() function.
 | |
| 
 | |
| NOTE: if you need better control over fitting process than provided by this
 | |
|       function, you may use LogisticFit45X().
 | |
|                 
 | |
| NOTE: step is automatically scaled according to scale of parameters  being
 | |
|       fitted before we compare its length with EpsX. Thus,  this  function
 | |
|       can be used to fit data with very small or very large values without
 | |
|       changing EpsX.
 | |
|     
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.02.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void logisticfit4(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      double* a,
 | |
|      double* b,
 | |
|      double* c,
 | |
|      double* d,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     double g;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     *a = 0;
 | |
|     *b = 0;
 | |
|     *c = 0;
 | |
|     *d = 0;
 | |
|     _lsfitreport_clear(rep);
 | |
| 
 | |
|     logisticfit45x(x, y, n, _state->v_nan, _state->v_nan, ae_true, 0.0, 0.0, 0, a, b, c, d, &g, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits four-parameter logistic (4PL) model  to  data  provided
 | |
| by user, with optional constraints on parameters A and D.  4PL  model  has
 | |
| following form:
 | |
| 
 | |
|     F(x|A,B,C,D) = D+(A-D)/(1+Power(x/C,B))
 | |
| 
 | |
| Here:
 | |
|     * A, D - with optional equality constraints
 | |
|     * B>=0
 | |
|     * C>0
 | |
|     
 | |
| IMPORTANT: output of this function is constrained in  such  way that  B>0.
 | |
|            Because 4PL model is symmetric with respect to B, there  is  no
 | |
|            need to explore  B<0.  Constraining  B  makes  algorithm easier
 | |
|            to stabilize and debug.
 | |
|            Users  who  for  some  reason  prefer to work with negative B's
 | |
|            should transform output themselves (swap A and D, replace B  by
 | |
|            -B).
 | |
|            
 | |
| 4PL fitting is implemented as follows:
 | |
| * we perform small number of restarts from random locations which helps to
 | |
|   solve problem of bad local extrema. Locations are only partially  random
 | |
|   - we use input data to determine good  initial  guess,  but  we  include
 | |
|   controlled amount of randomness.
 | |
| * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
 | |
|   parameters B and C - it allows us to find good  initial  guess  for  the
 | |
|   second stage without risk of running into "flat spot".
 | |
| * second  Levenberg-Marquardt  round  is   performed   without   excessive
 | |
|   constraints. Results from the previous round are used as initial guess.
 | |
| * after fitting is done, we compare results with best values found so far,
 | |
|   rewrite "best solution" if needed, and move to next random location.
 | |
|   
 | |
| Overall algorithm is very stable and is not prone to  bad  local  extrema.
 | |
| Furthermore, it automatically scales when input data have  very  large  or
 | |
| very small range.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N], stores X-values.
 | |
|                 MUST include only non-negative numbers  (but  may  include
 | |
|                 zero values). Can be unsorted.
 | |
|     Y       -   array[N], values to fit.
 | |
|     N       -   number of points. If N is less than  length  of  X/Y, only
 | |
|                 leading N elements are used.
 | |
|     CnstrLeft-  optional equality constraint for model value at the   left
 | |
|                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
 | |
|                 not need constraint on the model value at X=0 (in C++  you
 | |
|                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
 | |
|                 Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
|     CnstrRight- optional equality constraint for model value at X=infinity.
 | |
|                 Specify NAN (Not-a-Number) if you do not  need  constraint
 | |
|                 on the model value (in C++  you can pass alglib::fp_nan as
 | |
|                 parameter, in  C# it will  be Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
|                 
 | |
| OUTPUT PARAMETERS:
 | |
|     A, B, C, D- parameters of 4PL model
 | |
|     Rep     -   fitting report. This structure has many fields,  but  ONLY
 | |
|                 ONES LISTED BELOW ARE SET:
 | |
|                 * Rep.IterationsCount - number of iterations performed
 | |
|                 * Rep.RMSError - root-mean-square error
 | |
|                 * Rep.AvgError - average absolute error
 | |
|                 * Rep.AvgRelError - average relative error (calculated for
 | |
|                   non-zero Y-values)
 | |
|                 * Rep.MaxError - maximum absolute error
 | |
|                 * Rep.R2 - coefficient of determination,  R-squared.  This
 | |
|                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
 | |
|                   of nonlinear  regression  there  are  multiple  ways  to
 | |
|                   define R2, each of them giving different results).
 | |
| 
 | |
| NOTE: for stability reasons the B parameter is restricted by [1/1000,1000]
 | |
|       range. It prevents  algorithm from making trial steps  deep into the
 | |
|       area of bad parameters.
 | |
| 
 | |
| NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
 | |
|       LogisticCalc4() function.
 | |
| 
 | |
| NOTE: if you need better control over fitting process than provided by this
 | |
|       function, you may use LogisticFit45X().
 | |
|                 
 | |
| NOTE: step is automatically scaled according to scale of parameters  being
 | |
|       fitted before we compare its length with EpsX. Thus,  this  function
 | |
|       can be used to fit data with very small or very large values without
 | |
|       changing EpsX.
 | |
| 
 | |
| EQUALITY CONSTRAINTS ON PARAMETERS
 | |
| 
 | |
| 4PL/5PL solver supports equality constraints on model values at  the  left
 | |
| boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
 | |
| completely optional and you can specify both of them, only  one  -  or  no
 | |
| constraints at all.
 | |
| 
 | |
| Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
 | |
| fitting), and CnstrRight contains right  one.  For  4PL,  left  constraint
 | |
| ALWAYS corresponds to parameter A, and right one is ALWAYS  constraint  on
 | |
| D. That's because 4PL model is normalized in such way that B>=0.
 | |
|     
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.02.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void logisticfit4ec(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      double cnstrleft,
 | |
|      double cnstrright,
 | |
|      double* a,
 | |
|      double* b,
 | |
|      double* c,
 | |
|      double* d,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     double g;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     *a = 0;
 | |
|     *b = 0;
 | |
|     *c = 0;
 | |
|     *d = 0;
 | |
|     _lsfitreport_clear(rep);
 | |
| 
 | |
|     logisticfit45x(x, y, n, cnstrleft, cnstrright, ae_true, 0.0, 0.0, 0, a, b, c, d, &g, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits five-parameter logistic (5PL) model  to  data  provided
 | |
| by user. 5PL model has following form:
 | |
| 
 | |
|     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
 | |
| 
 | |
| Here:
 | |
|     * A, D - unconstrained
 | |
|     * B - unconstrained
 | |
|     * C>0
 | |
|     * G>0
 | |
|     
 | |
| IMPORTANT: unlike in  4PL  fitting,  output  of  this  function   is   NOT
 | |
|            constrained in  such  way that B is guaranteed to be  positive.
 | |
|            Furthermore,  unlike  4PL,  5PL  model  is  NOT  symmetric with
 | |
|            respect to B, so you can NOT transform model to equivalent one,
 | |
|            with B having desired sign (>0 or <0).
 | |
|     
 | |
| 5PL fitting is implemented as follows:
 | |
| * we perform small number of restarts from random locations which helps to
 | |
|   solve problem of bad local extrema. Locations are only partially  random
 | |
|   - we use input data to determine good  initial  guess,  but  we  include
 | |
|   controlled amount of randomness.
 | |
| * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
 | |
|   parameters B and C - it allows us to find good  initial  guess  for  the
 | |
|   second stage without risk of running into "flat spot".  Parameter  G  is
 | |
|   fixed at G=1.
 | |
| * second  Levenberg-Marquardt  round  is   performed   without   excessive
 | |
|   constraints on B and C, but with G still equal to 1.  Results  from  the
 | |
|   previous round are used as initial guess.
 | |
| * third Levenberg-Marquardt round relaxes constraints on G  and  tries  two
 | |
|   different models - one with B>0 and one with B<0.
 | |
| * after fitting is done, we compare results with best values found so far,
 | |
|   rewrite "best solution" if needed, and move to next random location.
 | |
|   
 | |
| Overall algorithm is very stable and is not prone to  bad  local  extrema.
 | |
| Furthermore, it automatically scales when input data have  very  large  or
 | |
| very small range.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N], stores X-values.
 | |
|                 MUST include only non-negative numbers  (but  may  include
 | |
|                 zero values). Can be unsorted.
 | |
|     Y       -   array[N], values to fit.
 | |
|     N       -   number of points. If N is less than  length  of  X/Y, only
 | |
|                 leading N elements are used.
 | |
|                 
 | |
| OUTPUT PARAMETERS:
 | |
|     A,B,C,D,G-  parameters of 5PL model
 | |
|     Rep     -   fitting report. This structure has many fields,  but  ONLY
 | |
|                 ONES LISTED BELOW ARE SET:
 | |
|                 * Rep.IterationsCount - number of iterations performed
 | |
|                 * Rep.RMSError - root-mean-square error
 | |
|                 * Rep.AvgError - average absolute error
 | |
|                 * Rep.AvgRelError - average relative error (calculated for
 | |
|                   non-zero Y-values)
 | |
|                 * Rep.MaxError - maximum absolute error
 | |
|                 * Rep.R2 - coefficient of determination,  R-squared.  This
 | |
|                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
 | |
|                   of nonlinear  regression  there  are  multiple  ways  to
 | |
|                   define R2, each of them giving different results).
 | |
| 
 | |
| NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
 | |
|       range, and G is restricted by [1/10,10] range. It prevents algorithm
 | |
|       from making trial steps deep into the area of bad parameters.
 | |
| 
 | |
| NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
 | |
|       LogisticCalc5() function.
 | |
| 
 | |
| NOTE: if you need better control over fitting process than provided by this
 | |
|       function, you may use LogisticFit45X().
 | |
|                 
 | |
| NOTE: step is automatically scaled according to scale of parameters  being
 | |
|       fitted before we compare its length with EpsX. Thus,  this  function
 | |
|       can be used to fit data with very small or very large values without
 | |
|       changing EpsX.
 | |
|     
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.02.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void logisticfit5(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      double* a,
 | |
|      double* b,
 | |
|      double* c,
 | |
|      double* d,
 | |
|      double* g,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     *a = 0;
 | |
|     *b = 0;
 | |
|     *c = 0;
 | |
|     *d = 0;
 | |
|     *g = 0;
 | |
|     _lsfitreport_clear(rep);
 | |
| 
 | |
|     logisticfit45x(x, y, n, _state->v_nan, _state->v_nan, ae_false, 0.0, 0.0, 0, a, b, c, d, g, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits five-parameter logistic (5PL) model  to  data  provided
 | |
| by user, subject to optional equality constraints on parameters A  and  D.
 | |
| 5PL model has following form:
 | |
| 
 | |
|     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)
 | |
| 
 | |
| Here:
 | |
|     * A, D - with optional equality constraints
 | |
|     * B - unconstrained
 | |
|     * C>0
 | |
|     * G>0
 | |
|     
 | |
| IMPORTANT: unlike in  4PL  fitting,  output  of  this  function   is   NOT
 | |
|            constrained in  such  way that B is guaranteed to be  positive.
 | |
|            Furthermore,  unlike  4PL,  5PL  model  is  NOT  symmetric with
 | |
|            respect to B, so you can NOT transform model to equivalent one,
 | |
|            with B having desired sign (>0 or <0).
 | |
|     
 | |
| 5PL fitting is implemented as follows:
 | |
| * we perform small number of restarts from random locations which helps to
 | |
|   solve problem of bad local extrema. Locations are only partially  random
 | |
|   - we use input data to determine good  initial  guess,  but  we  include
 | |
|   controlled amount of randomness.
 | |
| * we perform Levenberg-Marquardt fitting with very  tight  constraints  on
 | |
|   parameters B and C - it allows us to find good  initial  guess  for  the
 | |
|   second stage without risk of running into "flat spot".  Parameter  G  is
 | |
|   fixed at G=1.
 | |
| * second  Levenberg-Marquardt  round  is   performed   without   excessive
 | |
|   constraints on B and C, but with G still equal to 1.  Results  from  the
 | |
|   previous round are used as initial guess.
 | |
| * third Levenberg-Marquardt round relaxes constraints on G  and  tries  two
 | |
|   different models - one with B>0 and one with B<0.
 | |
| * after fitting is done, we compare results with best values found so far,
 | |
|   rewrite "best solution" if needed, and move to next random location.
 | |
|   
 | |
| Overall algorithm is very stable and is not prone to  bad  local  extrema.
 | |
| Furthermore, it automatically scales when input data have  very  large  or
 | |
| very small range.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N], stores X-values.
 | |
|                 MUST include only non-negative numbers  (but  may  include
 | |
|                 zero values). Can be unsorted.
 | |
|     Y       -   array[N], values to fit.
 | |
|     N       -   number of points. If N is less than  length  of  X/Y, only
 | |
|                 leading N elements are used.
 | |
|     CnstrLeft-  optional equality constraint for model value at the   left
 | |
|                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
 | |
|                 not need constraint on the model value at X=0 (in C++  you
 | |
|                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
 | |
|                 Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
|     CnstrRight- optional equality constraint for model value at X=infinity.
 | |
|                 Specify NAN (Not-a-Number) if you do not  need  constraint
 | |
|                 on the model value (in C++  you can pass alglib::fp_nan as
 | |
|                 parameter, in  C# it will  be Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
|                 
 | |
| OUTPUT PARAMETERS:
 | |
|     A,B,C,D,G-  parameters of 5PL model
 | |
|     Rep     -   fitting report. This structure has many fields,  but  ONLY
 | |
|                 ONES LISTED BELOW ARE SET:
 | |
|                 * Rep.IterationsCount - number of iterations performed
 | |
|                 * Rep.RMSError - root-mean-square error
 | |
|                 * Rep.AvgError - average absolute error
 | |
|                 * Rep.AvgRelError - average relative error (calculated for
 | |
|                   non-zero Y-values)
 | |
|                 * Rep.MaxError - maximum absolute error
 | |
|                 * Rep.R2 - coefficient of determination,  R-squared.  This
 | |
|                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
 | |
|                   of nonlinear  regression  there  are  multiple  ways  to
 | |
|                   define R2, each of them giving different results).
 | |
| 
 | |
| NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
 | |
|       range, and G is restricted by [1/10,10] range. It prevents algorithm
 | |
|       from making trial steps deep into the area of bad parameters.
 | |
| 
 | |
| NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
 | |
|       LogisticCalc5() function.
 | |
| 
 | |
| NOTE: if you need better control over fitting process than provided by this
 | |
|       function, you may use LogisticFit45X().
 | |
|                 
 | |
| NOTE: step is automatically scaled according to scale of parameters  being
 | |
|       fitted before we compare its length with EpsX. Thus,  this  function
 | |
|       can be used to fit data with very small or very large values without
 | |
|       changing EpsX.
 | |
| 
 | |
| EQUALITY CONSTRAINTS ON PARAMETERS
 | |
| 
 | |
| 5PL solver supports equality constraints on model  values  at   the   left
 | |
| boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
 | |
| completely optional and you can specify both of them, only  one  -  or  no
 | |
| constraints at all.
 | |
| 
 | |
| Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
 | |
| fitting), and CnstrRight contains right  one.
 | |
| 
 | |
| Unlike 4PL one, 5PL model is NOT symmetric with respect to  change in sign
 | |
| of B. Thus, negative B's are possible, and left constraint  may  constrain
 | |
| parameter A (for positive B's)  -  or  parameter  D  (for  negative  B's).
 | |
| Similarly changes meaning of right constraint.
 | |
| 
 | |
| You do not have to decide what parameter to  constrain  -  algorithm  will
 | |
| automatically determine correct parameters as fitting progresses. However,
 | |
| question highlighted above is important when you interpret fitting results.
 | |
|     
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.02.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void logisticfit5ec(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      double cnstrleft,
 | |
|      double cnstrright,
 | |
|      double* a,
 | |
|      double* b,
 | |
|      double* c,
 | |
|      double* d,
 | |
|      double* g,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     *a = 0;
 | |
|     *b = 0;
 | |
|     *c = 0;
 | |
|     *d = 0;
 | |
|     *g = 0;
 | |
|     _lsfitreport_clear(rep);
 | |
| 
 | |
|     logisticfit45x(x, y, n, cnstrleft, cnstrright, ae_false, 0.0, 0.0, 0, a, b, c, d, g, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This is "expert" 4PL/5PL fitting function, which can be used if  you  need
 | |
| better control over fitting process than provided  by  LogisticFit4()  or
 | |
| LogisticFit5().
 | |
| 
 | |
| This function fits model of the form
 | |
| 
 | |
|     F(x|A,B,C,D)   = D+(A-D)/(1+Power(x/C,B))           (4PL model)
 | |
| 
 | |
| or
 | |
| 
 | |
|     F(x|A,B,C,D,G) = D+(A-D)/Power(1+Power(x/C,B),G)    (5PL model)
 | |
|     
 | |
| Here:
 | |
|     * A, D - unconstrained
 | |
|     * B>=0 for 4PL, unconstrained for 5PL
 | |
|     * C>0
 | |
|     * G>0 (if present)
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N], stores X-values.
 | |
|                 MUST include only non-negative numbers  (but  may  include
 | |
|                 zero values). Can be unsorted.
 | |
|     Y       -   array[N], values to fit.
 | |
|     N       -   number of points. If N is less than  length  of  X/Y, only
 | |
|                 leading N elements are used.
 | |
|     CnstrLeft-  optional equality constraint for model value at the   left
 | |
|                 boundary (at X=0). Specify NAN (Not-a-Number)  if  you  do
 | |
|                 not need constraint on the model value at X=0 (in C++  you
 | |
|                 can pass alglib::fp_nan as parameter, in  C#  it  will  be
 | |
|                 Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
|     CnstrRight- optional equality constraint for model value at X=infinity.
 | |
|                 Specify NAN (Not-a-Number) if you do not  need  constraint
 | |
|                 on the model value (in C++  you can pass alglib::fp_nan as
 | |
|                 parameter, in  C# it will  be Double.NaN).
 | |
|                 See  below,  section  "EQUALITY  CONSTRAINTS"   for   more
 | |
|                 information about constraints.
 | |
|     Is4PL   -   whether 4PL or 5PL models are fitted
 | |
|     LambdaV -   regularization coefficient, LambdaV>=0.
 | |
|                 Set it to zero unless you know what you are doing.
 | |
|     EpsX    -   stopping condition (step size), EpsX>=0.
 | |
|                 Zero value means that small step is automatically chosen.
 | |
|                 See notes below for more information.
 | |
|     RsCnt   -   number of repeated restarts from  random  points.  4PL/5PL
 | |
|                 models are prone to problem of bad local extrema. Utilizing
 | |
|                 multiple random restarts allows  us  to  improve algorithm
 | |
|                 convergence.
 | |
|                 RsCnt>=0.
 | |
|                 Zero value means that function automatically choose  small
 | |
|                 amount of restarts (recommended).
 | |
|                 
 | |
| OUTPUT PARAMETERS:
 | |
|     A, B, C, D- parameters of 4PL model
 | |
|     G       -   parameter of 5PL model; for Is4PL=True, G=1 is returned.
 | |
|     Rep     -   fitting report. This structure has many fields,  but  ONLY
 | |
|                 ONES LISTED BELOW ARE SET:
 | |
|                 * Rep.IterationsCount - number of iterations performed
 | |
|                 * Rep.RMSError - root-mean-square error
 | |
|                 * Rep.AvgError - average absolute error
 | |
|                 * Rep.AvgRelError - average relative error (calculated for
 | |
|                   non-zero Y-values)
 | |
|                 * Rep.MaxError - maximum absolute error
 | |
|                 * Rep.R2 - coefficient of determination,  R-squared.  This
 | |
|                   coefficient   is  calculated  as  R2=1-RSS/TSS  (in case
 | |
|                   of nonlinear  regression  there  are  multiple  ways  to
 | |
|                   define R2, each of them giving different results).
 | |
|                 
 | |
| NOTE: for better stability B  parameter is restricted by [+-1/1000,+-1000]
 | |
|       range, and G is restricted by [1/10,10] range. It prevents algorithm
 | |
|       from making trial steps deep into the area of bad parameters.
 | |
| 
 | |
| NOTE: after  you  obtained  coefficients,  you  can  evaluate  model  with
 | |
|       LogisticCalc5() function.
 | |
| 
 | |
| NOTE: step is automatically scaled according to scale of parameters  being
 | |
|       fitted before we compare its length with EpsX. Thus,  this  function
 | |
|       can be used to fit data with very small or very large values without
 | |
|       changing EpsX.
 | |
| 
 | |
| EQUALITY CONSTRAINTS ON PARAMETERS
 | |
| 
 | |
| 4PL/5PL solver supports equality constraints on model values at  the  left
 | |
| boundary (X=0) and right  boundary  (X=infinity).  These  constraints  are
 | |
| completely optional and you can specify both of them, only  one  -  or  no
 | |
| constraints at all.
 | |
| 
 | |
| Parameter  CnstrLeft  contains  left  constraint (or NAN for unconstrained
 | |
| fitting), and CnstrRight contains right  one.  For  4PL,  left  constraint
 | |
| ALWAYS corresponds to parameter A, and right one is ALWAYS  constraint  on
 | |
| D. That's because 4PL model is normalized in such way that B>=0.
 | |
| 
 | |
| For 5PL model things are different. Unlike  4PL  one,  5PL  model  is  NOT
 | |
| symmetric with respect to  change  in  sign  of  B. Thus, negative B's are
 | |
| possible, and left constraint may constrain parameter A (for positive B's)
 | |
| - or parameter D (for negative B's). Similarly changes  meaning  of  right
 | |
| constraint.
 | |
| 
 | |
| You do not have to decide what parameter to  constrain  -  algorithm  will
 | |
| automatically determine correct parameters as fitting progresses. However,
 | |
| question highlighted above is important when you interpret fitting results.
 | |
|     
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 14.02.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void logisticfit45x(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      double cnstrleft,
 | |
|      double cnstrright,
 | |
|      ae_bool is4pl,
 | |
|      double lambdav,
 | |
|      double epsx,
 | |
|      ae_int_t rscnt,
 | |
|      double* a,
 | |
|      double* b,
 | |
|      double* c,
 | |
|      double* d,
 | |
|      double* g,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_int_t i;
 | |
|     ae_int_t outerit;
 | |
|     ae_int_t nz;
 | |
|     double v;
 | |
|     ae_vector p0;
 | |
|     ae_vector p1;
 | |
|     ae_vector p2;
 | |
|     ae_vector bndl;
 | |
|     ae_vector bndu;
 | |
|     ae_vector s;
 | |
|     ae_vector bndl1;
 | |
|     ae_vector bndu1;
 | |
|     ae_vector bndl2;
 | |
|     ae_vector bndu2;
 | |
|     ae_matrix z;
 | |
|     hqrndstate rs;
 | |
|     minlmstate state;
 | |
|     minlmreport replm;
 | |
|     ae_int_t maxits;
 | |
|     double fbest;
 | |
|     double flast;
 | |
|     double scalex;
 | |
|     double scaley;
 | |
|     ae_vector bufx;
 | |
|     ae_vector bufy;
 | |
|     double fposb;
 | |
|     double fnegb;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&p0, 0, sizeof(p0));
 | |
|     memset(&p1, 0, sizeof(p1));
 | |
|     memset(&p2, 0, sizeof(p2));
 | |
|     memset(&bndl, 0, sizeof(bndl));
 | |
|     memset(&bndu, 0, sizeof(bndu));
 | |
|     memset(&s, 0, sizeof(s));
 | |
|     memset(&bndl1, 0, sizeof(bndl1));
 | |
|     memset(&bndu1, 0, sizeof(bndu1));
 | |
|     memset(&bndl2, 0, sizeof(bndl2));
 | |
|     memset(&bndu2, 0, sizeof(bndu2));
 | |
|     memset(&z, 0, sizeof(z));
 | |
|     memset(&rs, 0, sizeof(rs));
 | |
|     memset(&state, 0, sizeof(state));
 | |
|     memset(&replm, 0, sizeof(replm));
 | |
|     memset(&bufx, 0, sizeof(bufx));
 | |
|     memset(&bufy, 0, sizeof(bufy));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     *a = 0;
 | |
|     *b = 0;
 | |
|     *c = 0;
 | |
|     *d = 0;
 | |
|     *g = 0;
 | |
|     _lsfitreport_clear(rep);
 | |
|     ae_vector_init(&p0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bndl, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bndu, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&s, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bndl1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bndu1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bndl2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bndu2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&z, 0, 0, DT_REAL, _state, ae_true);
 | |
|     _hqrndstate_init(&rs, _state, ae_true);
 | |
|     _minlmstate_init(&state, _state, ae_true);
 | |
|     _minlmreport_init(&replm, _state, ae_true);
 | |
|     ae_vector_init(&bufx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bufy, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(ae_isfinite(epsx, _state), "LogisticFitX: EpsX is infinite/NAN", _state);
 | |
|     ae_assert(ae_isfinite(lambdav, _state), "LogisticFitX: LambdaV is infinite/NAN", _state);
 | |
|     ae_assert(ae_isfinite(cnstrleft, _state)||ae_isnan(cnstrleft, _state), "LogisticFitX: CnstrLeft is NOT finite or NAN", _state);
 | |
|     ae_assert(ae_isfinite(cnstrright, _state)||ae_isnan(cnstrright, _state), "LogisticFitX: CnstrRight is NOT finite or NAN", _state);
 | |
|     ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "LogisticFitX: negative LambdaV", _state);
 | |
|     ae_assert(n>0, "LogisticFitX: N<=0", _state);
 | |
|     ae_assert(rscnt>=0, "LogisticFitX: RsCnt<0", _state);
 | |
|     ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "LogisticFitX: EpsX<0", _state);
 | |
|     ae_assert(x->cnt>=n, "LogisticFitX: Length(X)<N", _state);
 | |
|     ae_assert(y->cnt>=n, "LogisticFitX: Length(Y)<N", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "LogisticFitX: X contains infinite/NAN values", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LogisticFitX: X contains infinite/NAN values", _state);
 | |
|     hqrndseed(2211, 1033044, &rs, _state);
 | |
|     lsfit_clearreport(rep, _state);
 | |
|     if( ae_fp_eq(epsx,(double)(0)) )
 | |
|     {
 | |
|         epsx = 1.0E-10;
 | |
|     }
 | |
|     if( rscnt==0 )
 | |
|     {
 | |
|         rscnt = 4;
 | |
|     }
 | |
|     maxits = 1000;
 | |
|     
 | |
|     /*
 | |
|      * Sort points by X.
 | |
|      * Determine number of zero and non-zero values.
 | |
|      */
 | |
|     tagsortfastr(x, y, &bufx, &bufy, n, _state);
 | |
|     ae_assert(ae_fp_greater_eq(x->ptr.p_double[0],(double)(0)), "LogisticFitX: some X[] are negative", _state);
 | |
|     nz = n;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             nz = i;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * For NZ=N (all X[] are zero) special code is used.
 | |
|      * For NZ<N we use general-purpose code.
 | |
|      */
 | |
|     rep->iterationscount = 0;
 | |
|     if( nz==n )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * NZ=N, degenerate problem.
 | |
|          * No need to run optimizer.
 | |
|          */
 | |
|         v = 0.0;
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             v = v+y->ptr.p_double[i];
 | |
|         }
 | |
|         v = v/n;
 | |
|         if( ae_isfinite(cnstrleft, _state) )
 | |
|         {
 | |
|             *a = cnstrleft;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             *a = v;
 | |
|         }
 | |
|         *b = (double)(1);
 | |
|         *c = (double)(1);
 | |
|         if( ae_isfinite(cnstrright, _state) )
 | |
|         {
 | |
|             *d = cnstrright;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             *d = *a;
 | |
|         }
 | |
|         *g = (double)(1);
 | |
|         lsfit_logisticfit45errors(x, y, n, *a, *b, *c, *d, *g, rep, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Non-degenerate problem.
 | |
|      * Determine scale of data.
 | |
|      */
 | |
|     scalex = x->ptr.p_double[nz+(n-nz)/2];
 | |
|     ae_assert(ae_fp_greater(scalex,(double)(0)), "LogisticFitX: internal error", _state);
 | |
|     v = 0.0;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         v = v+y->ptr.p_double[i];
 | |
|     }
 | |
|     v = v/n;
 | |
|     scaley = 0.0;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         scaley = scaley+ae_sqr(y->ptr.p_double[i]-v, _state);
 | |
|     }
 | |
|     scaley = ae_sqrt(scaley/n, _state);
 | |
|     if( ae_fp_eq(scaley,(double)(0)) )
 | |
|     {
 | |
|         scaley = 1.0;
 | |
|     }
 | |
|     ae_vector_set_length(&s, 5, _state);
 | |
|     s.ptr.p_double[0] = scaley;
 | |
|     s.ptr.p_double[1] = 0.1;
 | |
|     s.ptr.p_double[2] = scalex;
 | |
|     s.ptr.p_double[3] = scaley;
 | |
|     s.ptr.p_double[4] = 0.1;
 | |
|     ae_vector_set_length(&p0, 5, _state);
 | |
|     p0.ptr.p_double[0] = (double)(0);
 | |
|     p0.ptr.p_double[1] = (double)(0);
 | |
|     p0.ptr.p_double[2] = (double)(0);
 | |
|     p0.ptr.p_double[3] = (double)(0);
 | |
|     p0.ptr.p_double[4] = (double)(0);
 | |
|     ae_vector_set_length(&bndl, 5, _state);
 | |
|     ae_vector_set_length(&bndu, 5, _state);
 | |
|     ae_vector_set_length(&bndl1, 5, _state);
 | |
|     ae_vector_set_length(&bndu1, 5, _state);
 | |
|     ae_vector_set_length(&bndl2, 5, _state);
 | |
|     ae_vector_set_length(&bndu2, 5, _state);
 | |
|     minlmcreatevj(5, n+5, &p0, &state, _state);
 | |
|     minlmsetscale(&state, &s, _state);
 | |
|     minlmsetcond(&state, epsx, maxits, _state);
 | |
|     minlmsetxrep(&state, ae_true, _state);
 | |
|     ae_vector_set_length(&p1, 5, _state);
 | |
|     ae_vector_set_length(&p2, 5, _state);
 | |
|     
 | |
|     /*
 | |
|      * Is it 4PL problem?
 | |
|      */
 | |
|     if( is4pl )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Run outer iterations
 | |
|          */
 | |
|         *a = (double)(0);
 | |
|         *b = (double)(1);
 | |
|         *c = (double)(1);
 | |
|         *d = (double)(1);
 | |
|         *g = (double)(1);
 | |
|         fbest = ae_maxrealnumber;
 | |
|         for(outerit=0; outerit<=rscnt-1; outerit++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Prepare initial point; use B>0
 | |
|              */
 | |
|             if( ae_isfinite(cnstrleft, _state) )
 | |
|             {
 | |
|                 p1.ptr.p_double[0] = cnstrleft;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 p1.ptr.p_double[0] = y->ptr.p_double[0]+0.15*scaley*(hqrnduniformr(&rs, _state)-0.5);
 | |
|             }
 | |
|             p1.ptr.p_double[1] = 0.5+hqrnduniformr(&rs, _state);
 | |
|             p1.ptr.p_double[2] = x->ptr.p_double[nz+hqrnduniformi(&rs, n-nz, _state)];
 | |
|             if( ae_isfinite(cnstrright, _state) )
 | |
|             {
 | |
|                 p1.ptr.p_double[3] = cnstrright;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 p1.ptr.p_double[3] = y->ptr.p_double[n-1]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5);
 | |
|             }
 | |
|             p1.ptr.p_double[4] = 1.0;
 | |
|             
 | |
|             /*
 | |
|              * Run optimization with tight constraints and increased regularization
 | |
|              */
 | |
|             if( ae_isfinite(cnstrleft, _state) )
 | |
|             {
 | |
|                 bndl.ptr.p_double[0] = cnstrleft;
 | |
|                 bndu.ptr.p_double[0] = cnstrleft;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 bndl.ptr.p_double[0] = _state->v_neginf;
 | |
|                 bndu.ptr.p_double[0] = _state->v_posinf;
 | |
|             }
 | |
|             bndl.ptr.p_double[1] = 0.5;
 | |
|             bndu.ptr.p_double[1] = 2.0;
 | |
|             bndl.ptr.p_double[2] = 0.5*scalex;
 | |
|             bndu.ptr.p_double[2] = 2.0*scalex;
 | |
|             if( ae_isfinite(cnstrright, _state) )
 | |
|             {
 | |
|                 bndl.ptr.p_double[3] = cnstrright;
 | |
|                 bndu.ptr.p_double[3] = cnstrright;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 bndl.ptr.p_double[3] = _state->v_neginf;
 | |
|                 bndu.ptr.p_double[3] = _state->v_posinf;
 | |
|             }
 | |
|             bndl.ptr.p_double[4] = 1.0;
 | |
|             bndu.ptr.p_double[4] = 1.0;
 | |
|             minlmsetbc(&state, &bndl, &bndu, _state);
 | |
|             lsfit_logisticfitinternal(x, y, n, is4pl, 100*lambdav, &state, &replm, &p1, &flast, _state);
 | |
|             rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Relax constraints, run optimization one more time
 | |
|              */
 | |
|             bndl.ptr.p_double[1] = 0.1;
 | |
|             bndu.ptr.p_double[1] = 10.0;
 | |
|             bndl.ptr.p_double[2] = ae_machineepsilon*scalex;
 | |
|             bndu.ptr.p_double[2] = scalex/ae_machineepsilon;
 | |
|             minlmsetbc(&state, &bndl, &bndu, _state);
 | |
|             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
 | |
|             rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Relax constraints more, run optimization one more time
 | |
|              */
 | |
|             bndl.ptr.p_double[1] = 0.01;
 | |
|             bndu.ptr.p_double[1] = 100.0;
 | |
|             minlmsetbc(&state, &bndl, &bndu, _state);
 | |
|             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
 | |
|             rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Relax constraints ever more, run optimization one more time
 | |
|              */
 | |
|             bndl.ptr.p_double[1] = 0.001;
 | |
|             bndu.ptr.p_double[1] = 1000.0;
 | |
|             minlmsetbc(&state, &bndl, &bndu, _state);
 | |
|             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
 | |
|             rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Compare results with best value found so far.
 | |
|              */
 | |
|             if( ae_fp_less(flast,fbest) )
 | |
|             {
 | |
|                 *a = p1.ptr.p_double[0];
 | |
|                 *b = p1.ptr.p_double[1];
 | |
|                 *c = p1.ptr.p_double[2];
 | |
|                 *d = p1.ptr.p_double[3];
 | |
|                 *g = p1.ptr.p_double[4];
 | |
|                 fbest = flast;
 | |
|             }
 | |
|         }
 | |
|         lsfit_logisticfit45errors(x, y, n, *a, *b, *c, *d, *g, rep, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Well.... we have 5PL fit, and we have to test two separate branches:
 | |
|      * B>0 and B<0, because of asymmetry in the curve. First, we run optimization
 | |
|      * with tight constraints two times, in order to determine better sign for B.
 | |
|      *
 | |
|      * Run outer iterations
 | |
|      */
 | |
|     *a = (double)(0);
 | |
|     *b = (double)(1);
 | |
|     *c = (double)(1);
 | |
|     *d = (double)(1);
 | |
|     *g = (double)(1);
 | |
|     fbest = ae_maxrealnumber;
 | |
|     for(outerit=0; outerit<=rscnt-1; outerit++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * First, we try positive B.
 | |
|          */
 | |
|         p1.ptr.p_double[0] = y->ptr.p_double[0]+0.15*scaley*(hqrnduniformr(&rs, _state)-0.5);
 | |
|         p1.ptr.p_double[1] = 0.5+hqrnduniformr(&rs, _state);
 | |
|         p1.ptr.p_double[2] = x->ptr.p_double[nz+hqrnduniformi(&rs, n-nz, _state)];
 | |
|         p1.ptr.p_double[3] = y->ptr.p_double[n-1]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5);
 | |
|         p1.ptr.p_double[4] = 1.0;
 | |
|         bndl1.ptr.p_double[0] = _state->v_neginf;
 | |
|         bndu1.ptr.p_double[0] = _state->v_posinf;
 | |
|         bndl1.ptr.p_double[1] = 0.5;
 | |
|         bndu1.ptr.p_double[1] = 2.0;
 | |
|         bndl1.ptr.p_double[2] = 0.5*scalex;
 | |
|         bndu1.ptr.p_double[2] = 2.0*scalex;
 | |
|         bndl1.ptr.p_double[3] = _state->v_neginf;
 | |
|         bndu1.ptr.p_double[3] = _state->v_posinf;
 | |
|         bndl1.ptr.p_double[4] = 0.5;
 | |
|         bndu1.ptr.p_double[4] = 2.0;
 | |
|         if( ae_isfinite(cnstrleft, _state) )
 | |
|         {
 | |
|             p1.ptr.p_double[0] = cnstrleft;
 | |
|             bndl1.ptr.p_double[0] = cnstrleft;
 | |
|             bndu1.ptr.p_double[0] = cnstrleft;
 | |
|         }
 | |
|         if( ae_isfinite(cnstrright, _state) )
 | |
|         {
 | |
|             p1.ptr.p_double[3] = cnstrright;
 | |
|             bndl1.ptr.p_double[3] = cnstrright;
 | |
|             bndu1.ptr.p_double[3] = cnstrright;
 | |
|         }
 | |
|         minlmsetbc(&state, &bndl1, &bndu1, _state);
 | |
|         lsfit_logisticfitinternal(x, y, n, is4pl, 100*lambdav, &state, &replm, &p1, &fposb, _state);
 | |
|         rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|         
 | |
|         /*
 | |
|          * Second attempt - with negative B (constraints are still tight).
 | |
|          */
 | |
|         p2.ptr.p_double[0] = y->ptr.p_double[n-1]+0.15*scaley*(hqrnduniformr(&rs, _state)-0.5);
 | |
|         p2.ptr.p_double[1] = -(0.5+hqrnduniformr(&rs, _state));
 | |
|         p2.ptr.p_double[2] = x->ptr.p_double[nz+hqrnduniformi(&rs, n-nz, _state)];
 | |
|         p2.ptr.p_double[3] = y->ptr.p_double[0]+0.25*scaley*(hqrnduniformr(&rs, _state)-0.5);
 | |
|         p2.ptr.p_double[4] = 1.0;
 | |
|         bndl2.ptr.p_double[0] = _state->v_neginf;
 | |
|         bndu2.ptr.p_double[0] = _state->v_posinf;
 | |
|         bndl2.ptr.p_double[1] = -2.0;
 | |
|         bndu2.ptr.p_double[1] = -0.5;
 | |
|         bndl2.ptr.p_double[2] = 0.5*scalex;
 | |
|         bndu2.ptr.p_double[2] = 2.0*scalex;
 | |
|         bndl2.ptr.p_double[3] = _state->v_neginf;
 | |
|         bndu2.ptr.p_double[3] = _state->v_posinf;
 | |
|         bndl2.ptr.p_double[4] = 0.5;
 | |
|         bndu2.ptr.p_double[4] = 2.0;
 | |
|         if( ae_isfinite(cnstrleft, _state) )
 | |
|         {
 | |
|             p2.ptr.p_double[3] = cnstrleft;
 | |
|             bndl2.ptr.p_double[3] = cnstrleft;
 | |
|             bndu2.ptr.p_double[3] = cnstrleft;
 | |
|         }
 | |
|         if( ae_isfinite(cnstrright, _state) )
 | |
|         {
 | |
|             p2.ptr.p_double[0] = cnstrright;
 | |
|             bndl2.ptr.p_double[0] = cnstrright;
 | |
|             bndu2.ptr.p_double[0] = cnstrright;
 | |
|         }
 | |
|         minlmsetbc(&state, &bndl2, &bndu2, _state);
 | |
|         lsfit_logisticfitinternal(x, y, n, is4pl, 100*lambdav, &state, &replm, &p2, &fnegb, _state);
 | |
|         rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|         
 | |
|         /*
 | |
|          * Select best version of B sign
 | |
|          */
 | |
|         if( ae_fp_less(fposb,fnegb) )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Prepare relaxed constraints assuming that B is positive
 | |
|              */
 | |
|             bndl1.ptr.p_double[1] = 0.1;
 | |
|             bndu1.ptr.p_double[1] = 10.0;
 | |
|             bndl1.ptr.p_double[2] = ae_machineepsilon*scalex;
 | |
|             bndu1.ptr.p_double[2] = scalex/ae_machineepsilon;
 | |
|             bndl1.ptr.p_double[4] = 0.1;
 | |
|             bndu1.ptr.p_double[4] = 10.0;
 | |
|             minlmsetbc(&state, &bndl1, &bndu1, _state);
 | |
|             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
 | |
|             rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Prepare stronger relaxation of constraints
 | |
|              */
 | |
|             bndl1.ptr.p_double[1] = 0.01;
 | |
|             bndu1.ptr.p_double[1] = 100.0;
 | |
|             minlmsetbc(&state, &bndl1, &bndu1, _state);
 | |
|             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
 | |
|             rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Prepare stronger relaxation of constraints
 | |
|              */
 | |
|             bndl1.ptr.p_double[1] = 0.001;
 | |
|             bndu1.ptr.p_double[1] = 1000.0;
 | |
|             minlmsetbc(&state, &bndl1, &bndu1, _state);
 | |
|             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p1, &flast, _state);
 | |
|             rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Compare results with best value found so far.
 | |
|              */
 | |
|             if( ae_fp_less(flast,fbest) )
 | |
|             {
 | |
|                 *a = p1.ptr.p_double[0];
 | |
|                 *b = p1.ptr.p_double[1];
 | |
|                 *c = p1.ptr.p_double[2];
 | |
|                 *d = p1.ptr.p_double[3];
 | |
|                 *g = p1.ptr.p_double[4];
 | |
|                 fbest = flast;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Prepare relaxed constraints assuming that B is negative
 | |
|              */
 | |
|             bndl2.ptr.p_double[1] = -10.0;
 | |
|             bndu2.ptr.p_double[1] = -0.1;
 | |
|             bndl2.ptr.p_double[2] = ae_machineepsilon*scalex;
 | |
|             bndu2.ptr.p_double[2] = scalex/ae_machineepsilon;
 | |
|             bndl2.ptr.p_double[4] = 0.1;
 | |
|             bndu2.ptr.p_double[4] = 10.0;
 | |
|             minlmsetbc(&state, &bndl2, &bndu2, _state);
 | |
|             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p2, &flast, _state);
 | |
|             rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Prepare stronger relaxation
 | |
|              */
 | |
|             bndl2.ptr.p_double[1] = -100.0;
 | |
|             bndu2.ptr.p_double[1] = -0.01;
 | |
|             minlmsetbc(&state, &bndl2, &bndu2, _state);
 | |
|             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p2, &flast, _state);
 | |
|             rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Prepare stronger relaxation
 | |
|              */
 | |
|             bndl2.ptr.p_double[1] = -1000.0;
 | |
|             bndu2.ptr.p_double[1] = -0.001;
 | |
|             minlmsetbc(&state, &bndl2, &bndu2, _state);
 | |
|             lsfit_logisticfitinternal(x, y, n, is4pl, lambdav, &state, &replm, &p2, &flast, _state);
 | |
|             rep->iterationscount = rep->iterationscount+replm.iterationscount;
 | |
|             
 | |
|             /*
 | |
|              * Compare results with best value found so far.
 | |
|              */
 | |
|             if( ae_fp_less(flast,fbest) )
 | |
|             {
 | |
|                 *a = p2.ptr.p_double[0];
 | |
|                 *b = p2.ptr.p_double[1];
 | |
|                 *c = p2.ptr.p_double[2];
 | |
|                 *d = p2.ptr.p_double[3];
 | |
|                 *g = p2.ptr.p_double[4];
 | |
|                 fbest = flast;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     lsfit_logisticfit45errors(x, y, n, *a, *b, *c, *d, *g, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Weghted rational least  squares  fitting  using  Floater-Hormann  rational
 | |
| functions  with  optimal  D  chosen  from  [0,9],  with  constraints   and
 | |
| individual weights.
 | |
| 
 | |
| Equidistant  grid  with M node on [min(x),max(x)]  is  used to build basis
 | |
| functions. Different values of D are tried, optimal D (least WEIGHTED root
 | |
| mean square error) is chosen.  Task  is  linear,  so  linear least squares
 | |
| solver  is  used.  Complexity  of  this  computational  scheme is O(N*M^2)
 | |
| (mostly dominated by the least squares solver).
 | |
| 
 | |
| SEE ALSO
 | |
| * BarycentricFitFloaterHormann(), "lightweight" fitting without invididual
 | |
|   weights and constraints.
 | |
|   
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points, N>0.
 | |
|     XC  -   points where function values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that S(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that S'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints, 0<=K<M.
 | |
|             K=0 means no constraints (XC/YC/DC are not used in such cases)
 | |
|     M   -   number of basis functions ( = number_of_nodes), M>=2.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearWC() subroutine.
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|                         -1 means another errors in parameters passed
 | |
|                            (N<=0, for example)
 | |
|     B   -   barycentric interpolant.
 | |
|     Rep -   report, same format as in LSFitLinearWC() subroutine.
 | |
|             Following fields are set:
 | |
|             * DBest         best value of the D parameter
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroutine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained barycentric interpolants:
 | |
| * excessive  constraints  can  be  inconsistent.   Floater-Hormann   basis
 | |
|   functions aren't as flexible as splines (although they are very smooth).
 | |
| * the more evenly constraints are spread across [min(x),max(x)],  the more
 | |
|   chances that they will be consistent
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints IS NOT GUARANTEED.
 | |
| * in the several special cases, however, we CAN guarantee consistency.
 | |
| * one of this cases is constraints on the function  VALUES at the interval
 | |
|   boundaries. Note that consustency of the  constraints  on  the  function
 | |
|   DERIVATIVES is NOT guaranteed (you can use in such cases  cubic  splines
 | |
|   which are more flexible).
 | |
| * another  special  case  is ONE constraint on the function value (OR, but
 | |
|   not AND, derivative) anywhere in the interval
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricfitfloaterhormannwc(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      barycentricinterpolant* b,
 | |
|      barycentricfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t d;
 | |
|     ae_int_t i;
 | |
|     double wrmscur;
 | |
|     double wrmsbest;
 | |
|     barycentricinterpolant locb;
 | |
|     barycentricfitreport locrep;
 | |
|     ae_int_t locinfo;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&locb, 0, sizeof(locb));
 | |
|     memset(&locrep, 0, sizeof(locrep));
 | |
|     *info = 0;
 | |
|     _barycentricinterpolant_clear(b);
 | |
|     _barycentricfitreport_clear(rep);
 | |
|     _barycentricinterpolant_init(&locb, _state, ae_true);
 | |
|     _barycentricfitreport_init(&locrep, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>0, "BarycentricFitFloaterHormannWC: N<=0!", _state);
 | |
|     ae_assert(m>0, "BarycentricFitFloaterHormannWC: M<=0!", _state);
 | |
|     ae_assert(k>=0, "BarycentricFitFloaterHormannWC: K<0!", _state);
 | |
|     ae_assert(k<m, "BarycentricFitFloaterHormannWC: K>=M!", _state);
 | |
|     ae_assert(x->cnt>=n, "BarycentricFitFloaterHormannWC: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "BarycentricFitFloaterHormannWC: Length(Y)<N!", _state);
 | |
|     ae_assert(w->cnt>=n, "BarycentricFitFloaterHormannWC: Length(W)<N!", _state);
 | |
|     ae_assert(xc->cnt>=k, "BarycentricFitFloaterHormannWC: Length(XC)<K!", _state);
 | |
|     ae_assert(yc->cnt>=k, "BarycentricFitFloaterHormannWC: Length(YC)<K!", _state);
 | |
|     ae_assert(dc->cnt>=k, "BarycentricFitFloaterHormannWC: Length(DC)<K!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "BarycentricFitFloaterHormannWC: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "BarycentricFitFloaterHormannWC: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(w, n, _state), "BarycentricFitFloaterHormannWC: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(xc, k, _state), "BarycentricFitFloaterHormannWC: XC contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(yc, k, _state), "BarycentricFitFloaterHormannWC: YC contains infinite or NaN values!", _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         ae_assert(dc->ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "BarycentricFitFloaterHormannWC: one of DC[] is not 0 or 1!", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Find optimal D
 | |
|      *
 | |
|      * Info is -3 by default (degenerate constraints).
 | |
|      * If LocInfo will always be equal to -3, Info will remain equal to -3.
 | |
|      * If at least once LocInfo will be -4, Info will be -4.
 | |
|      */
 | |
|     wrmsbest = ae_maxrealnumber;
 | |
|     rep->dbest = -1;
 | |
|     *info = -3;
 | |
|     for(d=0; d<=ae_minint(9, n-1, _state); d++)
 | |
|     {
 | |
|         lsfit_barycentricfitwcfixedd(x, y, w, n, xc, yc, dc, k, m, d, &locinfo, &locb, &locrep, _state);
 | |
|         ae_assert((locinfo==-4||locinfo==-3)||locinfo>0, "BarycentricFitFloaterHormannWC: unexpected result from BarycentricFitWCFixedD!", _state);
 | |
|         if( locinfo>0 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Calculate weghted RMS
 | |
|              */
 | |
|             wrmscur = (double)(0);
 | |
|             for(i=0; i<=n-1; i++)
 | |
|             {
 | |
|                 wrmscur = wrmscur+ae_sqr(w->ptr.p_double[i]*(y->ptr.p_double[i]-barycentriccalc(&locb, x->ptr.p_double[i], _state)), _state);
 | |
|             }
 | |
|             wrmscur = ae_sqrt(wrmscur/n, _state);
 | |
|             if( ae_fp_less(wrmscur,wrmsbest)||rep->dbest<0 )
 | |
|             {
 | |
|                 barycentriccopy(&locb, b, _state);
 | |
|                 rep->dbest = d;
 | |
|                 *info = 1;
 | |
|                 rep->rmserror = locrep.rmserror;
 | |
|                 rep->avgerror = locrep.avgerror;
 | |
|                 rep->avgrelerror = locrep.avgrelerror;
 | |
|                 rep->maxerror = locrep.maxerror;
 | |
|                 rep->taskrcond = locrep.taskrcond;
 | |
|                 wrmsbest = wrmscur;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if( locinfo!=-3&&*info<0 )
 | |
|             {
 | |
|                 *info = locinfo;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Rational least squares fitting using  Floater-Hormann  rational  functions
 | |
| with optimal D chosen from [0,9].
 | |
| 
 | |
| Equidistant  grid  with M node on [min(x),max(x)]  is  used to build basis
 | |
| functions. Different values of D are tried, optimal  D  (least  root  mean
 | |
| square error) is chosen.  Task  is  linear, so linear least squares solver
 | |
| is used. Complexity  of  this  computational  scheme is  O(N*M^2)  (mostly
 | |
| dominated by the least squares solver).
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     N   -   number of points, N>0.
 | |
|     M   -   number of basis functions ( = number_of_nodes), M>=2.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearWC() subroutine.
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|     B   -   barycentric interpolant.
 | |
|     Rep -   report, same format as in LSFitLinearWC() subroutine.
 | |
|             Following fields are set:
 | |
|             * DBest         best value of the D parameter
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void barycentricfitfloaterhormann(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      barycentricinterpolant* b,
 | |
|      barycentricfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector w;
 | |
|     ae_vector xc;
 | |
|     ae_vector yc;
 | |
|     ae_vector dc;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     memset(&xc, 0, sizeof(xc));
 | |
|     memset(&yc, 0, sizeof(yc));
 | |
|     memset(&dc, 0, sizeof(dc));
 | |
|     *info = 0;
 | |
|     _barycentricinterpolant_clear(b);
 | |
|     _barycentricfitreport_clear(rep);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&yc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dc, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>0, "BarycentricFitFloaterHormann: N<=0!", _state);
 | |
|     ae_assert(m>0, "BarycentricFitFloaterHormann: M<=0!", _state);
 | |
|     ae_assert(x->cnt>=n, "BarycentricFitFloaterHormann: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "BarycentricFitFloaterHormann: Length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "BarycentricFitFloaterHormann: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "BarycentricFitFloaterHormann: Y contains infinite or NaN values!", _state);
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         w.ptr.p_double[i] = (double)(1);
 | |
|     }
 | |
|     barycentricfitfloaterhormannwc(x, y, &w, n, &xc, &yc, &dc, 0, m, info, b, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted fitting by cubic  spline,  with constraints on function values or
 | |
| derivatives.
 | |
| 
 | |
| Equidistant grid with M-2 nodes on [min(x,xc),max(x,xc)] is  used to build
 | |
| basis functions. Basis functions are cubic splines with continuous  second
 | |
| derivatives  and  non-fixed first  derivatives  at  interval  ends.  Small
 | |
| regularizing term is used  when  solving  constrained  tasks  (to  improve
 | |
| stability).
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO
 | |
|     Spline1DFitHermiteWC()  -   fitting by Hermite splines (more flexible,
 | |
|                                 less smooth)
 | |
|     Spline1DFitCubic()      -   "lightweight" fitting  by  cubic  splines,
 | |
|                                 without invididual weights and constraints
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
|                                 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points (optional):
 | |
|             * N>0
 | |
|             * if given, only first N elements of X/Y/W are processed
 | |
|             * if not given, automatically determined from X/Y/W sizes
 | |
|     XC  -   points where spline values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that S(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that S'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints (optional):
 | |
|             * 0<=K<M.
 | |
|             * K=0 means no constraints (XC/YC/DC are not used)
 | |
|             * if given, only first K elements of XC/YC/DC are used
 | |
|             * if not given, automatically determined from XC/YC/DC
 | |
|     M   -   number of basis functions ( = number_of_nodes+2), M>=4.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearWC() subroutine.
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|     S   -   spline interpolant.
 | |
|     Rep -   report, same format as in LSFitLinearWC() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained regression splines:
 | |
| * excessive constraints can be inconsistent. Splines are  piecewise  cubic
 | |
|   functions, and it is easy to create an example, where  large  number  of
 | |
|   constraints  concentrated  in  small  area will result in inconsistency.
 | |
|   Just because spline is not flexible enough to satisfy all of  them.  And
 | |
|   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
 | |
|   consistent.
 | |
| * the more evenly constraints are spread across [min(x),max(x)],  the more
 | |
|   chances that they will be consistent
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints IS NOT GUARANTEED.
 | |
| * in the several special cases, however, we CAN guarantee consistency.
 | |
| * one of this cases is constraints  on  the  function  values  AND/OR  its
 | |
|   derivatives at the interval boundaries.
 | |
| * another  special  case  is ONE constraint on the function value (OR, but
 | |
|   not AND, derivative) anywhere in the interval
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  WHEN  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfitcubicwc(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      spline1dinterpolant* s,
 | |
|      spline1dfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
|     *info = 0;
 | |
|     _spline1dinterpolant_clear(s);
 | |
|     _spline1dfitreport_clear(rep);
 | |
| 
 | |
|     ae_assert(n>=1, "Spline1DFitCubicWC: N<1!", _state);
 | |
|     ae_assert(m>=4, "Spline1DFitCubicWC: M<4!", _state);
 | |
|     ae_assert(k>=0, "Spline1DFitCubicWC: K<0!", _state);
 | |
|     ae_assert(k<m, "Spline1DFitCubicWC: K>=M!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DFitCubicWC: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DFitCubicWC: Length(Y)<N!", _state);
 | |
|     ae_assert(w->cnt>=n, "Spline1DFitCubicWC: Length(W)<N!", _state);
 | |
|     ae_assert(xc->cnt>=k, "Spline1DFitCubicWC: Length(XC)<K!", _state);
 | |
|     ae_assert(yc->cnt>=k, "Spline1DFitCubicWC: Length(YC)<K!", _state);
 | |
|     ae_assert(dc->cnt>=k, "Spline1DFitCubicWC: Length(DC)<K!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DFitCubicWC: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DFitCubicWC: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(w, n, _state), "Spline1DFitCubicWC: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(xc, k, _state), "Spline1DFitCubicWC: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(yc, k, _state), "Spline1DFitCubicWC: Y contains infinite or NAN values!", _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         ae_assert(dc->ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "Spline1DFitCubicWC: DC[i] is neither 0 or 1!", _state);
 | |
|     }
 | |
|     lsfit_spline1dfitinternal(0, x, y, w, n, xc, yc, dc, k, m, info, s, rep, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted  fitting  by Hermite spline,  with constraints on function values
 | |
| or first derivatives.
 | |
| 
 | |
| Equidistant grid with M nodes on [min(x,xc),max(x,xc)] is  used  to  build
 | |
| basis functions. Basis functions are Hermite splines.  Small  regularizing
 | |
| term is used when solving constrained tasks (to improve stability).
 | |
| 
 | |
| Task is linear, so linear least squares solver is used. Complexity of this
 | |
| computational scheme is O(N*M^2), mostly dominated by least squares solver
 | |
| 
 | |
| SEE ALSO
 | |
|     Spline1DFitCubicWC()    -   fitting by Cubic splines (less flexible,
 | |
|                                 more smooth)
 | |
|     Spline1DFitHermite()    -   "lightweight" Hermite fitting, without
 | |
|                                 invididual weights and constraints
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
|                                 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|             Each summand in square  sum  of  approximation deviations from
 | |
|             given  values  is  multiplied  by  the square of corresponding
 | |
|             weight. Fill it by 1's if you don't  want  to  solve  weighted
 | |
|             task.
 | |
|     N   -   number of points (optional):
 | |
|             * N>0
 | |
|             * if given, only first N elements of X/Y/W are processed
 | |
|             * if not given, automatically determined from X/Y/W sizes
 | |
|     XC  -   points where spline values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that S(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that S'(XC[i])=YC[i]
 | |
|             SEE BELOW FOR IMPORTANT INFORMATION ON CONSTRAINTS
 | |
|     K   -   number of constraints (optional):
 | |
|             * 0<=K<M.
 | |
|             * K=0 means no constraints (XC/YC/DC are not used)
 | |
|             * if given, only first K elements of XC/YC/DC are used
 | |
|             * if not given, automatically determined from XC/YC/DC
 | |
|     M   -   number of basis functions (= 2 * number of nodes),
 | |
|             M>=4,
 | |
|             M IS EVEN!
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearW() subroutine:
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|                         -2 means odd M was passed (which is not supported)
 | |
|                         -1 means another errors in parameters passed
 | |
|                            (N<=0, for example)
 | |
|     S   -   spline interpolant.
 | |
|     Rep -   report, same format as in LSFitLinearW() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine supports only even M's
 | |
| 
 | |
| 
 | |
| ORDER OF POINTS
 | |
| 
 | |
| Subroutine automatically sorts points, so caller may pass unsorted array.
 | |
| 
 | |
| SETTING CONSTRAINTS - DANGERS AND OPPORTUNITIES:
 | |
| 
 | |
| Setting constraints can lead  to undesired  results,  like ill-conditioned
 | |
| behavior, or inconsistency being detected. From the other side,  it allows
 | |
| us to improve quality of the fit. Here we summarize  our  experience  with
 | |
| constrained regression splines:
 | |
| * excessive constraints can be inconsistent. Splines are  piecewise  cubic
 | |
|   functions, and it is easy to create an example, where  large  number  of
 | |
|   constraints  concentrated  in  small  area will result in inconsistency.
 | |
|   Just because spline is not flexible enough to satisfy all of  them.  And
 | |
|   same constraints spread across the  [min(x),max(x)]  will  be  perfectly
 | |
|   consistent.
 | |
| * the more evenly constraints are spread across [min(x),max(x)],  the more
 | |
|   chances that they will be consistent
 | |
| * the  greater  is  M (given  fixed  constraints),  the  more chances that
 | |
|   constraints will be consistent
 | |
| * in the general case, consistency of constraints is NOT GUARANTEED.
 | |
| * in the several special cases, however, we can guarantee consistency.
 | |
| * one of this cases is  M>=4  and   constraints  on   the  function  value
 | |
|   (AND/OR its derivative) at the interval boundaries.
 | |
| * another special case is M>=4  and  ONE  constraint on the function value
 | |
|   (OR, BUT NOT AND, derivative) anywhere in [min(x),max(x)]
 | |
| 
 | |
| Our final recommendation is to use constraints  WHEN  AND  ONLY  when  you
 | |
| can't solve your task without them. Anything beyond  special  cases  given
 | |
| above is not guaranteed and may result in inconsistency.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfithermitewc(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      spline1dinterpolant* s,
 | |
|      spline1dfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
|     *info = 0;
 | |
|     _spline1dinterpolant_clear(s);
 | |
|     _spline1dfitreport_clear(rep);
 | |
| 
 | |
|     ae_assert(n>=1, "Spline1DFitHermiteWC: N<1!", _state);
 | |
|     ae_assert(m>=4, "Spline1DFitHermiteWC: M<4!", _state);
 | |
|     ae_assert(m%2==0, "Spline1DFitHermiteWC: M is odd!", _state);
 | |
|     ae_assert(k>=0, "Spline1DFitHermiteWC: K<0!", _state);
 | |
|     ae_assert(k<m, "Spline1DFitHermiteWC: K>=M!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DFitHermiteWC: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DFitHermiteWC: Length(Y)<N!", _state);
 | |
|     ae_assert(w->cnt>=n, "Spline1DFitHermiteWC: Length(W)<N!", _state);
 | |
|     ae_assert(xc->cnt>=k, "Spline1DFitHermiteWC: Length(XC)<K!", _state);
 | |
|     ae_assert(yc->cnt>=k, "Spline1DFitHermiteWC: Length(YC)<K!", _state);
 | |
|     ae_assert(dc->cnt>=k, "Spline1DFitHermiteWC: Length(DC)<K!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DFitHermiteWC: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DFitHermiteWC: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(w, n, _state), "Spline1DFitHermiteWC: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(xc, k, _state), "Spline1DFitHermiteWC: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(yc, k, _state), "Spline1DFitHermiteWC: Y contains infinite or NAN values!", _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         ae_assert(dc->ptr.p_int[i]==0||dc->ptr.p_int[i]==1, "Spline1DFitHermiteWC: DC[i] is neither 0 or 1!", _state);
 | |
|     }
 | |
|     lsfit_spline1dfitinternal(1, x, y, w, n, xc, yc, dc, k, m, info, s, rep, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Least squares fitting by cubic spline.
 | |
| 
 | |
| This subroutine is "lightweight" alternative for more complex and feature-
 | |
| rich Spline1DFitCubicWC().  See  Spline1DFitCubicWC() for more information
 | |
| about subroutine parameters (we don't duplicate it here because of length)
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfitcubic(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      spline1dinterpolant* s,
 | |
|      spline1dfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_vector w;
 | |
|     ae_vector xc;
 | |
|     ae_vector yc;
 | |
|     ae_vector dc;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     memset(&xc, 0, sizeof(xc));
 | |
|     memset(&yc, 0, sizeof(yc));
 | |
|     memset(&dc, 0, sizeof(dc));
 | |
|     *info = 0;
 | |
|     _spline1dinterpolant_clear(s);
 | |
|     _spline1dfitreport_clear(rep);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&yc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dc, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=1, "Spline1DFitCubic: N<1!", _state);
 | |
|     ae_assert(m>=4, "Spline1DFitCubic: M<4!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DFitCubic: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DFitCubic: Length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DFitCubic: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DFitCubic: Y contains infinite or NAN values!", _state);
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         w.ptr.p_double[i] = (double)(1);
 | |
|     }
 | |
|     spline1dfitcubicwc(x, y, &w, n, &xc, &yc, &dc, 0, m, info, s, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Least squares fitting by Hermite spline.
 | |
| 
 | |
| This subroutine is "lightweight" alternative for more complex and feature-
 | |
| rich Spline1DFitHermiteWC().  See Spline1DFitHermiteWC()  description  for
 | |
| more information about subroutine parameters (we don't duplicate  it  here
 | |
| because of length).
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfithermite(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      spline1dinterpolant* s,
 | |
|      spline1dfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_vector w;
 | |
|     ae_vector xc;
 | |
|     ae_vector yc;
 | |
|     ae_vector dc;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     memset(&xc, 0, sizeof(xc));
 | |
|     memset(&yc, 0, sizeof(yc));
 | |
|     memset(&dc, 0, sizeof(dc));
 | |
|     *info = 0;
 | |
|     _spline1dinterpolant_clear(s);
 | |
|     _spline1dfitreport_clear(rep);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&yc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dc, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=1, "Spline1DFitHermite: N<1!", _state);
 | |
|     ae_assert(m>=4, "Spline1DFitHermite: M<4!", _state);
 | |
|     ae_assert(m%2==0, "Spline1DFitHermite: M is odd!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DFitHermite: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DFitHermite: Length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DFitHermite: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DFitHermite: Y contains infinite or NAN values!", _state);
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         w.ptr.p_double[i] = (double)(1);
 | |
|     }
 | |
|     spline1dfithermitewc(x, y, &w, n, &xc, &yc, &dc, 0, m, info, s, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted linear least squares fitting.
 | |
| 
 | |
| QR decomposition is used to reduce task to MxM, then triangular solver  or
 | |
| SVD-based solver is used depending on condition number of the  system.  It
 | |
| allows to maximize speed and retain decent accuracy.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
|            
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     W       -   array[0..N-1]  Weights  corresponding to function  values.
 | |
|                 Each summand in square  sum  of  approximation  deviations
 | |
|                 from  given  values  is  multiplied  by  the   square   of
 | |
|                 corresponding weight.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I, J] - value of J-th basis function in I-th point.
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 * -1    incorrect N/M were specified
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * Rep.TaskRCond     reciprocal of condition number
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
|                 
 | |
| ERRORS IN PARAMETERS                
 | |
|                 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
|             
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
|             
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
|             
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
|             
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitlinearw(/* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      /* Real    */ ae_matrix* fmatrix,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     *info = 0;
 | |
|     ae_vector_clear(c);
 | |
|     _lsfitreport_clear(rep);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitLinearW: N<1!", _state);
 | |
|     ae_assert(m>=1, "LSFitLinearW: M<1!", _state);
 | |
|     ae_assert(y->cnt>=n, "LSFitLinearW: length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LSFitLinearW: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(w->cnt>=n, "LSFitLinearW: length(W)<N!", _state);
 | |
|     ae_assert(isfinitevector(w, n, _state), "LSFitLinearW: W contains infinite or NaN values!", _state);
 | |
|     ae_assert(fmatrix->rows>=n, "LSFitLinearW: rows(FMatrix)<N!", _state);
 | |
|     ae_assert(fmatrix->cols>=m, "LSFitLinearW: cols(FMatrix)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(fmatrix, n, m, _state), "LSFitLinearW: FMatrix contains infinite or NaN values!", _state);
 | |
|     lsfit_lsfitlinearinternal(y, w, fmatrix, n, m, info, c, rep, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted constained linear least squares fitting.
 | |
| 
 | |
| This  is  variation  of LSFitLinearW(), which searchs for min|A*x=b| given
 | |
| that  K  additional  constaints  C*x=bc are satisfied. It reduces original
 | |
| task to modified one: min|B*y-d| WITHOUT constraints,  then LSFitLinearW()
 | |
| is called.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
|            
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     W       -   array[0..N-1]  Weights  corresponding to function  values.
 | |
|                 Each summand in square  sum  of  approximation  deviations
 | |
|                 from  given  values  is  multiplied  by  the   square   of
 | |
|                 corresponding weight.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I,J] - value of J-th basis function in I-th point.
 | |
|     CMatrix -   a table of constaints, array[0..K-1,0..M].
 | |
|                 I-th row of CMatrix corresponds to I-th linear constraint:
 | |
|                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
|     K       -   number of constraints, 0 <= K < M
 | |
|                 K=0 corresponds to absence of constraints.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 * -3    either   too   many  constraints  (M   or   more),
 | |
|                         degenerate  constraints   (some   constraints  are
 | |
|                         repetead twice) or inconsistent  constraints  were
 | |
|                         specified.
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
|                 
 | |
| ERRORS IN PARAMETERS                
 | |
|                 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
 | |
|             account boundary/linear constraints! Presence  of  constraints
 | |
|             changes distribution of errors, but there is no  easy  way  to
 | |
|             account for constraints when you calculate covariance matrix.
 | |
|             
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
|             
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
|             
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
|             
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 07.09.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitlinearwc(/* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      /* Real    */ ae_matrix* fmatrix,
 | |
|      /* Real    */ ae_matrix* cmatrix,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t k,
 | |
|      ae_int_t* info,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _y;
 | |
|     ae_matrix _cmatrix;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_vector tau;
 | |
|     ae_matrix q;
 | |
|     ae_matrix f2;
 | |
|     ae_vector tmp;
 | |
|     ae_vector c0;
 | |
|     double v;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&_cmatrix, 0, sizeof(_cmatrix));
 | |
|     memset(&tau, 0, sizeof(tau));
 | |
|     memset(&q, 0, sizeof(q));
 | |
|     memset(&f2, 0, sizeof(f2));
 | |
|     memset(&tmp, 0, sizeof(tmp));
 | |
|     memset(&c0, 0, sizeof(c0));
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_matrix_init_copy(&_cmatrix, cmatrix, _state, ae_true);
 | |
|     cmatrix = &_cmatrix;
 | |
|     *info = 0;
 | |
|     ae_vector_clear(c);
 | |
|     _lsfitreport_clear(rep);
 | |
|     ae_vector_init(&tau, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&f2, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&c0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitLinearWC: N<1!", _state);
 | |
|     ae_assert(m>=1, "LSFitLinearWC: M<1!", _state);
 | |
|     ae_assert(k>=0, "LSFitLinearWC: K<0!", _state);
 | |
|     ae_assert(y->cnt>=n, "LSFitLinearWC: length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LSFitLinearWC: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(w->cnt>=n, "LSFitLinearWC: length(W)<N!", _state);
 | |
|     ae_assert(isfinitevector(w, n, _state), "LSFitLinearWC: W contains infinite or NaN values!", _state);
 | |
|     ae_assert(fmatrix->rows>=n, "LSFitLinearWC: rows(FMatrix)<N!", _state);
 | |
|     ae_assert(fmatrix->cols>=m, "LSFitLinearWC: cols(FMatrix)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(fmatrix, n, m, _state), "LSFitLinearWC: FMatrix contains infinite or NaN values!", _state);
 | |
|     ae_assert(cmatrix->rows>=k, "LSFitLinearWC: rows(CMatrix)<K!", _state);
 | |
|     ae_assert(cmatrix->cols>=m+1||k==0, "LSFitLinearWC: cols(CMatrix)<M+1!", _state);
 | |
|     ae_assert(apservisfinitematrix(cmatrix, k, m+1, _state), "LSFitLinearWC: CMatrix contains infinite or NaN values!", _state);
 | |
|     if( k>=m )
 | |
|     {
 | |
|         *info = -3;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Solve
 | |
|      */
 | |
|     if( k==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * no constraints
 | |
|          */
 | |
|         lsfit_lsfitlinearinternal(y, w, fmatrix, n, m, info, c, rep, _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * First, find general form solution of constraints system:
 | |
|          * * factorize C = L*Q
 | |
|          * * unpack Q
 | |
|          * * fill upper part of C with zeros (for RCond)
 | |
|          *
 | |
|          * We got C=C0+Q2'*y where Q2 is lower M-K rows of Q.
 | |
|          */
 | |
|         rmatrixlq(cmatrix, k, m, &tau, _state);
 | |
|         rmatrixlqunpackq(cmatrix, k, m, &tau, m, &q, _state);
 | |
|         for(i=0; i<=k-1; i++)
 | |
|         {
 | |
|             for(j=i+1; j<=m-1; j++)
 | |
|             {
 | |
|                 cmatrix->ptr.pp_double[i][j] = 0.0;
 | |
|             }
 | |
|         }
 | |
|         if( ae_fp_less(rmatrixlurcondinf(cmatrix, k, _state),1000*ae_machineepsilon) )
 | |
|         {
 | |
|             *info = -3;
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         ae_vector_set_length(&tmp, k, _state);
 | |
|         for(i=0; i<=k-1; i++)
 | |
|         {
 | |
|             if( i>0 )
 | |
|             {
 | |
|                 v = ae_v_dotproduct(&cmatrix->ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,i-1));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 v = (double)(0);
 | |
|             }
 | |
|             tmp.ptr.p_double[i] = (cmatrix->ptr.pp_double[i][m]-v)/cmatrix->ptr.pp_double[i][i];
 | |
|         }
 | |
|         ae_vector_set_length(&c0, m, _state);
 | |
|         for(i=0; i<=m-1; i++)
 | |
|         {
 | |
|             c0.ptr.p_double[i] = (double)(0);
 | |
|         }
 | |
|         for(i=0; i<=k-1; i++)
 | |
|         {
 | |
|             v = tmp.ptr.p_double[i];
 | |
|             ae_v_addd(&c0.ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Second, prepare modified matrix F2 = F*Q2' and solve modified task
 | |
|          */
 | |
|         ae_vector_set_length(&tmp, ae_maxint(n, m, _state)+1, _state);
 | |
|         ae_matrix_set_length(&f2, n, m-k, _state);
 | |
|         matrixvectormultiply(fmatrix, 0, n-1, 0, m-1, ae_false, &c0, 0, m-1, -1.0, y, 0, n-1, 1.0, _state);
 | |
|         rmatrixgemm(n, m-k, m, 1.0, fmatrix, 0, 0, 0, &q, k, 0, 1, 0.0, &f2, 0, 0, _state);
 | |
|         lsfit_lsfitlinearinternal(y, w, &f2, n, m-k, info, &tmp, rep, _state);
 | |
|         rep->taskrcond = (double)(-1);
 | |
|         if( *info<=0 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * then, convert back to original answer: C = C0 + Q2'*Y0
 | |
|          */
 | |
|         ae_vector_set_length(c, m, _state);
 | |
|         ae_v_move(&c->ptr.p_double[0], 1, &c0.ptr.p_double[0], 1, ae_v_len(0,m-1));
 | |
|         matrixvectormultiply(&q, k, m-1, 0, m-1, ae_true, &tmp, 0, m-k-1, 1.0, c, 0, m-1, 1.0, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Linear least squares fitting.
 | |
| 
 | |
| QR decomposition is used to reduce task to MxM, then triangular solver  or
 | |
| SVD-based solver is used depending on condition number of the  system.  It
 | |
| allows to maximize speed and retain decent accuracy.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
|            
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I, J] - value of J-th basis function in I-th point.
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * Rep.TaskRCond     reciprocal of condition number
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
|                 
 | |
| ERRORS IN PARAMETERS                
 | |
|                 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
|             
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
|             
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
|             
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
|             
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitlinear(/* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_matrix* fmatrix,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector w;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     *info = 0;
 | |
|     ae_vector_clear(c);
 | |
|     _lsfitreport_clear(rep);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitLinear: N<1!", _state);
 | |
|     ae_assert(m>=1, "LSFitLinear: M<1!", _state);
 | |
|     ae_assert(y->cnt>=n, "LSFitLinear: length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LSFitLinear: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(fmatrix->rows>=n, "LSFitLinear: rows(FMatrix)<N!", _state);
 | |
|     ae_assert(fmatrix->cols>=m, "LSFitLinear: cols(FMatrix)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(fmatrix, n, m, _state), "LSFitLinear: FMatrix contains infinite or NaN values!", _state);
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         w.ptr.p_double[i] = (double)(1);
 | |
|     }
 | |
|     lsfit_lsfitlinearinternal(y, &w, fmatrix, n, m, info, c, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Constained linear least squares fitting.
 | |
| 
 | |
| This  is  variation  of LSFitLinear(),  which searchs for min|A*x=b| given
 | |
| that  K  additional  constaints  C*x=bc are satisfied. It reduces original
 | |
| task to modified one: min|B*y-d| WITHOUT constraints,  then  LSFitLinear()
 | |
| is called.
 | |
| 
 | |
| IMPORTANT: if you want to perform  polynomial  fitting,  it  may  be  more
 | |
|            convenient to use PolynomialFit() function. This function gives
 | |
|            best  results  on  polynomial  problems  and  solves  numerical
 | |
|            stability  issues  which  arise  when   you   fit   high-degree
 | |
|            polynomials to your data.
 | |
|            
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     Y       -   array[0..N-1] Function values in  N  points.
 | |
|     FMatrix -   a table of basis functions values, array[0..N-1, 0..M-1].
 | |
|                 FMatrix[I,J] - value of J-th basis function in I-th point.
 | |
|     CMatrix -   a table of constaints, array[0..K-1,0..M].
 | |
|                 I-th row of CMatrix corresponds to I-th linear constraint:
 | |
|                 CMatrix[I,0]*C[0] + ... + CMatrix[I,M-1]*C[M-1] = CMatrix[I,M]
 | |
|     N       -   number of points used. N>=1.
 | |
|     M       -   number of basis functions, M>=1.
 | |
|     K       -   number of constraints, 0 <= K < M
 | |
|                 K=0 corresponds to absence of constraints.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   error code:
 | |
|                 * -4    internal SVD decomposition subroutine failed (very
 | |
|                         rare and for degenerate systems only)
 | |
|                 * -3    either   too   many  constraints  (M   or   more),
 | |
|                         degenerate  constraints   (some   constraints  are
 | |
|                         repetead twice) or inconsistent  constraints  were
 | |
|                         specified.
 | |
|                 *  1    task is solved
 | |
|     C       -   decomposition coefficients, array[0..M-1]
 | |
|     Rep     -   fitting report. Following fields are set:
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
|                 
 | |
| ERRORS IN PARAMETERS                
 | |
|                 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(F*CovPar*F')),
 | |
|                     where F is functions matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
 | |
|             account boundary/linear constraints! Presence  of  constraints
 | |
|             changes distribution of errors, but there is no  easy  way  to
 | |
|             account for constraints when you calculate covariance matrix.
 | |
|             
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
|             
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
|             
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
|             
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 07.09.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitlinearc(/* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_matrix* fmatrix,
 | |
|      /* Real    */ ae_matrix* cmatrix,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t k,
 | |
|      ae_int_t* info,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _y;
 | |
|     ae_vector w;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     *info = 0;
 | |
|     ae_vector_clear(c);
 | |
|     _lsfitreport_clear(rep);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitLinearC: N<1!", _state);
 | |
|     ae_assert(m>=1, "LSFitLinearC: M<1!", _state);
 | |
|     ae_assert(k>=0, "LSFitLinearC: K<0!", _state);
 | |
|     ae_assert(y->cnt>=n, "LSFitLinearC: length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LSFitLinearC: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(fmatrix->rows>=n, "LSFitLinearC: rows(FMatrix)<N!", _state);
 | |
|     ae_assert(fmatrix->cols>=m, "LSFitLinearC: cols(FMatrix)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(fmatrix, n, m, _state), "LSFitLinearC: FMatrix contains infinite or NaN values!", _state);
 | |
|     ae_assert(cmatrix->rows>=k, "LSFitLinearC: rows(CMatrix)<K!", _state);
 | |
|     ae_assert(cmatrix->cols>=m+1||k==0, "LSFitLinearC: cols(CMatrix)<M+1!", _state);
 | |
|     ae_assert(apservisfinitematrix(cmatrix, k, m+1, _state), "LSFitLinearC: CMatrix contains infinite or NaN values!", _state);
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         w.ptr.p_double[i] = (double)(1);
 | |
|     }
 | |
|     lsfitlinearwc(y, &w, fmatrix, cmatrix, n, m, k, info, c, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted nonlinear least squares fitting using function values only.
 | |
| 
 | |
| Combination of numerical differentiation and secant updates is used to
 | |
| obtain function Jacobian.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     W       -   weights, array[0..N-1]
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     DiffStep-   numerical differentiation step;
 | |
|                 should not be very small or large;
 | |
|                 large = loss of accuracy
 | |
|                 small = growth of round-off errors
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 18.10.2008 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatewf(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t k,
 | |
|      double diffstep,
 | |
|      lsfitstate* state,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
|     _lsfitstate_clear(state);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitCreateWF: N<1!", _state);
 | |
|     ae_assert(m>=1, "LSFitCreateWF: M<1!", _state);
 | |
|     ae_assert(k>=1, "LSFitCreateWF: K<1!", _state);
 | |
|     ae_assert(c->cnt>=k, "LSFitCreateWF: length(C)<K!", _state);
 | |
|     ae_assert(isfinitevector(c, k, _state), "LSFitCreateWF: C contains infinite or NaN values!", _state);
 | |
|     ae_assert(y->cnt>=n, "LSFitCreateWF: length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LSFitCreateWF: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(w->cnt>=n, "LSFitCreateWF: length(W)<N!", _state);
 | |
|     ae_assert(isfinitevector(w, n, _state), "LSFitCreateWF: W contains infinite or NaN values!", _state);
 | |
|     ae_assert(x->rows>=n, "LSFitCreateWF: rows(X)<N!", _state);
 | |
|     ae_assert(x->cols>=m, "LSFitCreateWF: cols(X)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateWF: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(ae_isfinite(diffstep, _state), "LSFitCreateWF: DiffStep is not finite!", _state);
 | |
|     ae_assert(ae_fp_greater(diffstep,(double)(0)), "LSFitCreateWF: DiffStep<=0!", _state);
 | |
|     state->teststep = (double)(0);
 | |
|     state->diffstep = diffstep;
 | |
|     state->npoints = n;
 | |
|     state->nweights = n;
 | |
|     state->wkind = 1;
 | |
|     state->m = m;
 | |
|     state->k = k;
 | |
|     lsfitsetcond(state, 0.0, 0, _state);
 | |
|     lsfitsetstpmax(state, 0.0, _state);
 | |
|     lsfitsetxrep(state, ae_false, _state);
 | |
|     ae_matrix_set_length(&state->taskx, n, m, _state);
 | |
|     ae_vector_set_length(&state->tasky, n, _state);
 | |
|     ae_vector_set_length(&state->taskw, n, _state);
 | |
|     ae_vector_set_length(&state->c, k, _state);
 | |
|     ae_vector_set_length(&state->c0, k, _state);
 | |
|     ae_vector_set_length(&state->c1, k, _state);
 | |
|     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_vector_set_length(&state->x, m, _state);
 | |
|     ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     ae_vector_set_length(&state->s, k, _state);
 | |
|     ae_vector_set_length(&state->bndl, k, _state);
 | |
|     ae_vector_set_length(&state->bndu, k, _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         state->s.ptr.p_double[i] = 1.0;
 | |
|         state->bndl.ptr.p_double[i] = _state->v_neginf;
 | |
|         state->bndu.ptr.p_double[i] = _state->v_posinf;
 | |
|     }
 | |
|     state->optalgo = 0;
 | |
|     state->prevnpt = -1;
 | |
|     state->prevalgo = -1;
 | |
|     state->nec = 0;
 | |
|     state->nic = 0;
 | |
|     minlmcreatev(k, n, &state->c0, diffstep, &state->optstate, _state);
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
 | |
|     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
 | |
|     state->rstate.stage = -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting using function values only.
 | |
| 
 | |
| Combination of numerical differentiation and secant updates is used to
 | |
| obtain function Jacobian.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (f(c,x[0])-y[0])^2 + ... + (f(c,x[n-1])-y[n-1])^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     DiffStep-   numerical differentiation step;
 | |
|                 should not be very small or large;
 | |
|                 large = loss of accuracy
 | |
|                 small = growth of round-off errors
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 18.10.2008 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatef(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t k,
 | |
|      double diffstep,
 | |
|      lsfitstate* state,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
|     _lsfitstate_clear(state);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitCreateF: N<1!", _state);
 | |
|     ae_assert(m>=1, "LSFitCreateF: M<1!", _state);
 | |
|     ae_assert(k>=1, "LSFitCreateF: K<1!", _state);
 | |
|     ae_assert(c->cnt>=k, "LSFitCreateF: length(C)<K!", _state);
 | |
|     ae_assert(isfinitevector(c, k, _state), "LSFitCreateF: C contains infinite or NaN values!", _state);
 | |
|     ae_assert(y->cnt>=n, "LSFitCreateF: length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LSFitCreateF: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(x->rows>=n, "LSFitCreateF: rows(X)<N!", _state);
 | |
|     ae_assert(x->cols>=m, "LSFitCreateF: cols(X)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateF: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(x->rows>=n, "LSFitCreateF: rows(X)<N!", _state);
 | |
|     ae_assert(x->cols>=m, "LSFitCreateF: cols(X)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateF: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(ae_isfinite(diffstep, _state), "LSFitCreateF: DiffStep is not finite!", _state);
 | |
|     ae_assert(ae_fp_greater(diffstep,(double)(0)), "LSFitCreateF: DiffStep<=0!", _state);
 | |
|     state->teststep = (double)(0);
 | |
|     state->diffstep = diffstep;
 | |
|     state->npoints = n;
 | |
|     state->wkind = 0;
 | |
|     state->m = m;
 | |
|     state->k = k;
 | |
|     lsfitsetcond(state, 0.0, 0, _state);
 | |
|     lsfitsetstpmax(state, 0.0, _state);
 | |
|     lsfitsetxrep(state, ae_false, _state);
 | |
|     ae_matrix_set_length(&state->taskx, n, m, _state);
 | |
|     ae_vector_set_length(&state->tasky, n, _state);
 | |
|     ae_vector_set_length(&state->c, k, _state);
 | |
|     ae_vector_set_length(&state->c0, k, _state);
 | |
|     ae_vector_set_length(&state->c1, k, _state);
 | |
|     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_vector_set_length(&state->x, m, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     ae_vector_set_length(&state->s, k, _state);
 | |
|     ae_vector_set_length(&state->bndl, k, _state);
 | |
|     ae_vector_set_length(&state->bndu, k, _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         state->s.ptr.p_double[i] = 1.0;
 | |
|         state->bndl.ptr.p_double[i] = _state->v_neginf;
 | |
|         state->bndu.ptr.p_double[i] = _state->v_posinf;
 | |
|     }
 | |
|     state->optalgo = 0;
 | |
|     state->prevnpt = -1;
 | |
|     state->prevalgo = -1;
 | |
|     state->nec = 0;
 | |
|     state->nic = 0;
 | |
|     minlmcreatev(k, n, &state->c0, diffstep, &state->optstate, _state);
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
 | |
|     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
 | |
|     state->rstate.stage = -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted nonlinear least squares fitting using gradient only.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
 | |
|     
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
|     
 | |
| This subroutine uses only f(c,x[i]) and its gradient.
 | |
|     
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     W       -   weights, array[0..N-1]
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     CheapFG -   boolean flag, which is:
 | |
|                 * True  if both function and gradient calculation complexity
 | |
|                         are less than O(M^2).  An improved  algorithm  can
 | |
|                         be  used  which corresponds  to  FGJ  scheme  from
 | |
|                         MINLM unit.
 | |
|                 * False otherwise.
 | |
|                         Standard Jacibian-bases  Levenberg-Marquardt  algo
 | |
|                         will be used (FJ scheme).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
| See also:
 | |
|     LSFitResults
 | |
|     LSFitCreateFG (fitting without weights)
 | |
|     LSFitCreateWFGH (fitting using Hessian)
 | |
|     LSFitCreateFGH (fitting using Hessian, without weights)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatewfg(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t k,
 | |
|      ae_bool cheapfg,
 | |
|      lsfitstate* state,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
|     _lsfitstate_clear(state);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitCreateWFG: N<1!", _state);
 | |
|     ae_assert(m>=1, "LSFitCreateWFG: M<1!", _state);
 | |
|     ae_assert(k>=1, "LSFitCreateWFG: K<1!", _state);
 | |
|     ae_assert(c->cnt>=k, "LSFitCreateWFG: length(C)<K!", _state);
 | |
|     ae_assert(isfinitevector(c, k, _state), "LSFitCreateWFG: C contains infinite or NaN values!", _state);
 | |
|     ae_assert(y->cnt>=n, "LSFitCreateWFG: length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LSFitCreateWFG: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(w->cnt>=n, "LSFitCreateWFG: length(W)<N!", _state);
 | |
|     ae_assert(isfinitevector(w, n, _state), "LSFitCreateWFG: W contains infinite or NaN values!", _state);
 | |
|     ae_assert(x->rows>=n, "LSFitCreateWFG: rows(X)<N!", _state);
 | |
|     ae_assert(x->cols>=m, "LSFitCreateWFG: cols(X)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateWFG: X contains infinite or NaN values!", _state);
 | |
|     state->teststep = (double)(0);
 | |
|     state->diffstep = (double)(0);
 | |
|     state->npoints = n;
 | |
|     state->nweights = n;
 | |
|     state->wkind = 1;
 | |
|     state->m = m;
 | |
|     state->k = k;
 | |
|     lsfitsetcond(state, 0.0, 0, _state);
 | |
|     lsfitsetstpmax(state, 0.0, _state);
 | |
|     lsfitsetxrep(state, ae_false, _state);
 | |
|     ae_matrix_set_length(&state->taskx, n, m, _state);
 | |
|     ae_vector_set_length(&state->tasky, n, _state);
 | |
|     ae_vector_set_length(&state->taskw, n, _state);
 | |
|     ae_vector_set_length(&state->c, k, _state);
 | |
|     ae_vector_set_length(&state->c0, k, _state);
 | |
|     ae_vector_set_length(&state->c1, k, _state);
 | |
|     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_vector_set_length(&state->x, m, _state);
 | |
|     ae_vector_set_length(&state->g, k, _state);
 | |
|     ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     ae_vector_set_length(&state->s, k, _state);
 | |
|     ae_vector_set_length(&state->bndl, k, _state);
 | |
|     ae_vector_set_length(&state->bndu, k, _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         state->s.ptr.p_double[i] = 1.0;
 | |
|         state->bndl.ptr.p_double[i] = _state->v_neginf;
 | |
|         state->bndu.ptr.p_double[i] = _state->v_posinf;
 | |
|     }
 | |
|     state->optalgo = 1;
 | |
|     state->prevnpt = -1;
 | |
|     state->prevalgo = -1;
 | |
|     state->nec = 0;
 | |
|     state->nic = 0;
 | |
|     if( cheapfg )
 | |
|     {
 | |
|         minlmcreatevgj(k, n, &state->c0, &state->optstate, _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         minlmcreatevj(k, n, &state->c0, &state->optstate, _state);
 | |
|     }
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
 | |
|     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
 | |
|     state->rstate.stage = -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting using gradient only, without individual
 | |
| weights.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses only f(c,x[i]) and its gradient.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
|     CheapFG -   boolean flag, which is:
 | |
|                 * True  if both function and gradient calculation complexity
 | |
|                         are less than O(M^2).  An improved  algorithm  can
 | |
|                         be  used  which corresponds  to  FGJ  scheme  from
 | |
|                         MINLM unit.
 | |
|                 * False otherwise.
 | |
|                         Standard Jacibian-bases  Levenberg-Marquardt  algo
 | |
|                         will be used (FJ scheme).
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatefg(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t k,
 | |
|      ae_bool cheapfg,
 | |
|      lsfitstate* state,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
|     _lsfitstate_clear(state);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitCreateFG: N<1!", _state);
 | |
|     ae_assert(m>=1, "LSFitCreateFG: M<1!", _state);
 | |
|     ae_assert(k>=1, "LSFitCreateFG: K<1!", _state);
 | |
|     ae_assert(c->cnt>=k, "LSFitCreateFG: length(C)<K!", _state);
 | |
|     ae_assert(isfinitevector(c, k, _state), "LSFitCreateFG: C contains infinite or NaN values!", _state);
 | |
|     ae_assert(y->cnt>=n, "LSFitCreateFG: length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LSFitCreateFG: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(x->rows>=n, "LSFitCreateFG: rows(X)<N!", _state);
 | |
|     ae_assert(x->cols>=m, "LSFitCreateFG: cols(X)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateFG: X contains infinite or NaN values!", _state);
 | |
|     ae_assert(x->rows>=n, "LSFitCreateFG: rows(X)<N!", _state);
 | |
|     ae_assert(x->cols>=m, "LSFitCreateFG: cols(X)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateFG: X contains infinite or NaN values!", _state);
 | |
|     state->teststep = (double)(0);
 | |
|     state->diffstep = (double)(0);
 | |
|     state->npoints = n;
 | |
|     state->wkind = 0;
 | |
|     state->m = m;
 | |
|     state->k = k;
 | |
|     lsfitsetcond(state, 0.0, 0, _state);
 | |
|     lsfitsetstpmax(state, 0.0, _state);
 | |
|     lsfitsetxrep(state, ae_false, _state);
 | |
|     ae_matrix_set_length(&state->taskx, n, m, _state);
 | |
|     ae_vector_set_length(&state->tasky, n, _state);
 | |
|     ae_vector_set_length(&state->c, k, _state);
 | |
|     ae_vector_set_length(&state->c0, k, _state);
 | |
|     ae_vector_set_length(&state->c1, k, _state);
 | |
|     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_vector_set_length(&state->x, m, _state);
 | |
|     ae_vector_set_length(&state->g, k, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     ae_vector_set_length(&state->s, k, _state);
 | |
|     ae_vector_set_length(&state->bndl, k, _state);
 | |
|     ae_vector_set_length(&state->bndu, k, _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         state->s.ptr.p_double[i] = 1.0;
 | |
|         state->bndl.ptr.p_double[i] = _state->v_neginf;
 | |
|         state->bndu.ptr.p_double[i] = _state->v_posinf;
 | |
|     }
 | |
|     state->optalgo = 1;
 | |
|     state->prevnpt = -1;
 | |
|     state->prevalgo = -1;
 | |
|     state->nec = 0;
 | |
|     state->nic = 0;
 | |
|     if( cheapfg )
 | |
|     {
 | |
|         minlmcreatevgj(k, n, &state->c0, &state->optstate, _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         minlmcreatevj(k, n, &state->c0, &state->optstate, _state);
 | |
|     }
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
 | |
|     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
 | |
|     state->rstate.stage = -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Weighted nonlinear least squares fitting using gradient/Hessian.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = (w[0]*(f(c,x[0])-y[0]))^2 + ... + (w[n-1]*(f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * w is an N-dimensional vector of weight coefficients,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses f(c,x[i]), its gradient and its Hessian.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     W       -   weights, array[0..N-1]
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatewfgh(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t k,
 | |
|      lsfitstate* state,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
|     _lsfitstate_clear(state);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitCreateWFGH: N<1!", _state);
 | |
|     ae_assert(m>=1, "LSFitCreateWFGH: M<1!", _state);
 | |
|     ae_assert(k>=1, "LSFitCreateWFGH: K<1!", _state);
 | |
|     ae_assert(c->cnt>=k, "LSFitCreateWFGH: length(C)<K!", _state);
 | |
|     ae_assert(isfinitevector(c, k, _state), "LSFitCreateWFGH: C contains infinite or NaN values!", _state);
 | |
|     ae_assert(y->cnt>=n, "LSFitCreateWFGH: length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LSFitCreateWFGH: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(w->cnt>=n, "LSFitCreateWFGH: length(W)<N!", _state);
 | |
|     ae_assert(isfinitevector(w, n, _state), "LSFitCreateWFGH: W contains infinite or NaN values!", _state);
 | |
|     ae_assert(x->rows>=n, "LSFitCreateWFGH: rows(X)<N!", _state);
 | |
|     ae_assert(x->cols>=m, "LSFitCreateWFGH: cols(X)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateWFGH: X contains infinite or NaN values!", _state);
 | |
|     state->teststep = (double)(0);
 | |
|     state->diffstep = (double)(0);
 | |
|     state->npoints = n;
 | |
|     state->nweights = n;
 | |
|     state->wkind = 1;
 | |
|     state->m = m;
 | |
|     state->k = k;
 | |
|     lsfitsetcond(state, 0.0, 0, _state);
 | |
|     lsfitsetstpmax(state, 0.0, _state);
 | |
|     lsfitsetxrep(state, ae_false, _state);
 | |
|     ae_matrix_set_length(&state->taskx, n, m, _state);
 | |
|     ae_vector_set_length(&state->tasky, n, _state);
 | |
|     ae_vector_set_length(&state->taskw, n, _state);
 | |
|     ae_vector_set_length(&state->c, k, _state);
 | |
|     ae_vector_set_length(&state->c0, k, _state);
 | |
|     ae_vector_set_length(&state->c1, k, _state);
 | |
|     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_matrix_set_length(&state->h, k, k, _state);
 | |
|     ae_vector_set_length(&state->x, m, _state);
 | |
|     ae_vector_set_length(&state->g, k, _state);
 | |
|     ae_v_move(&state->taskw.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     ae_vector_set_length(&state->s, k, _state);
 | |
|     ae_vector_set_length(&state->bndl, k, _state);
 | |
|     ae_vector_set_length(&state->bndu, k, _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         state->s.ptr.p_double[i] = 1.0;
 | |
|         state->bndl.ptr.p_double[i] = _state->v_neginf;
 | |
|         state->bndu.ptr.p_double[i] = _state->v_posinf;
 | |
|     }
 | |
|     state->optalgo = 2;
 | |
|     state->prevnpt = -1;
 | |
|     state->prevalgo = -1;
 | |
|     state->nec = 0;
 | |
|     state->nic = 0;
 | |
|     minlmcreatefgh(k, &state->c0, &state->optstate, _state);
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
 | |
|     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
 | |
|     state->rstate.stage = -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting using gradient/Hessian, without individial
 | |
| weights.
 | |
| 
 | |
| Nonlinear task min(F(c)) is solved, where
 | |
| 
 | |
|     F(c) = ((f(c,x[0])-y[0]))^2 + ... + ((f(c,x[n-1])-y[n-1]))^2,
 | |
| 
 | |
|     * N is a number of points,
 | |
|     * M is a dimension of a space points belong to,
 | |
|     * K is a dimension of a space of parameters being fitted,
 | |
|     * x is a set of N points, each of them is an M-dimensional vector,
 | |
|     * c is a K-dimensional vector of parameters being fitted
 | |
| 
 | |
| This subroutine uses f(c,x[i]), its gradient and its Hessian.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[0..N-1,0..M-1], points (one row = one point)
 | |
|     Y       -   array[0..N-1], function values.
 | |
|     C       -   array[0..K-1], initial approximation to the solution,
 | |
|     N       -   number of points, N>1
 | |
|     M       -   dimension of space
 | |
|     K       -   number of parameters being fitted
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitcreatefgh(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t k,
 | |
|      lsfitstate* state,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
|     _lsfitstate_clear(state);
 | |
| 
 | |
|     ae_assert(n>=1, "LSFitCreateFGH: N<1!", _state);
 | |
|     ae_assert(m>=1, "LSFitCreateFGH: M<1!", _state);
 | |
|     ae_assert(k>=1, "LSFitCreateFGH: K<1!", _state);
 | |
|     ae_assert(c->cnt>=k, "LSFitCreateFGH: length(C)<K!", _state);
 | |
|     ae_assert(isfinitevector(c, k, _state), "LSFitCreateFGH: C contains infinite or NaN values!", _state);
 | |
|     ae_assert(y->cnt>=n, "LSFitCreateFGH: length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "LSFitCreateFGH: Y contains infinite or NaN values!", _state);
 | |
|     ae_assert(x->rows>=n, "LSFitCreateFGH: rows(X)<N!", _state);
 | |
|     ae_assert(x->cols>=m, "LSFitCreateFGH: cols(X)<M!", _state);
 | |
|     ae_assert(apservisfinitematrix(x, n, m, _state), "LSFitCreateFGH: X contains infinite or NaN values!", _state);
 | |
|     state->teststep = (double)(0);
 | |
|     state->diffstep = (double)(0);
 | |
|     state->npoints = n;
 | |
|     state->wkind = 0;
 | |
|     state->m = m;
 | |
|     state->k = k;
 | |
|     lsfitsetcond(state, 0.0, 0, _state);
 | |
|     lsfitsetstpmax(state, 0.0, _state);
 | |
|     lsfitsetxrep(state, ae_false, _state);
 | |
|     ae_matrix_set_length(&state->taskx, n, m, _state);
 | |
|     ae_vector_set_length(&state->tasky, n, _state);
 | |
|     ae_vector_set_length(&state->c, k, _state);
 | |
|     ae_vector_set_length(&state->c0, k, _state);
 | |
|     ae_vector_set_length(&state->c1, k, _state);
 | |
|     ae_v_move(&state->c0.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->c1.ptr.p_double[0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_matrix_set_length(&state->h, k, k, _state);
 | |
|     ae_vector_set_length(&state->x, m, _state);
 | |
|     ae_vector_set_length(&state->g, k, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         ae_v_move(&state->taskx.ptr.pp_double[i][0], 1, &x->ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|         state->tasky.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     ae_vector_set_length(&state->s, k, _state);
 | |
|     ae_vector_set_length(&state->bndl, k, _state);
 | |
|     ae_vector_set_length(&state->bndu, k, _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         state->s.ptr.p_double[i] = 1.0;
 | |
|         state->bndl.ptr.p_double[i] = _state->v_neginf;
 | |
|         state->bndu.ptr.p_double[i] = _state->v_posinf;
 | |
|     }
 | |
|     state->optalgo = 2;
 | |
|     state->prevnpt = -1;
 | |
|     state->prevalgo = -1;
 | |
|     state->nec = 0;
 | |
|     state->nic = 0;
 | |
|     minlmcreatefgh(k, &state->c0, &state->optstate, _state);
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     ae_vector_set_length(&state->rstate.ia, 6+1, _state);
 | |
|     ae_vector_set_length(&state->rstate.ra, 8+1, _state);
 | |
|     state->rstate.stage = -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Stopping conditions for nonlinear least squares fitting.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
|     EpsX    -   >=0
 | |
|                 The subroutine finishes its work if  on  k+1-th  iteration
 | |
|                 the condition |v|<=EpsX is fulfilled, where:
 | |
|                 * |.| means Euclidian norm
 | |
|                 * v - scaled step vector, v[i]=dx[i]/s[i]
 | |
|                 * dx - ste pvector, dx=X(k+1)-X(k)
 | |
|                 * s - scaling coefficients set by LSFitSetScale()
 | |
|     MaxIts  -   maximum number of iterations. If MaxIts=0, the  number  of
 | |
|                 iterations   is    unlimited.   Only   Levenberg-Marquardt
 | |
|                 iterations  are  counted  (L-BFGS/CG  iterations  are  NOT
 | |
|                 counted because their cost is very low compared to that of
 | |
|                 LM).
 | |
| 
 | |
| NOTE
 | |
| 
 | |
| Passing EpsX=0  and  MaxIts=0  (simultaneously)  will  lead  to  automatic
 | |
| stopping criterion selection (according to the scheme used by MINLM unit).
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetcond(lsfitstate* state,
 | |
|      double epsx,
 | |
|      ae_int_t maxits,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(epsx, _state), "LSFitSetCond: EpsX is not finite!", _state);
 | |
|     ae_assert(ae_fp_greater_eq(epsx,(double)(0)), "LSFitSetCond: negative EpsX!", _state);
 | |
|     ae_assert(maxits>=0, "LSFitSetCond: negative MaxIts!", _state);
 | |
|     state->epsx = epsx;
 | |
|     state->maxits = maxits;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets maximum step length
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
|     StpMax  -   maximum step length, >=0. Set StpMax to 0.0,  if you don't
 | |
|                 want to limit step length.
 | |
| 
 | |
| Use this subroutine when you optimize target function which contains exp()
 | |
| or  other  fast  growing  functions,  and optimization algorithm makes too
 | |
| large  steps  which  leads  to overflow. This function allows us to reject
 | |
| steps  that  are  too  large  (and  therefore  expose  us  to the possible
 | |
| overflow) without actually calculating function value at the x+stp*d.
 | |
| 
 | |
| NOTE: non-zero StpMax leads to moderate  performance  degradation  because
 | |
| intermediate  step  of  preconditioned L-BFGS optimization is incompatible
 | |
| with limits on step size.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.04.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetstpmax(lsfitstate* state, double stpmax, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_fp_greater_eq(stpmax,(double)(0)), "LSFitSetStpMax: StpMax<0!", _state);
 | |
|     state->stpmax = stpmax;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function turns on/off reporting.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure which stores algorithm state
 | |
|     NeedXRep-   whether iteration reports are needed or not
 | |
|     
 | |
| When reports are needed, State.C (current parameters) and State.F (current
 | |
| value of fitting function) are reported.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 15.08.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetxrep(lsfitstate* state, ae_bool needxrep, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     state->xrep = needxrep;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets scaling coefficients for underlying optimizer.
 | |
| 
 | |
| ALGLIB optimizers use scaling matrices to test stopping  conditions  (step
 | |
| size and gradient are scaled before comparison with tolerances).  Scale of
 | |
| the I-th variable is a translation invariant measure of:
 | |
| a) "how large" the variable is
 | |
| b) how large the step should be to make significant changes in the function
 | |
| 
 | |
| Generally, scale is NOT considered to be a form of preconditioner.  But LM
 | |
| optimizer is unique in that it uses scaling matrix both  in  the  stopping
 | |
| condition tests and as Marquardt damping factor.
 | |
| 
 | |
| Proper scaling is very important for the algorithm performance. It is less
 | |
| important for the quality of results, but still has some influence (it  is
 | |
| easier  to  converge  when  variables  are  properly  scaled, so premature
 | |
| stopping is possible when very badly scalled variables are  combined  with
 | |
| relaxed stopping conditions).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure stores algorithm state
 | |
|     S       -   array[N], non-zero scaling coefficients
 | |
|                 S[i] may be negative, sign doesn't matter.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.01.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetscale(lsfitstate* state,
 | |
|      /* Real    */ ae_vector* s,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
| 
 | |
|     ae_assert(s->cnt>=state->k, "LSFitSetScale: Length(S)<K", _state);
 | |
|     for(i=0; i<=state->k-1; i++)
 | |
|     {
 | |
|         ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "LSFitSetScale: S contains infinite or NAN elements", _state);
 | |
|         ae_assert(ae_fp_neq(s->ptr.p_double[i],(double)(0)), "LSFitSetScale: S contains infinite or NAN elements", _state);
 | |
|         state->s.ptr.p_double[i] = ae_fabs(s->ptr.p_double[i], _state);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets boundary constraints for underlying optimizer
 | |
| 
 | |
| Boundary constraints are inactive by default (after initial creation).
 | |
| They are preserved until explicitly turned off with another SetBC() call.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure stores algorithm state
 | |
|     BndL    -   lower bounds, array[K].
 | |
|                 If some (all) variables are unbounded, you may specify
 | |
|                 very small number or -INF (latter is recommended because
 | |
|                 it will allow solver to use better algorithm).
 | |
|     BndU    -   upper bounds, array[K].
 | |
|                 If some (all) variables are unbounded, you may specify
 | |
|                 very large number or +INF (latter is recommended because
 | |
|                 it will allow solver to use better algorithm).
 | |
| 
 | |
| NOTE 1: it is possible to specify BndL[i]=BndU[i]. In this case I-th
 | |
| variable will be "frozen" at X[i]=BndL[i]=BndU[i].
 | |
| 
 | |
| NOTE 2: unlike other constrained optimization algorithms, this solver  has
 | |
| following useful properties:
 | |
| * bound constraints are always satisfied exactly
 | |
| * function is evaluated only INSIDE area specified by bound constraints
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.01.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetbc(lsfitstate* state,
 | |
|      /* Real    */ ae_vector* bndl,
 | |
|      /* Real    */ ae_vector* bndu,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t k;
 | |
| 
 | |
| 
 | |
|     k = state->k;
 | |
|     ae_assert(bndl->cnt>=k, "LSFitSetBC: Length(BndL)<K", _state);
 | |
|     ae_assert(bndu->cnt>=k, "LSFitSetBC: Length(BndU)<K", _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         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);
 | |
|         ae_assert(ae_isfinite(bndu->ptr.p_double[i], _state)||ae_isposinf(bndu->ptr.p_double[i], _state), "LSFitSetBC: BndU contains NAN or -INF", _state);
 | |
|         if( ae_isfinite(bndl->ptr.p_double[i], _state)&&ae_isfinite(bndu->ptr.p_double[i], _state) )
 | |
|         {
 | |
|             ae_assert(ae_fp_less_eq(bndl->ptr.p_double[i],bndu->ptr.p_double[i]), "LSFitSetBC: BndL[i]>BndU[i]", _state);
 | |
|         }
 | |
|         state->bndl.ptr.p_double[i] = bndl->ptr.p_double[i];
 | |
|         state->bndu.ptr.p_double[i] = bndu->ptr.p_double[i];
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets linear constraints for underlying optimizer
 | |
| 
 | |
| Linear constraints are inactive by default (after initial creation).
 | |
| They are preserved until explicitly turned off with another SetLC() call.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   structure stores algorithm state
 | |
|     C       -   linear constraints, array[K,N+1].
 | |
|                 Each row of C represents one constraint, either equality
 | |
|                 or inequality (see below):
 | |
|                 * first N elements correspond to coefficients,
 | |
|                 * last element corresponds to the right part.
 | |
|                 All elements of C (including right part) must be finite.
 | |
|     CT      -   type of constraints, array[K]:
 | |
|                 * if CT[i]>0, then I-th constraint is C[i,*]*x >= C[i,n+1]
 | |
|                 * if CT[i]=0, then I-th constraint is C[i,*]*x  = C[i,n+1]
 | |
|                 * if CT[i]<0, then I-th constraint is C[i,*]*x <= C[i,n+1]
 | |
|     K       -   number of equality/inequality constraints, K>=0:
 | |
|                 * if given, only leading K elements of C/CT are used
 | |
|                 * if not given, automatically determined from sizes of C/CT
 | |
| 
 | |
| IMPORTANT: if you have linear constraints, it is strongly  recommended  to
 | |
|            set scale of variables with lsfitsetscale(). QP solver which is
 | |
|            used to calculate linearly constrained steps heavily relies  on
 | |
|            good scaling of input problems.
 | |
|            
 | |
| NOTE: linear  (non-box)  constraints  are  satisfied only approximately  -
 | |
|       there  always  exists some violation due  to  numerical  errors  and
 | |
|       algorithmic limitations.
 | |
| 
 | |
| NOTE: general linear constraints  add  significant  overhead  to  solution
 | |
|       process. Although solver performs roughly same amount of  iterations
 | |
|       (when compared  with  similar  box-only  constrained  problem), each
 | |
|       iteration   now    involves  solution  of  linearly  constrained  QP
 | |
|       subproblem, which requires ~3-5 times more Cholesky  decompositions.
 | |
|       Thus, if you can reformulate your problem in such way  this  it  has
 | |
|       only box constraints, it may be beneficial to do so.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 29.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetlc(lsfitstate* state,
 | |
|      /* Real    */ ae_matrix* c,
 | |
|      /* Integer */ ae_vector* ct,
 | |
|      ae_int_t k,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t n;
 | |
| 
 | |
| 
 | |
|     n = state->k;
 | |
|     
 | |
|     /*
 | |
|      * First, check for errors in the inputs
 | |
|      */
 | |
|     ae_assert(k>=0, "LSFitSetLC: K<0", _state);
 | |
|     ae_assert(c->cols>=n+1||k==0, "LSFitSetLC: Cols(C)<N+1", _state);
 | |
|     ae_assert(c->rows>=k, "LSFitSetLC: Rows(C)<K", _state);
 | |
|     ae_assert(ct->cnt>=k, "LSFitSetLC: Length(CT)<K", _state);
 | |
|     ae_assert(apservisfinitematrix(c, k, n+1, _state), "LSFitSetLC: C contains infinite or NaN values!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Handle zero K
 | |
|      */
 | |
|     if( k==0 )
 | |
|     {
 | |
|         state->nec = 0;
 | |
|         state->nic = 0;
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Equality constraints are stored first, in the upper
 | |
|      * NEC rows of State.CLEIC matrix. Inequality constraints
 | |
|      * are stored in the next NIC rows.
 | |
|      *
 | |
|      * NOTE: we convert inequality constraints to the form
 | |
|      * A*x<=b before copying them.
 | |
|      */
 | |
|     rmatrixsetlengthatleast(&state->cleic, k, n+1, _state);
 | |
|     state->nec = 0;
 | |
|     state->nic = 0;
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         if( ct->ptr.p_int[i]==0 )
 | |
|         {
 | |
|             ae_v_move(&state->cleic.ptr.pp_double[state->nec][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n));
 | |
|             state->nec = state->nec+1;
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         if( ct->ptr.p_int[i]!=0 )
 | |
|         {
 | |
|             if( ct->ptr.p_int[i]>0 )
 | |
|             {
 | |
|                 ae_v_moveneg(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ae_v_move(&state->cleic.ptr.pp_double[state->nec+state->nic][0], 1, &c->ptr.pp_double[i][0], 1, ae_v_len(0,n));
 | |
|             }
 | |
|             state->nic = state->nic+1;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| NOTES:
 | |
| 
 | |
| 1. this algorithm is somewhat unusual because it works with  parameterized
 | |
|    function f(C,X), where X is a function argument (we  have  many  points
 | |
|    which are characterized by different  argument  values),  and  C  is  a
 | |
|    parameter to fit.
 | |
| 
 | |
|    For example, if we want to do linear fit by f(c0,c1,x) = c0*x+c1,  then
 | |
|    x will be argument, and {c0,c1} will be parameters.
 | |
|    
 | |
|    It is important to understand that this algorithm finds minimum in  the
 | |
|    space of function PARAMETERS (not arguments), so it  needs  derivatives
 | |
|    of f() with respect to C, not X.
 | |
|    
 | |
|    In the example above it will need f=c0*x+c1 and {df/dc0,df/dc1} = {x,1}
 | |
|    instead of {df/dx} = {c0}.
 | |
| 
 | |
| 2. Callback functions accept C as the first parameter, and X as the second
 | |
| 
 | |
| 3. If  state  was  created  with  LSFitCreateFG(),  algorithm  needs  just
 | |
|    function   and   its   gradient,   but   if   state   was  created with
 | |
|    LSFitCreateFGH(), algorithm will need function, gradient and Hessian.
 | |
|    
 | |
|    According  to  the  said  above,  there  ase  several  versions of this
 | |
|    function, which accept different sets of callbacks.
 | |
|    
 | |
|    This flexibility opens way to subtle errors - you may create state with
 | |
|    LSFitCreateFGH() (optimization using Hessian), but call function  which
 | |
|    does not accept Hessian. So when algorithm will request Hessian,  there
 | |
|    will be no callback to call. In this case exception will be thrown.
 | |
|    
 | |
|    Be careful to avoid such errors because there is no way to find them at
 | |
|    compile time - you can see them at runtime only.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| ae_bool lsfititeration(lsfitstate* state, ae_state *_state)
 | |
| {
 | |
|     double lx;
 | |
|     double lf;
 | |
|     double ld;
 | |
|     double rx;
 | |
|     double rf;
 | |
|     double rd;
 | |
|     ae_int_t n;
 | |
|     ae_int_t m;
 | |
|     ae_int_t k;
 | |
|     double v;
 | |
|     double vv;
 | |
|     double relcnt;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t j1;
 | |
|     ae_int_t info;
 | |
|     ae_bool result;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Reverse communication preparations
 | |
|      * I know it looks ugly, but it works the same way
 | |
|      * anywhere from C++ to Python.
 | |
|      *
 | |
|      * This code initializes locals by:
 | |
|      * * random values determined during code
 | |
|      *   generation - on first subroutine call
 | |
|      * * values from previous call - on subsequent calls
 | |
|      */
 | |
|     if( state->rstate.stage>=0 )
 | |
|     {
 | |
|         n = state->rstate.ia.ptr.p_int[0];
 | |
|         m = state->rstate.ia.ptr.p_int[1];
 | |
|         k = state->rstate.ia.ptr.p_int[2];
 | |
|         i = state->rstate.ia.ptr.p_int[3];
 | |
|         j = state->rstate.ia.ptr.p_int[4];
 | |
|         j1 = state->rstate.ia.ptr.p_int[5];
 | |
|         info = state->rstate.ia.ptr.p_int[6];
 | |
|         lx = state->rstate.ra.ptr.p_double[0];
 | |
|         lf = state->rstate.ra.ptr.p_double[1];
 | |
|         ld = state->rstate.ra.ptr.p_double[2];
 | |
|         rx = state->rstate.ra.ptr.p_double[3];
 | |
|         rf = state->rstate.ra.ptr.p_double[4];
 | |
|         rd = state->rstate.ra.ptr.p_double[5];
 | |
|         v = state->rstate.ra.ptr.p_double[6];
 | |
|         vv = state->rstate.ra.ptr.p_double[7];
 | |
|         relcnt = state->rstate.ra.ptr.p_double[8];
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         n = 359;
 | |
|         m = -58;
 | |
|         k = -919;
 | |
|         i = -909;
 | |
|         j = 81;
 | |
|         j1 = 255;
 | |
|         info = 74;
 | |
|         lx = -788;
 | |
|         lf = 809;
 | |
|         ld = 205;
 | |
|         rx = -838;
 | |
|         rf = 939;
 | |
|         rd = -526;
 | |
|         v = 763;
 | |
|         vv = -541;
 | |
|         relcnt = -698;
 | |
|     }
 | |
|     if( state->rstate.stage==0 )
 | |
|     {
 | |
|         goto lbl_0;
 | |
|     }
 | |
|     if( state->rstate.stage==1 )
 | |
|     {
 | |
|         goto lbl_1;
 | |
|     }
 | |
|     if( state->rstate.stage==2 )
 | |
|     {
 | |
|         goto lbl_2;
 | |
|     }
 | |
|     if( state->rstate.stage==3 )
 | |
|     {
 | |
|         goto lbl_3;
 | |
|     }
 | |
|     if( state->rstate.stage==4 )
 | |
|     {
 | |
|         goto lbl_4;
 | |
|     }
 | |
|     if( state->rstate.stage==5 )
 | |
|     {
 | |
|         goto lbl_5;
 | |
|     }
 | |
|     if( state->rstate.stage==6 )
 | |
|     {
 | |
|         goto lbl_6;
 | |
|     }
 | |
|     if( state->rstate.stage==7 )
 | |
|     {
 | |
|         goto lbl_7;
 | |
|     }
 | |
|     if( state->rstate.stage==8 )
 | |
|     {
 | |
|         goto lbl_8;
 | |
|     }
 | |
|     if( state->rstate.stage==9 )
 | |
|     {
 | |
|         goto lbl_9;
 | |
|     }
 | |
|     if( state->rstate.stage==10 )
 | |
|     {
 | |
|         goto lbl_10;
 | |
|     }
 | |
|     if( state->rstate.stage==11 )
 | |
|     {
 | |
|         goto lbl_11;
 | |
|     }
 | |
|     if( state->rstate.stage==12 )
 | |
|     {
 | |
|         goto lbl_12;
 | |
|     }
 | |
|     if( state->rstate.stage==13 )
 | |
|     {
 | |
|         goto lbl_13;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Routine body
 | |
|      */
 | |
|     
 | |
|     /*
 | |
|      * Init
 | |
|      */
 | |
|     if( state->wkind==1 )
 | |
|     {
 | |
|         ae_assert(state->npoints==state->nweights, "LSFitFit: number of points is not equal to the number of weights", _state);
 | |
|     }
 | |
|     state->repvaridx = -1;
 | |
|     n = state->npoints;
 | |
|     m = state->m;
 | |
|     k = state->k;
 | |
|     ivectorsetlengthatleast(&state->tmpct, state->nec+state->nic, _state);
 | |
|     for(i=0; i<=state->nec-1; i++)
 | |
|     {
 | |
|         state->tmpct.ptr.p_int[i] = 0;
 | |
|     }
 | |
|     for(i=0; i<=state->nic-1; i++)
 | |
|     {
 | |
|         state->tmpct.ptr.p_int[state->nec+i] = -1;
 | |
|     }
 | |
|     minlmsetcond(&state->optstate, state->epsx, state->maxits, _state);
 | |
|     minlmsetstpmax(&state->optstate, state->stpmax, _state);
 | |
|     minlmsetxrep(&state->optstate, state->xrep, _state);
 | |
|     minlmsetscale(&state->optstate, &state->s, _state);
 | |
|     minlmsetbc(&state->optstate, &state->bndl, &state->bndu, _state);
 | |
|     minlmsetlc(&state->optstate, &state->cleic, &state->tmpct, state->nec+state->nic, _state);
 | |
|     
 | |
|     /*
 | |
|      *  Check that user-supplied gradient is correct
 | |
|      */
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     if( !(ae_fp_greater(state->teststep,(double)(0))&&state->optalgo==1) )
 | |
|     {
 | |
|         goto lbl_14;
 | |
|     }
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         state->c.ptr.p_double[i] = state->c0.ptr.p_double[i];
 | |
|         if( ae_isfinite(state->bndl.ptr.p_double[i], _state) )
 | |
|         {
 | |
|             state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state);
 | |
|         }
 | |
|         if( ae_isfinite(state->bndu.ptr.p_double[i], _state) )
 | |
|         {
 | |
|             state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
 | |
|         }
 | |
|     }
 | |
|     state->needfg = ae_true;
 | |
|     i = 0;
 | |
| lbl_16:
 | |
|     if( i>k-1 )
 | |
|     {
 | |
|         goto lbl_18;
 | |
|     }
 | |
|     ae_assert(ae_fp_less_eq(state->bndl.ptr.p_double[i],state->c.ptr.p_double[i])&&ae_fp_less_eq(state->c.ptr.p_double[i],state->bndu.ptr.p_double[i]), "LSFitIteration: internal error(State.C is out of bounds)", _state);
 | |
|     v = state->c.ptr.p_double[i];
 | |
|     j = 0;
 | |
| lbl_19:
 | |
|     if( j>n-1 )
 | |
|     {
 | |
|         goto lbl_21;
 | |
|     }
 | |
|     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[j][0], 1, ae_v_len(0,m-1));
 | |
|     state->c.ptr.p_double[i] = v-state->teststep*state->s.ptr.p_double[i];
 | |
|     if( ae_isfinite(state->bndl.ptr.p_double[i], _state) )
 | |
|     {
 | |
|         state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state);
 | |
|     }
 | |
|     lx = state->c.ptr.p_double[i];
 | |
|     state->rstate.stage = 0;
 | |
|     goto lbl_rcomm;
 | |
| lbl_0:
 | |
|     lf = state->f;
 | |
|     ld = state->g.ptr.p_double[i];
 | |
|     state->c.ptr.p_double[i] = v+state->teststep*state->s.ptr.p_double[i];
 | |
|     if( ae_isfinite(state->bndu.ptr.p_double[i], _state) )
 | |
|     {
 | |
|         state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
 | |
|     }
 | |
|     rx = state->c.ptr.p_double[i];
 | |
|     state->rstate.stage = 1;
 | |
|     goto lbl_rcomm;
 | |
| lbl_1:
 | |
|     rf = state->f;
 | |
|     rd = state->g.ptr.p_double[i];
 | |
|     state->c.ptr.p_double[i] = (lx+rx)/2;
 | |
|     if( ae_isfinite(state->bndl.ptr.p_double[i], _state) )
 | |
|     {
 | |
|         state->c.ptr.p_double[i] = ae_maxreal(state->c.ptr.p_double[i], state->bndl.ptr.p_double[i], _state);
 | |
|     }
 | |
|     if( ae_isfinite(state->bndu.ptr.p_double[i], _state) )
 | |
|     {
 | |
|         state->c.ptr.p_double[i] = ae_minreal(state->c.ptr.p_double[i], state->bndu.ptr.p_double[i], _state);
 | |
|     }
 | |
|     state->rstate.stage = 2;
 | |
|     goto lbl_rcomm;
 | |
| lbl_2:
 | |
|     state->c.ptr.p_double[i] = v;
 | |
|     if( !derivativecheck(lf, ld, rf, rd, state->f, state->g.ptr.p_double[i], rx-lx, _state) )
 | |
|     {
 | |
|         state->repvaridx = i;
 | |
|         state->repterminationtype = -7;
 | |
|         result = ae_false;
 | |
|         return result;
 | |
|     }
 | |
|     j = j+1;
 | |
|     goto lbl_19;
 | |
| lbl_21:
 | |
|     i = i+1;
 | |
|     goto lbl_16;
 | |
| lbl_18:
 | |
|     state->needfg = ae_false;
 | |
| lbl_14:
 | |
|     
 | |
|     /*
 | |
|      * Fill WCur by weights:
 | |
|      * * for WKind=0 unit weights are chosen
 | |
|      * * for WKind=1 we use user-supplied weights stored in State.TaskW
 | |
|      */
 | |
|     rvectorsetlengthatleast(&state->wcur, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         state->wcur.ptr.p_double[i] = 1.0;
 | |
|         if( state->wkind==1 )
 | |
|         {
 | |
|             state->wcur.ptr.p_double[i] = state->taskw.ptr.p_double[i];
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Optimize
 | |
|      */
 | |
| lbl_22:
 | |
|     if( !minlmiteration(&state->optstate, _state) )
 | |
|     {
 | |
|         goto lbl_23;
 | |
|     }
 | |
|     if( !state->optstate.needfi )
 | |
|     {
 | |
|         goto lbl_24;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * calculate f[] = wi*(f(xi,c)-yi)
 | |
|      */
 | |
|     i = 0;
 | |
| lbl_26:
 | |
|     if( i>n-1 )
 | |
|     {
 | |
|         goto lbl_28;
 | |
|     }
 | |
|     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|     state->pointindex = i;
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     state->needf = ae_true;
 | |
|     state->rstate.stage = 3;
 | |
|     goto lbl_rcomm;
 | |
| lbl_3:
 | |
|     state->needf = ae_false;
 | |
|     vv = state->wcur.ptr.p_double[i];
 | |
|     state->optstate.fi.ptr.p_double[i] = vv*(state->f-state->tasky.ptr.p_double[i]);
 | |
|     i = i+1;
 | |
|     goto lbl_26;
 | |
| lbl_28:
 | |
|     goto lbl_22;
 | |
| lbl_24:
 | |
|     if( !state->optstate.needf )
 | |
|     {
 | |
|         goto lbl_29;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * calculate F = sum (wi*(f(xi,c)-yi))^2
 | |
|      */
 | |
|     state->optstate.f = (double)(0);
 | |
|     i = 0;
 | |
| lbl_31:
 | |
|     if( i>n-1 )
 | |
|     {
 | |
|         goto lbl_33;
 | |
|     }
 | |
|     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|     state->pointindex = i;
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     state->needf = ae_true;
 | |
|     state->rstate.stage = 4;
 | |
|     goto lbl_rcomm;
 | |
| lbl_4:
 | |
|     state->needf = ae_false;
 | |
|     vv = state->wcur.ptr.p_double[i];
 | |
|     state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state);
 | |
|     i = i+1;
 | |
|     goto lbl_31;
 | |
| lbl_33:
 | |
|     goto lbl_22;
 | |
| lbl_29:
 | |
|     if( !state->optstate.needfg )
 | |
|     {
 | |
|         goto lbl_34;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * calculate F/gradF
 | |
|      */
 | |
|     state->optstate.f = (double)(0);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         state->optstate.g.ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     i = 0;
 | |
| lbl_36:
 | |
|     if( i>n-1 )
 | |
|     {
 | |
|         goto lbl_38;
 | |
|     }
 | |
|     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|     state->pointindex = i;
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     state->needfg = ae_true;
 | |
|     state->rstate.stage = 5;
 | |
|     goto lbl_rcomm;
 | |
| lbl_5:
 | |
|     state->needfg = ae_false;
 | |
|     vv = state->wcur.ptr.p_double[i];
 | |
|     state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state);
 | |
|     v = ae_sqr(vv, _state)*2*(state->f-state->tasky.ptr.p_double[i]);
 | |
|     ae_v_addd(&state->optstate.g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), v);
 | |
|     i = i+1;
 | |
|     goto lbl_36;
 | |
| lbl_38:
 | |
|     goto lbl_22;
 | |
| lbl_34:
 | |
|     if( !state->optstate.needfij )
 | |
|     {
 | |
|         goto lbl_39;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * calculate Fi/jac(Fi)
 | |
|      */
 | |
|     i = 0;
 | |
| lbl_41:
 | |
|     if( i>n-1 )
 | |
|     {
 | |
|         goto lbl_43;
 | |
|     }
 | |
|     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|     state->pointindex = i;
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     state->needfg = ae_true;
 | |
|     state->rstate.stage = 6;
 | |
|     goto lbl_rcomm;
 | |
| lbl_6:
 | |
|     state->needfg = ae_false;
 | |
|     vv = state->wcur.ptr.p_double[i];
 | |
|     state->optstate.fi.ptr.p_double[i] = vv*(state->f-state->tasky.ptr.p_double[i]);
 | |
|     ae_v_moved(&state->optstate.j.ptr.pp_double[i][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), vv);
 | |
|     i = i+1;
 | |
|     goto lbl_41;
 | |
| lbl_43:
 | |
|     goto lbl_22;
 | |
| lbl_39:
 | |
|     if( !state->optstate.needfgh )
 | |
|     {
 | |
|         goto lbl_44;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * calculate F/grad(F)/hess(F)
 | |
|      */
 | |
|     state->optstate.f = (double)(0);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         state->optstate.g.ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=k-1; j++)
 | |
|         {
 | |
|             state->optstate.h.ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     i = 0;
 | |
| lbl_46:
 | |
|     if( i>n-1 )
 | |
|     {
 | |
|         goto lbl_48;
 | |
|     }
 | |
|     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|     state->pointindex = i;
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     state->needfgh = ae_true;
 | |
|     state->rstate.stage = 7;
 | |
|     goto lbl_rcomm;
 | |
| lbl_7:
 | |
|     state->needfgh = ae_false;
 | |
|     vv = state->wcur.ptr.p_double[i];
 | |
|     state->optstate.f = state->optstate.f+ae_sqr(vv*(state->f-state->tasky.ptr.p_double[i]), _state);
 | |
|     v = ae_sqr(vv, _state)*2*(state->f-state->tasky.ptr.p_double[i]);
 | |
|     ae_v_addd(&state->optstate.g.ptr.p_double[0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), v);
 | |
|     for(j=0; j<=k-1; j++)
 | |
|     {
 | |
|         v = 2*ae_sqr(vv, _state)*state->g.ptr.p_double[j];
 | |
|         ae_v_addd(&state->optstate.h.ptr.pp_double[j][0], 1, &state->g.ptr.p_double[0], 1, ae_v_len(0,k-1), v);
 | |
|         v = 2*ae_sqr(vv, _state)*(state->f-state->tasky.ptr.p_double[i]);
 | |
|         ae_v_addd(&state->optstate.h.ptr.pp_double[j][0], 1, &state->h.ptr.pp_double[j][0], 1, ae_v_len(0,k-1), v);
 | |
|     }
 | |
|     i = i+1;
 | |
|     goto lbl_46;
 | |
| lbl_48:
 | |
|     goto lbl_22;
 | |
| lbl_44:
 | |
|     if( !state->optstate.xupdated )
 | |
|     {
 | |
|         goto lbl_49;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Report new iteration
 | |
|      */
 | |
|     ae_v_move(&state->c.ptr.p_double[0], 1, &state->optstate.x.ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     state->f = state->optstate.f;
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     state->xupdated = ae_true;
 | |
|     state->rstate.stage = 8;
 | |
|     goto lbl_rcomm;
 | |
| lbl_8:
 | |
|     state->xupdated = ae_false;
 | |
|     goto lbl_22;
 | |
| lbl_49:
 | |
|     goto lbl_22;
 | |
| lbl_23:
 | |
|     
 | |
|     /*
 | |
|      * Extract results
 | |
|      *
 | |
|      * NOTE: reverse communication protocol used by this unit does NOT
 | |
|      *       allow us to reallocate State.C[] array. Thus, we extract
 | |
|      *       results to the temporary variable in order to avoid possible
 | |
|      *       reallocation.
 | |
|      */
 | |
|     minlmresults(&state->optstate, &state->c1, &state->optrep, _state);
 | |
|     state->repterminationtype = state->optrep.terminationtype;
 | |
|     state->repiterationscount = state->optrep.iterationscount;
 | |
|     
 | |
|     /*
 | |
|      * calculate errors
 | |
|      */
 | |
|     if( state->repterminationtype<=0 )
 | |
|     {
 | |
|         goto lbl_51;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Calculate RMS/Avg/Max/... errors
 | |
|      */
 | |
|     state->reprmserror = (double)(0);
 | |
|     state->repwrmserror = (double)(0);
 | |
|     state->repavgerror = (double)(0);
 | |
|     state->repavgrelerror = (double)(0);
 | |
|     state->repmaxerror = (double)(0);
 | |
|     relcnt = (double)(0);
 | |
|     i = 0;
 | |
| lbl_53:
 | |
|     if( i>n-1 )
 | |
|     {
 | |
|         goto lbl_55;
 | |
|     }
 | |
|     ae_v_move(&state->c.ptr.p_double[0], 1, &state->c1.ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|     state->pointindex = i;
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     state->needf = ae_true;
 | |
|     state->rstate.stage = 9;
 | |
|     goto lbl_rcomm;
 | |
| lbl_9:
 | |
|     state->needf = ae_false;
 | |
|     v = state->f;
 | |
|     vv = state->wcur.ptr.p_double[i];
 | |
|     state->reprmserror = state->reprmserror+ae_sqr(v-state->tasky.ptr.p_double[i], _state);
 | |
|     state->repwrmserror = state->repwrmserror+ae_sqr(vv*(v-state->tasky.ptr.p_double[i]), _state);
 | |
|     state->repavgerror = state->repavgerror+ae_fabs(v-state->tasky.ptr.p_double[i], _state);
 | |
|     if( ae_fp_neq(state->tasky.ptr.p_double[i],(double)(0)) )
 | |
|     {
 | |
|         state->repavgrelerror = state->repavgrelerror+ae_fabs(v-state->tasky.ptr.p_double[i], _state)/ae_fabs(state->tasky.ptr.p_double[i], _state);
 | |
|         relcnt = relcnt+1;
 | |
|     }
 | |
|     state->repmaxerror = ae_maxreal(state->repmaxerror, ae_fabs(v-state->tasky.ptr.p_double[i], _state), _state);
 | |
|     i = i+1;
 | |
|     goto lbl_53;
 | |
| lbl_55:
 | |
|     state->reprmserror = ae_sqrt(state->reprmserror/n, _state);
 | |
|     state->repwrmserror = ae_sqrt(state->repwrmserror/n, _state);
 | |
|     state->repavgerror = state->repavgerror/n;
 | |
|     if( ae_fp_neq(relcnt,(double)(0)) )
 | |
|     {
 | |
|         state->repavgrelerror = state->repavgrelerror/relcnt;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Calculate covariance matrix
 | |
|      */
 | |
|     rmatrixsetlengthatleast(&state->tmpjac, n, k, _state);
 | |
|     rvectorsetlengthatleast(&state->tmpf, n, _state);
 | |
|     rvectorsetlengthatleast(&state->tmp, k, _state);
 | |
|     if( ae_fp_less_eq(state->diffstep,(double)(0)) )
 | |
|     {
 | |
|         goto lbl_56;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Compute Jacobian by means of numerical differentiation
 | |
|      */
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     state->needf = ae_true;
 | |
|     i = 0;
 | |
| lbl_58:
 | |
|     if( i>n-1 )
 | |
|     {
 | |
|         goto lbl_60;
 | |
|     }
 | |
|     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|     state->pointindex = i;
 | |
|     state->rstate.stage = 10;
 | |
|     goto lbl_rcomm;
 | |
| lbl_10:
 | |
|     state->tmpf.ptr.p_double[i] = state->f;
 | |
|     j = 0;
 | |
| lbl_61:
 | |
|     if( j>k-1 )
 | |
|     {
 | |
|         goto lbl_63;
 | |
|     }
 | |
|     v = state->c.ptr.p_double[j];
 | |
|     lx = v-state->diffstep*state->s.ptr.p_double[j];
 | |
|     state->c.ptr.p_double[j] = lx;
 | |
|     if( ae_isfinite(state->bndl.ptr.p_double[j], _state) )
 | |
|     {
 | |
|         state->c.ptr.p_double[j] = ae_maxreal(state->c.ptr.p_double[j], state->bndl.ptr.p_double[j], _state);
 | |
|     }
 | |
|     state->rstate.stage = 11;
 | |
|     goto lbl_rcomm;
 | |
| lbl_11:
 | |
|     lf = state->f;
 | |
|     rx = v+state->diffstep*state->s.ptr.p_double[j];
 | |
|     state->c.ptr.p_double[j] = rx;
 | |
|     if( ae_isfinite(state->bndu.ptr.p_double[j], _state) )
 | |
|     {
 | |
|         state->c.ptr.p_double[j] = ae_minreal(state->c.ptr.p_double[j], state->bndu.ptr.p_double[j], _state);
 | |
|     }
 | |
|     state->rstate.stage = 12;
 | |
|     goto lbl_rcomm;
 | |
| lbl_12:
 | |
|     rf = state->f;
 | |
|     state->c.ptr.p_double[j] = v;
 | |
|     if( ae_fp_neq(rx,lx) )
 | |
|     {
 | |
|         state->tmpjac.ptr.pp_double[i][j] = (rf-lf)/(rx-lx);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         state->tmpjac.ptr.pp_double[i][j] = (double)(0);
 | |
|     }
 | |
|     j = j+1;
 | |
|     goto lbl_61;
 | |
| lbl_63:
 | |
|     i = i+1;
 | |
|     goto lbl_58;
 | |
| lbl_60:
 | |
|     state->needf = ae_false;
 | |
|     goto lbl_57;
 | |
| lbl_56:
 | |
|     
 | |
|     /*
 | |
|      * Jacobian is calculated with user-provided analytic gradient
 | |
|      */
 | |
|     lsfit_lsfitclearrequestfields(state, _state);
 | |
|     state->needfg = ae_true;
 | |
|     i = 0;
 | |
| lbl_64:
 | |
|     if( i>n-1 )
 | |
|     {
 | |
|         goto lbl_66;
 | |
|     }
 | |
|     ae_v_move(&state->x.ptr.p_double[0], 1, &state->taskx.ptr.pp_double[i][0], 1, ae_v_len(0,m-1));
 | |
|     state->pointindex = i;
 | |
|     state->rstate.stage = 13;
 | |
|     goto lbl_rcomm;
 | |
| lbl_13:
 | |
|     state->tmpf.ptr.p_double[i] = state->f;
 | |
|     for(j=0; j<=k-1; j++)
 | |
|     {
 | |
|         state->tmpjac.ptr.pp_double[i][j] = state->g.ptr.p_double[j];
 | |
|     }
 | |
|     i = i+1;
 | |
|     goto lbl_64;
 | |
| lbl_66:
 | |
|     state->needfg = ae_false;
 | |
| lbl_57:
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         state->tmp.ptr.p_double[i] = 0.0;
 | |
|     }
 | |
|     lsfit_estimateerrors(&state->tmpjac, &state->tmpf, &state->tasky, &state->wcur, &state->tmp, &state->s, n, k, &state->rep, &state->tmpjacw, 0, _state);
 | |
| lbl_51:
 | |
|     result = ae_false;
 | |
|     return result;
 | |
|     
 | |
|     /*
 | |
|      * Saving state
 | |
|      */
 | |
| lbl_rcomm:
 | |
|     result = ae_true;
 | |
|     state->rstate.ia.ptr.p_int[0] = n;
 | |
|     state->rstate.ia.ptr.p_int[1] = m;
 | |
|     state->rstate.ia.ptr.p_int[2] = k;
 | |
|     state->rstate.ia.ptr.p_int[3] = i;
 | |
|     state->rstate.ia.ptr.p_int[4] = j;
 | |
|     state->rstate.ia.ptr.p_int[5] = j1;
 | |
|     state->rstate.ia.ptr.p_int[6] = info;
 | |
|     state->rstate.ra.ptr.p_double[0] = lx;
 | |
|     state->rstate.ra.ptr.p_double[1] = lf;
 | |
|     state->rstate.ra.ptr.p_double[2] = ld;
 | |
|     state->rstate.ra.ptr.p_double[3] = rx;
 | |
|     state->rstate.ra.ptr.p_double[4] = rf;
 | |
|     state->rstate.ra.ptr.p_double[5] = rd;
 | |
|     state->rstate.ra.ptr.p_double[6] = v;
 | |
|     state->rstate.ra.ptr.p_double[7] = vv;
 | |
|     state->rstate.ra.ptr.p_double[8] = relcnt;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Nonlinear least squares fitting results.
 | |
| 
 | |
| Called after return from LSFitFit().
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   algorithm state
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info    -   completion code:
 | |
|                     * -8    optimizer   detected  NAN/INF  in  the  target
 | |
|                             function and/or gradient
 | |
|                     * -7    gradient verification failed.
 | |
|                             See LSFitSetGradientCheck() for more information.
 | |
|                     * -3    inconsistent constraints
 | |
|                     *  2    relative step is no more than EpsX.
 | |
|                     *  5    MaxIts steps was taken
 | |
|                     *  7    stopping conditions are too stringent,
 | |
|                             further improvement is impossible
 | |
|     C       -   array[0..K-1], solution
 | |
|     Rep     -   optimization report. On success following fields are set:
 | |
|                 * R2                non-adjusted coefficient of determination
 | |
|                                     (non-weighted)
 | |
|                 * RMSError          rms error on the (X,Y).
 | |
|                 * AvgError          average error on the (X,Y).
 | |
|                 * AvgRelError       average relative error on the non-zero Y
 | |
|                 * MaxError          maximum error
 | |
|                                     NON-WEIGHTED ERRORS ARE CALCULATED
 | |
|                 * WRMSError         weighted rms error on the (X,Y).
 | |
|                 
 | |
| ERRORS IN PARAMETERS                
 | |
|                 
 | |
| This  solver  also  calculates different kinds of errors in parameters and
 | |
| fills corresponding fields of report:
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(J*CovPar*J')),
 | |
|                     where J is Jacobian matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| 
 | |
| IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
 | |
|             account boundary/linear constraints! Presence  of  constraints
 | |
|             changes distribution of errors, but there is no  easy  way  to
 | |
|             account for constraints when you calculate covariance matrix.
 | |
|             
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
|             
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
|             
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
|             
 | |
| NOTE:       covariance matrix is estimated using  correction  for  degrees
 | |
|             of freedom (covariances are divided by N-M instead of dividing
 | |
|             by N).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitresults(lsfitstate* state,
 | |
|      ae_int_t* info,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     *info = 0;
 | |
|     ae_vector_clear(c);
 | |
|     _lsfitreport_clear(rep);
 | |
| 
 | |
|     lsfit_clearreport(rep, _state);
 | |
|     *info = state->repterminationtype;
 | |
|     rep->varidx = state->repvaridx;
 | |
|     if( *info>0 )
 | |
|     {
 | |
|         ae_vector_set_length(c, state->k, _state);
 | |
|         ae_v_move(&c->ptr.p_double[0], 1, &state->c1.ptr.p_double[0], 1, ae_v_len(0,state->k-1));
 | |
|         rep->rmserror = state->reprmserror;
 | |
|         rep->wrmserror = state->repwrmserror;
 | |
|         rep->avgerror = state->repavgerror;
 | |
|         rep->avgrelerror = state->repavgrelerror;
 | |
|         rep->maxerror = state->repmaxerror;
 | |
|         rep->iterationscount = state->repiterationscount;
 | |
|         ae_matrix_set_length(&rep->covpar, state->k, state->k, _state);
 | |
|         ae_vector_set_length(&rep->errpar, state->k, _state);
 | |
|         ae_vector_set_length(&rep->errcurve, state->npoints, _state);
 | |
|         ae_vector_set_length(&rep->noise, state->npoints, _state);
 | |
|         rep->r2 = state->rep.r2;
 | |
|         for(i=0; i<=state->k-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=state->k-1; j++)
 | |
|             {
 | |
|                 rep->covpar.ptr.pp_double[i][j] = state->rep.covpar.ptr.pp_double[i][j];
 | |
|             }
 | |
|             rep->errpar.ptr.p_double[i] = state->rep.errpar.ptr.p_double[i];
 | |
|         }
 | |
|         for(i=0; i<=state->npoints-1; i++)
 | |
|         {
 | |
|             rep->errcurve.ptr.p_double[i] = state->rep.errcurve.ptr.p_double[i];
 | |
|             rep->noise.ptr.p_double[i] = state->rep.noise.ptr.p_double[i];
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  subroutine  turns  on  verification  of  the  user-supplied analytic
 | |
| gradient:
 | |
| * user calls this subroutine before fitting begins
 | |
| * LSFitFit() is called
 | |
| * prior to actual fitting, for  each  point  in  data  set  X_i  and  each
 | |
|   component  of  parameters  being  fited C_j algorithm performs following
 | |
|   steps:
 | |
|   * two trial steps are made to C_j-TestStep*S[j] and C_j+TestStep*S[j],
 | |
|     where C_j is j-th parameter and S[j] is a scale of j-th parameter
 | |
|   * if needed, steps are bounded with respect to constraints on C[]
 | |
|   * F(X_i|C) is evaluated at these trial points
 | |
|   * we perform one more evaluation in the middle point of the interval
 | |
|   * we  build  cubic  model using function values and derivatives at trial
 | |
|     points and we compare its prediction with actual value in  the  middle
 | |
|     point
 | |
|   * in case difference between prediction and actual value is higher  than
 | |
|     some predetermined threshold, algorithm stops with completion code -7;
 | |
|     Rep.VarIdx is set to index of the parameter with incorrect derivative.
 | |
| * after verification is over, algorithm proceeds to the actual optimization.
 | |
| 
 | |
| NOTE 1: verification needs N*K (points count * parameters count)  gradient
 | |
|         evaluations. It is very costly and you should use it only for  low
 | |
|         dimensional  problems,  when  you  want  to  be  sure  that you've
 | |
|         correctly calculated analytic derivatives. You should not  use  it
 | |
|         in the production code  (unless  you  want  to  check  derivatives
 | |
|         provided by some third party).
 | |
| 
 | |
| NOTE 2: you  should  carefully  choose  TestStep. Value which is too large
 | |
|         (so large that function behaviour is significantly non-cubic) will
 | |
|         lead to false alarms. You may use  different  step  for  different
 | |
|         parameters by means of setting scale with LSFitSetScale().
 | |
| 
 | |
| NOTE 3: this function may lead to false positives. In case it reports that
 | |
|         I-th  derivative was calculated incorrectly, you may decrease test
 | |
|         step  and  try  one  more  time  - maybe your function changes too
 | |
|         sharply  and  your  step  is  too  large for such rapidly chanding
 | |
|         function.
 | |
| 
 | |
| NOTE 4: this function works only for optimizers created with LSFitCreateWFG()
 | |
|         or LSFitCreateFG() constructors.
 | |
|         
 | |
| INPUT PARAMETERS:
 | |
|     State       -   structure used to store algorithm state
 | |
|     TestStep    -   verification step:
 | |
|                     * TestStep=0 turns verification off
 | |
|                     * TestStep>0 activates verification
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 15.06.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void lsfitsetgradientcheck(lsfitstate* state,
 | |
|      double teststep,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(teststep, _state), "LSFitSetGradientCheck: TestStep contains NaN or Infinite", _state);
 | |
|     ae_assert(ae_fp_greater_eq(teststep,(double)(0)), "LSFitSetGradientCheck: invalid argument TestStep(TestStep<0)", _state);
 | |
|     state->teststep = teststep;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function analyzes section of curve for processing by RDP algorithm:
 | |
| given set of points X,Y with indexes [I0,I1] it returns point with
 | |
| worst deviation from linear model (non-parametric version which sees curve
 | |
| as Y(x)).
 | |
| 
 | |
| Input parameters:
 | |
|     X, Y        -   SORTED arrays.
 | |
|     I0,I1       -   interval (boundaries included) to process
 | |
|     Eps         -   desired precision
 | |
|     
 | |
| OUTPUT PARAMETERS:
 | |
|     WorstIdx    -   index of worst point
 | |
|     WorstError  -   error at worst point
 | |
|     
 | |
| NOTE: this function guarantees that it returns exactly zero for a section
 | |
|       with less than 3 points.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 02.10.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void lsfit_rdpanalyzesection(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t i0,
 | |
|      ae_int_t i1,
 | |
|      ae_int_t* worstidx,
 | |
|      double* worsterror,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     double xleft;
 | |
|     double xright;
 | |
|     double vx;
 | |
|     double ve;
 | |
|     double a;
 | |
|     double b;
 | |
| 
 | |
|     *worstidx = 0;
 | |
|     *worsterror = 0;
 | |
| 
 | |
|     xleft = x->ptr.p_double[i0];
 | |
|     xright = x->ptr.p_double[i1];
 | |
|     if( i1-i0+1<3||ae_fp_eq(xright,xleft) )
 | |
|     {
 | |
|         *worstidx = i0;
 | |
|         *worsterror = 0.0;
 | |
|         return;
 | |
|     }
 | |
|     a = (y->ptr.p_double[i1]-y->ptr.p_double[i0])/(xright-xleft);
 | |
|     b = (y->ptr.p_double[i0]*xright-y->ptr.p_double[i1]*xleft)/(xright-xleft);
 | |
|     *worstidx = -1;
 | |
|     *worsterror = (double)(0);
 | |
|     for(i=i0+1; i<=i1-1; i++)
 | |
|     {
 | |
|         vx = x->ptr.p_double[i];
 | |
|         ve = ae_fabs(a*vx+b-y->ptr.p_double[i], _state);
 | |
|         if( (ae_fp_greater(vx,xleft)&&ae_fp_less(vx,xright))&&ae_fp_greater(ve,*worsterror) )
 | |
|         {
 | |
|             *worsterror = ve;
 | |
|             *worstidx = i;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Recursive splitting of interval [I0,I1] (right boundary included) with RDP
 | |
| algorithm (non-parametric version which sees curve as Y(x)).
 | |
| 
 | |
| Input parameters:
 | |
|     X, Y        -   SORTED arrays.
 | |
|     I0,I1       -   interval (boundaries included) to process
 | |
|     Eps         -   desired precision
 | |
|     XOut,YOut   -   preallocated output arrays large enough to store result;
 | |
|                     XOut[0..1], YOut[0..1] contain first and last points of
 | |
|                     curve
 | |
|     NOut        -   must contain 2 on input
 | |
|     
 | |
| OUTPUT PARAMETERS:
 | |
|     XOut, YOut  -   curve generated by RDP algorithm, UNSORTED
 | |
|     NOut        -   number of points in curve
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 02.10.2014 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void lsfit_rdprecursive(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t i0,
 | |
|      ae_int_t i1,
 | |
|      double eps,
 | |
|      /* Real    */ ae_vector* xout,
 | |
|      /* Real    */ ae_vector* yout,
 | |
|      ae_int_t* nout,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t worstidx;
 | |
|     double worsterror;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_fp_greater(eps,(double)(0)), "RDPRecursive: internal error, Eps<0", _state);
 | |
|     lsfit_rdpanalyzesection(x, y, i0, i1, &worstidx, &worsterror, _state);
 | |
|     if( ae_fp_less_eq(worsterror,eps) )
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
|     xout->ptr.p_double[*nout] = x->ptr.p_double[worstidx];
 | |
|     yout->ptr.p_double[*nout] = y->ptr.p_double[worstidx];
 | |
|     *nout = *nout+1;
 | |
|     if( worstidx-i0<i1-worstidx )
 | |
|     {
 | |
|         lsfit_rdprecursive(x, y, i0, worstidx, eps, xout, yout, nout, _state);
 | |
|         lsfit_rdprecursive(x, y, worstidx, i1, eps, xout, yout, nout, _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         lsfit_rdprecursive(x, y, worstidx, i1, eps, xout, yout, nout, _state);
 | |
|         lsfit_rdprecursive(x, y, i0, worstidx, eps, xout, yout, nout, _state);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal 4PL/5PL fitting function.
 | |
| 
 | |
| Accepts X, Y and already initialized and prepared MinLMState structure.
 | |
| On input P1 contains initial guess, on output it contains solution.  FLast
 | |
| stores function value at P1.
 | |
| *************************************************************************/
 | |
| static void lsfit_logisticfitinternal(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_bool is4pl,
 | |
|      double lambdav,
 | |
|      minlmstate* state,
 | |
|      minlmreport* replm,
 | |
|      /* Real    */ ae_vector* p1,
 | |
|      double* flast,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double ta;
 | |
|     double tb;
 | |
|     double tc;
 | |
|     double td;
 | |
|     double tg;
 | |
|     double vp0;
 | |
|     double vp1;
 | |
| 
 | |
|     *flast = 0;
 | |
| 
 | |
|     minlmrestartfrom(state, p1, _state);
 | |
|     while(minlmiteration(state, _state))
 | |
|     {
 | |
|         ta = state->x.ptr.p_double[0];
 | |
|         tb = state->x.ptr.p_double[1];
 | |
|         tc = state->x.ptr.p_double[2];
 | |
|         td = state->x.ptr.p_double[3];
 | |
|         tg = state->x.ptr.p_double[4];
 | |
|         if( state->xupdated )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Save best function value obtained so far.
 | |
|              */
 | |
|             *flast = state->f;
 | |
|             continue;
 | |
|         }
 | |
|         if( state->needfi||state->needfij )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Function vector and Jacobian
 | |
|              */
 | |
|             for(i=0; i<=n-1; i++)
 | |
|             {
 | |
|                 ae_assert(ae_fp_greater_eq(x->ptr.p_double[i],(double)(0)), "LogisticFitInternal: integrity error", _state);
 | |
|                 
 | |
|                 /*
 | |
|                  * Handle zero X
 | |
|                  */
 | |
|                 if( ae_fp_eq(x->ptr.p_double[i],(double)(0)) )
 | |
|                 {
 | |
|                     if( ae_fp_greater_eq(tb,(double)(0)) )
 | |
|                     {
 | |
|                         
 | |
|                         /*
 | |
|                          * Positive or zero TB, limit X^TB subject to X->+0 is equal to zero.
 | |
|                          */
 | |
|                         state->fi.ptr.p_double[i] = ta-y->ptr.p_double[i];
 | |
|                         if( state->needfij )
 | |
|                         {
 | |
|                             state->j.ptr.pp_double[i][0] = (double)(1);
 | |
|                             state->j.ptr.pp_double[i][1] = (double)(0);
 | |
|                             state->j.ptr.pp_double[i][2] = (double)(0);
 | |
|                             state->j.ptr.pp_double[i][3] = (double)(0);
 | |
|                             state->j.ptr.pp_double[i][4] = (double)(0);
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         
 | |
|                         /*
 | |
|                          * Negative TB, limit X^TB subject to X->+0 is equal to +INF.
 | |
|                          */
 | |
|                         state->fi.ptr.p_double[i] = td-y->ptr.p_double[i];
 | |
|                         if( state->needfij )
 | |
|                         {
 | |
|                             state->j.ptr.pp_double[i][0] = (double)(0);
 | |
|                             state->j.ptr.pp_double[i][1] = (double)(0);
 | |
|                             state->j.ptr.pp_double[i][2] = (double)(0);
 | |
|                             state->j.ptr.pp_double[i][3] = (double)(1);
 | |
|                             state->j.ptr.pp_double[i][4] = (double)(0);
 | |
|                         }
 | |
|                     }
 | |
|                     continue;
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * Positive X.
 | |
|                  * Prepare VP0/VP1, it may become infinite or nearly overflow in some rare cases,
 | |
|                  * handle these cases
 | |
|                  */
 | |
|                 vp0 = ae_pow(x->ptr.p_double[i]/tc, tb, _state);
 | |
|                 if( is4pl )
 | |
|                 {
 | |
|                     vp1 = 1+vp0;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     vp1 = ae_pow(1+vp0, tg, _state);
 | |
|                 }
 | |
|                 if( (!ae_isfinite(vp1, _state)||ae_fp_greater(vp0,1.0E50))||ae_fp_greater(vp1,1.0E50) )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      * VP0/VP1 are not finite, assume that it is +INF or -INF
 | |
|                      */
 | |
|                     state->fi.ptr.p_double[i] = td-y->ptr.p_double[i];
 | |
|                     if( state->needfij )
 | |
|                     {
 | |
|                         state->j.ptr.pp_double[i][0] = (double)(0);
 | |
|                         state->j.ptr.pp_double[i][1] = (double)(0);
 | |
|                         state->j.ptr.pp_double[i][2] = (double)(0);
 | |
|                         state->j.ptr.pp_double[i][3] = (double)(1);
 | |
|                         state->j.ptr.pp_double[i][4] = (double)(0);
 | |
|                     }
 | |
|                     continue;
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * VP0/VP1 are finite, normal processing
 | |
|                  */
 | |
|                 if( is4pl )
 | |
|                 {
 | |
|                     state->fi.ptr.p_double[i] = td+(ta-td)/vp1-y->ptr.p_double[i];
 | |
|                     if( state->needfij )
 | |
|                     {
 | |
|                         state->j.ptr.pp_double[i][0] = 1/vp1;
 | |
|                         state->j.ptr.pp_double[i][1] = -(ta-td)*vp0*ae_log(x->ptr.p_double[i]/tc, _state)/ae_sqr(vp1, _state);
 | |
|                         state->j.ptr.pp_double[i][2] = (ta-td)*(tb/tc)*vp0/ae_sqr(vp1, _state);
 | |
|                         state->j.ptr.pp_double[i][3] = 1-1/vp1;
 | |
|                         state->j.ptr.pp_double[i][4] = (double)(0);
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     state->fi.ptr.p_double[i] = td+(ta-td)/vp1-y->ptr.p_double[i];
 | |
|                     if( state->needfij )
 | |
|                     {
 | |
|                         state->j.ptr.pp_double[i][0] = 1/vp1;
 | |
|                         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);
 | |
|                         state->j.ptr.pp_double[i][2] = (ta-td)*(-tg)*ae_pow(1+vp0, -tg-1, _state)*vp0*(-tb/tc);
 | |
|                         state->j.ptr.pp_double[i][3] = 1-1/vp1;
 | |
|                         state->j.ptr.pp_double[i][4] = -(ta-td)/vp1*ae_log(1+vp0, _state);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Add regularizer
 | |
|              */
 | |
|             for(i=0; i<=4; i++)
 | |
|             {
 | |
|                 state->fi.ptr.p_double[n+i] = lambdav*state->x.ptr.p_double[i];
 | |
|                 if( state->needfij )
 | |
|                 {
 | |
|                     for(j=0; j<=4; j++)
 | |
|                     {
 | |
|                         state->j.ptr.pp_double[n+i][j] = 0.0;
 | |
|                     }
 | |
|                     state->j.ptr.pp_double[n+i][i] = lambdav;
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Done
 | |
|              */
 | |
|             continue;
 | |
|         }
 | |
|         ae_assert(ae_false, "LogisticFitX: internal error", _state);
 | |
|     }
 | |
|     minlmresultsbuf(state, p1, replm, _state);
 | |
|     ae_assert(replm->terminationtype>0, "LogisticFitX: internal error", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Calculate errors for 4PL/5PL fit.
 | |
| Leaves other fields of Rep unchanged, so caller should properly initialize
 | |
| it with ClearRep() call.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 28.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void lsfit_logisticfit45errors(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      double a,
 | |
|      double b,
 | |
|      double c,
 | |
|      double d,
 | |
|      double g,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t k;
 | |
|     double v;
 | |
|     double rss;
 | |
|     double tss;
 | |
|     double meany;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Calculate errors
 | |
|      */
 | |
|     rep->rmserror = (double)(0);
 | |
|     rep->avgerror = (double)(0);
 | |
|     rep->avgrelerror = (double)(0);
 | |
|     rep->maxerror = (double)(0);
 | |
|     k = 0;
 | |
|     rss = 0.0;
 | |
|     tss = 0.0;
 | |
|     meany = 0.0;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         meany = meany+y->ptr.p_double[i];
 | |
|     }
 | |
|     meany = meany/n;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Calculate residual from regression
 | |
|          */
 | |
|         if( ae_fp_greater(x->ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             v = d+(a-d)/ae_pow(1.0+ae_pow(x->ptr.p_double[i]/c, b, _state), g, _state)-y->ptr.p_double[i];
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if( ae_fp_greater_eq(b,(double)(0)) )
 | |
|             {
 | |
|                 v = a-y->ptr.p_double[i];
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 v = d-y->ptr.p_double[i];
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Update RSS (residual sum of squares) and TSS (total sum of squares)
 | |
|          * which are used to calculate coefficient of determination.
 | |
|          *
 | |
|          * NOTE: we use formula R2 = 1-RSS/TSS because it has nice property of
 | |
|          *       being equal to 0.0 if and only if model perfectly fits data.
 | |
|          *
 | |
|          *       When we fit nonlinear models, there are exist multiple ways of
 | |
|          *       determining R2, each of them giving different results. Formula
 | |
|          *       above is the most intuitive one.
 | |
|          */
 | |
|         rss = rss+v*v;
 | |
|         tss = tss+ae_sqr(y->ptr.p_double[i]-meany, _state);
 | |
|         
 | |
|         /*
 | |
|          * Update errors
 | |
|          */
 | |
|         rep->rmserror = rep->rmserror+ae_sqr(v, _state);
 | |
|         rep->avgerror = rep->avgerror+ae_fabs(v, _state);
 | |
|         if( ae_fp_neq(y->ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             rep->avgrelerror = rep->avgrelerror+ae_fabs(v/y->ptr.p_double[i], _state);
 | |
|             k = k+1;
 | |
|         }
 | |
|         rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
 | |
|     }
 | |
|     rep->rmserror = ae_sqrt(rep->rmserror/n, _state);
 | |
|     rep->avgerror = rep->avgerror/n;
 | |
|     if( k>0 )
 | |
|     {
 | |
|         rep->avgrelerror = rep->avgrelerror/k;
 | |
|     }
 | |
|     rep->r2 = 1.0-rss/tss;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal spline fitting subroutine
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 08.09.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void lsfit_spline1dfitinternal(ae_int_t st,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      spline1dinterpolant* s,
 | |
|      spline1dfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector _w;
 | |
|     ae_vector _xc;
 | |
|     ae_vector _yc;
 | |
|     ae_matrix fmatrix;
 | |
|     ae_matrix cmatrix;
 | |
|     ae_vector y2;
 | |
|     ae_vector w2;
 | |
|     ae_vector sx;
 | |
|     ae_vector sy;
 | |
|     ae_vector sd;
 | |
|     ae_vector tmp;
 | |
|     ae_vector xoriginal;
 | |
|     ae_vector yoriginal;
 | |
|     lsfitreport lrep;
 | |
|     double v0;
 | |
|     double v1;
 | |
|     double v2;
 | |
|     double mx;
 | |
|     spline1dinterpolant s2;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t relcnt;
 | |
|     double xa;
 | |
|     double xb;
 | |
|     double sa;
 | |
|     double sb;
 | |
|     double bl;
 | |
|     double br;
 | |
|     double decay;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&_w, 0, sizeof(_w));
 | |
|     memset(&_xc, 0, sizeof(_xc));
 | |
|     memset(&_yc, 0, sizeof(_yc));
 | |
|     memset(&fmatrix, 0, sizeof(fmatrix));
 | |
|     memset(&cmatrix, 0, sizeof(cmatrix));
 | |
|     memset(&y2, 0, sizeof(y2));
 | |
|     memset(&w2, 0, sizeof(w2));
 | |
|     memset(&sx, 0, sizeof(sx));
 | |
|     memset(&sy, 0, sizeof(sy));
 | |
|     memset(&sd, 0, sizeof(sd));
 | |
|     memset(&tmp, 0, sizeof(tmp));
 | |
|     memset(&xoriginal, 0, sizeof(xoriginal));
 | |
|     memset(&yoriginal, 0, sizeof(yoriginal));
 | |
|     memset(&lrep, 0, sizeof(lrep));
 | |
|     memset(&s2, 0, sizeof(s2));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_init_copy(&_w, w, _state, ae_true);
 | |
|     w = &_w;
 | |
|     ae_vector_init_copy(&_xc, xc, _state, ae_true);
 | |
|     xc = &_xc;
 | |
|     ae_vector_init_copy(&_yc, yc, _state, ae_true);
 | |
|     yc = &_yc;
 | |
|     *info = 0;
 | |
|     _spline1dinterpolant_clear(s);
 | |
|     _spline1dfitreport_clear(rep);
 | |
|     ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&y2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&w2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sy, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sd, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true);
 | |
|     _lsfitreport_init(&lrep, _state, ae_true);
 | |
|     _spline1dinterpolant_init(&s2, _state, ae_true);
 | |
| 
 | |
|     ae_assert(st==0||st==1, "Spline1DFit: internal error!", _state);
 | |
|     if( st==0&&m<4 )
 | |
|     {
 | |
|         *info = -1;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     if( st==1&&m<4 )
 | |
|     {
 | |
|         *info = -1;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     if( (n<1||k<0)||k>=m )
 | |
|     {
 | |
|         *info = -1;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         *info = 0;
 | |
|         if( dc->ptr.p_int[i]<0 )
 | |
|         {
 | |
|             *info = -1;
 | |
|         }
 | |
|         if( dc->ptr.p_int[i]>1 )
 | |
|         {
 | |
|             *info = -1;
 | |
|         }
 | |
|         if( *info<0 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     if( st==1&&m%2!=0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Hermite fitter must have even number of basis functions
 | |
|          */
 | |
|         *info = -2;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * weight decay for correct handling of task which becomes
 | |
|      * degenerate after constraints are applied
 | |
|      */
 | |
|     decay = 10000*ae_machineepsilon;
 | |
|     
 | |
|     /*
 | |
|      * Scale X, Y, XC, YC
 | |
|      */
 | |
|     lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state);
 | |
|     
 | |
|     /*
 | |
|      * allocate space, initialize:
 | |
|      * * SX     -   grid for basis functions
 | |
|      * * SY     -   values of basis functions at grid points
 | |
|      * * FMatrix-   values of basis functions at X[]
 | |
|      * * CMatrix-   values (derivatives) of basis functions at XC[]
 | |
|      */
 | |
|     ae_vector_set_length(&y2, n+m, _state);
 | |
|     ae_vector_set_length(&w2, n+m, _state);
 | |
|     ae_matrix_set_length(&fmatrix, n+m, m, _state);
 | |
|     if( k>0 )
 | |
|     {
 | |
|         ae_matrix_set_length(&cmatrix, k, m+1, _state);
 | |
|     }
 | |
|     if( st==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * allocate space for cubic spline
 | |
|          */
 | |
|         ae_vector_set_length(&sx, m-2, _state);
 | |
|         ae_vector_set_length(&sy, m-2, _state);
 | |
|         for(j=0; j<=m-2-1; j++)
 | |
|         {
 | |
|             sx.ptr.p_double[j] = (double)(2*j)/(double)(m-2-1)-1;
 | |
|         }
 | |
|     }
 | |
|     if( st==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * allocate space for Hermite spline
 | |
|          */
 | |
|         ae_vector_set_length(&sx, m/2, _state);
 | |
|         ae_vector_set_length(&sy, m/2, _state);
 | |
|         ae_vector_set_length(&sd, m/2, _state);
 | |
|         for(j=0; j<=m/2-1; j++)
 | |
|         {
 | |
|             sx.ptr.p_double[j] = (double)(2*j)/(double)(m/2-1)-1;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare design and constraints matrices:
 | |
|      * * fill constraints matrix
 | |
|      * * fill first N rows of design matrix with values
 | |
|      * * fill next M rows of design matrix with regularizing term
 | |
|      * * append M zeros to Y
 | |
|      * * append M elements, mean(abs(W)) each, to W
 | |
|      */
 | |
|     for(j=0; j<=m-1; j++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * prepare Jth basis function
 | |
|          */
 | |
|         if( st==0 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * cubic spline basis
 | |
|              */
 | |
|             for(i=0; i<=m-2-1; i++)
 | |
|             {
 | |
|                 sy.ptr.p_double[i] = (double)(0);
 | |
|             }
 | |
|             bl = (double)(0);
 | |
|             br = (double)(0);
 | |
|             if( j<m-2 )
 | |
|             {
 | |
|                 sy.ptr.p_double[j] = (double)(1);
 | |
|             }
 | |
|             if( j==m-2 )
 | |
|             {
 | |
|                 bl = (double)(1);
 | |
|             }
 | |
|             if( j==m-1 )
 | |
|             {
 | |
|                 br = (double)(1);
 | |
|             }
 | |
|             spline1dbuildcubic(&sx, &sy, m-2, 1, bl, 1, br, &s2, _state);
 | |
|         }
 | |
|         if( st==1 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Hermite basis
 | |
|              */
 | |
|             for(i=0; i<=m/2-1; i++)
 | |
|             {
 | |
|                 sy.ptr.p_double[i] = (double)(0);
 | |
|                 sd.ptr.p_double[i] = (double)(0);
 | |
|             }
 | |
|             if( j%2==0 )
 | |
|             {
 | |
|                 sy.ptr.p_double[j/2] = (double)(1);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 sd.ptr.p_double[j/2] = (double)(1);
 | |
|             }
 | |
|             spline1dbuildhermite(&sx, &sy, &sd, m/2, &s2, _state);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * values at X[], XC[]
 | |
|          */
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             fmatrix.ptr.pp_double[i][j] = spline1dcalc(&s2, x->ptr.p_double[i], _state);
 | |
|         }
 | |
|         for(i=0; i<=k-1; i++)
 | |
|         {
 | |
|             ae_assert(dc->ptr.p_int[i]>=0&&dc->ptr.p_int[i]<=2, "Spline1DFit: internal error!", _state);
 | |
|             spline1ddiff(&s2, xc->ptr.p_double[i], &v0, &v1, &v2, _state);
 | |
|             if( dc->ptr.p_int[i]==0 )
 | |
|             {
 | |
|                 cmatrix.ptr.pp_double[i][j] = v0;
 | |
|             }
 | |
|             if( dc->ptr.p_int[i]==1 )
 | |
|             {
 | |
|                 cmatrix.ptr.pp_double[i][j] = v1;
 | |
|             }
 | |
|             if( dc->ptr.p_int[i]==2 )
 | |
|             {
 | |
|                 cmatrix.ptr.pp_double[i][j] = v2;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=m-1; j++)
 | |
|         {
 | |
|             if( i==j )
 | |
|             {
 | |
|                 fmatrix.ptr.pp_double[n+i][j] = decay;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 fmatrix.ptr.pp_double[n+i][j] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     ae_vector_set_length(&y2, n+m, _state);
 | |
|     ae_vector_set_length(&w2, n+m, _state);
 | |
|     ae_v_move(&y2.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     ae_v_move(&w2.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     mx = (double)(0);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         mx = mx+ae_fabs(w->ptr.p_double[i], _state);
 | |
|     }
 | |
|     mx = mx/n;
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         y2.ptr.p_double[n+i] = (double)(0);
 | |
|         w2.ptr.p_double[n+i] = mx;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Solve constrained task
 | |
|      */
 | |
|     if( k>0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * solve using regularization
 | |
|          */
 | |
|         lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, &tmp, &lrep, _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * no constraints, no regularization needed
 | |
|          */
 | |
|         lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, k, info, &tmp, &lrep, _state);
 | |
|     }
 | |
|     if( *info<0 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Generate spline and scale it
 | |
|      */
 | |
|     if( st==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * cubic spline basis
 | |
|          */
 | |
|         ae_v_move(&sy.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-2-1));
 | |
|         spline1dbuildcubic(&sx, &sy, m-2, 1, tmp.ptr.p_double[m-2], 1, tmp.ptr.p_double[m-1], s, _state);
 | |
|     }
 | |
|     if( st==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Hermite basis
 | |
|          */
 | |
|         for(i=0; i<=m/2-1; i++)
 | |
|         {
 | |
|             sy.ptr.p_double[i] = tmp.ptr.p_double[2*i];
 | |
|             sd.ptr.p_double[i] = tmp.ptr.p_double[2*i+1];
 | |
|         }
 | |
|         spline1dbuildhermite(&sx, &sy, &sd, m/2, s, _state);
 | |
|     }
 | |
|     spline1dlintransx(s, 2/(xb-xa), -(xa+xb)/(xb-xa), _state);
 | |
|     spline1dlintransy(s, sb-sa, sa, _state);
 | |
|     
 | |
|     /*
 | |
|      * Scale absolute errors obtained from LSFitLinearW.
 | |
|      * Relative error should be calculated separately
 | |
|      * (because of shifting/scaling of the task)
 | |
|      */
 | |
|     rep->taskrcond = lrep.taskrcond;
 | |
|     rep->rmserror = lrep.rmserror*(sb-sa);
 | |
|     rep->avgerror = lrep.avgerror*(sb-sa);
 | |
|     rep->maxerror = lrep.maxerror*(sb-sa);
 | |
|     rep->avgrelerror = (double)(0);
 | |
|     relcnt = 0;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             rep->avgrelerror = rep->avgrelerror+ae_fabs(spline1dcalc(s, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state);
 | |
|             relcnt = relcnt+1;
 | |
|         }
 | |
|     }
 | |
|     if( relcnt!=0 )
 | |
|     {
 | |
|         rep->avgrelerror = rep->avgrelerror/relcnt;
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal fitting subroutine
 | |
| *************************************************************************/
 | |
| static void lsfit_lsfitlinearinternal(/* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      /* Real    */ ae_matrix* fmatrix,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     double threshold;
 | |
|     ae_matrix ft;
 | |
|     ae_matrix q;
 | |
|     ae_matrix l;
 | |
|     ae_matrix r;
 | |
|     ae_vector b;
 | |
|     ae_vector wmod;
 | |
|     ae_vector tau;
 | |
|     ae_vector nzeros;
 | |
|     ae_vector s;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double v;
 | |
|     ae_vector sv;
 | |
|     ae_matrix u;
 | |
|     ae_matrix vt;
 | |
|     ae_vector tmp;
 | |
|     ae_vector utb;
 | |
|     ae_vector sutb;
 | |
|     ae_int_t relcnt;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&ft, 0, sizeof(ft));
 | |
|     memset(&q, 0, sizeof(q));
 | |
|     memset(&l, 0, sizeof(l));
 | |
|     memset(&r, 0, sizeof(r));
 | |
|     memset(&b, 0, sizeof(b));
 | |
|     memset(&wmod, 0, sizeof(wmod));
 | |
|     memset(&tau, 0, sizeof(tau));
 | |
|     memset(&nzeros, 0, sizeof(nzeros));
 | |
|     memset(&s, 0, sizeof(s));
 | |
|     memset(&sv, 0, sizeof(sv));
 | |
|     memset(&u, 0, sizeof(u));
 | |
|     memset(&vt, 0, sizeof(vt));
 | |
|     memset(&tmp, 0, sizeof(tmp));
 | |
|     memset(&utb, 0, sizeof(utb));
 | |
|     memset(&sutb, 0, sizeof(sutb));
 | |
|     *info = 0;
 | |
|     ae_vector_clear(c);
 | |
|     _lsfitreport_clear(rep);
 | |
|     ae_matrix_init(&ft, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&q, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&l, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&r, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&wmod, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tau, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&nzeros, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&s, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sv, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&u, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&vt, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&utb, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sutb, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     lsfit_clearreport(rep, _state);
 | |
|     if( n<1||m<1 )
 | |
|     {
 | |
|         *info = -1;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     *info = 1;
 | |
|     threshold = ae_sqrt(ae_machineepsilon, _state);
 | |
|     
 | |
|     /*
 | |
|      * Degenerate case, needs special handling
 | |
|      */
 | |
|     if( n<m )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Create design matrix.
 | |
|          */
 | |
|         ae_matrix_set_length(&ft, n, m, _state);
 | |
|         ae_vector_set_length(&b, n, _state);
 | |
|         ae_vector_set_length(&wmod, n, _state);
 | |
|         for(j=0; j<=n-1; j++)
 | |
|         {
 | |
|             v = w->ptr.p_double[j];
 | |
|             ae_v_moved(&ft.ptr.pp_double[j][0], 1, &fmatrix->ptr.pp_double[j][0], 1, ae_v_len(0,m-1), v);
 | |
|             b.ptr.p_double[j] = w->ptr.p_double[j]*y->ptr.p_double[j];
 | |
|             wmod.ptr.p_double[j] = (double)(1);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * LQ decomposition and reduction to M=N
 | |
|          */
 | |
|         ae_vector_set_length(c, m, _state);
 | |
|         for(i=0; i<=m-1; i++)
 | |
|         {
 | |
|             c->ptr.p_double[i] = (double)(0);
 | |
|         }
 | |
|         rep->taskrcond = (double)(0);
 | |
|         rmatrixlq(&ft, n, m, &tau, _state);
 | |
|         rmatrixlqunpackq(&ft, n, m, &tau, n, &q, _state);
 | |
|         rmatrixlqunpackl(&ft, n, m, &l, _state);
 | |
|         lsfit_lsfitlinearinternal(&b, &wmod, &l, n, n, info, &tmp, rep, _state);
 | |
|         if( *info<=0 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             v = tmp.ptr.p_double[i];
 | |
|             ae_v_addd(&c->ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * N>=M. Generate design matrix and reduce to N=M using
 | |
|      * QR decomposition.
 | |
|      */
 | |
|     ae_matrix_set_length(&ft, n, m, _state);
 | |
|     ae_vector_set_length(&b, n, _state);
 | |
|     for(j=0; j<=n-1; j++)
 | |
|     {
 | |
|         v = w->ptr.p_double[j];
 | |
|         ae_v_moved(&ft.ptr.pp_double[j][0], 1, &fmatrix->ptr.pp_double[j][0], 1, ae_v_len(0,m-1), v);
 | |
|         b.ptr.p_double[j] = w->ptr.p_double[j]*y->ptr.p_double[j];
 | |
|     }
 | |
|     rmatrixqr(&ft, n, m, &tau, _state);
 | |
|     rmatrixqrunpackq(&ft, n, m, &tau, m, &q, _state);
 | |
|     rmatrixqrunpackr(&ft, n, m, &r, _state);
 | |
|     ae_vector_set_length(&tmp, m, _state);
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         tmp.ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         v = b.ptr.p_double[i];
 | |
|         ae_v_addd(&tmp.ptr.p_double[0], 1, &q.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
 | |
|     }
 | |
|     ae_vector_set_length(&b, m, _state);
 | |
|     ae_v_move(&b.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1));
 | |
|     
 | |
|     /*
 | |
|      * R contains reduced MxM design upper triangular matrix,
 | |
|      * B contains reduced Mx1 right part.
 | |
|      *
 | |
|      * Determine system condition number and decide
 | |
|      * should we use triangular solver (faster) or
 | |
|      * SVD-based solver (more stable).
 | |
|      *
 | |
|      * We can use LU-based RCond estimator for this task.
 | |
|      */
 | |
|     rep->taskrcond = rmatrixlurcondinf(&r, m, _state);
 | |
|     if( ae_fp_greater(rep->taskrcond,threshold) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * use QR-based solver
 | |
|          */
 | |
|         ae_vector_set_length(c, m, _state);
 | |
|         c->ptr.p_double[m-1] = b.ptr.p_double[m-1]/r.ptr.pp_double[m-1][m-1];
 | |
|         for(i=m-2; i>=0; i--)
 | |
|         {
 | |
|             v = ae_v_dotproduct(&r.ptr.pp_double[i][i+1], 1, &c->ptr.p_double[i+1], 1, ae_v_len(i+1,m-1));
 | |
|             c->ptr.p_double[i] = (b.ptr.p_double[i]-v)/r.ptr.pp_double[i][i];
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * use SVD-based solver
 | |
|          */
 | |
|         if( !rmatrixsvd(&r, m, m, 1, 1, 2, &sv, &u, &vt, _state) )
 | |
|         {
 | |
|             *info = -4;
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         ae_vector_set_length(&utb, m, _state);
 | |
|         ae_vector_set_length(&sutb, m, _state);
 | |
|         for(i=0; i<=m-1; i++)
 | |
|         {
 | |
|             utb.ptr.p_double[i] = (double)(0);
 | |
|         }
 | |
|         for(i=0; i<=m-1; i++)
 | |
|         {
 | |
|             v = b.ptr.p_double[i];
 | |
|             ae_v_addd(&utb.ptr.p_double[0], 1, &u.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
 | |
|         }
 | |
|         if( ae_fp_greater(sv.ptr.p_double[0],(double)(0)) )
 | |
|         {
 | |
|             rep->taskrcond = sv.ptr.p_double[m-1]/sv.ptr.p_double[0];
 | |
|             for(i=0; i<=m-1; i++)
 | |
|             {
 | |
|                 if( ae_fp_greater(sv.ptr.p_double[i],threshold*sv.ptr.p_double[0]) )
 | |
|                 {
 | |
|                     sutb.ptr.p_double[i] = utb.ptr.p_double[i]/sv.ptr.p_double[i];
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     sutb.ptr.p_double[i] = (double)(0);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             rep->taskrcond = (double)(0);
 | |
|             for(i=0; i<=m-1; i++)
 | |
|             {
 | |
|                 sutb.ptr.p_double[i] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|         ae_vector_set_length(c, m, _state);
 | |
|         for(i=0; i<=m-1; i++)
 | |
|         {
 | |
|             c->ptr.p_double[i] = (double)(0);
 | |
|         }
 | |
|         for(i=0; i<=m-1; i++)
 | |
|         {
 | |
|             v = sutb.ptr.p_double[i];
 | |
|             ae_v_addd(&c->ptr.p_double[0], 1, &vt.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * calculate errors
 | |
|      */
 | |
|     rep->rmserror = (double)(0);
 | |
|     rep->avgerror = (double)(0);
 | |
|     rep->avgrelerror = (double)(0);
 | |
|     rep->maxerror = (double)(0);
 | |
|     relcnt = 0;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         v = ae_v_dotproduct(&fmatrix->ptr.pp_double[i][0], 1, &c->ptr.p_double[0], 1, ae_v_len(0,m-1));
 | |
|         rep->rmserror = rep->rmserror+ae_sqr(v-y->ptr.p_double[i], _state);
 | |
|         rep->avgerror = rep->avgerror+ae_fabs(v-y->ptr.p_double[i], _state);
 | |
|         if( ae_fp_neq(y->ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             rep->avgrelerror = rep->avgrelerror+ae_fabs(v-y->ptr.p_double[i], _state)/ae_fabs(y->ptr.p_double[i], _state);
 | |
|             relcnt = relcnt+1;
 | |
|         }
 | |
|         rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-y->ptr.p_double[i], _state), _state);
 | |
|     }
 | |
|     rep->rmserror = ae_sqrt(rep->rmserror/n, _state);
 | |
|     rep->avgerror = rep->avgerror/n;
 | |
|     if( relcnt!=0 )
 | |
|     {
 | |
|         rep->avgrelerror = rep->avgrelerror/relcnt;
 | |
|     }
 | |
|     ae_vector_set_length(&nzeros, n, _state);
 | |
|     ae_vector_set_length(&s, m, _state);
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         s.ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=m-1; j++)
 | |
|         {
 | |
|             s.ptr.p_double[j] = s.ptr.p_double[j]+ae_sqr(fmatrix->ptr.pp_double[i][j], _state);
 | |
|         }
 | |
|         nzeros.ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         if( ae_fp_neq(s.ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             s.ptr.p_double[i] = ae_sqrt(1/s.ptr.p_double[i], _state);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             s.ptr.p_double[i] = (double)(1);
 | |
|         }
 | |
|     }
 | |
|     lsfit_estimateerrors(fmatrix, &nzeros, y, w, c, &s, n, m, rep, &r, 1, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal subroutine
 | |
| *************************************************************************/
 | |
| static void lsfit_lsfitclearrequestfields(lsfitstate* state,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     state->needf = ae_false;
 | |
|     state->needfg = ae_false;
 | |
|     state->needfgh = ae_false;
 | |
|     state->xupdated = ae_false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal subroutine, calculates barycentric basis functions.
 | |
| Used for efficient simultaneous calculation of N basis functions.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void lsfit_barycentriccalcbasis(barycentricinterpolant* b,
 | |
|      double t,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double s2;
 | |
|     double s;
 | |
|     double v;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * special case: N=1
 | |
|      */
 | |
|     if( b->n==1 )
 | |
|     {
 | |
|         y->ptr.p_double[0] = (double)(1);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Here we assume that task is normalized, i.e.:
 | |
|      * 1. abs(Y[i])<=1
 | |
|      * 2. abs(W[i])<=1
 | |
|      * 3. X[] is ordered
 | |
|      *
 | |
|      * First, we decide: should we use "safe" formula (guarded
 | |
|      * against overflow) or fast one?
 | |
|      */
 | |
|     s = ae_fabs(t-b->x.ptr.p_double[0], _state);
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         v = b->x.ptr.p_double[i];
 | |
|         if( ae_fp_eq(v,t) )
 | |
|         {
 | |
|             for(j=0; j<=b->n-1; j++)
 | |
|             {
 | |
|                 y->ptr.p_double[j] = (double)(0);
 | |
|             }
 | |
|             y->ptr.p_double[i] = (double)(1);
 | |
|             return;
 | |
|         }
 | |
|         v = ae_fabs(t-v, _state);
 | |
|         if( ae_fp_less(v,s) )
 | |
|         {
 | |
|             s = v;
 | |
|         }
 | |
|     }
 | |
|     s2 = (double)(0);
 | |
|     for(i=0; i<=b->n-1; i++)
 | |
|     {
 | |
|         v = s/(t-b->x.ptr.p_double[i]);
 | |
|         v = v*b->w.ptr.p_double[i];
 | |
|         y->ptr.p_double[i] = v;
 | |
|         s2 = s2+v;
 | |
|     }
 | |
|     v = 1/s2;
 | |
|     ae_v_muld(&y->ptr.p_double[0], 1, ae_v_len(0,b->n-1), v);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This is internal function for Chebyshev fitting.
 | |
| 
 | |
| It assumes that input data are normalized:
 | |
| * X/XC belong to [-1,+1],
 | |
| * mean(Y)=0, stddev(Y)=1.
 | |
| 
 | |
| It does not checks inputs for errors.
 | |
| 
 | |
| This function is used to fit general (shifted) Chebyshev models, power
 | |
| basis models or barycentric models.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X   -   points, array[0..N-1].
 | |
|     Y   -   function values, array[0..N-1].
 | |
|     W   -   weights, array[0..N-1]
 | |
|     N   -   number of points, N>0.
 | |
|     XC  -   points where polynomial values/derivatives are constrained,
 | |
|             array[0..K-1].
 | |
|     YC  -   values of constraints, array[0..K-1]
 | |
|     DC  -   array[0..K-1], types of constraints:
 | |
|             * DC[i]=0   means that P(XC[i])=YC[i]
 | |
|             * DC[i]=1   means that P'(XC[i])=YC[i]
 | |
|     K   -   number of constraints, 0<=K<M.
 | |
|             K=0 means no constraints (XC/YC/DC are not used in such cases)
 | |
|     M   -   number of basis functions (= polynomial_degree + 1), M>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Info-   same format as in LSFitLinearW() subroutine:
 | |
|             * Info>0    task is solved
 | |
|             * Info<=0   an error occured:
 | |
|                         -4 means inconvergence of internal SVD
 | |
|                         -3 means inconsistent constraints
 | |
|     C   -   interpolant in Chebyshev form; [-1,+1] is used as base interval
 | |
|     Rep -   report, same format as in LSFitLinearW() subroutine.
 | |
|             Following fields are set:
 | |
|             * RMSError      rms error on the (X,Y).
 | |
|             * AvgError      average error on the (X,Y).
 | |
|             * AvgRelError   average relative error on the non-zero Y
 | |
|             * MaxError      maximum error
 | |
|                             NON-WEIGHTED ERRORS ARE CALCULATED
 | |
| 
 | |
| IMPORTANT:
 | |
|     this subroitine doesn't calculate task's condition number for K<>0.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 10.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void lsfit_internalchebyshevfit(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      ae_int_t m,
 | |
|      ae_int_t* info,
 | |
|      /* Real    */ ae_vector* c,
 | |
|      lsfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _xc;
 | |
|     ae_vector _yc;
 | |
|     ae_vector y2;
 | |
|     ae_vector w2;
 | |
|     ae_vector tmp;
 | |
|     ae_vector tmp2;
 | |
|     ae_vector tmpdiff;
 | |
|     ae_vector bx;
 | |
|     ae_vector by;
 | |
|     ae_vector bw;
 | |
|     ae_matrix fmatrix;
 | |
|     ae_matrix cmatrix;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double mx;
 | |
|     double decay;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_xc, 0, sizeof(_xc));
 | |
|     memset(&_yc, 0, sizeof(_yc));
 | |
|     memset(&y2, 0, sizeof(y2));
 | |
|     memset(&w2, 0, sizeof(w2));
 | |
|     memset(&tmp, 0, sizeof(tmp));
 | |
|     memset(&tmp2, 0, sizeof(tmp2));
 | |
|     memset(&tmpdiff, 0, sizeof(tmpdiff));
 | |
|     memset(&bx, 0, sizeof(bx));
 | |
|     memset(&by, 0, sizeof(by));
 | |
|     memset(&bw, 0, sizeof(bw));
 | |
|     memset(&fmatrix, 0, sizeof(fmatrix));
 | |
|     memset(&cmatrix, 0, sizeof(cmatrix));
 | |
|     ae_vector_init_copy(&_xc, xc, _state, ae_true);
 | |
|     xc = &_xc;
 | |
|     ae_vector_init_copy(&_yc, yc, _state, ae_true);
 | |
|     yc = &_yc;
 | |
|     *info = 0;
 | |
|     ae_vector_clear(c);
 | |
|     _lsfitreport_clear(rep);
 | |
|     ae_vector_init(&y2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&w2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpdiff, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&by, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bw, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     lsfit_clearreport(rep, _state);
 | |
|     
 | |
|     /*
 | |
|      * weight decay for correct handling of task which becomes
 | |
|      * degenerate after constraints are applied
 | |
|      */
 | |
|     decay = 10000*ae_machineepsilon;
 | |
|     
 | |
|     /*
 | |
|      * allocate space, initialize/fill:
 | |
|      * * FMatrix-   values of basis functions at X[]
 | |
|      * * CMatrix-   values (derivatives) of basis functions at XC[]
 | |
|      * * fill constraints matrix
 | |
|      * * fill first N rows of design matrix with values
 | |
|      * * fill next M rows of design matrix with regularizing term
 | |
|      * * append M zeros to Y
 | |
|      * * append M elements, mean(abs(W)) each, to W
 | |
|      */
 | |
|     ae_vector_set_length(&y2, n+m, _state);
 | |
|     ae_vector_set_length(&w2, n+m, _state);
 | |
|     ae_vector_set_length(&tmp, m, _state);
 | |
|     ae_vector_set_length(&tmpdiff, m, _state);
 | |
|     ae_matrix_set_length(&fmatrix, n+m, m, _state);
 | |
|     if( k>0 )
 | |
|     {
 | |
|         ae_matrix_set_length(&cmatrix, k, m+1, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Fill design matrix, Y2, W2:
 | |
|      * * first N rows with basis functions for original points
 | |
|      * * next M rows with decay terms
 | |
|      */
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * prepare Ith row
 | |
|          * use Tmp for calculations to avoid multidimensional arrays overhead
 | |
|          */
 | |
|         for(j=0; j<=m-1; j++)
 | |
|         {
 | |
|             if( j==0 )
 | |
|             {
 | |
|                 tmp.ptr.p_double[j] = (double)(1);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( j==1 )
 | |
|                 {
 | |
|                     tmp.ptr.p_double[j] = x->ptr.p_double[i];
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     tmp.ptr.p_double[j] = 2*x->ptr.p_double[i]*tmp.ptr.p_double[j-1]-tmp.ptr.p_double[j-2];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         ae_v_move(&fmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1));
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=m-1; j++)
 | |
|         {
 | |
|             if( i==j )
 | |
|             {
 | |
|                 fmatrix.ptr.pp_double[n+i][j] = decay;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 fmatrix.ptr.pp_double[n+i][j] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     ae_v_move(&y2.ptr.p_double[0], 1, &y->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     ae_v_move(&w2.ptr.p_double[0], 1, &w->ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|     mx = (double)(0);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         mx = mx+ae_fabs(w->ptr.p_double[i], _state);
 | |
|     }
 | |
|     mx = mx/n;
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         y2.ptr.p_double[n+i] = (double)(0);
 | |
|         w2.ptr.p_double[n+i] = mx;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * fill constraints matrix
 | |
|      */
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * prepare Ith row
 | |
|          * use Tmp for basis function values,
 | |
|          * TmpDiff for basos function derivatives
 | |
|          */
 | |
|         for(j=0; j<=m-1; j++)
 | |
|         {
 | |
|             if( j==0 )
 | |
|             {
 | |
|                 tmp.ptr.p_double[j] = (double)(1);
 | |
|                 tmpdiff.ptr.p_double[j] = (double)(0);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( j==1 )
 | |
|                 {
 | |
|                     tmp.ptr.p_double[j] = xc->ptr.p_double[i];
 | |
|                     tmpdiff.ptr.p_double[j] = (double)(1);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     tmp.ptr.p_double[j] = 2*xc->ptr.p_double[i]*tmp.ptr.p_double[j-1]-tmp.ptr.p_double[j-2];
 | |
|                     tmpdiff.ptr.p_double[j] = 2*(tmp.ptr.p_double[j-1]+xc->ptr.p_double[i]*tmpdiff.ptr.p_double[j-1])-tmpdiff.ptr.p_double[j-2];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if( dc->ptr.p_int[i]==0 )
 | |
|         {
 | |
|             ae_v_move(&cmatrix.ptr.pp_double[i][0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1));
 | |
|         }
 | |
|         if( dc->ptr.p_int[i]==1 )
 | |
|         {
 | |
|             ae_v_move(&cmatrix.ptr.pp_double[i][0], 1, &tmpdiff.ptr.p_double[0], 1, ae_v_len(0,m-1));
 | |
|         }
 | |
|         cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i];
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Solve constrained task
 | |
|      */
 | |
|     if( k>0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * solve using regularization
 | |
|          */
 | |
|         lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, c, rep, _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * no constraints, no regularization needed
 | |
|          */
 | |
|         lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, 0, info, c, rep, _state);
 | |
|     }
 | |
|     if( *info<0 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal Floater-Hormann fitting subroutine for fixed D
 | |
| *************************************************************************/
 | |
| static void lsfit_barycentricfitwcfixedd(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* xc,
 | |
|      /* Real    */ ae_vector* yc,
 | |
|      /* Integer */ ae_vector* dc,
 | |
|      ae_int_t k,
 | |
|      ae_int_t m,
 | |
|      ae_int_t d,
 | |
|      ae_int_t* info,
 | |
|      barycentricinterpolant* b,
 | |
|      barycentricfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector _w;
 | |
|     ae_vector _xc;
 | |
|     ae_vector _yc;
 | |
|     ae_matrix fmatrix;
 | |
|     ae_matrix cmatrix;
 | |
|     ae_vector y2;
 | |
|     ae_vector w2;
 | |
|     ae_vector sx;
 | |
|     ae_vector sy;
 | |
|     ae_vector sbf;
 | |
|     ae_vector xoriginal;
 | |
|     ae_vector yoriginal;
 | |
|     ae_vector tmp;
 | |
|     lsfitreport lrep;
 | |
|     double v0;
 | |
|     double v1;
 | |
|     double mx;
 | |
|     barycentricinterpolant b2;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t relcnt;
 | |
|     double xa;
 | |
|     double xb;
 | |
|     double sa;
 | |
|     double sb;
 | |
|     double decay;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&_w, 0, sizeof(_w));
 | |
|     memset(&_xc, 0, sizeof(_xc));
 | |
|     memset(&_yc, 0, sizeof(_yc));
 | |
|     memset(&fmatrix, 0, sizeof(fmatrix));
 | |
|     memset(&cmatrix, 0, sizeof(cmatrix));
 | |
|     memset(&y2, 0, sizeof(y2));
 | |
|     memset(&w2, 0, sizeof(w2));
 | |
|     memset(&sx, 0, sizeof(sx));
 | |
|     memset(&sy, 0, sizeof(sy));
 | |
|     memset(&sbf, 0, sizeof(sbf));
 | |
|     memset(&xoriginal, 0, sizeof(xoriginal));
 | |
|     memset(&yoriginal, 0, sizeof(yoriginal));
 | |
|     memset(&tmp, 0, sizeof(tmp));
 | |
|     memset(&lrep, 0, sizeof(lrep));
 | |
|     memset(&b2, 0, sizeof(b2));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_init_copy(&_w, w, _state, ae_true);
 | |
|     w = &_w;
 | |
|     ae_vector_init_copy(&_xc, xc, _state, ae_true);
 | |
|     xc = &_xc;
 | |
|     ae_vector_init_copy(&_yc, yc, _state, ae_true);
 | |
|     yc = &_yc;
 | |
|     *info = 0;
 | |
|     _barycentricinterpolant_clear(b);
 | |
|     _barycentricfitreport_clear(rep);
 | |
|     ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&cmatrix, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&y2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&w2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sy, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&sbf, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp, 0, DT_REAL, _state, ae_true);
 | |
|     _lsfitreport_init(&lrep, _state, ae_true);
 | |
|     _barycentricinterpolant_init(&b2, _state, ae_true);
 | |
| 
 | |
|     if( ((n<1||m<2)||k<0)||k>=m )
 | |
|     {
 | |
|         *info = -1;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         *info = 0;
 | |
|         if( dc->ptr.p_int[i]<0 )
 | |
|         {
 | |
|             *info = -1;
 | |
|         }
 | |
|         if( dc->ptr.p_int[i]>1 )
 | |
|         {
 | |
|             *info = -1;
 | |
|         }
 | |
|         if( *info<0 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * weight decay for correct handling of task which becomes
 | |
|      * degenerate after constraints are applied
 | |
|      */
 | |
|     decay = 10000*ae_machineepsilon;
 | |
|     
 | |
|     /*
 | |
|      * Scale X, Y, XC, YC
 | |
|      */
 | |
|     lsfitscalexy(x, y, w, n, xc, yc, dc, k, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state);
 | |
|     
 | |
|     /*
 | |
|      * allocate space, initialize:
 | |
|      * * FMatrix-   values of basis functions at X[]
 | |
|      * * CMatrix-   values (derivatives) of basis functions at XC[]
 | |
|      */
 | |
|     ae_vector_set_length(&y2, n+m, _state);
 | |
|     ae_vector_set_length(&w2, n+m, _state);
 | |
|     ae_matrix_set_length(&fmatrix, n+m, m, _state);
 | |
|     if( k>0 )
 | |
|     {
 | |
|         ae_matrix_set_length(&cmatrix, k, m+1, _state);
 | |
|     }
 | |
|     ae_vector_set_length(&y2, n+m, _state);
 | |
|     ae_vector_set_length(&w2, n+m, _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare design and constraints matrices:
 | |
|      * * fill constraints matrix
 | |
|      * * fill first N rows of design matrix with values
 | |
|      * * fill next M rows of design matrix with regularizing term
 | |
|      * * append M zeros to Y
 | |
|      * * append M elements, mean(abs(W)) each, to W
 | |
|      */
 | |
|     ae_vector_set_length(&sx, m, _state);
 | |
|     ae_vector_set_length(&sy, m, _state);
 | |
|     ae_vector_set_length(&sbf, m, _state);
 | |
|     for(j=0; j<=m-1; j++)
 | |
|     {
 | |
|         sx.ptr.p_double[j] = (double)(2*j)/(double)(m-1)-1;
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         sy.ptr.p_double[i] = (double)(1);
 | |
|     }
 | |
|     barycentricbuildfloaterhormann(&sx, &sy, m, d, &b2, _state);
 | |
|     mx = (double)(0);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         lsfit_barycentriccalcbasis(&b2, x->ptr.p_double[i], &sbf, _state);
 | |
|         ae_v_move(&fmatrix.ptr.pp_double[i][0], 1, &sbf.ptr.p_double[0], 1, ae_v_len(0,m-1));
 | |
|         y2.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|         w2.ptr.p_double[i] = w->ptr.p_double[i];
 | |
|         mx = mx+ae_fabs(w->ptr.p_double[i], _state)/n;
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=m-1; j++)
 | |
|         {
 | |
|             if( i==j )
 | |
|             {
 | |
|                 fmatrix.ptr.pp_double[n+i][j] = decay;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 fmatrix.ptr.pp_double[n+i][j] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|         y2.ptr.p_double[n+i] = (double)(0);
 | |
|         w2.ptr.p_double[n+i] = mx;
 | |
|     }
 | |
|     if( k>0 )
 | |
|     {
 | |
|         for(j=0; j<=m-1; j++)
 | |
|         {
 | |
|             for(i=0; i<=m-1; i++)
 | |
|             {
 | |
|                 sy.ptr.p_double[i] = (double)(0);
 | |
|             }
 | |
|             sy.ptr.p_double[j] = (double)(1);
 | |
|             barycentricbuildfloaterhormann(&sx, &sy, m, d, &b2, _state);
 | |
|             for(i=0; i<=k-1; i++)
 | |
|             {
 | |
|                 ae_assert(dc->ptr.p_int[i]>=0&&dc->ptr.p_int[i]<=1, "BarycentricFit: internal error!", _state);
 | |
|                 barycentricdiff1(&b2, xc->ptr.p_double[i], &v0, &v1, _state);
 | |
|                 if( dc->ptr.p_int[i]==0 )
 | |
|                 {
 | |
|                     cmatrix.ptr.pp_double[i][j] = v0;
 | |
|                 }
 | |
|                 if( dc->ptr.p_int[i]==1 )
 | |
|                 {
 | |
|                     cmatrix.ptr.pp_double[i][j] = v1;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         for(i=0; i<=k-1; i++)
 | |
|         {
 | |
|             cmatrix.ptr.pp_double[i][m] = yc->ptr.p_double[i];
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Solve constrained task
 | |
|      */
 | |
|     if( k>0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * solve using regularization
 | |
|          */
 | |
|         lsfitlinearwc(&y2, &w2, &fmatrix, &cmatrix, n+m, m, k, info, &tmp, &lrep, _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * no constraints, no regularization needed
 | |
|          */
 | |
|         lsfitlinearwc(y, w, &fmatrix, &cmatrix, n, m, k, info, &tmp, &lrep, _state);
 | |
|     }
 | |
|     if( *info<0 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Generate interpolant and scale it
 | |
|      */
 | |
|     ae_v_move(&sy.ptr.p_double[0], 1, &tmp.ptr.p_double[0], 1, ae_v_len(0,m-1));
 | |
|     barycentricbuildfloaterhormann(&sx, &sy, m, d, b, _state);
 | |
|     barycentriclintransx(b, 2/(xb-xa), -(xa+xb)/(xb-xa), _state);
 | |
|     barycentriclintransy(b, sb-sa, sa, _state);
 | |
|     
 | |
|     /*
 | |
|      * Scale absolute errors obtained from LSFitLinearW.
 | |
|      * Relative error should be calculated separately
 | |
|      * (because of shifting/scaling of the task)
 | |
|      */
 | |
|     rep->taskrcond = lrep.taskrcond;
 | |
|     rep->rmserror = lrep.rmserror*(sb-sa);
 | |
|     rep->avgerror = lrep.avgerror*(sb-sa);
 | |
|     rep->maxerror = lrep.maxerror*(sb-sa);
 | |
|     rep->avgrelerror = (double)(0);
 | |
|     relcnt = 0;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             rep->avgrelerror = rep->avgrelerror+ae_fabs(barycentriccalc(b, xoriginal.ptr.p_double[i], _state)-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state);
 | |
|             relcnt = relcnt+1;
 | |
|         }
 | |
|     }
 | |
|     if( relcnt!=0 )
 | |
|     {
 | |
|         rep->avgrelerror = rep->avgrelerror/relcnt;
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void lsfit_clearreport(lsfitreport* rep, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     rep->taskrcond = (double)(0);
 | |
|     rep->iterationscount = 0;
 | |
|     rep->varidx = -1;
 | |
|     rep->rmserror = (double)(0);
 | |
|     rep->avgerror = (double)(0);
 | |
|     rep->avgrelerror = (double)(0);
 | |
|     rep->maxerror = (double)(0);
 | |
|     rep->wrmserror = (double)(0);
 | |
|     rep->r2 = (double)(0);
 | |
|     ae_matrix_set_length(&rep->covpar, 0, 0, _state);
 | |
|     ae_vector_set_length(&rep->errpar, 0, _state);
 | |
|     ae_vector_set_length(&rep->errcurve, 0, _state);
 | |
|     ae_vector_set_length(&rep->noise, 0, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This internal function estimates covariance matrix and other error-related
 | |
| information for linear/nonlinear least squares model.
 | |
| 
 | |
| It has a bit awkward interface, but it can be used  for  both  linear  and
 | |
| nonlinear problems.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     F1  -   array[0..N-1,0..K-1]:
 | |
|             * for linear problems - matrix of function values
 | |
|             * for nonlinear problems - Jacobian matrix
 | |
|     F0  -   array[0..N-1]:
 | |
|             * for linear problems - must be filled with zeros
 | |
|             * for nonlinear problems - must store values of function being
 | |
|               fitted
 | |
|     Y   -   array[0..N-1]:
 | |
|             * for linear and nonlinear problems - must store target values
 | |
|     W   -   weights, array[0..N-1]:
 | |
|             * for linear and nonlinear problems - weights
 | |
|     X   -   array[0..K-1]:
 | |
|             * for linear and nonlinear problems - current solution
 | |
|     S   -   array[0..K-1]:
 | |
|             * its components should be strictly positive
 | |
|             * squared inverse of this diagonal matrix is used as damping
 | |
|               factor for covariance matrix (linear and nonlinear problems)
 | |
|             * for nonlinear problems, when scale of the variables is usually
 | |
|               explicitly given by user, you may use scale vector for this
 | |
|               parameter
 | |
|             * for linear problems you may set this parameter to
 | |
|               S=sqrt(1/diag(F'*F))
 | |
|             * this parameter is automatically rescaled by this function,
 | |
|               only relative magnitudes of its components (with respect to
 | |
|               each other) matter.
 | |
|     N   -   number of points, N>0.
 | |
|     K   -   number of dimensions
 | |
|     Rep -   structure which is used to store results
 | |
|     Z   -   additional matrix which, depending on ZKind, may contain some
 | |
|             information used to accelerate calculations - or just can be
 | |
|             temporary buffer:
 | |
|             * for ZKind=0       Z contains no information, just temporary
 | |
|                                 buffer which can be resized and used as needed
 | |
|             * for ZKind=1       Z contains triangular matrix from QR
 | |
|                                 decomposition of W*F1. This matrix can be used
 | |
|                                 to speedup calculation of covariance matrix.
 | |
|                                 It should not be changed by algorithm.
 | |
|     ZKind-  contents of Z
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
| 
 | |
| * Rep.CovPar        covariance matrix for parameters, array[K,K].
 | |
| * Rep.ErrPar        errors in parameters, array[K],
 | |
|                     errpar = sqrt(diag(CovPar))
 | |
| * Rep.ErrCurve      vector of fit errors - standard deviations of empirical
 | |
|                     best-fit curve from "ideal" best-fit curve built  with
 | |
|                     infinite number of samples, array[N].
 | |
|                     errcurve = sqrt(diag(J*CovPar*J')),
 | |
|                     where J is Jacobian matrix.
 | |
| * Rep.Noise         vector of per-point estimates of noise, array[N]
 | |
| * Rep.R2            coefficient of determination (non-weighted)
 | |
| 
 | |
| Other fields of Rep are not changed.
 | |
| 
 | |
| IMPORTANT:  errors  in  parameters  are  calculated  without  taking  into
 | |
|             account boundary/linear constraints! Presence  of  constraints
 | |
|             changes distribution of errors, but there is no  easy  way  to
 | |
|             account for constraints when you calculate covariance matrix.
 | |
|             
 | |
| NOTE:       noise in the data is estimated as follows:
 | |
|             * for fitting without user-supplied  weights  all  points  are
 | |
|               assumed to have same level of noise, which is estimated from
 | |
|               the data
 | |
|             * for fitting with user-supplied weights we assume that  noise
 | |
|               level in I-th point is inversely proportional to Ith weight.
 | |
|               Coefficient of proportionality is estimated from the data.
 | |
|             
 | |
| NOTE:       we apply small amount of regularization when we invert squared
 | |
|             Jacobian and calculate covariance matrix. It  guarantees  that
 | |
|             algorithm won't divide by zero  during  inversion,  but  skews
 | |
|             error estimates a bit (fractional error is about 10^-9).
 | |
|             
 | |
|             However, we believe that this difference is insignificant  for
 | |
|             all practical purposes except for the situation when you  want
 | |
|             to compare ALGLIB results with "reference"  implementation  up
 | |
|             to the last significant digit.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 10.12.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void lsfit_estimateerrors(/* Real    */ ae_matrix* f1,
 | |
|      /* Real    */ ae_vector* f0,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* s,
 | |
|      ae_int_t n,
 | |
|      ae_int_t k,
 | |
|      lsfitreport* rep,
 | |
|      /* Real    */ ae_matrix* z,
 | |
|      ae_int_t zkind,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _s;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t j1;
 | |
|     double v;
 | |
|     double noisec;
 | |
|     ae_int_t info;
 | |
|     matinvreport invrep;
 | |
|     ae_int_t nzcnt;
 | |
|     double avg;
 | |
|     double rss;
 | |
|     double tss;
 | |
|     double sz;
 | |
|     double ss;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_s, 0, sizeof(_s));
 | |
|     memset(&invrep, 0, sizeof(invrep));
 | |
|     ae_vector_init_copy(&_s, s, _state, ae_true);
 | |
|     s = &_s;
 | |
|     _matinvreport_init(&invrep, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Compute NZCnt - count of non-zero weights
 | |
|      */
 | |
|     nzcnt = 0;
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             nzcnt = nzcnt+1;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Compute R2
 | |
|      */
 | |
|     if( nzcnt>0 )
 | |
|     {
 | |
|         avg = 0.0;
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) )
 | |
|             {
 | |
|                 avg = avg+y->ptr.p_double[i];
 | |
|             }
 | |
|         }
 | |
|         avg = avg/nzcnt;
 | |
|         rss = 0.0;
 | |
|         tss = 0.0;
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) )
 | |
|             {
 | |
|                 v = ae_v_dotproduct(&f1->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|                 v = v+f0->ptr.p_double[i];
 | |
|                 rss = rss+ae_sqr(v-y->ptr.p_double[i], _state);
 | |
|                 tss = tss+ae_sqr(y->ptr.p_double[i]-avg, _state);
 | |
|             }
 | |
|         }
 | |
|         if( ae_fp_neq(tss,(double)(0)) )
 | |
|         {
 | |
|             rep->r2 = ae_maxreal(1.0-rss/tss, 0.0, _state);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             rep->r2 = 1.0;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         rep->r2 = (double)(0);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Compute estimate of proportionality between noise in the data and weights:
 | |
|      *     NoiseC = mean(per-point-noise*per-point-weight)
 | |
|      * Noise level (standard deviation) at each point is equal to NoiseC/W[I].
 | |
|      */
 | |
|     if( nzcnt>k )
 | |
|     {
 | |
|         noisec = 0.0;
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) )
 | |
|             {
 | |
|                 v = ae_v_dotproduct(&f1->ptr.pp_double[i][0], 1, &x->ptr.p_double[0], 1, ae_v_len(0,k-1));
 | |
|                 v = v+f0->ptr.p_double[i];
 | |
|                 noisec = noisec+ae_sqr((v-y->ptr.p_double[i])*w->ptr.p_double[i], _state);
 | |
|             }
 | |
|         }
 | |
|         noisec = ae_sqrt(noisec/(nzcnt-k), _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         noisec = 0.0;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Two branches on noise level:
 | |
|      * * NoiseC>0   normal situation
 | |
|      * * NoiseC=0   degenerate case CovPar is filled by zeros
 | |
|      */
 | |
|     rmatrixsetlengthatleast(&rep->covpar, k, k, _state);
 | |
|     if( ae_fp_greater(noisec,(double)(0)) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Normal situation: non-zero noise level
 | |
|          */
 | |
|         ae_assert(zkind==0||zkind==1, "LSFit: internal error in EstimateErrors() function", _state);
 | |
|         if( zkind==0 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Z contains no additional information which can be used to speed up
 | |
|              * calculations. We have to calculate covariance matrix on our own:
 | |
|              * * Compute scaled Jacobian N*J, where N[i,i]=WCur[I]/NoiseC, store in Z
 | |
|              * * Compute Z'*Z, store in CovPar
 | |
|              * * Apply moderate regularization to CovPar and compute matrix inverse.
 | |
|              *   In case inverse failed, increase regularization parameter and try
 | |
|              *   again.
 | |
|              */
 | |
|             rmatrixsetlengthatleast(z, n, k, _state);
 | |
|             for(i=0; i<=n-1; i++)
 | |
|             {
 | |
|                 v = w->ptr.p_double[i]/noisec;
 | |
|                 ae_v_moved(&z->ptr.pp_double[i][0], 1, &f1->ptr.pp_double[i][0], 1, ae_v_len(0,k-1), v);
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Convert S to automatically scaled damped matrix:
 | |
|              * * calculate SZ - sum of diagonal elements of Z'*Z
 | |
|              * * calculate SS - sum of diagonal elements of S^(-2)
 | |
|              * * overwrite S by (SZ/SS)*S^(-2)
 | |
|              * * now S has approximately same magnitude as giagonal of Z'*Z
 | |
|              */
 | |
|             sz = (double)(0);
 | |
|             for(i=0; i<=n-1; i++)
 | |
|             {
 | |
|                 for(j=0; j<=k-1; j++)
 | |
|                 {
 | |
|                     sz = sz+z->ptr.pp_double[i][j]*z->ptr.pp_double[i][j];
 | |
|                 }
 | |
|             }
 | |
|             if( ae_fp_eq(sz,(double)(0)) )
 | |
|             {
 | |
|                 sz = (double)(1);
 | |
|             }
 | |
|             ss = (double)(0);
 | |
|             for(j=0; j<=k-1; j++)
 | |
|             {
 | |
|                 ss = ss+1/ae_sqr(s->ptr.p_double[j], _state);
 | |
|             }
 | |
|             for(j=0; j<=k-1; j++)
 | |
|             {
 | |
|                 s->ptr.p_double[j] = sz/ss/ae_sqr(s->ptr.p_double[j], _state);
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Calculate damped inverse inv(Z'*Z+S).
 | |
|              * We increase damping factor V until Z'*Z become well-conditioned.
 | |
|              */
 | |
|             v = 1.0E3*ae_machineepsilon;
 | |
|             do
 | |
|             {
 | |
|                 rmatrixsyrk(k, n, 1.0, z, 0, 0, 2, 0.0, &rep->covpar, 0, 0, ae_true, _state);
 | |
|                 for(i=0; i<=k-1; i++)
 | |
|                 {
 | |
|                     rep->covpar.ptr.pp_double[i][i] = rep->covpar.ptr.pp_double[i][i]+v*s->ptr.p_double[i];
 | |
|                 }
 | |
|                 spdmatrixinverse(&rep->covpar, k, ae_true, &info, &invrep, _state);
 | |
|                 v = 10*v;
 | |
|             }
 | |
|             while(info<=0);
 | |
|             for(i=0; i<=k-1; i++)
 | |
|             {
 | |
|                 for(j=i+1; j<=k-1; j++)
 | |
|                 {
 | |
|                     rep->covpar.ptr.pp_double[j][i] = rep->covpar.ptr.pp_double[i][j];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if( zkind==1 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * We can reuse additional information:
 | |
|              * * Z contains R matrix from QR decomposition of W*F1 
 | |
|              * * After multiplication by 1/NoiseC we get Z_mod = N*F1, where diag(N)=w[i]/NoiseC
 | |
|              * * Such triangular Z_mod is a Cholesky factor from decomposition of J'*N'*N*J.
 | |
|              *   Thus, we can calculate covariance matrix as inverse of the matrix given by
 | |
|              *   its Cholesky decomposition. It allow us to avoid time-consuming calculation
 | |
|              *   of J'*N'*N*J in CovPar - complexity is reduced from O(N*K^2) to O(K^3), which
 | |
|              *   is quite good because K is usually orders of magnitude smaller than N.
 | |
|              *
 | |
|              * First, convert S to automatically scaled damped matrix:
 | |
|              * * calculate SZ - sum of magnitudes of diagonal elements of Z/NoiseC
 | |
|              * * calculate SS - sum of diagonal elements of S^(-1)
 | |
|              * * overwrite S by (SZ/SS)*S^(-1)
 | |
|              * * now S has approximately same magnitude as giagonal of Z'*Z
 | |
|              */
 | |
|             sz = (double)(0);
 | |
|             for(j=0; j<=k-1; j++)
 | |
|             {
 | |
|                 sz = sz+ae_fabs(z->ptr.pp_double[j][j]/noisec, _state);
 | |
|             }
 | |
|             if( ae_fp_eq(sz,(double)(0)) )
 | |
|             {
 | |
|                 sz = (double)(1);
 | |
|             }
 | |
|             ss = (double)(0);
 | |
|             for(j=0; j<=k-1; j++)
 | |
|             {
 | |
|                 ss = ss+1/s->ptr.p_double[j];
 | |
|             }
 | |
|             for(j=0; j<=k-1; j++)
 | |
|             {
 | |
|                 s->ptr.p_double[j] = sz/ss/s->ptr.p_double[j];
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Calculate damped inverse of inv((Z+v*S)'*(Z+v*S))
 | |
|              * We increase damping factor V until matrix become well-conditioned.
 | |
|              */
 | |
|             v = 1.0E3*ae_machineepsilon;
 | |
|             do
 | |
|             {
 | |
|                 for(i=0; i<=k-1; i++)
 | |
|                 {
 | |
|                     for(j=i; j<=k-1; j++)
 | |
|                     {
 | |
|                         rep->covpar.ptr.pp_double[i][j] = z->ptr.pp_double[i][j]/noisec;
 | |
|                     }
 | |
|                     rep->covpar.ptr.pp_double[i][i] = rep->covpar.ptr.pp_double[i][i]+v*s->ptr.p_double[i];
 | |
|                 }
 | |
|                 spdmatrixcholeskyinverse(&rep->covpar, k, ae_true, &info, &invrep, _state);
 | |
|                 v = 10*v;
 | |
|             }
 | |
|             while(info<=0);
 | |
|             for(i=0; i<=k-1; i++)
 | |
|             {
 | |
|                 for(j=i+1; j<=k-1; j++)
 | |
|                 {
 | |
|                     rep->covpar.ptr.pp_double[j][i] = rep->covpar.ptr.pp_double[i][j];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Degenerate situation: zero noise level, covariance matrix is zero.
 | |
|          */
 | |
|         for(i=0; i<=k-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=k-1; j++)
 | |
|             {
 | |
|                 rep->covpar.ptr.pp_double[j][i] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Estimate erorrs in parameters, curve and per-point noise
 | |
|      */
 | |
|     rvectorsetlengthatleast(&rep->errpar, k, _state);
 | |
|     rvectorsetlengthatleast(&rep->errcurve, n, _state);
 | |
|     rvectorsetlengthatleast(&rep->noise, n, _state);
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         rep->errpar.ptr.p_double[i] = ae_sqrt(rep->covpar.ptr.pp_double[i][i], _state);
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * ErrCurve[I] is sqrt(P[i,i]) where P=J*CovPar*J'
 | |
|          */
 | |
|         v = 0.0;
 | |
|         for(j=0; j<=k-1; j++)
 | |
|         {
 | |
|             for(j1=0; j1<=k-1; j1++)
 | |
|             {
 | |
|                 v = v+f1->ptr.pp_double[i][j]*rep->covpar.ptr.pp_double[j][j1]*f1->ptr.pp_double[i][j1];
 | |
|             }
 | |
|         }
 | |
|         rep->errcurve.ptr.p_double[i] = ae_sqrt(v, _state);
 | |
|         
 | |
|         /*
 | |
|          * Noise[i] is filled using weights and current estimate of noise level
 | |
|          */
 | |
|         if( ae_fp_neq(w->ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             rep->noise.ptr.p_double[i] = noisec/w->ptr.p_double[i];
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             rep->noise.ptr.p_double[i] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _polynomialfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     polynomialfitreport *p = (polynomialfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _polynomialfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     polynomialfitreport *dst = (polynomialfitreport*)_dst;
 | |
|     polynomialfitreport *src = (polynomialfitreport*)_src;
 | |
|     dst->taskrcond = src->taskrcond;
 | |
|     dst->rmserror = src->rmserror;
 | |
|     dst->avgerror = src->avgerror;
 | |
|     dst->avgrelerror = src->avgrelerror;
 | |
|     dst->maxerror = src->maxerror;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _polynomialfitreport_clear(void* _p)
 | |
| {
 | |
|     polynomialfitreport *p = (polynomialfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _polynomialfitreport_destroy(void* _p)
 | |
| {
 | |
|     polynomialfitreport *p = (polynomialfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _barycentricfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     barycentricfitreport *p = (barycentricfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _barycentricfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     barycentricfitreport *dst = (barycentricfitreport*)_dst;
 | |
|     barycentricfitreport *src = (barycentricfitreport*)_src;
 | |
|     dst->taskrcond = src->taskrcond;
 | |
|     dst->dbest = src->dbest;
 | |
|     dst->rmserror = src->rmserror;
 | |
|     dst->avgerror = src->avgerror;
 | |
|     dst->avgrelerror = src->avgrelerror;
 | |
|     dst->maxerror = src->maxerror;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _barycentricfitreport_clear(void* _p)
 | |
| {
 | |
|     barycentricfitreport *p = (barycentricfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _barycentricfitreport_destroy(void* _p)
 | |
| {
 | |
|     barycentricfitreport *p = (barycentricfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _lsfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     lsfitreport *p = (lsfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_matrix_init(&p->covpar, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->errpar, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->errcurve, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->noise, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _lsfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     lsfitreport *dst = (lsfitreport*)_dst;
 | |
|     lsfitreport *src = (lsfitreport*)_src;
 | |
|     dst->taskrcond = src->taskrcond;
 | |
|     dst->iterationscount = src->iterationscount;
 | |
|     dst->varidx = src->varidx;
 | |
|     dst->rmserror = src->rmserror;
 | |
|     dst->avgerror = src->avgerror;
 | |
|     dst->avgrelerror = src->avgrelerror;
 | |
|     dst->maxerror = src->maxerror;
 | |
|     dst->wrmserror = src->wrmserror;
 | |
|     ae_matrix_init_copy(&dst->covpar, &src->covpar, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->errpar, &src->errpar, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->errcurve, &src->errcurve, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->noise, &src->noise, _state, make_automatic);
 | |
|     dst->r2 = src->r2;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _lsfitreport_clear(void* _p)
 | |
| {
 | |
|     lsfitreport *p = (lsfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_matrix_clear(&p->covpar);
 | |
|     ae_vector_clear(&p->errpar);
 | |
|     ae_vector_clear(&p->errcurve);
 | |
|     ae_vector_clear(&p->noise);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _lsfitreport_destroy(void* _p)
 | |
| {
 | |
|     lsfitreport *p = (lsfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_matrix_destroy(&p->covpar);
 | |
|     ae_vector_destroy(&p->errpar);
 | |
|     ae_vector_destroy(&p->errcurve);
 | |
|     ae_vector_destroy(&p->noise);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _lsfitstate_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     lsfitstate *p = (lsfitstate*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->c0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->c1, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->bndl, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->bndu, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->taskx, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tasky, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->taskw, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->cleic, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->c, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->g, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->h, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->wcur, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmpct, 0, DT_INT, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmp, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmpf, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->tmpjac, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->tmpjacw, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     _matinvreport_init(&p->invrep, _state, make_automatic);
 | |
|     _lsfitreport_init(&p->rep, _state, make_automatic);
 | |
|     _minlmstate_init(&p->optstate, _state, make_automatic);
 | |
|     _minlmreport_init(&p->optrep, _state, make_automatic);
 | |
|     _rcommstate_init(&p->rstate, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _lsfitstate_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     lsfitstate *dst = (lsfitstate*)_dst;
 | |
|     lsfitstate *src = (lsfitstate*)_src;
 | |
|     dst->optalgo = src->optalgo;
 | |
|     dst->m = src->m;
 | |
|     dst->k = src->k;
 | |
|     dst->epsx = src->epsx;
 | |
|     dst->maxits = src->maxits;
 | |
|     dst->stpmax = src->stpmax;
 | |
|     dst->xrep = src->xrep;
 | |
|     ae_vector_init_copy(&dst->c0, &src->c0, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->c1, &src->c1, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->bndl, &src->bndl, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->bndu, &src->bndu, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->taskx, &src->taskx, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tasky, &src->tasky, _state, make_automatic);
 | |
|     dst->npoints = src->npoints;
 | |
|     ae_vector_init_copy(&dst->taskw, &src->taskw, _state, make_automatic);
 | |
|     dst->nweights = src->nweights;
 | |
|     dst->wkind = src->wkind;
 | |
|     dst->wits = src->wits;
 | |
|     dst->diffstep = src->diffstep;
 | |
|     dst->teststep = src->teststep;
 | |
|     ae_matrix_init_copy(&dst->cleic, &src->cleic, _state, make_automatic);
 | |
|     dst->nec = src->nec;
 | |
|     dst->nic = src->nic;
 | |
|     dst->xupdated = src->xupdated;
 | |
|     dst->needf = src->needf;
 | |
|     dst->needfg = src->needfg;
 | |
|     dst->needfgh = src->needfgh;
 | |
|     dst->pointindex = src->pointindex;
 | |
|     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->c, &src->c, _state, make_automatic);
 | |
|     dst->f = src->f;
 | |
|     ae_vector_init_copy(&dst->g, &src->g, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->h, &src->h, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->wcur, &src->wcur, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmpct, &src->tmpct, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmp, &src->tmp, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmpf, &src->tmpf, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->tmpjac, &src->tmpjac, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->tmpjacw, &src->tmpjacw, _state, make_automatic);
 | |
|     dst->tmpnoise = src->tmpnoise;
 | |
|     _matinvreport_init_copy(&dst->invrep, &src->invrep, _state, make_automatic);
 | |
|     dst->repiterationscount = src->repiterationscount;
 | |
|     dst->repterminationtype = src->repterminationtype;
 | |
|     dst->repvaridx = src->repvaridx;
 | |
|     dst->reprmserror = src->reprmserror;
 | |
|     dst->repavgerror = src->repavgerror;
 | |
|     dst->repavgrelerror = src->repavgrelerror;
 | |
|     dst->repmaxerror = src->repmaxerror;
 | |
|     dst->repwrmserror = src->repwrmserror;
 | |
|     _lsfitreport_init_copy(&dst->rep, &src->rep, _state, make_automatic);
 | |
|     _minlmstate_init_copy(&dst->optstate, &src->optstate, _state, make_automatic);
 | |
|     _minlmreport_init_copy(&dst->optrep, &src->optrep, _state, make_automatic);
 | |
|     dst->prevnpt = src->prevnpt;
 | |
|     dst->prevalgo = src->prevalgo;
 | |
|     _rcommstate_init_copy(&dst->rstate, &src->rstate, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _lsfitstate_clear(void* _p)
 | |
| {
 | |
|     lsfitstate *p = (lsfitstate*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->c0);
 | |
|     ae_vector_clear(&p->c1);
 | |
|     ae_vector_clear(&p->s);
 | |
|     ae_vector_clear(&p->bndl);
 | |
|     ae_vector_clear(&p->bndu);
 | |
|     ae_matrix_clear(&p->taskx);
 | |
|     ae_vector_clear(&p->tasky);
 | |
|     ae_vector_clear(&p->taskw);
 | |
|     ae_matrix_clear(&p->cleic);
 | |
|     ae_vector_clear(&p->x);
 | |
|     ae_vector_clear(&p->c);
 | |
|     ae_vector_clear(&p->g);
 | |
|     ae_matrix_clear(&p->h);
 | |
|     ae_vector_clear(&p->wcur);
 | |
|     ae_vector_clear(&p->tmpct);
 | |
|     ae_vector_clear(&p->tmp);
 | |
|     ae_vector_clear(&p->tmpf);
 | |
|     ae_matrix_clear(&p->tmpjac);
 | |
|     ae_matrix_clear(&p->tmpjacw);
 | |
|     _matinvreport_clear(&p->invrep);
 | |
|     _lsfitreport_clear(&p->rep);
 | |
|     _minlmstate_clear(&p->optstate);
 | |
|     _minlmreport_clear(&p->optrep);
 | |
|     _rcommstate_clear(&p->rstate);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _lsfitstate_destroy(void* _p)
 | |
| {
 | |
|     lsfitstate *p = (lsfitstate*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->c0);
 | |
|     ae_vector_destroy(&p->c1);
 | |
|     ae_vector_destroy(&p->s);
 | |
|     ae_vector_destroy(&p->bndl);
 | |
|     ae_vector_destroy(&p->bndu);
 | |
|     ae_matrix_destroy(&p->taskx);
 | |
|     ae_vector_destroy(&p->tasky);
 | |
|     ae_vector_destroy(&p->taskw);
 | |
|     ae_matrix_destroy(&p->cleic);
 | |
|     ae_vector_destroy(&p->x);
 | |
|     ae_vector_destroy(&p->c);
 | |
|     ae_vector_destroy(&p->g);
 | |
|     ae_matrix_destroy(&p->h);
 | |
|     ae_vector_destroy(&p->wcur);
 | |
|     ae_vector_destroy(&p->tmpct);
 | |
|     ae_vector_destroy(&p->tmp);
 | |
|     ae_vector_destroy(&p->tmpf);
 | |
|     ae_matrix_destroy(&p->tmpjac);
 | |
|     ae_matrix_destroy(&p->tmpjacw);
 | |
|     _matinvreport_destroy(&p->invrep);
 | |
|     _lsfitreport_destroy(&p->rep);
 | |
|     _minlmstate_destroy(&p->optstate);
 | |
|     _minlmreport_destroy(&p->optrep);
 | |
|     _rcommstate_destroy(&p->rstate);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_RBFV2) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function creates RBF  model  for  a  scalar (NY=1)  or  vector (NY>1)
 | |
| function in a NX-dimensional space (NX=2 or NX=3).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     NX      -   dimension of the space, NX=2 or NX=3
 | |
|     NY      -   function dimension, NY>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     S       -   RBF model (initially equals to zero)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv2create(ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      rbfv2model* s,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     _rbfv2model_clear(s);
 | |
| 
 | |
|     ae_assert(nx>=1, "RBFCreate: NX<1", _state);
 | |
|     ae_assert(ny>=1, "RBFCreate: NY<1", _state);
 | |
|     
 | |
|     /*
 | |
|      * Serializable parameters
 | |
|      */
 | |
|     s->nx = nx;
 | |
|     s->ny = ny;
 | |
|     s->bf = 0;
 | |
|     s->nh = 0;
 | |
|     ae_matrix_set_length(&s->v, ny, nx+1, _state);
 | |
|     for(i=0; i<=ny-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx; j++)
 | |
|         {
 | |
|             s->v.ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Non-serializable parameters
 | |
|      */
 | |
|     s->lambdareg = rbfv2_defaultlambdareg;
 | |
|     s->maxits = rbfv2_defaultmaxits;
 | |
|     s->supportr = rbfv2_defaultsupportr;
 | |
|     s->basisfunction = rbfv2_defaultbf;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function creates buffer  structure  which  can  be  used  to  perform
 | |
| parallel  RBF  model  evaluations  (with  one  RBF  model  instance  being
 | |
| used from multiple threads, as long as  different  threads  use  different
 | |
| instances of buffer).
 | |
| 
 | |
| This buffer object can be used with  rbftscalcbuf()  function  (here  "ts"
 | |
| stands for "thread-safe", "buf" is a suffix which denotes  function  which
 | |
| reuses previously allocated output space).
 | |
| 
 | |
| How to use it:
 | |
| * create RBF model structure with rbfcreate()
 | |
| * load data, tune parameters
 | |
| * call rbfbuildmodel()
 | |
| * call rbfcreatecalcbuffer(), once per thread working with RBF model  (you
 | |
|   should call this function only AFTER call to rbfbuildmodel(), see  below
 | |
|   for more information)
 | |
| * call rbftscalcbuf() from different threads,  with  each  thread  working
 | |
|   with its own copy of buffer object.
 | |
| 
 | |
| INPUT PARAMETERS
 | |
|     S           -   RBF model
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     Buf         -   external buffer.
 | |
|     
 | |
|     
 | |
| IMPORTANT: buffer object should be used only with  RBF model object  which
 | |
|            was used to initialize buffer. Any attempt to use buffer   with
 | |
|            different object is dangerous - you may  get  memory  violation
 | |
|            error because sizes of internal arrays do not fit to dimensions
 | |
|            of RBF structure.
 | |
|            
 | |
| IMPORTANT: you  should  call  this function only for model which was built
 | |
|            with rbfbuildmodel() function, after successful  invocation  of
 | |
|            rbfbuildmodel().  Sizes   of   some   internal  structures  are
 | |
|            determined only after model is built, so buffer object  created
 | |
|            before model  construction  stage  will  be  useless  (and  any
 | |
|            attempt to use it will result in exception).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.04.2016 by Sergey Bochkanov
 | |
| *************************************************************************/
 | |
| void rbfv2createcalcbuffer(rbfv2model* s,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _rbfv2calcbuffer_clear(buf);
 | |
| 
 | |
|     rbfv2_allocatecalcbuffer(s, buf, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This   function  builds hierarchical RBF model.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   array[N,S.NX], X-values
 | |
|     Y       -   array[N,S.NY], Y-values
 | |
|     ScaleVec-   array[S.NX], vector of per-dimension scales
 | |
|     N       -   points count
 | |
|     ATerm   -   linear term type, 1 for linear, 2 for constant, 3 for zero.
 | |
|     NH      -   hierarchy height
 | |
|     RBase   -   base RBF radius
 | |
|     BF      -   basis function type: 0 for Gaussian, 1 for compact
 | |
|     LambdaNS-   non-smoothness penalty coefficient. Exactly zero value means
 | |
|                 that no penalty is applied, and even system matrix does not
 | |
|                 contain penalty-related rows. Value of 1 means
 | |
|     S       -   RBF model, initialized by RBFCreate() call.
 | |
|     progress10000- variable used for progress reports, it is regularly set
 | |
|                 to the current progress multiplied by 10000, in order to
 | |
|                 get value in [0,10000] range. The rationale for such scaling
 | |
|                 is that it allows us to use integer type to store progress,
 | |
|                 which has less potential for non-atomic corruption on unprotected
 | |
|                 reads from another threads.
 | |
|                 You can read this variable from some other thread to get
 | |
|                 estimate of the current progress.
 | |
|                 Initial value of this variable is ignored, it is written by
 | |
|                 this function, but not read.
 | |
|     terminationrequest - variable used for termination requests; its initial
 | |
|                 value must be False, and you can set it to True from some
 | |
|                 other thread. This routine regularly checks this variable
 | |
|                 and will terminate model construction shortly upon discovering
 | |
|                 that termination was requested.
 | |
|     
 | |
| OUTPUT PARAMETERS:
 | |
|     S       -   updated model (for rep.terminationtype>0, unchanged otherwise)
 | |
|     Rep     -   report:
 | |
|                 * Rep.TerminationType:
 | |
|                   * -5 - non-distinct basis function centers were detected,
 | |
|                          interpolation aborted
 | |
|                   * -4 - nonconvergence of the internal SVD solver
 | |
|                   *  1 - successful termination
 | |
|                   *  8 terminated by user via rbfrequesttermination()
 | |
|                 Fields are used for debugging purposes:
 | |
|                 * Rep.IterationsCount - iterations count of the LSQR solver
 | |
|                 * Rep.NMV - number of matrix-vector products
 | |
|                 * Rep.ARows - rows count for the system matrix
 | |
|                 * Rep.ACols - columns count for the system matrix
 | |
|                 * Rep.ANNZ - number of significantly non-zero elements
 | |
|                   (elements above some algorithm-determined threshold)
 | |
| 
 | |
| NOTE:  failure  to  build  model will leave current state of the structure
 | |
| unchanged.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv2buildhierarchical(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* scalevec,
 | |
|      ae_int_t aterm,
 | |
|      ae_int_t nh,
 | |
|      double rbase,
 | |
|      double lambdans,
 | |
|      rbfv2model* s,
 | |
|      ae_int_t* progress10000,
 | |
|      ae_bool* terminationrequest,
 | |
|      rbfv2report* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
|     ae_int_t bf;
 | |
|     ae_matrix rhs;
 | |
|     ae_matrix residualy;
 | |
|     ae_matrix v;
 | |
|     ae_int_t rowsperpoint;
 | |
|     ae_vector hidx;
 | |
|     ae_vector xr;
 | |
|     ae_vector ri;
 | |
|     ae_vector kdroots;
 | |
|     ae_vector kdnodes;
 | |
|     ae_vector kdsplits;
 | |
|     ae_vector kdboxmin;
 | |
|     ae_vector kdboxmax;
 | |
|     ae_vector cw;
 | |
|     ae_vector cwrange;
 | |
|     ae_matrix curxy;
 | |
|     ae_int_t curn;
 | |
|     ae_int_t nbasis;
 | |
|     kdtree curtree;
 | |
|     kdtree globaltree;
 | |
|     ae_vector x0;
 | |
|     ae_vector x1;
 | |
|     ae_vector tags;
 | |
|     ae_vector dist;
 | |
|     ae_vector nncnt;
 | |
|     ae_vector rowsizes;
 | |
|     ae_vector diagata;
 | |
|     ae_vector prec;
 | |
|     ae_vector tmpx;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t k2;
 | |
|     ae_int_t levelidx;
 | |
|     ae_int_t offsi;
 | |
|     ae_int_t offsj;
 | |
|     double val;
 | |
|     double criticalr;
 | |
|     ae_int_t cnt;
 | |
|     double avgdiagata;
 | |
|     ae_vector avgrowsize;
 | |
|     double sumrowsize;
 | |
|     double rprogress;
 | |
|     ae_int_t maxits;
 | |
|     linlsqrstate linstate;
 | |
|     linlsqrreport lsqrrep;
 | |
|     sparsematrix sparseacrs;
 | |
|     ae_vector densew1;
 | |
|     ae_vector denseb1;
 | |
|     rbfv2calcbuffer calcbuf;
 | |
|     ae_vector vr2;
 | |
|     ae_vector voffs;
 | |
|     ae_vector rowindexes;
 | |
|     ae_vector rowvals;
 | |
|     double penalty;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&rhs, 0, sizeof(rhs));
 | |
|     memset(&residualy, 0, sizeof(residualy));
 | |
|     memset(&v, 0, sizeof(v));
 | |
|     memset(&hidx, 0, sizeof(hidx));
 | |
|     memset(&xr, 0, sizeof(xr));
 | |
|     memset(&ri, 0, sizeof(ri));
 | |
|     memset(&kdroots, 0, sizeof(kdroots));
 | |
|     memset(&kdnodes, 0, sizeof(kdnodes));
 | |
|     memset(&kdsplits, 0, sizeof(kdsplits));
 | |
|     memset(&kdboxmin, 0, sizeof(kdboxmin));
 | |
|     memset(&kdboxmax, 0, sizeof(kdboxmax));
 | |
|     memset(&cw, 0, sizeof(cw));
 | |
|     memset(&cwrange, 0, sizeof(cwrange));
 | |
|     memset(&curxy, 0, sizeof(curxy));
 | |
|     memset(&curtree, 0, sizeof(curtree));
 | |
|     memset(&globaltree, 0, sizeof(globaltree));
 | |
|     memset(&x0, 0, sizeof(x0));
 | |
|     memset(&x1, 0, sizeof(x1));
 | |
|     memset(&tags, 0, sizeof(tags));
 | |
|     memset(&dist, 0, sizeof(dist));
 | |
|     memset(&nncnt, 0, sizeof(nncnt));
 | |
|     memset(&rowsizes, 0, sizeof(rowsizes));
 | |
|     memset(&diagata, 0, sizeof(diagata));
 | |
|     memset(&prec, 0, sizeof(prec));
 | |
|     memset(&tmpx, 0, sizeof(tmpx));
 | |
|     memset(&avgrowsize, 0, sizeof(avgrowsize));
 | |
|     memset(&linstate, 0, sizeof(linstate));
 | |
|     memset(&lsqrrep, 0, sizeof(lsqrrep));
 | |
|     memset(&sparseacrs, 0, sizeof(sparseacrs));
 | |
|     memset(&densew1, 0, sizeof(densew1));
 | |
|     memset(&denseb1, 0, sizeof(denseb1));
 | |
|     memset(&calcbuf, 0, sizeof(calcbuf));
 | |
|     memset(&vr2, 0, sizeof(vr2));
 | |
|     memset(&voffs, 0, sizeof(voffs));
 | |
|     memset(&rowindexes, 0, sizeof(rowindexes));
 | |
|     memset(&rowvals, 0, sizeof(rowvals));
 | |
|     _rbfv2report_clear(rep);
 | |
|     ae_matrix_init(&rhs, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&residualy, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&v, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&hidx, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&xr, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ri, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&kdroots, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&kdnodes, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&kdsplits, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&kdboxmin, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&kdboxmax, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&cw, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&cwrange, 0, DT_INT, _state, ae_true);
 | |
|     ae_matrix_init(&curxy, 0, 0, DT_REAL, _state, ae_true);
 | |
|     _kdtree_init(&curtree, _state, ae_true);
 | |
|     _kdtree_init(&globaltree, _state, ae_true);
 | |
|     ae_vector_init(&x0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&x1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tags, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&dist, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&nncnt, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&rowsizes, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&diagata, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&prec, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&avgrowsize, 0, DT_REAL, _state, ae_true);
 | |
|     _linlsqrstate_init(&linstate, _state, ae_true);
 | |
|     _linlsqrreport_init(&lsqrrep, _state, ae_true);
 | |
|     _sparsematrix_init(&sparseacrs, _state, ae_true);
 | |
|     ae_vector_init(&densew1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&denseb1, 0, DT_REAL, _state, ae_true);
 | |
|     _rbfv2calcbuffer_init(&calcbuf, _state, ae_true);
 | |
|     ae_vector_init(&vr2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&voffs, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&rowindexes, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&rowvals, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(s->nx>0, "RBFV2BuildHierarchical: incorrect NX", _state);
 | |
|     ae_assert(s->ny>0, "RBFV2BuildHierarchical: incorrect NY", _state);
 | |
|     ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "RBFV2BuildHierarchical: incorrect LambdaNS", _state);
 | |
|     for(j=0; j<=s->nx-1; j++)
 | |
|     {
 | |
|         ae_assert(ae_fp_greater(scalevec->ptr.p_double[j],(double)(0)), "RBFV2BuildHierarchical: incorrect ScaleVec", _state);
 | |
|     }
 | |
|     nx = s->nx;
 | |
|     ny = s->ny;
 | |
|     bf = s->basisfunction;
 | |
|     ae_assert(bf==0||bf==1, "RBFV2BuildHierarchical: incorrect BF", _state);
 | |
|     
 | |
|     /*
 | |
|      * Clean up communication and report fields
 | |
|      */
 | |
|     *progress10000 = 0;
 | |
|     rep->maxerror = (double)(0);
 | |
|     rep->rmserror = (double)(0);
 | |
|     
 | |
|     /*
 | |
|      * Quick exit when we have no points
 | |
|      */
 | |
|     if( n==0 )
 | |
|     {
 | |
|         rbfv2_zerofill(s, nx, ny, bf, _state);
 | |
|         rep->terminationtype = 1;
 | |
|         *progress10000 = 10000;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * First model in a sequence - linear model.
 | |
|      * Residuals from linear regression are stored in the ResidualY variable
 | |
|      * (used later to build RBF models).
 | |
|      */
 | |
|     ae_matrix_set_length(&residualy, n, ny, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             residualy.ptr.pp_double[i][j] = y->ptr.pp_double[i][j];
 | |
|         }
 | |
|     }
 | |
|     if( !rbfv2_rbfv2buildlinearmodel(x, &residualy, n, nx, ny, aterm, &v, _state) )
 | |
|     {
 | |
|         rbfv2_zerofill(s, nx, ny, bf, _state);
 | |
|         rep->terminationtype = -5;
 | |
|         *progress10000 = 10000;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Handle special case: multilayer model with NLayers=0.
 | |
|      * Quick exit.
 | |
|      */
 | |
|     if( nh==0 )
 | |
|     {
 | |
|         rep->terminationtype = 1;
 | |
|         rbfv2_zerofill(s, nx, ny, bf, _state);
 | |
|         for(i=0; i<=ny-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx; j++)
 | |
|             {
 | |
|                 s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j];
 | |
|             }
 | |
|         }
 | |
|         rep->maxerror = (double)(0);
 | |
|         rep->rmserror = (double)(0);
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(residualy.ptr.pp_double[i][j], _state), _state);
 | |
|                 rep->rmserror = rep->rmserror+ae_sqr(residualy.ptr.pp_double[i][j], _state);
 | |
|             }
 | |
|         }
 | |
|         rep->rmserror = ae_sqrt(rep->rmserror/(n*ny), _state);
 | |
|         *progress10000 = 10000;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Penalty coefficient is set to LambdaNS*RBase^2.
 | |
|      *
 | |
|      * We use such normalization because VALUES of radial basis
 | |
|      * functions have roughly unit magnitude, but their DERIVATIVES
 | |
|      * are (roughly) inversely proportional to the radius. Thus,
 | |
|      * without additional scaling, regularization coefficient
 | |
|      * looses invariancy w.r.t. scaling of variables.
 | |
|      */
 | |
|     if( ae_fp_eq(lambdans,(double)(0)) )
 | |
|     {
 | |
|         rowsperpoint = 1;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * NOTE: simplified penalty function is used, which does not provide rotation invariance
 | |
|          */
 | |
|         rowsperpoint = 1+nx;
 | |
|     }
 | |
|     penalty = lambdans*ae_sqr(rbase, _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare temporary structures
 | |
|      */
 | |
|     ae_matrix_set_length(&rhs, n*rowsperpoint, ny, _state);
 | |
|     ae_matrix_set_length(&curxy, n, nx+ny, _state);
 | |
|     ae_vector_set_length(&x0, nx, _state);
 | |
|     ae_vector_set_length(&x1, nx, _state);
 | |
|     ae_vector_set_length(&tags, n, _state);
 | |
|     ae_vector_set_length(&dist, n, _state);
 | |
|     ae_vector_set_length(&vr2, n, _state);
 | |
|     ae_vector_set_length(&voffs, n, _state);
 | |
|     ae_vector_set_length(&nncnt, n, _state);
 | |
|     ae_vector_set_length(&rowsizes, n*rowsperpoint, _state);
 | |
|     ae_vector_set_length(&denseb1, n*rowsperpoint, _state);
 | |
|     for(i=0; i<=n*rowsperpoint-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             rhs.ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             curxy.ptr.pp_double[i][j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j];
 | |
|         }
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             rhs.ptr.pp_double[i*rowsperpoint][j] = residualy.ptr.pp_double[i][j];
 | |
|         }
 | |
|         tags.ptr.p_int[i] = i;
 | |
|     }
 | |
|     kdtreebuildtagged(&curxy, &tags, n, nx, 0, 2, &globaltree, _state);
 | |
|     
 | |
|     /*
 | |
|      * Generate sequence of layer radii.
 | |
|      * Prepare assignment of different levels to points.
 | |
|      */
 | |
|     ae_assert(n>0, "RBFV2BuildHierarchical: integrity check failed", _state);
 | |
|     ae_vector_set_length(&ri, nh, _state);
 | |
|     for(levelidx=0; levelidx<=nh-1; levelidx++)
 | |
|     {
 | |
|         ri.ptr.p_double[levelidx] = rbase*ae_pow((double)(2), (double)(-levelidx), _state);
 | |
|     }
 | |
|     ae_vector_set_length(&hidx, n, _state);
 | |
|     ae_vector_set_length(&xr, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         hidx.ptr.p_int[i] = nh;
 | |
|         xr.ptr.p_double[i] = ae_maxrealnumber;
 | |
|         ae_assert(ae_fp_greater(xr.ptr.p_double[i],ri.ptr.p_double[0]), "RBFV2BuildHierarchical: integrity check failed", _state);
 | |
|     }
 | |
|     for(levelidx=0; levelidx<=nh-1; levelidx++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Scan dataset points, for each such point that distance to nearest
 | |
|          * "support" point is larger than SupportR*Ri[LevelIdx] we:
 | |
|          * * set distance of current point to 0 (it is support now) and update HIdx
 | |
|          * * perform R-NN request with radius SupportR*Ri[LevelIdx]
 | |
|          * * for each point in request update its distance
 | |
|          */
 | |
|         criticalr = s->supportr*ri.ptr.p_double[levelidx];
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             if( ae_fp_greater(xr.ptr.p_double[i],criticalr) )
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * Mark point as support
 | |
|                  */
 | |
|                 ae_assert(hidx.ptr.p_int[i]==nh, "RBFV2BuildHierarchical: integrity check failed", _state);
 | |
|                 hidx.ptr.p_int[i] = levelidx;
 | |
|                 xr.ptr.p_double[i] = (double)(0);
 | |
|                 
 | |
|                 /*
 | |
|                  * Update neighbors
 | |
|                  */
 | |
|                 for(j=0; j<=nx-1; j++)
 | |
|                 {
 | |
|                     x0.ptr.p_double[j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j];
 | |
|                 }
 | |
|                 k = kdtreequeryrnn(&globaltree, &x0, criticalr, ae_true, _state);
 | |
|                 kdtreequeryresultstags(&globaltree, &tags, _state);
 | |
|                 kdtreequeryresultsdistances(&globaltree, &dist, _state);
 | |
|                 for(j=0; j<=k-1; j++)
 | |
|                 {
 | |
|                     xr.ptr.p_double[tags.ptr.p_int[j]] = ae_minreal(xr.ptr.p_double[tags.ptr.p_int[j]], dist.ptr.p_double[j], _state);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Build multitree (with zero weights) according to hierarchy.
 | |
|      *
 | |
|      * NOTE: this code assumes that during every iteration kdNodes,
 | |
|      *       kdSplits and CW have size which EXACTLY fits their
 | |
|      *       contents, and that these variables are resized at each
 | |
|      *       iteration when we add new hierarchical model.
 | |
|      */
 | |
|     ae_vector_set_length(&kdroots, nh+1, _state);
 | |
|     ae_vector_set_length(&kdnodes, 0, _state);
 | |
|     ae_vector_set_length(&kdsplits, 0, _state);
 | |
|     ae_vector_set_length(&kdboxmin, nx, _state);
 | |
|     ae_vector_set_length(&kdboxmax, nx, _state);
 | |
|     ae_vector_set_length(&cw, 0, _state);
 | |
|     ae_vector_set_length(&cwrange, nh+1, _state);
 | |
|     kdtreeexplorebox(&globaltree, &kdboxmin, &kdboxmax, _state);
 | |
|     cwrange.ptr.p_int[0] = 0;
 | |
|     for(levelidx=0; levelidx<=nh-1; levelidx++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Prepare radius and root offset
 | |
|          */
 | |
|         kdroots.ptr.p_int[levelidx] = kdnodes.cnt;
 | |
|         
 | |
|         /*
 | |
|          * Generate LevelIdx-th tree and append to multi-tree
 | |
|          */
 | |
|         curn = 0;
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             if( hidx.ptr.p_int[i]<=levelidx )
 | |
|             {
 | |
|                 for(j=0; j<=nx-1; j++)
 | |
|                 {
 | |
|                     curxy.ptr.pp_double[curn][j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j];
 | |
|                 }
 | |
|                 for(j=0; j<=ny-1; j++)
 | |
|                 {
 | |
|                     curxy.ptr.pp_double[curn][nx+j] = (double)(0);
 | |
|                 }
 | |
|                 inc(&curn, _state);
 | |
|             }
 | |
|         }
 | |
|         ae_assert(curn>0, "RBFV2BuildHierarchical: integrity check failed", _state);
 | |
|         kdtreebuild(&curxy, curn, nx, ny, 2, &curtree, _state);
 | |
|         rbfv2_convertandappendtree(&curtree, curn, nx, ny, &kdnodes, &kdsplits, &cw, _state);
 | |
|         
 | |
|         /*
 | |
|          * Fill entry of CWRange (we assume that length of CW exactly fits its actual size)
 | |
|          */
 | |
|         cwrange.ptr.p_int[levelidx+1] = cw.cnt;
 | |
|     }
 | |
|     kdroots.ptr.p_int[nh] = kdnodes.cnt;
 | |
|     
 | |
|     /*
 | |
|      * Prepare buffer and scaled dataset
 | |
|      */
 | |
|     rbfv2_allocatecalcbuffer(s, &calcbuf, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             curxy.ptr.pp_double[i][j] = x->ptr.pp_double[i][j]/scalevec->ptr.p_double[j];
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Calculate average row sizes for each layer; these values are used
 | |
|      * for smooth progress reporting (it adds some overhead, but in most
 | |
|      * cases - insignificant one).
 | |
|      */
 | |
|     rvectorsetlengthatleast(&avgrowsize, nh, _state);
 | |
|     sumrowsize = (double)(0);
 | |
|     for(levelidx=0; levelidx<=nh-1; levelidx++)
 | |
|     {
 | |
|         cnt = 0;
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j];
 | |
|             }
 | |
|             cnt = cnt+rbfv2_designmatrixrowsize(&kdnodes, &kdsplits, &cw, &ri, &kdroots, &kdboxmin, &kdboxmax, nx, ny, nh, levelidx, rbfv2nearradius(bf, _state), &x0, &calcbuf, _state);
 | |
|         }
 | |
|         avgrowsize.ptr.p_double[levelidx] = coalesce((double)(cnt), (double)(1), _state)/coalesce((double)(n), (double)(1), _state);
 | |
|         sumrowsize = sumrowsize+avgrowsize.ptr.p_double[levelidx];
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Build unconstrained model with LSQR solver, applied layer by layer
 | |
|      */
 | |
|     for(levelidx=0; levelidx<=nh-1; levelidx++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Generate A - matrix of basis functions (near radius is used)
 | |
|          *
 | |
|          * NOTE: AvgDiagATA is average value of diagonal element of A^T*A.
 | |
|          *       It is used to calculate value of Tikhonov regularization
 | |
|          *       coefficient.
 | |
|          */
 | |
|         nbasis = (cwrange.ptr.p_int[levelidx+1]-cwrange.ptr.p_int[levelidx])/(nx+ny);
 | |
|         ae_assert(cwrange.ptr.p_int[levelidx+1]-cwrange.ptr.p_int[levelidx]==nbasis*(nx+ny), "Assertion failed", _state);
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j];
 | |
|             }
 | |
|             cnt = rbfv2_designmatrixrowsize(&kdnodes, &kdsplits, &cw, &ri, &kdroots, &kdboxmin, &kdboxmax, nx, ny, nh, levelidx, rbfv2nearradius(bf, _state), &x0, &calcbuf, _state);
 | |
|             nncnt.ptr.p_int[i] = cnt;
 | |
|             for(j=0; j<=rowsperpoint-1; j++)
 | |
|             {
 | |
|                 rowsizes.ptr.p_int[i*rowsperpoint+j] = cnt;
 | |
|             }
 | |
|         }
 | |
|         ivectorsetlengthatleast(&rowindexes, nbasis, _state);
 | |
|         rvectorsetlengthatleast(&rowvals, nbasis*rowsperpoint, _state);
 | |
|         rvectorsetlengthatleast(&diagata, nbasis, _state);
 | |
|         sparsecreatecrsbuf(n*rowsperpoint, nbasis, &rowsizes, &sparseacrs, _state);
 | |
|         avgdiagata = 0.0;
 | |
|         for(j=0; j<=nbasis-1; j++)
 | |
|         {
 | |
|             diagata.ptr.p_double[j] = (double)(0);
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Fill design matrix row, diagonal of A^T*A
 | |
|              */
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j];
 | |
|             }
 | |
|             rbfv2_designmatrixgeneraterow(&kdnodes, &kdsplits, &cw, &ri, &kdroots, &kdboxmin, &kdboxmax, &cwrange, nx, ny, nh, levelidx, bf, rbfv2nearradius(bf, _state), rowsperpoint, penalty, &x0, &calcbuf, &vr2, &voffs, &rowindexes, &rowvals, &cnt, _state);
 | |
|             ae_assert(cnt==nncnt.ptr.p_int[i], "RBFV2BuildHierarchical: integrity check failed", _state);
 | |
|             for(k=0; k<=rowsperpoint-1; k++)
 | |
|             {
 | |
|                 for(j=0; j<=cnt-1; j++)
 | |
|                 {
 | |
|                     val = rowvals.ptr.p_double[j*rowsperpoint+k];
 | |
|                     sparseset(&sparseacrs, i*rowsperpoint+k, rowindexes.ptr.p_int[j], val, _state);
 | |
|                     avgdiagata = avgdiagata+ae_sqr(val, _state);
 | |
|                     diagata.ptr.p_double[rowindexes.ptr.p_int[j]] = diagata.ptr.p_double[rowindexes.ptr.p_int[j]]+ae_sqr(val, _state);
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Handle possible termination requests
 | |
|              */
 | |
|             if( *terminationrequest )
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * Request for termination was submitted, terminate immediately
 | |
|                  */
 | |
|                 rbfv2_zerofill(s, nx, ny, bf, _state);
 | |
|                 rep->terminationtype = 8;
 | |
|                 *progress10000 = 10000;
 | |
|                 ae_frame_leave(_state);
 | |
|                 return;
 | |
|             }
 | |
|         }
 | |
|         avgdiagata = avgdiagata/nbasis;
 | |
|         rvectorsetlengthatleast(&prec, nbasis, _state);
 | |
|         for(j=0; j<=nbasis-1; j++)
 | |
|         {
 | |
|             prec.ptr.p_double[j] = 1/coalesce(ae_sqrt(diagata.ptr.p_double[j], _state), (double)(1), _state);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * solve
 | |
|          */
 | |
|         maxits = coalescei(s->maxits, rbfv2_defaultmaxits, _state);
 | |
|         rvectorsetlengthatleast(&tmpx, nbasis, _state);
 | |
|         linlsqrcreate(n*rowsperpoint, nbasis, &linstate, _state);
 | |
|         linlsqrsetcond(&linstate, 0.0, 0.0, maxits, _state);
 | |
|         linlsqrsetlambdai(&linstate, ae_sqrt(s->lambdareg*avgdiagata, _state), _state);
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             for(i=0; i<=n*rowsperpoint-1; i++)
 | |
|             {
 | |
|                 denseb1.ptr.p_double[i] = rhs.ptr.pp_double[i][j];
 | |
|             }
 | |
|             linlsqrsetb(&linstate, &denseb1, _state);
 | |
|             linlsqrrestart(&linstate, _state);
 | |
|             linlsqrsetxrep(&linstate, ae_true, _state);
 | |
|             while(linlsqriteration(&linstate, _state))
 | |
|             {
 | |
|                 if( *terminationrequest )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      * Request for termination was submitted, terminate immediately
 | |
|                      */
 | |
|                     rbfv2_zerofill(s, nx, ny, bf, _state);
 | |
|                     rep->terminationtype = 8;
 | |
|                     *progress10000 = 10000;
 | |
|                     ae_frame_leave(_state);
 | |
|                     return;
 | |
|                 }
 | |
|                 if( linstate.needmv )
 | |
|                 {
 | |
|                     for(i=0; i<=nbasis-1; i++)
 | |
|                     {
 | |
|                         tmpx.ptr.p_double[i] = prec.ptr.p_double[i]*linstate.x.ptr.p_double[i];
 | |
|                     }
 | |
|                     sparsemv(&sparseacrs, &tmpx, &linstate.mv, _state);
 | |
|                     continue;
 | |
|                 }
 | |
|                 if( linstate.needmtv )
 | |
|                 {
 | |
|                     sparsemtv(&sparseacrs, &linstate.x, &linstate.mtv, _state);
 | |
|                     for(i=0; i<=nbasis-1; i++)
 | |
|                     {
 | |
|                         linstate.mtv.ptr.p_double[i] = prec.ptr.p_double[i]*linstate.mtv.ptr.p_double[i];
 | |
|                     }
 | |
|                     continue;
 | |
|                 }
 | |
|                 if( linstate.xupdated )
 | |
|                 {
 | |
|                     rprogress = (double)(0);
 | |
|                     for(i=0; i<=levelidx-1; i++)
 | |
|                     {
 | |
|                         rprogress = rprogress+maxits*ny*avgrowsize.ptr.p_double[i];
 | |
|                     }
 | |
|                     rprogress = rprogress+(linlsqrpeekiterationscount(&linstate, _state)+j*maxits)*avgrowsize.ptr.p_double[levelidx];
 | |
|                     rprogress = rprogress/(sumrowsize*maxits*ny);
 | |
|                     rprogress = 10000*rprogress;
 | |
|                     rprogress = ae_maxreal(rprogress, (double)(0), _state);
 | |
|                     rprogress = ae_minreal(rprogress, (double)(10000), _state);
 | |
|                     ae_assert(*progress10000<=ae_round(rprogress, _state)+1, "HRBF: integrity check failed (progress indicator) even after +1 safeguard correction", _state);
 | |
|                     *progress10000 = ae_round(rprogress, _state);
 | |
|                     continue;
 | |
|                 }
 | |
|                 ae_assert(ae_false, "HRBF: unexpected request from LSQR solver", _state);
 | |
|             }
 | |
|             linlsqrresults(&linstate, &densew1, &lsqrrep, _state);
 | |
|             ae_assert(lsqrrep.terminationtype>0, "RBFV2BuildHierarchical: integrity check failed", _state);
 | |
|             for(i=0; i<=nbasis-1; i++)
 | |
|             {
 | |
|                 densew1.ptr.p_double[i] = prec.ptr.p_double[i]*densew1.ptr.p_double[i];
 | |
|             }
 | |
|             for(i=0; i<=nbasis-1; i++)
 | |
|             {
 | |
|                 offsi = cwrange.ptr.p_int[levelidx]+(nx+ny)*i;
 | |
|                 cw.ptr.p_double[offsi+nx+j] = densew1.ptr.p_double[i];
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Update residuals (far radius is used)
 | |
|          */
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 x0.ptr.p_double[j] = curxy.ptr.pp_double[i][j];
 | |
|             }
 | |
|             rbfv2_designmatrixgeneraterow(&kdnodes, &kdsplits, &cw, &ri, &kdroots, &kdboxmin, &kdboxmax, &cwrange, nx, ny, nh, levelidx, bf, rbfv2farradius(bf, _state), rowsperpoint, penalty, &x0, &calcbuf, &vr2, &voffs, &rowindexes, &rowvals, &cnt, _state);
 | |
|             for(j=0; j<=cnt-1; j++)
 | |
|             {
 | |
|                 offsj = cwrange.ptr.p_int[levelidx]+(nx+ny)*rowindexes.ptr.p_int[j]+nx;
 | |
|                 for(k=0; k<=rowsperpoint-1; k++)
 | |
|                 {
 | |
|                     val = rowvals.ptr.p_double[j*rowsperpoint+k];
 | |
|                     for(k2=0; k2<=ny-1; k2++)
 | |
|                     {
 | |
|                         rhs.ptr.pp_double[i*rowsperpoint+k][k2] = rhs.ptr.pp_double[i*rowsperpoint+k][k2]-val*cw.ptr.p_double[offsj+k2];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Model is built.
 | |
|      *
 | |
|      * Copy local variables by swapping, global ones (ScaleVec) are copied
 | |
|      * explicitly.
 | |
|      */
 | |
|     s->bf = bf;
 | |
|     s->nh = nh;
 | |
|     ae_swap_vectors(&s->ri, &ri);
 | |
|     ae_swap_vectors(&s->kdroots, &kdroots);
 | |
|     ae_swap_vectors(&s->kdnodes, &kdnodes);
 | |
|     ae_swap_vectors(&s->kdsplits, &kdsplits);
 | |
|     ae_swap_vectors(&s->kdboxmin, &kdboxmin);
 | |
|     ae_swap_vectors(&s->kdboxmax, &kdboxmax);
 | |
|     ae_swap_vectors(&s->cw, &cw);
 | |
|     ae_swap_matrices(&s->v, &v);
 | |
|     ae_vector_set_length(&s->s, nx, _state);
 | |
|     for(i=0; i<=nx-1; i++)
 | |
|     {
 | |
|         s->s.ptr.p_double[i] = scalevec->ptr.p_double[i];
 | |
|     }
 | |
|     rep->terminationtype = 1;
 | |
|     
 | |
|     /*
 | |
|      * Calculate maximum and RMS errors
 | |
|      */
 | |
|     rep->maxerror = (double)(0);
 | |
|     rep->rmserror = (double)(0);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(rhs.ptr.pp_double[i*rowsperpoint][j], _state), _state);
 | |
|             rep->rmserror = rep->rmserror+ae_sqr(rhs.ptr.pp_double[i*rowsperpoint][j], _state);
 | |
|         }
 | |
|     }
 | |
|     rep->rmserror = ae_sqrt(rep->rmserror/(n*ny), _state);
 | |
|     
 | |
|     /*
 | |
|      * Update progress reports
 | |
|      */
 | |
|     *progress10000 = 10000;
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: allocation
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.02.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv2alloc(ae_serializer* s, rbfv2model* model, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Data
 | |
|      */
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     allocrealarray(s, &model->ri, -1, _state);
 | |
|     allocrealarray(s, &model->s, -1, _state);
 | |
|     allocintegerarray(s, &model->kdroots, -1, _state);
 | |
|     allocintegerarray(s, &model->kdnodes, -1, _state);
 | |
|     allocrealarray(s, &model->kdsplits, -1, _state);
 | |
|     allocrealarray(s, &model->kdboxmin, -1, _state);
 | |
|     allocrealarray(s, &model->kdboxmax, -1, _state);
 | |
|     allocrealarray(s, &model->cw, -1, _state);
 | |
|     allocrealmatrix(s, &model->v, -1, -1, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: serialization
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.02.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv2serialize(ae_serializer* s, rbfv2model* model, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Data
 | |
|      */
 | |
|     ae_serializer_serialize_int(s, model->nx, _state);
 | |
|     ae_serializer_serialize_int(s, model->ny, _state);
 | |
|     ae_serializer_serialize_int(s, model->nh, _state);
 | |
|     ae_serializer_serialize_int(s, model->bf, _state);
 | |
|     serializerealarray(s, &model->ri, -1, _state);
 | |
|     serializerealarray(s, &model->s, -1, _state);
 | |
|     serializeintegerarray(s, &model->kdroots, -1, _state);
 | |
|     serializeintegerarray(s, &model->kdnodes, -1, _state);
 | |
|     serializerealarray(s, &model->kdsplits, -1, _state);
 | |
|     serializerealarray(s, &model->kdboxmin, -1, _state);
 | |
|     serializerealarray(s, &model->kdboxmax, -1, _state);
 | |
|     serializerealarray(s, &model->cw, -1, _state);
 | |
|     serializerealmatrix(s, &model->v, -1, -1, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: unserialization
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.02.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv2unserialize(ae_serializer* s,
 | |
|      rbfv2model* model,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
| 
 | |
|     _rbfv2model_clear(model);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Unserialize primary model parameters, initialize model.
 | |
|      *
 | |
|      * It is necessary to call RBFCreate() because some internal fields
 | |
|      * which are NOT unserialized will need initialization.
 | |
|      */
 | |
|     ae_serializer_unserialize_int(s, &nx, _state);
 | |
|     ae_serializer_unserialize_int(s, &ny, _state);
 | |
|     rbfv2create(nx, ny, model, _state);
 | |
|     ae_serializer_unserialize_int(s, &model->nh, _state);
 | |
|     ae_serializer_unserialize_int(s, &model->bf, _state);
 | |
|     unserializerealarray(s, &model->ri, _state);
 | |
|     unserializerealarray(s, &model->s, _state);
 | |
|     unserializeintegerarray(s, &model->kdroots, _state);
 | |
|     unserializeintegerarray(s, &model->kdnodes, _state);
 | |
|     unserializerealarray(s, &model->kdsplits, _state);
 | |
|     unserializerealarray(s, &model->kdboxmin, _state);
 | |
|     unserializerealarray(s, &model->kdboxmax, _state);
 | |
|     unserializerealarray(s, &model->cw, _state);
 | |
|     unserializerealmatrix(s, &model->v, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Returns far radius for basis function type
 | |
| *************************************************************************/
 | |
| double rbfv2farradius(ae_int_t bf, ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     result = (double)(1);
 | |
|     if( bf==0 )
 | |
|     {
 | |
|         result = 5.0;
 | |
|     }
 | |
|     if( bf==1 )
 | |
|     {
 | |
|         result = (double)(3);
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Returns near radius for basis function type
 | |
| *************************************************************************/
 | |
| double rbfv2nearradius(ae_int_t bf, ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     result = (double)(1);
 | |
|     if( bf==0 )
 | |
|     {
 | |
|         result = 3.0;
 | |
|     }
 | |
|     if( bf==1 )
 | |
|     {
 | |
|         result = (double)(3);
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Returns basis function value.
 | |
| Assumes that D2>=0
 | |
| *************************************************************************/
 | |
| double rbfv2basisfunc(ae_int_t bf, double d2, ae_state *_state)
 | |
| {
 | |
|     double v;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     result = (double)(0);
 | |
|     if( bf==0 )
 | |
|     {
 | |
|         result = ae_exp(-d2, _state);
 | |
|         return result;
 | |
|     }
 | |
|     if( bf==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * if D2<3:
 | |
|          *     Exp(1)*Exp(-D2)*Exp(-1/(1-D2/9))
 | |
|          * else:
 | |
|          *     0
 | |
|          */
 | |
|         v = 1-d2/9;
 | |
|         if( ae_fp_less_eq(v,(double)(0)) )
 | |
|         {
 | |
|             result = (double)(0);
 | |
|             return result;
 | |
|         }
 | |
|         result = 2.718281828459045*ae_exp(-d2, _state)*ae_exp(-1/v, _state);
 | |
|         return result;
 | |
|     }
 | |
|     ae_assert(ae_false, "RBFV2BasisFunc: unknown BF type", _state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Returns basis function value, first and second derivatives
 | |
| Assumes that D2>=0
 | |
| *************************************************************************/
 | |
| void rbfv2basisfuncdiff2(ae_int_t bf,
 | |
|      double d2,
 | |
|      double* f,
 | |
|      double* df,
 | |
|      double* d2f,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double v;
 | |
| 
 | |
|     *f = 0;
 | |
|     *df = 0;
 | |
|     *d2f = 0;
 | |
| 
 | |
|     if( bf==0 )
 | |
|     {
 | |
|         *f = ae_exp(-d2, _state);
 | |
|         *df = -*f;
 | |
|         *d2f = *f;
 | |
|         return;
 | |
|     }
 | |
|     if( bf==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * if D2<3:
 | |
|          *       F = Exp(1)*Exp(-D2)*Exp(-1/(1-D2/9))
 | |
|          *      dF =  -F * [pow(D2/9-1,-2)/9 + 1]
 | |
|          *     d2F = -dF * [pow(D2/9-1,-2)/9 + 1] + F*(2/81)*pow(D2/9-1,-3)
 | |
|          * else:
 | |
|          *     0
 | |
|          */
 | |
|         v = 1-d2/9;
 | |
|         if( ae_fp_less_eq(v,(double)(0)) )
 | |
|         {
 | |
|             *f = (double)(0);
 | |
|             *df = (double)(0);
 | |
|             *d2f = (double)(0);
 | |
|             return;
 | |
|         }
 | |
|         *f = ae_exp((double)(1), _state)*ae_exp(-d2, _state)*ae_exp(-1/v, _state);
 | |
|         *df = -*f*(1/(9*v*v)+1);
 | |
|         *d2f = -*df*(1/(9*v*v)+1)+*f*((double)2/(double)81)/(v*v*v);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(ae_false, "RBFV2BasisFuncDiff2: unknown BF type", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model in the given point.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=1
 | |
| (1-dimensional space).
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>1
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   X-coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfv2calc1(rbfv2model* s, double x0, ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(x0, _state), "RBFCalc1: invalid value for X0 (X0 is Inf)!", _state);
 | |
|     if( s->ny!=1||s->nx!=1 )
 | |
|     {
 | |
|         result = (double)(0);
 | |
|         return result;
 | |
|     }
 | |
|     result = s->v.ptr.pp_double[0][0]*x0-s->v.ptr.pp_double[0][1];
 | |
|     if( s->nh==0 )
 | |
|     {
 | |
|         return result;
 | |
|     }
 | |
|     rbfv2_allocatecalcbuffer(s, &s->calcbuf, _state);
 | |
|     s->calcbuf.x123.ptr.p_double[0] = x0;
 | |
|     rbfv2tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state);
 | |
|     result = s->calcbuf.y123.ptr.p_double[0];
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model in the given point.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=2
 | |
| (2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If
 | |
| you have general situation (NX-dimensional space, NY-dimensional function)
 | |
| you should use general, less efficient implementation RBFCalc().
 | |
| 
 | |
| If  you  want  to  calculate  function  values  many times, consider using 
 | |
| RBFGridCalc2(), which is far more efficient than many subsequent calls  to
 | |
| RBFCalc2().
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>2
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   first coordinate, finite number
 | |
|     X1      -   second coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfv2calc2(rbfv2model* s, double x0, double x1, ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state);
 | |
|     ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state);
 | |
|     if( s->ny!=1||s->nx!=2 )
 | |
|     {
 | |
|         result = (double)(0);
 | |
|         return result;
 | |
|     }
 | |
|     result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2];
 | |
|     if( s->nh==0 )
 | |
|     {
 | |
|         return result;
 | |
|     }
 | |
|     rbfv2_allocatecalcbuffer(s, &s->calcbuf, _state);
 | |
|     s->calcbuf.x123.ptr.p_double[0] = x0;
 | |
|     s->calcbuf.x123.ptr.p_double[1] = x1;
 | |
|     rbfv2tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state);
 | |
|     result = s->calcbuf.y123.ptr.p_double[0];
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model in the given point.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=3
 | |
| (3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If
 | |
| you have general situation (NX-dimensional space, NY-dimensional function)
 | |
| you should use general, less efficient implementation RBFCalc().
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>3
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   first coordinate, finite number
 | |
|     X1      -   second coordinate, finite number
 | |
|     X2      -   third coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfv2calc3(rbfv2model* s,
 | |
|      double x0,
 | |
|      double x1,
 | |
|      double x2,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state);
 | |
|     ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state);
 | |
|     ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state);
 | |
|     if( s->ny!=1||s->nx!=3 )
 | |
|     {
 | |
|         result = (double)(0);
 | |
|         return result;
 | |
|     }
 | |
|     result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2]*x2+s->v.ptr.pp_double[0][3];
 | |
|     if( s->nh==0 )
 | |
|     {
 | |
|         return result;
 | |
|     }
 | |
|     rbfv2_allocatecalcbuffer(s, &s->calcbuf, _state);
 | |
|     s->calcbuf.x123.ptr.p_double[0] = x0;
 | |
|     s->calcbuf.x123.ptr.p_double[1] = x1;
 | |
|     s->calcbuf.x123.ptr.p_double[2] = x2;
 | |
|     rbfv2tscalcbuf(s, &s->calcbuf, &s->calcbuf.x123, &s->calcbuf.y123, _state);
 | |
|     result = s->calcbuf.y123.ptr.p_double[0];
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the given point.
 | |
| 
 | |
| Same as RBFCalc(), but does not reallocate Y when in is large enough to 
 | |
| store function values.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X       -   coordinates, array[NX].
 | |
|                 X may have more than NX elements, in this case only 
 | |
|                 leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv2calcbuf(rbfv2model* s,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     rbfv2tscalcbuf(s, &s->calcbuf, x, y, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the given point, using
 | |
| external  buffer  object  (internal  temporaries  of  RBF  model  are  not
 | |
| modified).
 | |
| 
 | |
| This function allows to use same RBF model object  in  different  threads,
 | |
| assuming  that  different   threads  use  different  instances  of  buffer
 | |
| structure.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, may be shared between different threads
 | |
|     Buf     -   buffer object created for this particular instance of  RBF
 | |
|                 model with rbfcreatecalcbuffer().
 | |
|     X       -   coordinates, array[NX].
 | |
|                 X may have more than NX elements, in this case only 
 | |
|                 leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv2tscalcbuf(rbfv2model* s,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t levelidx;
 | |
|     double rcur;
 | |
|     double rquery2;
 | |
|     double invrc2;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
| 
 | |
| 
 | |
|     ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)<NX", _state);
 | |
|     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state);
 | |
|     nx = s->nx;
 | |
|     ny = s->ny;
 | |
|     
 | |
|     /*
 | |
|      * Handle linear term
 | |
|      */
 | |
|     if( y->cnt<ny )
 | |
|     {
 | |
|         ae_vector_set_length(y, ny, _state);
 | |
|     }
 | |
|     for(i=0; i<=ny-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[i] = s->v.ptr.pp_double[i][nx];
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j];
 | |
|         }
 | |
|     }
 | |
|     if( s->nh==0 )
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Handle nonlinear term
 | |
|      */
 | |
|     rbfv2_allocatecalcbuffer(s, buf, _state);
 | |
|     for(j=0; j<=nx-1; j++)
 | |
|     {
 | |
|         buf->x.ptr.p_double[j] = x->ptr.p_double[j]/s->s.ptr.p_double[j];
 | |
|     }
 | |
|     for(levelidx=0; levelidx<=s->nh-1; levelidx++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Prepare fields of Buf required by PartialCalcRec()
 | |
|          */
 | |
|         buf->curdist2 = (double)(0);
 | |
|         for(j=0; j<=nx-1; j++)
 | |
|         {
 | |
|             buf->curboxmin.ptr.p_double[j] = s->kdboxmin.ptr.p_double[j];
 | |
|             buf->curboxmax.ptr.p_double[j] = s->kdboxmax.ptr.p_double[j];
 | |
|             if( ae_fp_less(buf->x.ptr.p_double[j],buf->curboxmin.ptr.p_double[j]) )
 | |
|             {
 | |
|                 buf->curdist2 = buf->curdist2+ae_sqr(buf->curboxmin.ptr.p_double[j]-buf->x.ptr.p_double[j], _state);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( ae_fp_greater(buf->x.ptr.p_double[j],buf->curboxmax.ptr.p_double[j]) )
 | |
|                 {
 | |
|                     buf->curdist2 = buf->curdist2+ae_sqr(buf->x.ptr.p_double[j]-buf->curboxmax.ptr.p_double[j], _state);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Call PartialCalcRec()
 | |
|          */
 | |
|         rcur = s->ri.ptr.p_double[levelidx];
 | |
|         invrc2 = 1/(rcur*rcur);
 | |
|         rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state);
 | |
|         rbfv2_partialcalcrec(s, buf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, &buf->x, y, _state);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the regular grid.
 | |
| 
 | |
| Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J])
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>2
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   array of grid nodes, first coordinates, array[N0]
 | |
|     N0      -   grid size (number of nodes) in the first dimension
 | |
|     X1      -   array of grid nodes, second coordinates, array[N1]
 | |
|     N1      -   grid size (number of nodes) in the second dimension
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function values, array[N0,N1]. Y is out-variable and 
 | |
|                 is reallocated by this function.
 | |
|                 
 | |
| NOTE: as a special exception, this function supports unordered  arrays  X0
 | |
|       and X1. However, future versions may be  more  efficient  for  X0/X1
 | |
|       ordered by ascending.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv2gridcalc2(rbfv2model* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector cpx0;
 | |
|     ae_vector cpx1;
 | |
|     ae_vector dummyx2;
 | |
|     ae_vector dummyx3;
 | |
|     ae_vector dummyflag;
 | |
|     ae_vector p01;
 | |
|     ae_vector p11;
 | |
|     ae_vector p2;
 | |
|     ae_vector vy;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&cpx0, 0, sizeof(cpx0));
 | |
|     memset(&cpx1, 0, sizeof(cpx1));
 | |
|     memset(&dummyx2, 0, sizeof(dummyx2));
 | |
|     memset(&dummyx3, 0, sizeof(dummyx3));
 | |
|     memset(&dummyflag, 0, sizeof(dummyflag));
 | |
|     memset(&p01, 0, sizeof(p01));
 | |
|     memset(&p11, 0, sizeof(p11));
 | |
|     memset(&p2, 0, sizeof(p2));
 | |
|     memset(&vy, 0, sizeof(vy));
 | |
|     ae_matrix_clear(y);
 | |
|     ae_vector_init(&cpx0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&cpx1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dummyx2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dummyx3, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dummyflag, 0, DT_BOOL, _state, ae_true);
 | |
|     ae_vector_init(&p01, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&p11, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&vy, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state);
 | |
|     ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state);
 | |
|     ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)<N0", _state);
 | |
|     ae_assert(x1->cnt>=n1, "RBFGridCalc2: Length(X1)<N1", _state);
 | |
|     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2: X0 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2: X1 contains infinite or NaN values!", _state);
 | |
|     ae_matrix_set_length(y, n0, n1, _state);
 | |
|     for(i=0; i<=n0-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=n1-1; j++)
 | |
|         {
 | |
|             y->ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     if( s->ny!=1||s->nx!=2 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      *create and sort arrays
 | |
|      */
 | |
|     ae_vector_set_length(&cpx0, n0, _state);
 | |
|     for(i=0; i<=n0-1; i++)
 | |
|     {
 | |
|         cpx0.ptr.p_double[i] = x0->ptr.p_double[i];
 | |
|     }
 | |
|     tagsort(&cpx0, n0, &p01, &p2, _state);
 | |
|     ae_vector_set_length(&cpx1, n1, _state);
 | |
|     for(i=0; i<=n1-1; i++)
 | |
|     {
 | |
|         cpx1.ptr.p_double[i] = x1->ptr.p_double[i];
 | |
|     }
 | |
|     tagsort(&cpx1, n1, &p11, &p2, _state);
 | |
|     ae_vector_set_length(&dummyx2, 1, _state);
 | |
|     dummyx2.ptr.p_double[0] = (double)(0);
 | |
|     ae_vector_set_length(&dummyx3, 1, _state);
 | |
|     dummyx3.ptr.p_double[0] = (double)(0);
 | |
|     ae_vector_set_length(&vy, n0*n1, _state);
 | |
|     rbfv2gridcalcvx(s, &cpx0, n0, &cpx1, n1, &dummyx2, 1, &dummyx3, 1, &dummyflag, ae_false, &vy, _state);
 | |
|     for(i=0; i<=n0-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=n1-1; j++)
 | |
|         {
 | |
|             y->ptr.pp_double[i][j] = vy.ptr.p_double[i+j*n0];
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is used to perform gridded calculation  for  2D,  3D  or  4D
 | |
| problems. It accepts parameters X0...X3 and counters N0...N3. If RBF model
 | |
| has dimensionality less than 4, corresponding arrays should  contain  just
 | |
| one element equal to zero, and corresponding N's should be equal to 1.
 | |
| 
 | |
| NOTE: array Y should be preallocated by caller.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 12.07.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv2gridcalcvx(rbfv2model* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      ae_int_t n2,
 | |
|      /* Real    */ ae_vector* x3,
 | |
|      ae_int_t n3,
 | |
|      /* Boolean */ ae_vector* flagy,
 | |
|      ae_bool sparsey,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_vector tx;
 | |
|     ae_vector ty;
 | |
|     ae_vector z;
 | |
|     ae_int_t dstoffs;
 | |
|     ae_int_t dummy;
 | |
|     rbfv2gridcalcbuffer bufseedv2;
 | |
|     ae_shared_pool bufpool;
 | |
|     ae_int_t rowidx;
 | |
|     ae_int_t rowcnt;
 | |
|     double v;
 | |
|     double rcur;
 | |
|     ae_int_t levelidx;
 | |
|     double searchradius2;
 | |
|     ae_int_t ntrials;
 | |
|     double avgfuncpernode;
 | |
|     hqrndstate rs;
 | |
|     ae_vector blocks0;
 | |
|     ae_vector blocks1;
 | |
|     ae_vector blocks2;
 | |
|     ae_vector blocks3;
 | |
|     ae_int_t blockscnt0;
 | |
|     ae_int_t blockscnt1;
 | |
|     ae_int_t blockscnt2;
 | |
|     ae_int_t blockscnt3;
 | |
|     double blockwidth0;
 | |
|     double blockwidth1;
 | |
|     double blockwidth2;
 | |
|     double blockwidth3;
 | |
|     ae_int_t maxblocksize;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&tx, 0, sizeof(tx));
 | |
|     memset(&ty, 0, sizeof(ty));
 | |
|     memset(&z, 0, sizeof(z));
 | |
|     memset(&bufseedv2, 0, sizeof(bufseedv2));
 | |
|     memset(&bufpool, 0, sizeof(bufpool));
 | |
|     memset(&rs, 0, sizeof(rs));
 | |
|     memset(&blocks0, 0, sizeof(blocks0));
 | |
|     memset(&blocks1, 0, sizeof(blocks1));
 | |
|     memset(&blocks2, 0, sizeof(blocks2));
 | |
|     memset(&blocks3, 0, sizeof(blocks3));
 | |
|     ae_vector_init(&tx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ty, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&z, 0, DT_REAL, _state, ae_true);
 | |
|     _rbfv2gridcalcbuffer_init(&bufseedv2, _state, ae_true);
 | |
|     ae_shared_pool_init(&bufpool, _state, ae_true);
 | |
|     _hqrndstate_init(&rs, _state, ae_true);
 | |
|     ae_vector_init(&blocks0, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&blocks1, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&blocks2, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&blocks3, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     nx = s->nx;
 | |
|     ny = s->ny;
 | |
|     hqrndseed(532, 54734, &rs, _state);
 | |
|     
 | |
|     /*
 | |
|      * Perform integrity checks
 | |
|      */
 | |
|     ae_assert(s->nx==2||s->nx==3, "RBFGridCalcVX: integrity check failed", _state);
 | |
|     ae_assert(s->nx>=4||((x3->cnt>=1&&ae_fp_eq(x3->ptr.p_double[0],(double)(0)))&&n3==1), "RBFGridCalcVX: integrity check failed", _state);
 | |
|     ae_assert(s->nx>=3||((x2->cnt>=1&&ae_fp_eq(x2->ptr.p_double[0],(double)(0)))&&n2==1), "RBFGridCalcVX: integrity check failed", _state);
 | |
|     ae_assert(s->nx>=2||((x1->cnt>=1&&ae_fp_eq(x1->ptr.p_double[0],(double)(0)))&&n1==1), "RBFGridCalcVX: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Allocate arrays
 | |
|      */
 | |
|     ae_assert(s->nx<=4, "RBFGridCalcVX: integrity check failed", _state);
 | |
|     ae_vector_set_length(&z, ny, _state);
 | |
|     ae_vector_set_length(&tx, 4, _state);
 | |
|     ae_vector_set_length(&ty, ny, _state);
 | |
|     
 | |
|     /*
 | |
|      * Calculate linear term
 | |
|      */
 | |
|     rowcnt = n1*n2*n3;
 | |
|     for(rowidx=0; rowidx<=rowcnt-1; rowidx++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Calculate TX - current position
 | |
|          */
 | |
|         k = rowidx;
 | |
|         tx.ptr.p_double[0] = (double)(0);
 | |
|         tx.ptr.p_double[1] = x1->ptr.p_double[k%n1];
 | |
|         k = k/n1;
 | |
|         tx.ptr.p_double[2] = x2->ptr.p_double[k%n2];
 | |
|         k = k/n2;
 | |
|         tx.ptr.p_double[3] = x3->ptr.p_double[k%n3];
 | |
|         k = k/n3;
 | |
|         ae_assert(k==0, "RBFGridCalcVX: integrity check failed", _state);
 | |
|         for(j=0; j<=ny-1; j++)
 | |
|         {
 | |
|             v = s->v.ptr.pp_double[j][nx];
 | |
|             for(k=1; k<=nx-1; k++)
 | |
|             {
 | |
|                 v = v+tx.ptr.p_double[k]*s->v.ptr.pp_double[j][k];
 | |
|             }
 | |
|             z.ptr.p_double[j] = v;
 | |
|         }
 | |
|         for(i=0; i<=n0-1; i++)
 | |
|         {
 | |
|             dstoffs = ny*(rowidx*n0+i);
 | |
|             if( sparsey&&!flagy->ptr.p_bool[rowidx*n0+i] )
 | |
|             {
 | |
|                 for(j=0; j<=ny-1; j++)
 | |
|                 {
 | |
|                     y->ptr.p_double[j+dstoffs] = (double)(0);
 | |
|                 }
 | |
|                 continue;
 | |
|             }
 | |
|             v = x0->ptr.p_double[i];
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 y->ptr.p_double[j+dstoffs] = z.ptr.p_double[j]+v*s->v.ptr.pp_double[j][0];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if( s->nh==0 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Process RBF terms, layer by layer
 | |
|      */
 | |
|     for(levelidx=0; levelidx<=s->nh-1; levelidx++)
 | |
|     {
 | |
|         rcur = s->ri.ptr.p_double[levelidx];
 | |
|         blockwidth0 = (double)(1);
 | |
|         blockwidth1 = (double)(1);
 | |
|         blockwidth2 = (double)(1);
 | |
|         blockwidth3 = (double)(1);
 | |
|         if( nx>=1 )
 | |
|         {
 | |
|             blockwidth0 = rcur*s->s.ptr.p_double[0];
 | |
|         }
 | |
|         if( nx>=2 )
 | |
|         {
 | |
|             blockwidth1 = rcur*s->s.ptr.p_double[1];
 | |
|         }
 | |
|         if( nx>=3 )
 | |
|         {
 | |
|             blockwidth2 = rcur*s->s.ptr.p_double[2];
 | |
|         }
 | |
|         if( nx>=4 )
 | |
|         {
 | |
|             blockwidth3 = rcur*s->s.ptr.p_double[3];
 | |
|         }
 | |
|         maxblocksize = 8;
 | |
|         
 | |
|         /*
 | |
|          * Group grid nodes into blocks according to current radius
 | |
|          */
 | |
|         ae_vector_set_length(&blocks0, n0+1, _state);
 | |
|         blockscnt0 = 0;
 | |
|         blocks0.ptr.p_int[0] = 0;
 | |
|         for(i=1; i<=n0-1; i++)
 | |
|         {
 | |
|             if( ae_fp_greater(x0->ptr.p_double[i]-x0->ptr.p_double[blocks0.ptr.p_int[blockscnt0]],blockwidth0)||i-blocks0.ptr.p_int[blockscnt0]>=maxblocksize )
 | |
|             {
 | |
|                 inc(&blockscnt0, _state);
 | |
|                 blocks0.ptr.p_int[blockscnt0] = i;
 | |
|             }
 | |
|         }
 | |
|         inc(&blockscnt0, _state);
 | |
|         blocks0.ptr.p_int[blockscnt0] = n0;
 | |
|         ae_vector_set_length(&blocks1, n1+1, _state);
 | |
|         blockscnt1 = 0;
 | |
|         blocks1.ptr.p_int[0] = 0;
 | |
|         for(i=1; i<=n1-1; i++)
 | |
|         {
 | |
|             if( ae_fp_greater(x1->ptr.p_double[i]-x1->ptr.p_double[blocks1.ptr.p_int[blockscnt1]],blockwidth1)||i-blocks1.ptr.p_int[blockscnt1]>=maxblocksize )
 | |
|             {
 | |
|                 inc(&blockscnt1, _state);
 | |
|                 blocks1.ptr.p_int[blockscnt1] = i;
 | |
|             }
 | |
|         }
 | |
|         inc(&blockscnt1, _state);
 | |
|         blocks1.ptr.p_int[blockscnt1] = n1;
 | |
|         ae_vector_set_length(&blocks2, n2+1, _state);
 | |
|         blockscnt2 = 0;
 | |
|         blocks2.ptr.p_int[0] = 0;
 | |
|         for(i=1; i<=n2-1; i++)
 | |
|         {
 | |
|             if( ae_fp_greater(x2->ptr.p_double[i]-x2->ptr.p_double[blocks2.ptr.p_int[blockscnt2]],blockwidth2)||i-blocks2.ptr.p_int[blockscnt2]>=maxblocksize )
 | |
|             {
 | |
|                 inc(&blockscnt2, _state);
 | |
|                 blocks2.ptr.p_int[blockscnt2] = i;
 | |
|             }
 | |
|         }
 | |
|         inc(&blockscnt2, _state);
 | |
|         blocks2.ptr.p_int[blockscnt2] = n2;
 | |
|         ae_vector_set_length(&blocks3, n3+1, _state);
 | |
|         blockscnt3 = 0;
 | |
|         blocks3.ptr.p_int[0] = 0;
 | |
|         for(i=1; i<=n3-1; i++)
 | |
|         {
 | |
|             if( ae_fp_greater(x3->ptr.p_double[i]-x3->ptr.p_double[blocks3.ptr.p_int[blockscnt3]],blockwidth3)||i-blocks3.ptr.p_int[blockscnt3]>=maxblocksize )
 | |
|             {
 | |
|                 inc(&blockscnt3, _state);
 | |
|                 blocks3.ptr.p_int[blockscnt3] = i;
 | |
|             }
 | |
|         }
 | |
|         inc(&blockscnt3, _state);
 | |
|         blocks3.ptr.p_int[blockscnt3] = n3;
 | |
|         
 | |
|         /*
 | |
|          * Prepare seed for shared pool
 | |
|          */
 | |
|         rbfv2_allocatecalcbuffer(s, &bufseedv2.calcbuf, _state);
 | |
|         ae_shared_pool_set_seed(&bufpool, &bufseedv2, sizeof(bufseedv2), _rbfv2gridcalcbuffer_init, _rbfv2gridcalcbuffer_init_copy, _rbfv2gridcalcbuffer_destroy, _state);
 | |
|         
 | |
|         /*
 | |
|          * Determine average number of neighbor per node
 | |
|          */
 | |
|         searchradius2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state);
 | |
|         ntrials = 100;
 | |
|         avgfuncpernode = 0.0;
 | |
|         for(i=0; i<=ntrials-1; i++)
 | |
|         {
 | |
|             tx.ptr.p_double[0] = x0->ptr.p_double[hqrnduniformi(&rs, n0, _state)];
 | |
|             tx.ptr.p_double[1] = x1->ptr.p_double[hqrnduniformi(&rs, n1, _state)];
 | |
|             tx.ptr.p_double[2] = x2->ptr.p_double[hqrnduniformi(&rs, n2, _state)];
 | |
|             tx.ptr.p_double[3] = x3->ptr.p_double[hqrnduniformi(&rs, n3, _state)];
 | |
|             rbfv2_preparepartialquery(&tx, &s->kdboxmin, &s->kdboxmax, nx, &bufseedv2.calcbuf, &dummy, _state);
 | |
|             avgfuncpernode = avgfuncpernode+(double)rbfv2_partialcountrec(&s->kdnodes, &s->kdsplits, &s->cw, nx, ny, &bufseedv2.calcbuf, s->kdroots.ptr.p_int[levelidx], searchradius2, &tx, _state)/(double)ntrials;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Perform calculation in multithreaded mode
 | |
|          */
 | |
|         rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, &blocks0, 0, blockscnt0, &blocks1, 0, blockscnt1, &blocks2, 0, blockscnt2, &blocks3, 0, blockscnt3, flagy, sparsey, levelidx, avgfuncpernode, &bufpool, y, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| void rbfv2partialgridcalcrec(rbfv2model* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      ae_int_t n2,
 | |
|      /* Real    */ ae_vector* x3,
 | |
|      ae_int_t n3,
 | |
|      /* Integer */ ae_vector* blocks0,
 | |
|      ae_int_t block0a,
 | |
|      ae_int_t block0b,
 | |
|      /* Integer */ ae_vector* blocks1,
 | |
|      ae_int_t block1a,
 | |
|      ae_int_t block1b,
 | |
|      /* Integer */ ae_vector* blocks2,
 | |
|      ae_int_t block2a,
 | |
|      ae_int_t block2b,
 | |
|      /* Integer */ ae_vector* blocks3,
 | |
|      ae_int_t block3a,
 | |
|      ae_int_t block3b,
 | |
|      /* Boolean */ ae_vector* flagy,
 | |
|      ae_bool sparsey,
 | |
|      ae_int_t levelidx,
 | |
|      double avgfuncpernode,
 | |
|      ae_shared_pool* bufpool,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
|     ae_int_t k;
 | |
|     ae_int_t l;
 | |
|     ae_int_t blkidx;
 | |
|     ae_int_t blkcnt;
 | |
|     ae_int_t nodeidx;
 | |
|     ae_int_t nodescnt;
 | |
|     ae_int_t rowidx;
 | |
|     ae_int_t rowscnt;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t i1;
 | |
|     ae_int_t i2;
 | |
|     ae_int_t i3;
 | |
|     ae_int_t j0;
 | |
|     ae_int_t j1;
 | |
|     ae_int_t j2;
 | |
|     ae_int_t j3;
 | |
|     double rcur;
 | |
|     double invrc2;
 | |
|     double rquery2;
 | |
|     double rfar2;
 | |
|     ae_int_t dstoffs;
 | |
|     ae_int_t srcoffs;
 | |
|     ae_int_t dummy;
 | |
|     double rowwidth;
 | |
|     double maxrowwidth;
 | |
|     double problemcost;
 | |
|     ae_int_t maxbs;
 | |
|     ae_int_t midpoint;
 | |
|     ae_bool emptyrow;
 | |
|     rbfv2gridcalcbuffer *buf;
 | |
|     ae_smart_ptr _buf;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_buf, 0, sizeof(_buf));
 | |
|     ae_smart_ptr_init(&_buf, (void**)&buf, _state, ae_true);
 | |
| 
 | |
|     nx = s->nx;
 | |
|     ny = s->ny;
 | |
|     
 | |
|     /*
 | |
|      * Integrity checks
 | |
|      */
 | |
|     ae_assert(s->nx==2||s->nx==3, "RBFV2PartialGridCalcRec: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Try to split large problem
 | |
|      */
 | |
|     problemcost = s->ny*2*(avgfuncpernode+1);
 | |
|     problemcost = problemcost*(blocks0->ptr.p_int[block0b]-blocks0->ptr.p_int[block0a]);
 | |
|     problemcost = problemcost*(blocks1->ptr.p_int[block1b]-blocks1->ptr.p_int[block1a]);
 | |
|     problemcost = problemcost*(blocks2->ptr.p_int[block2b]-blocks2->ptr.p_int[block2a]);
 | |
|     problemcost = problemcost*(blocks3->ptr.p_int[block3b]-blocks3->ptr.p_int[block3a]);
 | |
|     maxbs = 0;
 | |
|     maxbs = ae_maxint(maxbs, block0b-block0a, _state);
 | |
|     maxbs = ae_maxint(maxbs, block1b-block1a, _state);
 | |
|     maxbs = ae_maxint(maxbs, block2b-block2a, _state);
 | |
|     maxbs = ae_maxint(maxbs, block3b-block3a, _state);
 | |
|     if( ae_fp_greater_eq(problemcost*rbfv2_complexitymultiplier,smpactivationlevel(_state)) )
 | |
|     {
 | |
|         if( _trypexec_rbfv2partialgridcalcrec(s,x0,n0,x1,n1,x2,n2,x3,n3,blocks0,block0a,block0b,blocks1,block1a,block1b,blocks2,block2a,block2b,blocks3,block3a,block3b,flagy,sparsey,levelidx,avgfuncpernode,bufpool,y, _state) )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     if( ae_fp_greater_eq(problemcost*rbfv2_complexitymultiplier,spawnlevel(_state))&&maxbs>=2 )
 | |
|     {
 | |
|         if( block0b-block0a==maxbs )
 | |
|         {
 | |
|             midpoint = block0a+maxbs/2;
 | |
|             rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, midpoint, blocks1, block1a, block1b, blocks2, block2a, block2b, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state);
 | |
|             rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, midpoint, block0b, blocks1, block1a, block1b, blocks2, block2a, block2b, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state);
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( block1b-block1a==maxbs )
 | |
|         {
 | |
|             midpoint = block1a+maxbs/2;
 | |
|             rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, block1a, midpoint, blocks2, block2a, block2b, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state);
 | |
|             rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, midpoint, block1b, blocks2, block2a, block2b, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state);
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( block2b-block2a==maxbs )
 | |
|         {
 | |
|             midpoint = block2a+maxbs/2;
 | |
|             rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, block2a, midpoint, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state);
 | |
|             rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, midpoint, block2b, blocks3, block3a, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state);
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( block3b-block3a==maxbs )
 | |
|         {
 | |
|             midpoint = block3a+maxbs/2;
 | |
|             rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, block2a, block2b, blocks3, block3a, midpoint, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state);
 | |
|             rbfv2partialgridcalcrec(s, x0, n0, x1, n1, x2, n2, x3, n3, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, block2a, block2b, blocks3, midpoint, block3b, flagy, sparsey, levelidx, avgfuncpernode, bufpool, y, _state);
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         ae_assert(ae_false, "RBFV2PartialGridCalcRec: integrity check failed", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Retrieve buffer object from pool (it will be returned later)
 | |
|      */
 | |
|     ae_shared_pool_retrieve(bufpool, &_buf, _state);
 | |
|     
 | |
|     /*
 | |
|      * Calculate RBF model
 | |
|      */
 | |
|     ae_assert(nx<=4, "RBFV2PartialGridCalcRec: integrity check failed", _state);
 | |
|     ae_vector_set_length(&buf->tx, 4, _state);
 | |
|     ae_vector_set_length(&buf->cx, 4, _state);
 | |
|     ae_vector_set_length(&buf->ty, ny, _state);
 | |
|     rcur = s->ri.ptr.p_double[levelidx];
 | |
|     invrc2 = 1/(rcur*rcur);
 | |
|     blkcnt = (block3b-block3a)*(block2b-block2a)*(block1b-block1a)*(block0b-block0a);
 | |
|     for(blkidx=0; blkidx<=blkcnt-1; blkidx++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Select block (I0,I1,I2,I3).
 | |
|          *
 | |
|          * NOTE: for problems with NX<4 corresponding I_? are zero.
 | |
|          */
 | |
|         k = blkidx;
 | |
|         i0 = block0a+k%(block0b-block0a);
 | |
|         k = k/(block0b-block0a);
 | |
|         i1 = block1a+k%(block1b-block1a);
 | |
|         k = k/(block1b-block1a);
 | |
|         i2 = block2a+k%(block2b-block2a);
 | |
|         k = k/(block2b-block2a);
 | |
|         i3 = block3a+k%(block3b-block3a);
 | |
|         k = k/(block3b-block3a);
 | |
|         ae_assert(k==0, "RBFV2PartialGridCalcRec: integrity check failed", _state);
 | |
|         
 | |
|         /*
 | |
|          * We partitioned grid into blocks and selected block with
 | |
|          * index (I0,I1,I2,I3). This block is a 4D cube (some dimensions
 | |
|          * may be zero) of nodes with indexes (J0,J1,J2,J3), which is
 | |
|          * further partitioned into a set of rows, each row corresponding
 | |
|          * to indexes J1...J3 being fixed.
 | |
|          *
 | |
|          * We process block row by row, and each row may be handled
 | |
|          * by either "generic" (nodes are processed separately) or
 | |
|          * batch algorithm (that's the reason to use rows, after all).
 | |
|          *
 | |
|          *
 | |
|          * Process nodes of the block
 | |
|          */
 | |
|         rowscnt = (blocks3->ptr.p_int[i3+1]-blocks3->ptr.p_int[i3])*(blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2])*(blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1]);
 | |
|         for(rowidx=0; rowidx<=rowscnt-1; rowidx++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Find out node indexes (*,J1,J2,J3).
 | |
|              *
 | |
|              * NOTE: for problems with NX<4 corresponding J_? are zero.
 | |
|              */
 | |
|             k = rowidx;
 | |
|             j1 = blocks1->ptr.p_int[i1]+k%(blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1]);
 | |
|             k = k/(blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1]);
 | |
|             j2 = blocks2->ptr.p_int[i2]+k%(blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2]);
 | |
|             k = k/(blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2]);
 | |
|             j3 = blocks3->ptr.p_int[i3]+k%(blocks3->ptr.p_int[i3+1]-blocks3->ptr.p_int[i3]);
 | |
|             k = k/(blocks3->ptr.p_int[i3+1]-blocks3->ptr.p_int[i3]);
 | |
|             ae_assert(k==0, "RBFV2PartialGridCalcRec: integrity check failed", _state);
 | |
|             
 | |
|             /*
 | |
|              * Analyze row, skip completely empty rows
 | |
|              */
 | |
|             nodescnt = blocks0->ptr.p_int[i0+1]-blocks0->ptr.p_int[i0];
 | |
|             srcoffs = blocks0->ptr.p_int[i0]+(j1+(j2+j3*n2)*n1)*n0;
 | |
|             emptyrow = ae_true;
 | |
|             for(nodeidx=0; nodeidx<=nodescnt-1; nodeidx++)
 | |
|             {
 | |
|                 emptyrow = emptyrow&&(sparsey&&!flagy->ptr.p_bool[srcoffs+nodeidx]);
 | |
|             }
 | |
|             if( emptyrow )
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Process row - use either "batch" (rowsize>1) or "generic"
 | |
|              * (row size is 1) algorithm.
 | |
|              *
 | |
|              * NOTE: "generic" version may also be used as fallback code for
 | |
|              *       situations when we do not want to use batch code.
 | |
|              */
 | |
|             maxrowwidth = 0.5*rbfv2nearradius(s->bf, _state)*rcur*s->s.ptr.p_double[0];
 | |
|             rowwidth = x0->ptr.p_double[blocks0->ptr.p_int[i0+1]-1]-x0->ptr.p_double[blocks0->ptr.p_int[i0]];
 | |
|             if( nodescnt>1&&ae_fp_less_eq(rowwidth,maxrowwidth) )
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * "Batch" code which processes entire row at once, saving
 | |
|                  * some time in kd-tree search code.
 | |
|                  */
 | |
|                 rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state)+0.5*rowwidth/s->s.ptr.p_double[0], _state);
 | |
|                 rfar2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state);
 | |
|                 j0 = blocks0->ptr.p_int[i0];
 | |
|                 if( nx>0 )
 | |
|                 {
 | |
|                     buf->cx.ptr.p_double[0] = (x0->ptr.p_double[j0]+0.5*rowwidth)/s->s.ptr.p_double[0];
 | |
|                 }
 | |
|                 if( nx>1 )
 | |
|                 {
 | |
|                     buf->cx.ptr.p_double[1] = x1->ptr.p_double[j1]/s->s.ptr.p_double[1];
 | |
|                 }
 | |
|                 if( nx>2 )
 | |
|                 {
 | |
|                     buf->cx.ptr.p_double[2] = x2->ptr.p_double[j2]/s->s.ptr.p_double[2];
 | |
|                 }
 | |
|                 if( nx>3 )
 | |
|                 {
 | |
|                     buf->cx.ptr.p_double[3] = x3->ptr.p_double[j3]/s->s.ptr.p_double[3];
 | |
|                 }
 | |
|                 srcoffs = j0+(j1+(j2+j3*n2)*n1)*n0;
 | |
|                 dstoffs = ny*srcoffs;
 | |
|                 rvectorsetlengthatleast(&buf->rx, nodescnt, _state);
 | |
|                 bvectorsetlengthatleast(&buf->rf, nodescnt, _state);
 | |
|                 rvectorsetlengthatleast(&buf->ry, nodescnt*ny, _state);
 | |
|                 for(nodeidx=0; nodeidx<=nodescnt-1; nodeidx++)
 | |
|                 {
 | |
|                     buf->rx.ptr.p_double[nodeidx] = x0->ptr.p_double[j0+nodeidx]/s->s.ptr.p_double[0];
 | |
|                     buf->rf.ptr.p_bool[nodeidx] = !sparsey||flagy->ptr.p_bool[srcoffs+nodeidx];
 | |
|                 }
 | |
|                 for(k=0; k<=nodescnt*ny-1; k++)
 | |
|                 {
 | |
|                     buf->ry.ptr.p_double[k] = (double)(0);
 | |
|                 }
 | |
|                 rbfv2_preparepartialquery(&buf->cx, &s->kdboxmin, &s->kdboxmax, nx, &buf->calcbuf, &dummy, _state);
 | |
|                 rbfv2_partialrowcalcrec(s, &buf->calcbuf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, rfar2, &buf->cx, &buf->rx, &buf->rf, nodescnt, &buf->ry, _state);
 | |
|                 for(k=0; k<=nodescnt*ny-1; k++)
 | |
|                 {
 | |
|                     y->ptr.p_double[dstoffs+k] = y->ptr.p_double[dstoffs+k]+buf->ry.ptr.p_double[k];
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * "Generic" code. Although we usually move here
 | |
|                  * only when NodesCnt=1, we still use a loop on
 | |
|                  * NodeIdx just to be able to use this branch as
 | |
|                  * fallback code without any modifications.
 | |
|                  */
 | |
|                 rquery2 = ae_sqr(rcur*rbfv2farradius(s->bf, _state), _state);
 | |
|                 for(nodeidx=0; nodeidx<=nodescnt-1; nodeidx++)
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      * Prepare TX - current point
 | |
|                      */
 | |
|                     j0 = blocks0->ptr.p_int[i0]+nodeidx;
 | |
|                     if( nx>0 )
 | |
|                     {
 | |
|                         buf->tx.ptr.p_double[0] = x0->ptr.p_double[j0]/s->s.ptr.p_double[0];
 | |
|                     }
 | |
|                     if( nx>1 )
 | |
|                     {
 | |
|                         buf->tx.ptr.p_double[1] = x1->ptr.p_double[j1]/s->s.ptr.p_double[1];
 | |
|                     }
 | |
|                     if( nx>2 )
 | |
|                     {
 | |
|                         buf->tx.ptr.p_double[2] = x2->ptr.p_double[j2]/s->s.ptr.p_double[2];
 | |
|                     }
 | |
|                     if( nx>3 )
 | |
|                     {
 | |
|                         buf->tx.ptr.p_double[3] = x3->ptr.p_double[j3]/s->s.ptr.p_double[3];
 | |
|                     }
 | |
|                     
 | |
|                     /*
 | |
|                      * Evaluate and add to Y
 | |
|                      */
 | |
|                     srcoffs = j0+(j1+(j2+j3*n2)*n1)*n0;
 | |
|                     dstoffs = ny*srcoffs;
 | |
|                     for(l=0; l<=ny-1; l++)
 | |
|                     {
 | |
|                         buf->ty.ptr.p_double[l] = (double)(0);
 | |
|                     }
 | |
|                     if( !sparsey||flagy->ptr.p_bool[srcoffs] )
 | |
|                     {
 | |
|                         rbfv2_preparepartialquery(&buf->tx, &s->kdboxmin, &s->kdboxmax, nx, &buf->calcbuf, &dummy, _state);
 | |
|                         rbfv2_partialcalcrec(s, &buf->calcbuf, s->kdroots.ptr.p_int[levelidx], invrc2, rquery2, &buf->tx, &buf->ty, _state);
 | |
|                     }
 | |
|                     for(l=0; l<=ny-1; l++)
 | |
|                     {
 | |
|                         y->ptr.p_double[dstoffs+l] = y->ptr.p_double[dstoffs+l]+buf->ty.ptr.p_double[l];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Recycle buffer object back to pool
 | |
|      */
 | |
|     ae_shared_pool_recycle(bufpool, &_buf, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serial stub for GPL edition.
 | |
| *************************************************************************/
 | |
| ae_bool _trypexec_rbfv2partialgridcalcrec(rbfv2model* s,
 | |
|     /* Real    */ ae_vector* x0,
 | |
|     ae_int_t n0,
 | |
|     /* Real    */ ae_vector* x1,
 | |
|     ae_int_t n1,
 | |
|     /* Real    */ ae_vector* x2,
 | |
|     ae_int_t n2,
 | |
|     /* Real    */ ae_vector* x3,
 | |
|     ae_int_t n3,
 | |
|     /* Integer */ ae_vector* blocks0,
 | |
|     ae_int_t block0a,
 | |
|     ae_int_t block0b,
 | |
|     /* Integer */ ae_vector* blocks1,
 | |
|     ae_int_t block1a,
 | |
|     ae_int_t block1b,
 | |
|     /* Integer */ ae_vector* blocks2,
 | |
|     ae_int_t block2a,
 | |
|     ae_int_t block2b,
 | |
|     /* Integer */ ae_vector* blocks3,
 | |
|     ae_int_t block3a,
 | |
|     ae_int_t block3b,
 | |
|     /* Boolean */ ae_vector* flagy,
 | |
|     ae_bool sparsey,
 | |
|     ae_int_t levelidx,
 | |
|     double avgfuncpernode,
 | |
|     ae_shared_pool* bufpool,
 | |
|     /* Real    */ ae_vector* y,
 | |
|     ae_state *_state)
 | |
| {
 | |
|     return ae_false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function "unpacks" RBF model by extracting its coefficients.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     NX      -   dimensionality of argument
 | |
|     NY      -   dimensionality of the target function
 | |
|     XWR     -   model information, array[NC,NX+NY+1].
 | |
|                 One row of the array corresponds to one basis function:
 | |
|                 * first NX columns  - coordinates of the center 
 | |
|                 * next NY columns   - weights, one per dimension of the 
 | |
|                                       function being modelled
 | |
|                 * last NX columns   - radii, per dimension
 | |
|     NC      -   number of the centers
 | |
|     V       -   polynomial  term , array[NY,NX+1]. One row per one 
 | |
|                 dimension of the function being modelled. First NX 
 | |
|                 elements are linear coefficients, V[NX] is equal to the 
 | |
|                 constant part.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv2unpack(rbfv2model* s,
 | |
|      ae_int_t* nx,
 | |
|      ae_int_t* ny,
 | |
|      /* Real    */ ae_matrix* xwr,
 | |
|      ae_int_t* nc,
 | |
|      /* Real    */ ae_matrix* v,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t ncactual;
 | |
| 
 | |
|     *nx = 0;
 | |
|     *ny = 0;
 | |
|     ae_matrix_clear(xwr);
 | |
|     *nc = 0;
 | |
|     ae_matrix_clear(v);
 | |
| 
 | |
|     *nx = s->nx;
 | |
|     *ny = s->ny;
 | |
|     *nc = 0;
 | |
|     
 | |
|     /*
 | |
|      * Fill V
 | |
|      */
 | |
|     ae_matrix_set_length(v, s->ny, s->nx+1, _state);
 | |
|     for(i=0; i<=s->ny-1; i++)
 | |
|     {
 | |
|         ae_v_move(&v->ptr.pp_double[i][0], 1, &s->v.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx));
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Fill XWR
 | |
|      */
 | |
|     ae_assert(s->cw.cnt%(s->nx+s->ny)==0, "RBFV2Unpack: integrity error", _state);
 | |
|     *nc = s->cw.cnt/(s->nx+s->ny);
 | |
|     ncactual = 0;
 | |
|     if( *nc>0 )
 | |
|     {
 | |
|         ae_matrix_set_length(xwr, *nc, s->nx+s->ny+s->nx, _state);
 | |
|         for(i=0; i<=s->nh-1; i++)
 | |
|         {
 | |
|             rbfv2_partialunpackrec(&s->kdnodes, &s->kdsplits, &s->cw, &s->s, s->nx, s->ny, s->kdroots.ptr.p_int[i], s->ri.ptr.p_double[i], xwr, &ncactual, _state);
 | |
|         }
 | |
|     }
 | |
|     ae_assert(*nc==ncactual, "RBFV2Unpack: integrity error", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| static ae_bool rbfv2_rbfv2buildlinearmodel(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t modeltype,
 | |
|      /* Real    */ ae_matrix* v,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector tmpy;
 | |
|     ae_matrix a;
 | |
|     double scaling;
 | |
|     ae_vector shifting;
 | |
|     double mn;
 | |
|     double mx;
 | |
|     ae_vector c;
 | |
|     lsfitreport rep;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t info;
 | |
|     ae_bool result;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&tmpy, 0, sizeof(tmpy));
 | |
|     memset(&a, 0, sizeof(a));
 | |
|     memset(&shifting, 0, sizeof(shifting));
 | |
|     memset(&c, 0, sizeof(c));
 | |
|     memset(&rep, 0, sizeof(rep));
 | |
|     ae_matrix_clear(v);
 | |
|     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&shifting, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&c, 0, DT_REAL, _state, ae_true);
 | |
|     _lsfitreport_init(&rep, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=0, "BuildLinearModel: N<0", _state);
 | |
|     ae_assert(nx>0, "BuildLinearModel: NX<=0", _state);
 | |
|     ae_assert(ny>0, "BuildLinearModel: NY<=0", _state);
 | |
|     
 | |
|     /*
 | |
|      * Handle degenerate case (N=0)
 | |
|      */
 | |
|     result = ae_true;
 | |
|     ae_matrix_set_length(v, ny, nx+1, _state);
 | |
|     if( n==0 )
 | |
|     {
 | |
|         for(j=0; j<=nx; j++)
 | |
|         {
 | |
|             for(i=0; i<=ny-1; i++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][j] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Allocate temporaries
 | |
|      */
 | |
|     ae_vector_set_length(&tmpy, n, _state);
 | |
|     
 | |
|     /*
 | |
|      * General linear model.
 | |
|      */
 | |
|     if( modeltype==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Calculate scaling/shifting, transform variables, prepare LLS problem
 | |
|          */
 | |
|         ae_matrix_set_length(&a, n, nx+1, _state);
 | |
|         ae_vector_set_length(&shifting, nx, _state);
 | |
|         scaling = (double)(0);
 | |
|         for(i=0; i<=nx-1; i++)
 | |
|         {
 | |
|             mn = x->ptr.pp_double[0][i];
 | |
|             mx = mn;
 | |
|             for(j=1; j<=n-1; j++)
 | |
|             {
 | |
|                 if( ae_fp_greater(mn,x->ptr.pp_double[j][i]) )
 | |
|                 {
 | |
|                     mn = x->ptr.pp_double[j][i];
 | |
|                 }
 | |
|                 if( ae_fp_less(mx,x->ptr.pp_double[j][i]) )
 | |
|                 {
 | |
|                     mx = x->ptr.pp_double[j][i];
 | |
|                 }
 | |
|             }
 | |
|             scaling = ae_maxreal(scaling, mx-mn, _state);
 | |
|             shifting.ptr.p_double[i] = 0.5*(mx+mn);
 | |
|         }
 | |
|         if( ae_fp_eq(scaling,(double)(0)) )
 | |
|         {
 | |
|             scaling = (double)(1);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             scaling = 0.5*scaling;
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 a.ptr.pp_double[i][j] = (x->ptr.pp_double[i][j]-shifting.ptr.p_double[j])/scaling;
 | |
|             }
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             a.ptr.pp_double[i][nx] = (double)(1);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Solve linear system in transformed variables, make backward 
 | |
|          */
 | |
|         for(i=0; i<=ny-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i];
 | |
|             }
 | |
|             lsfitlinear(&tmpy, &a, n, nx+1, &info, &c, &rep, _state);
 | |
|             if( info<=0 )
 | |
|             {
 | |
|                 result = ae_false;
 | |
|                 ae_frame_leave(_state);
 | |
|                 return result;
 | |
|             }
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][j] = c.ptr.p_double[j]/scaling;
 | |
|             }
 | |
|             v->ptr.pp_double[i][nx] = c.ptr.p_double[nx];
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][nx] = v->ptr.pp_double[i][nx]-shifting.ptr.p_double[j]*v->ptr.pp_double[i][j];
 | |
|             }
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 for(k=0; k<=nx-1; k++)
 | |
|                 {
 | |
|                     y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-x->ptr.pp_double[j][k]*v->ptr.pp_double[i][k];
 | |
|                 }
 | |
|                 y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][nx];
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Constant model, very simple
 | |
|      */
 | |
|     if( modeltype==2 )
 | |
|     {
 | |
|         for(i=0; i<=ny-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][j] = (double)(0);
 | |
|             }
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][nx] = v->ptr.pp_double[i][nx]+y->ptr.pp_double[j][i];
 | |
|             }
 | |
|             if( n>0 )
 | |
|             {
 | |
|                 v->ptr.pp_double[i][nx] = v->ptr.pp_double[i][nx]/n;
 | |
|             }
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][nx];
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Zero model
 | |
|      */
 | |
|     ae_assert(modeltype==3, "BuildLinearModel: unknown model type", _state);
 | |
|     for(i=0; i<=ny-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx; j++)
 | |
|         {
 | |
|             v->ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Reallocates calcBuf if necessary, reuses previously allocated space if
 | |
| possible.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Sergey Bochkanov
 | |
| *************************************************************************/
 | |
| static void rbfv2_allocatecalcbuffer(rbfv2model* s,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     if( buf->x.cnt<s->nx )
 | |
|     {
 | |
|         ae_vector_set_length(&buf->x, s->nx, _state);
 | |
|     }
 | |
|     if( buf->curboxmin.cnt<s->nx )
 | |
|     {
 | |
|         ae_vector_set_length(&buf->curboxmin, s->nx, _state);
 | |
|     }
 | |
|     if( buf->curboxmax.cnt<s->nx )
 | |
|     {
 | |
|         ae_vector_set_length(&buf->curboxmax, s->nx, _state);
 | |
|     }
 | |
|     if( buf->x123.cnt<s->nx )
 | |
|     {
 | |
|         ae_vector_set_length(&buf->x123, s->nx, _state);
 | |
|     }
 | |
|     if( buf->y123.cnt<s->ny )
 | |
|     {
 | |
|         ae_vector_set_length(&buf->y123, s->ny, _state);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Extracts structure (and XY-values too) from  kd-tree  built  for  a  small
 | |
| subset of points and appends it to multi-tree.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Sergey Bochkanov
 | |
| *************************************************************************/
 | |
| static void rbfv2_convertandappendtree(kdtree* curtree,
 | |
|      ae_int_t n,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      /* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t nodesbase;
 | |
|     ae_int_t splitsbase;
 | |
|     ae_int_t cwbase;
 | |
|     ae_vector localnodes;
 | |
|     ae_vector localsplits;
 | |
|     ae_vector localcw;
 | |
|     ae_matrix xybuf;
 | |
|     ae_int_t localnodessize;
 | |
|     ae_int_t localsplitssize;
 | |
|     ae_int_t localcwsize;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&localnodes, 0, sizeof(localnodes));
 | |
|     memset(&localsplits, 0, sizeof(localsplits));
 | |
|     memset(&localcw, 0, sizeof(localcw));
 | |
|     memset(&xybuf, 0, sizeof(xybuf));
 | |
|     ae_vector_init(&localnodes, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&localsplits, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&localcw, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&xybuf, 0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Calculate base offsets
 | |
|      */
 | |
|     nodesbase = kdnodes->cnt;
 | |
|     splitsbase = kdsplits->cnt;
 | |
|     cwbase = cw->cnt;
 | |
|     
 | |
|     /*
 | |
|      * Prepare local copy of tree
 | |
|      */
 | |
|     ae_vector_set_length(&localnodes, n*rbfv2_maxnodesize, _state);
 | |
|     ae_vector_set_length(&localsplits, n, _state);
 | |
|     ae_vector_set_length(&localcw, (nx+ny)*n, _state);
 | |
|     localnodessize = 0;
 | |
|     localsplitssize = 0;
 | |
|     localcwsize = 0;
 | |
|     rbfv2_converttreerec(curtree, n, nx, ny, 0, nodesbase, splitsbase, cwbase, &localnodes, &localnodessize, &localsplits, &localsplitssize, &localcw, &localcwsize, &xybuf, _state);
 | |
|     
 | |
|     /*
 | |
|      * Append to multi-tree
 | |
|      */
 | |
|     ivectorresize(kdnodes, kdnodes->cnt+localnodessize, _state);
 | |
|     rvectorresize(kdsplits, kdsplits->cnt+localsplitssize, _state);
 | |
|     rvectorresize(cw, cw->cnt+localcwsize, _state);
 | |
|     for(i=0; i<=localnodessize-1; i++)
 | |
|     {
 | |
|         kdnodes->ptr.p_int[nodesbase+i] = localnodes.ptr.p_int[i];
 | |
|     }
 | |
|     for(i=0; i<=localsplitssize-1; i++)
 | |
|     {
 | |
|         kdsplits->ptr.p_double[splitsbase+i] = localsplits.ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=localcwsize-1; i++)
 | |
|     {
 | |
|         cw->ptr.p_double[cwbase+i] = localcw.ptr.p_double[i];
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Recurrent tree conversion
 | |
| 
 | |
|     CurTree         -   tree to convert
 | |
|     N, NX, NY       -   dataset metrics
 | |
|     NodeOffset      -   offset of current tree node, 0 for root
 | |
|     NodesBase       -   a value which is added to intra-tree node indexes;
 | |
|                         although this tree is stored in separate array, it
 | |
|                         is intended to be stored in the larger tree,  with
 | |
|                         localNodes being moved to offset NodesBase.
 | |
|     SplitsBase      -   similarly, offset of localSplits in the final tree
 | |
|     CWBase          -   similarly, offset of localCW in the final tree
 | |
| *************************************************************************/
 | |
| static void rbfv2_converttreerec(kdtree* curtree,
 | |
|      ae_int_t n,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t nodeoffset,
 | |
|      ae_int_t nodesbase,
 | |
|      ae_int_t splitsbase,
 | |
|      ae_int_t cwbase,
 | |
|      /* Integer */ ae_vector* localnodes,
 | |
|      ae_int_t* localnodessize,
 | |
|      /* Real    */ ae_vector* localsplits,
 | |
|      ae_int_t* localsplitssize,
 | |
|      /* Real    */ ae_vector* localcw,
 | |
|      ae_int_t* localcwsize,
 | |
|      /* Real    */ ae_matrix* xybuf,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t nodetype;
 | |
|     ae_int_t cnt;
 | |
|     ae_int_t d;
 | |
|     double s;
 | |
|     ae_int_t nodele;
 | |
|     ae_int_t nodege;
 | |
|     ae_int_t oldnodessize;
 | |
| 
 | |
| 
 | |
|     kdtreeexplorenodetype(curtree, nodeoffset, &nodetype, _state);
 | |
|     
 | |
|     /*
 | |
|      * Leaf node
 | |
|      */
 | |
|     if( nodetype==0 )
 | |
|     {
 | |
|         kdtreeexploreleaf(curtree, nodeoffset, xybuf, &cnt, _state);
 | |
|         ae_assert(localnodes->cnt>=*localnodessize+2, "ConvertTreeRec: integrity check failed", _state);
 | |
|         ae_assert(localcw->cnt>=*localcwsize+cnt*(nx+ny), "ConvertTreeRec: integrity check failed", _state);
 | |
|         localnodes->ptr.p_int[*localnodessize+0] = cnt;
 | |
|         localnodes->ptr.p_int[*localnodessize+1] = cwbase+(*localcwsize);
 | |
|         *localnodessize = *localnodessize+2;
 | |
|         for(i=0; i<=cnt-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=nx+ny-1; j++)
 | |
|             {
 | |
|                 localcw->ptr.p_double[*localcwsize+i*(nx+ny)+j] = xybuf->ptr.pp_double[i][j];
 | |
|             }
 | |
|         }
 | |
|         *localcwsize = *localcwsize+cnt*(nx+ny);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Split node
 | |
|      */
 | |
|     if( nodetype==1 )
 | |
|     {
 | |
|         kdtreeexploresplit(curtree, nodeoffset, &d, &s, &nodele, &nodege, _state);
 | |
|         ae_assert(localnodes->cnt>=*localnodessize+rbfv2_maxnodesize, "ConvertTreeRec: integrity check failed", _state);
 | |
|         ae_assert(localsplits->cnt>=*localsplitssize+1, "ConvertTreeRec: integrity check failed", _state);
 | |
|         oldnodessize = *localnodessize;
 | |
|         localnodes->ptr.p_int[*localnodessize+0] = 0;
 | |
|         localnodes->ptr.p_int[*localnodessize+1] = d;
 | |
|         localnodes->ptr.p_int[*localnodessize+2] = splitsbase+(*localsplitssize);
 | |
|         localnodes->ptr.p_int[*localnodessize+3] = -1;
 | |
|         localnodes->ptr.p_int[*localnodessize+4] = -1;
 | |
|         *localnodessize = *localnodessize+5;
 | |
|         localsplits->ptr.p_double[*localsplitssize+0] = s;
 | |
|         *localsplitssize = *localsplitssize+1;
 | |
|         localnodes->ptr.p_int[oldnodessize+3] = nodesbase+(*localnodessize);
 | |
|         rbfv2_converttreerec(curtree, n, nx, ny, nodele, nodesbase, splitsbase, cwbase, localnodes, localnodessize, localsplits, localsplitssize, localcw, localcwsize, xybuf, _state);
 | |
|         localnodes->ptr.p_int[oldnodessize+4] = nodesbase+(*localnodessize);
 | |
|         rbfv2_converttreerec(curtree, n, nx, ny, nodege, nodesbase, splitsbase, cwbase, localnodes, localnodessize, localsplits, localsplitssize, localcw, localcwsize, xybuf, _state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Integrity error
 | |
|      */
 | |
|     ae_assert(ae_false, "ConvertTreeRec: integrity check failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs partial calculation of  hierarchical  model:  given
 | |
| evaluation point X and partially computed value Y, it updates Y by  values
 | |
| computed using part of multi-tree given by RootIdx.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   V2 model
 | |
|     Buf     -   calc-buffer, this function uses following fields:
 | |
|                 * Buf.CurBoxMin - should be set by caller
 | |
|                 * Buf.CurBoxMax - should be set by caller
 | |
|                 * Buf.CurDist2  - squared distance from X to current bounding box,
 | |
|                   should be set by caller
 | |
|     RootIdx -   offset of partial kd-tree
 | |
|     InvR2   -   1/R^2, where R is basis function radius
 | |
|     QueryR2 -   squared query radius, usually it is (R*FarRadius(BasisFunction))^2
 | |
|     X       -   evaluation point, array[NX]
 | |
|     Y       -   partial value, array[NY]
 | |
|     
 | |
| OUTPUT PARAMETERS
 | |
|     Y       -   updated partial value
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbfv2_partialcalcrec(rbfv2model* s,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_int_t rootidx,
 | |
|      double invr2,
 | |
|      double queryr2,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double ptdist2;
 | |
|     double v;
 | |
|     double v0;
 | |
|     double v1;
 | |
|     ae_int_t cwoffs;
 | |
|     ae_int_t cwcnt;
 | |
|     ae_int_t itemoffs;
 | |
|     double arg;
 | |
|     double val;
 | |
|     ae_int_t d;
 | |
|     double split;
 | |
|     ae_int_t childle;
 | |
|     ae_int_t childge;
 | |
|     ae_int_t childoffs;
 | |
|     ae_bool updatemin;
 | |
|     double prevdist2;
 | |
|     double t1;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
| 
 | |
| 
 | |
|     nx = s->nx;
 | |
|     ny = s->ny;
 | |
|     
 | |
|     /*
 | |
|      * Helps to avoid spurious warnings
 | |
|      */
 | |
|     val = (double)(0);
 | |
|     
 | |
|     /*
 | |
|      * Leaf node.
 | |
|      */
 | |
|     if( s->kdnodes.ptr.p_int[rootidx]>0 )
 | |
|     {
 | |
|         cwcnt = s->kdnodes.ptr.p_int[rootidx+0];
 | |
|         cwoffs = s->kdnodes.ptr.p_int[rootidx+1];
 | |
|         for(i=0; i<=cwcnt-1; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Calculate distance
 | |
|              */
 | |
|             itemoffs = cwoffs+i*(nx+ny);
 | |
|             ptdist2 = (double)(0);
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 v = s->cw.ptr.p_double[itemoffs+j]-x->ptr.p_double[j];
 | |
|                 ptdist2 = ptdist2+v*v;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Skip points if distance too large
 | |
|              */
 | |
|             if( ptdist2>=queryr2 )
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Update Y
 | |
|              */
 | |
|             arg = ptdist2*invr2;
 | |
|             if( s->bf==0 )
 | |
|             {
 | |
|                 val = ae_exp(-arg, _state);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if( s->bf==1 )
 | |
|                 {
 | |
|                     val = rbfv2basisfunc(s->bf, arg, _state);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state);
 | |
|                 }
 | |
|             }
 | |
|             itemoffs = itemoffs+nx;
 | |
|             for(j=0; j<=ny-1; j++)
 | |
|             {
 | |
|                 y->ptr.p_double[j] = y->ptr.p_double[j]+val*s->cw.ptr.p_double[itemoffs+j];
 | |
|             }
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Simple split
 | |
|      */
 | |
|     if( s->kdnodes.ptr.p_int[rootidx]==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Load:
 | |
|          * * D      dimension to split
 | |
|          * * Split  split position
 | |
|          * * ChildLE, ChildGE - indexes of childs
 | |
|          */
 | |
|         d = s->kdnodes.ptr.p_int[rootidx+1];
 | |
|         split = s->kdsplits.ptr.p_double[s->kdnodes.ptr.p_int[rootidx+2]];
 | |
|         childle = s->kdnodes.ptr.p_int[rootidx+3];
 | |
|         childge = s->kdnodes.ptr.p_int[rootidx+4];
 | |
|         
 | |
|         /*
 | |
|          * Navigate through childs
 | |
|          */
 | |
|         for(i=0; i<=1; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Select child to process:
 | |
|              * * ChildOffs      current child offset in Nodes[]
 | |
|              * * UpdateMin      whether minimum or maximum value
 | |
|              *                  of bounding box is changed on update
 | |
|              */
 | |
|             updatemin = i!=0;
 | |
|             if( i==0 )
 | |
|             {
 | |
|                 childoffs = childle;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 childoffs = childge;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Update bounding box and current distance
 | |
|              */
 | |
|             prevdist2 = buf->curdist2;
 | |
|             t1 = x->ptr.p_double[d];
 | |
|             if( updatemin )
 | |
|             {
 | |
|                 v = buf->curboxmin.ptr.p_double[d];
 | |
|                 if( t1<=split )
 | |
|                 {
 | |
|                     v0 = v-t1;
 | |
|                     if( v0<0 )
 | |
|                     {
 | |
|                         v0 = (double)(0);
 | |
|                     }
 | |
|                     v1 = split-t1;
 | |
|                     buf->curdist2 = buf->curdist2-v0*v0+v1*v1;
 | |
|                 }
 | |
|                 buf->curboxmin.ptr.p_double[d] = split;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 v = buf->curboxmax.ptr.p_double[d];
 | |
|                 if( t1>=split )
 | |
|                 {
 | |
|                     v0 = t1-v;
 | |
|                     if( v0<0 )
 | |
|                     {
 | |
|                         v0 = (double)(0);
 | |
|                     }
 | |
|                     v1 = t1-split;
 | |
|                     buf->curdist2 = buf->curdist2-v0*v0+v1*v1;
 | |
|                 }
 | |
|                 buf->curboxmax.ptr.p_double[d] = split;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Decide: to dive into cell or not to dive
 | |
|              */
 | |
|             if( buf->curdist2<queryr2 )
 | |
|             {
 | |
|                 rbfv2_partialcalcrec(s, buf, childoffs, invr2, queryr2, x, y, _state);
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Restore bounding box and distance
 | |
|              */
 | |
|             if( updatemin )
 | |
|             {
 | |
|                 buf->curboxmin.ptr.p_double[d] = v;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 buf->curboxmax.ptr.p_double[d] = v;
 | |
|             }
 | |
|             buf->curdist2 = prevdist2;
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Integrity failure
 | |
|      */
 | |
|     ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs same operation as partialcalcrec(), but  for entire
 | |
| row of the grid. "Row" is a set of nodes (x0,x1,x2,x3) which share x1..x3,
 | |
| but have different x0's. (note: for 2D/3D problems x2..x3 are zero).
 | |
| 
 | |
| Row is given by:
 | |
| * central point XC, which is located at the center of the row, and used to
 | |
|   perform kd-tree requests
 | |
| * set of x0 coordinates stored in RX array (array may be unordered, but it
 | |
|   is expected that spread of x0  is  no  more  than  R;  function  may  be
 | |
|   inefficient for larger spreads).
 | |
| * set of YFlag values stored in RF
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   V2 model
 | |
|     Buf     -   calc-buffer, this function uses following fields:
 | |
|                 * Buf.CurBoxMin - should be set by caller
 | |
|                 * Buf.CurBoxMax - should be set by caller
 | |
|                 * Buf.CurDist2  - squared distance from X to current bounding box,
 | |
|                   should be set by caller
 | |
|     RootIdx -   offset of partial kd-tree
 | |
|     InvR2   -   1/R^2, where R is basis function radius
 | |
|     RQuery2 -   squared query radius, usually it is (R*FarRadius(BasisFunction)+0.5*RowWidth)^2,
 | |
|                 where RowWidth is its spatial  extent  (after  scaling  of
 | |
|                 variables). This radius is used to perform  initial  query
 | |
|                 for neighbors of CX.
 | |
|     RFar2   -   squared far radius; far radius is used to perform actual
 | |
|                 filtering of results of query made with RQuery2.
 | |
|     CX      -   central point, array[NX], used for queries
 | |
|     RX      -   x0 coordinates, array[RowSize]
 | |
|     RF      -   sparsity flags, array[RowSize]
 | |
|     RowSize -   row size in elements
 | |
|     RY      -   input partial value, array[NY]
 | |
|     
 | |
| OUTPUT PARAMETERS
 | |
|     RY      -   updated partial value (function adds its results to RY)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbfv2_partialrowcalcrec(rbfv2model* s,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_int_t rootidx,
 | |
|      double invr2,
 | |
|      double rquery2,
 | |
|      double rfar2,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      /* Real    */ ae_vector* rx,
 | |
|      /* Boolean */ ae_vector* rf,
 | |
|      ae_int_t rowsize,
 | |
|      /* Real    */ ae_vector* ry,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t i1;
 | |
|     double partialptdist2;
 | |
|     double ptdist2;
 | |
|     double v;
 | |
|     double v0;
 | |
|     double v1;
 | |
|     ae_int_t cwoffs;
 | |
|     ae_int_t cwcnt;
 | |
|     ae_int_t itemoffs;
 | |
|     ae_int_t woffs;
 | |
|     double val;
 | |
|     ae_int_t d;
 | |
|     double split;
 | |
|     ae_int_t childle;
 | |
|     ae_int_t childge;
 | |
|     ae_int_t childoffs;
 | |
|     ae_bool updatemin;
 | |
|     double prevdist2;
 | |
|     double t1;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
| 
 | |
| 
 | |
|     nx = s->nx;
 | |
|     ny = s->ny;
 | |
|     
 | |
|     /*
 | |
|      * Leaf node.
 | |
|      */
 | |
|     if( s->kdnodes.ptr.p_int[rootidx]>0 )
 | |
|     {
 | |
|         cwcnt = s->kdnodes.ptr.p_int[rootidx+0];
 | |
|         cwoffs = s->kdnodes.ptr.p_int[rootidx+1];
 | |
|         for(i0=0; i0<=cwcnt-1; i0++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Calculate partial distance (components from 1 to NX-1)
 | |
|              */
 | |
|             itemoffs = cwoffs+i0*(nx+ny);
 | |
|             partialptdist2 = (double)(0);
 | |
|             for(j=1; j<=nx-1; j++)
 | |
|             {
 | |
|                 v = s->cw.ptr.p_double[itemoffs+j]-cx->ptr.p_double[j];
 | |
|                 partialptdist2 = partialptdist2+v*v;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Process each element of the row
 | |
|              */
 | |
|             for(i1=0; i1<=rowsize-1; i1++)
 | |
|             {
 | |
|                 if( rf->ptr.p_bool[i1] )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      * Calculate distance
 | |
|                      */
 | |
|                     v = s->cw.ptr.p_double[itemoffs]-rx->ptr.p_double[i1];
 | |
|                     ptdist2 = partialptdist2+v*v;
 | |
|                     
 | |
|                     /*
 | |
|                      * Skip points if distance too large
 | |
|                      */
 | |
|                     if( ptdist2>=rfar2 )
 | |
|                     {
 | |
|                         continue;
 | |
|                     }
 | |
|                     
 | |
|                     /*
 | |
|                      * Update Y
 | |
|                      */
 | |
|                     val = rbfv2basisfunc(s->bf, ptdist2*invr2, _state);
 | |
|                     woffs = itemoffs+nx;
 | |
|                     for(j=0; j<=ny-1; j++)
 | |
|                     {
 | |
|                         ry->ptr.p_double[j+i1*ny] = ry->ptr.p_double[j+i1*ny]+val*s->cw.ptr.p_double[woffs+j];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Simple split
 | |
|      */
 | |
|     if( s->kdnodes.ptr.p_int[rootidx]==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Load:
 | |
|          * * D      dimension to split
 | |
|          * * Split  split position
 | |
|          * * ChildLE, ChildGE - indexes of childs
 | |
|          */
 | |
|         d = s->kdnodes.ptr.p_int[rootidx+1];
 | |
|         split = s->kdsplits.ptr.p_double[s->kdnodes.ptr.p_int[rootidx+2]];
 | |
|         childle = s->kdnodes.ptr.p_int[rootidx+3];
 | |
|         childge = s->kdnodes.ptr.p_int[rootidx+4];
 | |
|         
 | |
|         /*
 | |
|          * Navigate through childs
 | |
|          */
 | |
|         for(i=0; i<=1; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Select child to process:
 | |
|              * * ChildOffs      current child offset in Nodes[]
 | |
|              * * UpdateMin      whether minimum or maximum value
 | |
|              *                  of bounding box is changed on update
 | |
|              */
 | |
|             updatemin = i!=0;
 | |
|             if( i==0 )
 | |
|             {
 | |
|                 childoffs = childle;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 childoffs = childge;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Update bounding box and current distance
 | |
|              */
 | |
|             prevdist2 = buf->curdist2;
 | |
|             t1 = cx->ptr.p_double[d];
 | |
|             if( updatemin )
 | |
|             {
 | |
|                 v = buf->curboxmin.ptr.p_double[d];
 | |
|                 if( t1<=split )
 | |
|                 {
 | |
|                     v0 = v-t1;
 | |
|                     if( v0<0 )
 | |
|                     {
 | |
|                         v0 = (double)(0);
 | |
|                     }
 | |
|                     v1 = split-t1;
 | |
|                     buf->curdist2 = buf->curdist2-v0*v0+v1*v1;
 | |
|                 }
 | |
|                 buf->curboxmin.ptr.p_double[d] = split;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 v = buf->curboxmax.ptr.p_double[d];
 | |
|                 if( t1>=split )
 | |
|                 {
 | |
|                     v0 = t1-v;
 | |
|                     if( v0<0 )
 | |
|                     {
 | |
|                         v0 = (double)(0);
 | |
|                     }
 | |
|                     v1 = t1-split;
 | |
|                     buf->curdist2 = buf->curdist2-v0*v0+v1*v1;
 | |
|                 }
 | |
|                 buf->curboxmax.ptr.p_double[d] = split;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Decide: to dive into cell or not to dive
 | |
|              */
 | |
|             if( buf->curdist2<rquery2 )
 | |
|             {
 | |
|                 rbfv2_partialrowcalcrec(s, buf, childoffs, invr2, rquery2, rfar2, cx, rx, rf, rowsize, ry, _state);
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Restore bounding box and distance
 | |
|              */
 | |
|             if( updatemin )
 | |
|             {
 | |
|                 buf->curboxmin.ptr.p_double[d] = v;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 buf->curboxmax.ptr.p_double[d] = v;
 | |
|             }
 | |
|             buf->curdist2 = prevdist2;
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Integrity failure
 | |
|      */
 | |
|     ae_assert(ae_false, "PartialCalcRec: integrity check failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function prepares partial query
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     X       -   query point
 | |
|     kdBoxMin, kdBoxMax - current bounding box
 | |
|     NX      -   problem size
 | |
|     Buf     -   preallocated buffer; this function just loads data, but
 | |
|                 does not allocate place for them.
 | |
|     Cnt     -   counter variable which is set to zery by this function, as
 | |
|                 convenience, and to remember about necessity to zero counter
 | |
|                 prior to calling partialqueryrec().
 | |
|     
 | |
| OUTPUT PARAMETERS
 | |
|     Buf     -   calc-buffer:
 | |
|                 * Buf.CurBoxMin - current box
 | |
|                 * Buf.CurBoxMax - current box
 | |
|                 * Buf.CurDist2  - squared distance from X to current box
 | |
|     Cnt     -   set to zero
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbfv2_preparepartialquery(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* kdboxmin,
 | |
|      /* Real    */ ae_vector* kdboxmax,
 | |
|      ae_int_t nx,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_int_t* cnt,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t j;
 | |
| 
 | |
| 
 | |
|     *cnt = 0;
 | |
|     buf->curdist2 = (double)(0);
 | |
|     for(j=0; j<=nx-1; j++)
 | |
|     {
 | |
|         buf->curboxmin.ptr.p_double[j] = kdboxmin->ptr.p_double[j];
 | |
|         buf->curboxmax.ptr.p_double[j] = kdboxmax->ptr.p_double[j];
 | |
|         if( ae_fp_less(x->ptr.p_double[j],buf->curboxmin.ptr.p_double[j]) )
 | |
|         {
 | |
|             buf->curdist2 = buf->curdist2+ae_sqr(buf->curboxmin.ptr.p_double[j]-x->ptr.p_double[j], _state);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if( ae_fp_greater(x->ptr.p_double[j],buf->curboxmax.ptr.p_double[j]) )
 | |
|             {
 | |
|                 buf->curdist2 = buf->curdist2+ae_sqr(x->ptr.p_double[j]-buf->curboxmax.ptr.p_double[j], _state);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs partial (for just one subtree of multi-tree)  query
 | |
| for neighbors located in R-sphere around X. It returns  squared  distances
 | |
| from X to points and offsets in S.CW[] array for points being found.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     kdNodes, kdSplits, CW, NX, NY - corresponding fields of V2 model
 | |
|     Buf     -   calc-buffer, this function uses following fields:
 | |
|                 * Buf.CurBoxMin - should be set by caller
 | |
|                 * Buf.CurBoxMax - should be set by caller
 | |
|                 * Buf.CurDist2  - squared distance from X to current
 | |
|                   bounding box, should be set by caller
 | |
|                 You may use preparepartialquery() function to initialize
 | |
|                 these fields.
 | |
|     RootIdx -   offset of partial kd-tree
 | |
|     QueryR2 -   squared query radius
 | |
|     X       -   array[NX], point being queried
 | |
|     R2      -   preallocated output buffer; it is caller's responsibility
 | |
|                 to make sure that R2 has enough space.
 | |
|     Offs    -   preallocated output buffer; it is caller's responsibility
 | |
|                 to make sure that Offs has enough space.
 | |
|     K       -   MUST BE ZERO ON INITIAL CALL. This variable is incremented,
 | |
|                 not set. So, any no-zero value will result in the incorrect
 | |
|                 points count being returned.
 | |
|     
 | |
| OUTPUT PARAMETERS
 | |
|     R2      -   squared distances in first K elements
 | |
|     Offs    -   offsets in S.CW in first K elements
 | |
|     K       -   points count
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbfv2_partialqueryrec(/* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_int_t rootidx,
 | |
|      double queryr2,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* r2,
 | |
|      /* Integer */ ae_vector* offs,
 | |
|      ae_int_t* k,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double ptdist2;
 | |
|     double v;
 | |
|     ae_int_t cwoffs;
 | |
|     ae_int_t cwcnt;
 | |
|     ae_int_t itemoffs;
 | |
|     ae_int_t d;
 | |
|     double split;
 | |
|     ae_int_t childle;
 | |
|     ae_int_t childge;
 | |
|     ae_int_t childoffs;
 | |
|     ae_bool updatemin;
 | |
|     double prevdist2;
 | |
|     double t1;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Leaf node.
 | |
|      */
 | |
|     if( kdnodes->ptr.p_int[rootidx]>0 )
 | |
|     {
 | |
|         cwcnt = kdnodes->ptr.p_int[rootidx+0];
 | |
|         cwoffs = kdnodes->ptr.p_int[rootidx+1];
 | |
|         for(i=0; i<=cwcnt-1; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Calculate distance
 | |
|              */
 | |
|             itemoffs = cwoffs+i*(nx+ny);
 | |
|             ptdist2 = (double)(0);
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 v = cw->ptr.p_double[itemoffs+j]-x->ptr.p_double[j];
 | |
|                 ptdist2 = ptdist2+v*v;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Skip points if distance too large
 | |
|              */
 | |
|             if( ae_fp_greater_eq(ptdist2,queryr2) )
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Output
 | |
|              */
 | |
|             r2->ptr.p_double[*k] = ptdist2;
 | |
|             offs->ptr.p_int[*k] = itemoffs;
 | |
|             *k = *k+1;
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Simple split
 | |
|      */
 | |
|     if( kdnodes->ptr.p_int[rootidx]==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Load:
 | |
|          * * D      dimension to split
 | |
|          * * Split  split position
 | |
|          * * ChildLE, ChildGE - indexes of childs
 | |
|          */
 | |
|         d = kdnodes->ptr.p_int[rootidx+1];
 | |
|         split = kdsplits->ptr.p_double[kdnodes->ptr.p_int[rootidx+2]];
 | |
|         childle = kdnodes->ptr.p_int[rootidx+3];
 | |
|         childge = kdnodes->ptr.p_int[rootidx+4];
 | |
|         
 | |
|         /*
 | |
|          * Navigate through childs
 | |
|          */
 | |
|         for(i=0; i<=1; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Select child to process:
 | |
|              * * ChildOffs      current child offset in Nodes[]
 | |
|              * * UpdateMin      whether minimum or maximum value
 | |
|              *                  of bounding box is changed on update
 | |
|              */
 | |
|             updatemin = i!=0;
 | |
|             if( i==0 )
 | |
|             {
 | |
|                 childoffs = childle;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 childoffs = childge;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Update bounding box and current distance
 | |
|              */
 | |
|             prevdist2 = buf->curdist2;
 | |
|             t1 = x->ptr.p_double[d];
 | |
|             if( updatemin )
 | |
|             {
 | |
|                 v = buf->curboxmin.ptr.p_double[d];
 | |
|                 if( ae_fp_less_eq(t1,split) )
 | |
|                 {
 | |
|                     buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(v-t1, (double)(0), _state), _state)+ae_sqr(split-t1, _state);
 | |
|                 }
 | |
|                 buf->curboxmin.ptr.p_double[d] = split;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 v = buf->curboxmax.ptr.p_double[d];
 | |
|                 if( ae_fp_greater_eq(t1,split) )
 | |
|                 {
 | |
|                     buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(t1-v, (double)(0), _state), _state)+ae_sqr(t1-split, _state);
 | |
|                 }
 | |
|                 buf->curboxmax.ptr.p_double[d] = split;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Decide: to dive into cell or not to dive
 | |
|              */
 | |
|             if( ae_fp_less(buf->curdist2,queryr2) )
 | |
|             {
 | |
|                 rbfv2_partialqueryrec(kdnodes, kdsplits, cw, nx, ny, buf, childoffs, queryr2, x, r2, offs, k, _state);
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Restore bounding box and distance
 | |
|              */
 | |
|             if( updatemin )
 | |
|             {
 | |
|                 buf->curboxmin.ptr.p_double[d] = v;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 buf->curboxmax.ptr.p_double[d] = v;
 | |
|             }
 | |
|             buf->curdist2 = prevdist2;
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Integrity failure
 | |
|      */
 | |
|     ae_assert(ae_false, "PartialQueryRec: integrity check failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs  partial  (for  just  one  subtree  of  multi-tree)
 | |
| counting of neighbors located in R-sphere around X.
 | |
| 
 | |
| This function does not guarantee consistency of results with other partial
 | |
| queries, it should be used only to get approximate estimates (well, we  do
 | |
| not  use   approximate   algorithms,  but  rounding  errors  may  give  us
 | |
| inconsistent results in just-at-the-boundary cases).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     kdNodes, kdSplits, CW, NX, NY - corresponding fields of V2 model
 | |
|     Buf     -   calc-buffer, this function uses following fields:
 | |
|                 * Buf.CurBoxMin - should be set by caller
 | |
|                 * Buf.CurBoxMax - should be set by caller
 | |
|                 * Buf.CurDist2  - squared distance from X to current
 | |
|                   bounding box, should be set by caller
 | |
|                 You may use preparepartialquery() function to initialize
 | |
|                 these fields.
 | |
|     RootIdx -   offset of partial kd-tree
 | |
|     QueryR2 -   squared query radius
 | |
|     X       -   array[NX], point being queried
 | |
|     
 | |
| RESULT:
 | |
|     points count
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static ae_int_t rbfv2_partialcountrec(/* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      rbfv2calcbuffer* buf,
 | |
|      ae_int_t rootidx,
 | |
|      double queryr2,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double ptdist2;
 | |
|     double v;
 | |
|     ae_int_t cwoffs;
 | |
|     ae_int_t cwcnt;
 | |
|     ae_int_t itemoffs;
 | |
|     ae_int_t d;
 | |
|     double split;
 | |
|     ae_int_t childle;
 | |
|     ae_int_t childge;
 | |
|     ae_int_t childoffs;
 | |
|     ae_bool updatemin;
 | |
|     double prevdist2;
 | |
|     double t1;
 | |
|     ae_int_t result;
 | |
| 
 | |
| 
 | |
|     result = 0;
 | |
|     
 | |
|     /*
 | |
|      * Leaf node.
 | |
|      */
 | |
|     if( kdnodes->ptr.p_int[rootidx]>0 )
 | |
|     {
 | |
|         cwcnt = kdnodes->ptr.p_int[rootidx+0];
 | |
|         cwoffs = kdnodes->ptr.p_int[rootidx+1];
 | |
|         for(i=0; i<=cwcnt-1; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Calculate distance
 | |
|              */
 | |
|             itemoffs = cwoffs+i*(nx+ny);
 | |
|             ptdist2 = (double)(0);
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 v = cw->ptr.p_double[itemoffs+j]-x->ptr.p_double[j];
 | |
|                 ptdist2 = ptdist2+v*v;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Skip points if distance too large
 | |
|              */
 | |
|             if( ae_fp_greater_eq(ptdist2,queryr2) )
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Output
 | |
|              */
 | |
|             result = result+1;
 | |
|         }
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Simple split
 | |
|      */
 | |
|     if( kdnodes->ptr.p_int[rootidx]==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Load:
 | |
|          * * D      dimension to split
 | |
|          * * Split  split position
 | |
|          * * ChildLE, ChildGE - indexes of childs
 | |
|          */
 | |
|         d = kdnodes->ptr.p_int[rootidx+1];
 | |
|         split = kdsplits->ptr.p_double[kdnodes->ptr.p_int[rootidx+2]];
 | |
|         childle = kdnodes->ptr.p_int[rootidx+3];
 | |
|         childge = kdnodes->ptr.p_int[rootidx+4];
 | |
|         
 | |
|         /*
 | |
|          * Navigate through childs
 | |
|          */
 | |
|         for(i=0; i<=1; i++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Select child to process:
 | |
|              * * ChildOffs      current child offset in Nodes[]
 | |
|              * * UpdateMin      whether minimum or maximum value
 | |
|              *                  of bounding box is changed on update
 | |
|              */
 | |
|             updatemin = i!=0;
 | |
|             if( i==0 )
 | |
|             {
 | |
|                 childoffs = childle;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 childoffs = childge;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Update bounding box and current distance
 | |
|              */
 | |
|             prevdist2 = buf->curdist2;
 | |
|             t1 = x->ptr.p_double[d];
 | |
|             if( updatemin )
 | |
|             {
 | |
|                 v = buf->curboxmin.ptr.p_double[d];
 | |
|                 if( ae_fp_less_eq(t1,split) )
 | |
|                 {
 | |
|                     buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(v-t1, (double)(0), _state), _state)+ae_sqr(split-t1, _state);
 | |
|                 }
 | |
|                 buf->curboxmin.ptr.p_double[d] = split;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 v = buf->curboxmax.ptr.p_double[d];
 | |
|                 if( ae_fp_greater_eq(t1,split) )
 | |
|                 {
 | |
|                     buf->curdist2 = buf->curdist2-ae_sqr(ae_maxreal(t1-v, (double)(0), _state), _state)+ae_sqr(t1-split, _state);
 | |
|                 }
 | |
|                 buf->curboxmax.ptr.p_double[d] = split;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Decide: to dive into cell or not to dive
 | |
|              */
 | |
|             if( ae_fp_less(buf->curdist2,queryr2) )
 | |
|             {
 | |
|                 result = result+rbfv2_partialcountrec(kdnodes, kdsplits, cw, nx, ny, buf, childoffs, queryr2, x, _state);
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Restore bounding box and distance
 | |
|              */
 | |
|             if( updatemin )
 | |
|             {
 | |
|                 buf->curboxmin.ptr.p_double[d] = v;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 buf->curboxmax.ptr.p_double[d] = v;
 | |
|             }
 | |
|             buf->curdist2 = prevdist2;
 | |
|         }
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Integrity failure
 | |
|      */
 | |
|     ae_assert(ae_false, "PartialCountRec: integrity check failed", _state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs partial (for just one subtree of multi-tree) unpack
 | |
| for RBF model. It appends center coordinates,  weights  and  per-dimension
 | |
| radii (according to current scaling) to preallocated output array.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     kdNodes, kdSplits, CW, S, NX, NY - corresponding fields of V2 model
 | |
|     RootIdx -   offset of partial kd-tree
 | |
|     R       -   radius for current partial tree
 | |
|     XWR     -   preallocated output buffer; it is caller's responsibility
 | |
|                 to make sure that XWR has enough space. First K rows are
 | |
|                 already occupied.
 | |
|     K       -   number of already occupied rows in XWR.
 | |
|     
 | |
| OUTPUT PARAMETERS
 | |
|     XWR     -   updated XWR
 | |
|     K       -   updated rows count
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbfv2_partialunpackrec(/* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      /* Real    */ ae_vector* s,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t rootidx,
 | |
|      double r,
 | |
|      /* Real    */ ae_matrix* xwr,
 | |
|      ae_int_t* k,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t childle;
 | |
|     ae_int_t childge;
 | |
|     ae_int_t itemoffs;
 | |
|     ae_int_t cwoffs;
 | |
|     ae_int_t cwcnt;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Leaf node.
 | |
|      */
 | |
|     if( kdnodes->ptr.p_int[rootidx]>0 )
 | |
|     {
 | |
|         cwcnt = kdnodes->ptr.p_int[rootidx+0];
 | |
|         cwoffs = kdnodes->ptr.p_int[rootidx+1];
 | |
|         for(i=0; i<=cwcnt-1; i++)
 | |
|         {
 | |
|             itemoffs = cwoffs+i*(nx+ny);
 | |
|             for(j=0; j<=nx+ny-1; j++)
 | |
|             {
 | |
|                 xwr->ptr.pp_double[*k][j] = cw->ptr.p_double[itemoffs+j];
 | |
|             }
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 xwr->ptr.pp_double[*k][j] = xwr->ptr.pp_double[*k][j]*s->ptr.p_double[j];
 | |
|             }
 | |
|             for(j=0; j<=nx-1; j++)
 | |
|             {
 | |
|                 xwr->ptr.pp_double[*k][nx+ny+j] = r*s->ptr.p_double[j];
 | |
|             }
 | |
|             *k = *k+1;
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Simple split
 | |
|      */
 | |
|     if( kdnodes->ptr.p_int[rootidx]==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Load:
 | |
|          * * ChildLE, ChildGE - indexes of childs
 | |
|          */
 | |
|         childle = kdnodes->ptr.p_int[rootidx+3];
 | |
|         childge = kdnodes->ptr.p_int[rootidx+4];
 | |
|         
 | |
|         /*
 | |
|          * Process both parts of split
 | |
|          */
 | |
|         rbfv2_partialunpackrec(kdnodes, kdsplits, cw, s, nx, ny, childle, r, xwr, k, _state);
 | |
|         rbfv2_partialunpackrec(kdnodes, kdsplits, cw, s, nx, ny, childge, r, xwr, k, _state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Integrity failure
 | |
|      */
 | |
|     ae_assert(ae_false, "PartialUnpackRec: integrity check failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function returns size of design matrix row for evaluation point X0,
 | |
| given:
 | |
| * query radius multiplier (either RBFV2NearRadius() or RBFV2FarRadius())
 | |
| * hierarchy level: value in [0,NH) for single-level model, or negative
 | |
|   value for multilevel model (all levels of hierarchy in single matrix,
 | |
|   like one used by nonnegative RBF)
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     kdNodes, kdSplits, CW, Ri, kdRoots, kdBoxMin, kdBoxMax, NX, NY, NH - corresponding fields of V2 model
 | |
|     Level   -   value in [0,NH) for single-level design matrix, negative
 | |
|                 value for multilevel design matrix
 | |
|     RCoeff  -   radius coefficient, either RBFV2NearRadius() or RBFV2FarRadius()
 | |
|     X0      -   query point
 | |
|     CalcBuf -   buffer for PreparePartialQuery(), allocated by caller
 | |
|     
 | |
| RESULT:
 | |
|     row size
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 28.09.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static ae_int_t rbfv2_designmatrixrowsize(/* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      /* Real    */ ae_vector* ri,
 | |
|      /* Integer */ ae_vector* kdroots,
 | |
|      /* Real    */ ae_vector* kdboxmin,
 | |
|      /* Real    */ ae_vector* kdboxmax,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t nh,
 | |
|      ae_int_t level,
 | |
|      double rcoeff,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      rbfv2calcbuffer* calcbuf,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t dummy;
 | |
|     ae_int_t levelidx;
 | |
|     ae_int_t level0;
 | |
|     ae_int_t level1;
 | |
|     double curradius2;
 | |
|     ae_int_t result;
 | |
| 
 | |
| 
 | |
|     ae_assert(nh>0, "DesignMatrixRowSize: integrity failure", _state);
 | |
|     if( level>=0 )
 | |
|     {
 | |
|         level0 = level;
 | |
|         level1 = level;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         level0 = 0;
 | |
|         level1 = nh-1;
 | |
|     }
 | |
|     result = 0;
 | |
|     for(levelidx=level0; levelidx<=level1; levelidx++)
 | |
|     {
 | |
|         curradius2 = ae_sqr(ri->ptr.p_double[levelidx]*rcoeff, _state);
 | |
|         rbfv2_preparepartialquery(x0, kdboxmin, kdboxmax, nx, calcbuf, &dummy, _state);
 | |
|         result = result+rbfv2_partialcountrec(kdnodes, kdsplits, cw, nx, ny, calcbuf, kdroots->ptr.p_int[levelidx], curradius2, x0, _state);
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function generates design matrix row for evaluation point X0, given:
 | |
| * query radius multiplier (either RBFV2NearRadius() or RBFV2FarRadius())
 | |
| * hierarchy level: value in [0,NH) for single-level model, or negative
 | |
|   value for multilevel model (all levels of hierarchy in single matrix,
 | |
|   like one used by nonnegative RBF)
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     kdNodes, kdSplits, CW, Ri, kdRoots, kdBoxMin, kdBoxMax, NX, NY, NH - corresponding fields of V2 model
 | |
| 
 | |
|     CWRange -   internal array[NH+1] used by RBF construction function,
 | |
|                 stores ranges of CW occupied by NH trees.
 | |
|     Level   -   value in [0,NH) for single-level design matrix, negative
 | |
|                 value for multilevel design matrix
 | |
|     BF      -   basis function type
 | |
|     RCoeff  -   radius coefficient, either RBFV2NearRadius() or RBFV2FarRadius()
 | |
|     RowsPerPoint-equal to:
 | |
|                 * 1 for unpenalized regression model
 | |
|                 * 1+NX for basic form of nonsmoothness penalty
 | |
|     Penalty -   nonsmoothness penalty coefficient
 | |
|     
 | |
|     X0      -   query point
 | |
|     
 | |
|     CalcBuf -   buffer for PreparePartialQuery(), allocated by caller
 | |
|     R2      -   preallocated temporary buffer, size is at least NPoints;
 | |
|                 it is caller's responsibility to make sure that R2 has enough space.
 | |
|     Offs    -   preallocated temporary buffer; size is at least NPoints;
 | |
|                 it is caller's responsibility to make sure that Offs has enough space.
 | |
|     K       -   MUST BE ZERO ON INITIAL CALL. This variable is incremented,
 | |
|                 not set. So, any no-zero value will result in the incorrect
 | |
|                 points count being returned.
 | |
|     RowIdx  -   preallocated array, at least RowSize elements
 | |
|     RowVal  -   preallocated array, at least RowSize*RowsPerPoint elements
 | |
|     
 | |
| RESULT:
 | |
|     RowIdx  -   RowSize elements are filled with column indexes of non-zero
 | |
|                 design matrix entries
 | |
|     RowVal  -   RowSize*RowsPerPoint elements are filled with design matrix
 | |
|                 values, with column RowIdx[0] being stored in first RowsPerPoint
 | |
|                 elements of RowVal, column RowIdx[1] being stored in next
 | |
|                 RowsPerPoint elements, and so on.
 | |
|                 
 | |
|                 First element in contiguous set of RowsPerPoint elements
 | |
|                 corresponds to 
 | |
|                 
 | |
|     RowSize -   number of columns per row
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 28.09.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbfv2_designmatrixgeneraterow(/* Integer */ ae_vector* kdnodes,
 | |
|      /* Real    */ ae_vector* kdsplits,
 | |
|      /* Real    */ ae_vector* cw,
 | |
|      /* Real    */ ae_vector* ri,
 | |
|      /* Integer */ ae_vector* kdroots,
 | |
|      /* Real    */ ae_vector* kdboxmin,
 | |
|      /* Real    */ ae_vector* kdboxmax,
 | |
|      /* Integer */ ae_vector* cwrange,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t nh,
 | |
|      ae_int_t level,
 | |
|      ae_int_t bf,
 | |
|      double rcoeff,
 | |
|      ae_int_t rowsperpoint,
 | |
|      double penalty,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      rbfv2calcbuffer* calcbuf,
 | |
|      /* Real    */ ae_vector* tmpr2,
 | |
|      /* Integer */ ae_vector* tmpoffs,
 | |
|      /* Integer */ ae_vector* rowidx,
 | |
|      /* Real    */ ae_vector* rowval,
 | |
|      ae_int_t* rowsize,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t cnt;
 | |
|     ae_int_t levelidx;
 | |
|     ae_int_t level0;
 | |
|     ae_int_t level1;
 | |
|     double invri2;
 | |
|     double curradius2;
 | |
|     double val;
 | |
|     double dval;
 | |
|     double d2val;
 | |
| 
 | |
|     *rowsize = 0;
 | |
| 
 | |
|     ae_assert(nh>0, "DesignMatrixGenerateRow: integrity failure (a)", _state);
 | |
|     ae_assert(rowsperpoint==1||rowsperpoint==1+nx, "DesignMatrixGenerateRow: integrity failure (b)", _state);
 | |
|     if( level>=0 )
 | |
|     {
 | |
|         level0 = level;
 | |
|         level1 = level;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         level0 = 0;
 | |
|         level1 = nh-1;
 | |
|     }
 | |
|     *rowsize = 0;
 | |
|     for(levelidx=level0; levelidx<=level1; levelidx++)
 | |
|     {
 | |
|         curradius2 = ae_sqr(ri->ptr.p_double[levelidx]*rcoeff, _state);
 | |
|         invri2 = 1/ae_sqr(ri->ptr.p_double[levelidx], _state);
 | |
|         rbfv2_preparepartialquery(x0, kdboxmin, kdboxmax, nx, calcbuf, &cnt, _state);
 | |
|         rbfv2_partialqueryrec(kdnodes, kdsplits, cw, nx, ny, calcbuf, kdroots->ptr.p_int[levelidx], curradius2, x0, tmpr2, tmpoffs, &cnt, _state);
 | |
|         ae_assert(tmpr2->cnt>=cnt, "DesignMatrixRowSize: integrity failure (c)", _state);
 | |
|         ae_assert(tmpoffs->cnt>=cnt, "DesignMatrixRowSize: integrity failure (d)", _state);
 | |
|         ae_assert(rowidx->cnt>=*rowsize+cnt, "DesignMatrixRowSize: integrity failure (e)", _state);
 | |
|         ae_assert(rowval->cnt>=rowsperpoint*(*rowsize+cnt), "DesignMatrixRowSize: integrity failure (f)", _state);
 | |
|         for(j=0; j<=cnt-1; j++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Generate element corresponding to fitting error.
 | |
|              * Store derivative information which may be required later.
 | |
|              */
 | |
|             ae_assert((tmpoffs->ptr.p_int[j]-cwrange->ptr.p_int[level0])%(nx+ny)==0, "DesignMatrixRowSize: integrity failure (g)", _state);
 | |
|             rbfv2basisfuncdiff2(bf, tmpr2->ptr.p_double[j]*invri2, &val, &dval, &d2val, _state);
 | |
|             rowidx->ptr.p_int[*rowsize+j] = (tmpoffs->ptr.p_int[j]-cwrange->ptr.p_int[level0])/(nx+ny);
 | |
|             rowval->ptr.p_double[(*rowsize+j)*rowsperpoint+0] = val;
 | |
|             if( rowsperpoint==1 )
 | |
|             {
 | |
|                 continue;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Generate elements corresponding to nonsmoothness penalty
 | |
|              */
 | |
|             ae_assert(rowsperpoint==1+nx, "DesignMatrixRowSize: integrity failure (h)", _state);
 | |
|             for(k=0; k<=nx-1; k++)
 | |
|             {
 | |
|                 rowval->ptr.p_double[(*rowsize+j)*rowsperpoint+1+k] = penalty*(dval*2*invri2+d2val*ae_sqr(2*(x0->ptr.p_double[k]-cw->ptr.p_double[tmpoffs->ptr.p_int[j]+k])*invri2, _state));
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Update columns counter
 | |
|          */
 | |
|         *rowsize = *rowsize+cnt;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fills RBF model by zeros.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.11.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbfv2_zerofill(rbfv2model* s,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t bf,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
| 
 | |
|     s->bf = bf;
 | |
|     s->nh = 0;
 | |
|     ae_vector_set_length(&s->ri, 0, _state);
 | |
|     ae_vector_set_length(&s->s, 0, _state);
 | |
|     ae_vector_set_length(&s->kdroots, 0, _state);
 | |
|     ae_vector_set_length(&s->kdnodes, 0, _state);
 | |
|     ae_vector_set_length(&s->kdsplits, 0, _state);
 | |
|     ae_vector_set_length(&s->kdboxmin, 0, _state);
 | |
|     ae_vector_set_length(&s->kdboxmax, 0, _state);
 | |
|     ae_vector_set_length(&s->cw, 0, _state);
 | |
|     ae_matrix_set_length(&s->v, ny, nx+1, _state);
 | |
|     for(i=0; i<=ny-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=nx; j++)
 | |
|         {
 | |
|             s->v.ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2calcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv2calcbuffer *p = (rbfv2calcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->curboxmin, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->curboxmax, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->x123, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->y123, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2calcbuffer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv2calcbuffer *dst = (rbfv2calcbuffer*)_dst;
 | |
|     rbfv2calcbuffer *src = (rbfv2calcbuffer*)_src;
 | |
|     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->curboxmin, &src->curboxmin, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->curboxmax, &src->curboxmax, _state, make_automatic);
 | |
|     dst->curdist2 = src->curdist2;
 | |
|     ae_vector_init_copy(&dst->x123, &src->x123, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->y123, &src->y123, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2calcbuffer_clear(void* _p)
 | |
| {
 | |
|     rbfv2calcbuffer *p = (rbfv2calcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->x);
 | |
|     ae_vector_clear(&p->curboxmin);
 | |
|     ae_vector_clear(&p->curboxmax);
 | |
|     ae_vector_clear(&p->x123);
 | |
|     ae_vector_clear(&p->y123);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2calcbuffer_destroy(void* _p)
 | |
| {
 | |
|     rbfv2calcbuffer *p = (rbfv2calcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->x);
 | |
|     ae_vector_destroy(&p->curboxmin);
 | |
|     ae_vector_destroy(&p->curboxmax);
 | |
|     ae_vector_destroy(&p->x123);
 | |
|     ae_vector_destroy(&p->y123);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2model_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv2model *p = (rbfv2model*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->ri, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->kdroots, 0, DT_INT, _state, make_automatic);
 | |
|     ae_vector_init(&p->kdnodes, 0, DT_INT, _state, make_automatic);
 | |
|     ae_vector_init(&p->kdsplits, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->kdboxmin, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->kdboxmax, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->cw, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->v, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     _rbfv2calcbuffer_init(&p->calcbuf, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2model_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv2model *dst = (rbfv2model*)_dst;
 | |
|     rbfv2model *src = (rbfv2model*)_src;
 | |
|     dst->ny = src->ny;
 | |
|     dst->nx = src->nx;
 | |
|     dst->bf = src->bf;
 | |
|     dst->nh = src->nh;
 | |
|     ae_vector_init_copy(&dst->ri, &src->ri, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->kdroots, &src->kdroots, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->kdnodes, &src->kdnodes, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->kdsplits, &src->kdsplits, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->kdboxmin, &src->kdboxmin, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->kdboxmax, &src->kdboxmax, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->cw, &src->cw, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->v, &src->v, _state, make_automatic);
 | |
|     dst->lambdareg = src->lambdareg;
 | |
|     dst->maxits = src->maxits;
 | |
|     dst->supportr = src->supportr;
 | |
|     dst->basisfunction = src->basisfunction;
 | |
|     _rbfv2calcbuffer_init_copy(&dst->calcbuf, &src->calcbuf, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2model_clear(void* _p)
 | |
| {
 | |
|     rbfv2model *p = (rbfv2model*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->ri);
 | |
|     ae_vector_clear(&p->s);
 | |
|     ae_vector_clear(&p->kdroots);
 | |
|     ae_vector_clear(&p->kdnodes);
 | |
|     ae_vector_clear(&p->kdsplits);
 | |
|     ae_vector_clear(&p->kdboxmin);
 | |
|     ae_vector_clear(&p->kdboxmax);
 | |
|     ae_vector_clear(&p->cw);
 | |
|     ae_matrix_clear(&p->v);
 | |
|     _rbfv2calcbuffer_clear(&p->calcbuf);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2model_destroy(void* _p)
 | |
| {
 | |
|     rbfv2model *p = (rbfv2model*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->ri);
 | |
|     ae_vector_destroy(&p->s);
 | |
|     ae_vector_destroy(&p->kdroots);
 | |
|     ae_vector_destroy(&p->kdnodes);
 | |
|     ae_vector_destroy(&p->kdsplits);
 | |
|     ae_vector_destroy(&p->kdboxmin);
 | |
|     ae_vector_destroy(&p->kdboxmax);
 | |
|     ae_vector_destroy(&p->cw);
 | |
|     ae_matrix_destroy(&p->v);
 | |
|     _rbfv2calcbuffer_destroy(&p->calcbuf);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2gridcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv2gridcalcbuffer *p = (rbfv2gridcalcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _rbfv2calcbuffer_init(&p->calcbuf, _state, make_automatic);
 | |
|     ae_vector_init(&p->cx, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->rx, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->ry, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tx, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->ty, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->rf, 0, DT_BOOL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2gridcalcbuffer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv2gridcalcbuffer *dst = (rbfv2gridcalcbuffer*)_dst;
 | |
|     rbfv2gridcalcbuffer *src = (rbfv2gridcalcbuffer*)_src;
 | |
|     _rbfv2calcbuffer_init_copy(&dst->calcbuf, &src->calcbuf, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->cx, &src->cx, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->rx, &src->rx, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->ry, &src->ry, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tx, &src->tx, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->ty, &src->ty, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->rf, &src->rf, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2gridcalcbuffer_clear(void* _p)
 | |
| {
 | |
|     rbfv2gridcalcbuffer *p = (rbfv2gridcalcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _rbfv2calcbuffer_clear(&p->calcbuf);
 | |
|     ae_vector_clear(&p->cx);
 | |
|     ae_vector_clear(&p->rx);
 | |
|     ae_vector_clear(&p->ry);
 | |
|     ae_vector_clear(&p->tx);
 | |
|     ae_vector_clear(&p->ty);
 | |
|     ae_vector_clear(&p->rf);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2gridcalcbuffer_destroy(void* _p)
 | |
| {
 | |
|     rbfv2gridcalcbuffer *p = (rbfv2gridcalcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _rbfv2calcbuffer_destroy(&p->calcbuf);
 | |
|     ae_vector_destroy(&p->cx);
 | |
|     ae_vector_destroy(&p->rx);
 | |
|     ae_vector_destroy(&p->ry);
 | |
|     ae_vector_destroy(&p->tx);
 | |
|     ae_vector_destroy(&p->ty);
 | |
|     ae_vector_destroy(&p->rf);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2report_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv2report *p = (rbfv2report*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2report_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv2report *dst = (rbfv2report*)_dst;
 | |
|     rbfv2report *src = (rbfv2report*)_src;
 | |
|     dst->terminationtype = src->terminationtype;
 | |
|     dst->maxerror = src->maxerror;
 | |
|     dst->rmserror = src->rmserror;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2report_clear(void* _p)
 | |
| {
 | |
|     rbfv2report *p = (rbfv2report*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv2report_destroy(void* _p)
 | |
| {
 | |
|     rbfv2report *p = (rbfv2report*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_SPLINE2D) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates the value of the bilinear or bicubic spline  at
 | |
| the given point X.
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   2D spline object.
 | |
|             Built by spline2dbuildbilinearv or spline2dbuildbicubicv.
 | |
|     X, Y-   point
 | |
| 
 | |
| Result:
 | |
|     S(x,y)
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 05.07.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double spline2dcalc(spline2dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t ix;
 | |
|     ae_int_t iy;
 | |
|     ae_int_t l;
 | |
|     ae_int_t r;
 | |
|     ae_int_t h;
 | |
|     double t;
 | |
|     double dt;
 | |
|     double u;
 | |
|     double du;
 | |
|     double y1;
 | |
|     double y2;
 | |
|     double y3;
 | |
|     double y4;
 | |
|     ae_int_t s1;
 | |
|     ae_int_t s2;
 | |
|     ae_int_t s3;
 | |
|     ae_int_t s4;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     double t2;
 | |
|     double t3;
 | |
|     double u2;
 | |
|     double u3;
 | |
|     double ht00;
 | |
|     double ht01;
 | |
|     double ht10;
 | |
|     double ht11;
 | |
|     double hu00;
 | |
|     double hu01;
 | |
|     double hu10;
 | |
|     double hu11;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalc: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalc: X or Y contains NaN or Infinite value", _state);
 | |
|     if( c->d!=1 )
 | |
|     {
 | |
|         result = (double)(0);
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Determine evaluation interval
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->n-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
 | |
|     t = (x-c->x.ptr.p_double[l])*dt;
 | |
|     ix = l;
 | |
|     l = 0;
 | |
|     r = c->m-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
 | |
|     u = (y-c->y.ptr.p_double[l])*du;
 | |
|     iy = l;
 | |
|     
 | |
|     /*
 | |
|      * Bilinear interpolation
 | |
|      */
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         y1 = c->f.ptr.p_double[c->n*iy+ix];
 | |
|         y2 = c->f.ptr.p_double[c->n*iy+(ix+1)];
 | |
|         y3 = c->f.ptr.p_double[c->n*(iy+1)+(ix+1)];
 | |
|         y4 = c->f.ptr.p_double[c->n*(iy+1)+ix];
 | |
|         result = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4;
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Bicubic interpolation:
 | |
|      * * calculate Hermite basis for dimensions X and Y (variables T and U),
 | |
|      *   here HTij means basis function whose I-th derivative has value 1 at T=J.
 | |
|      *   Same for HUij.
 | |
|      * * after initial calculation, apply scaling by DT/DU to the basis
 | |
|      * * calculate using stored table of second derivatives
 | |
|      */
 | |
|     ae_assert(c->stype==-3, "Spline2DCalc: integrity check failed", _state);
 | |
|     sfx = c->n*c->m;
 | |
|     sfy = 2*c->n*c->m;
 | |
|     sfxy = 3*c->n*c->m;
 | |
|     s1 = c->n*iy+ix;
 | |
|     s2 = c->n*iy+(ix+1);
 | |
|     s3 = c->n*(iy+1)+ix;
 | |
|     s4 = c->n*(iy+1)+(ix+1);
 | |
|     t2 = t*t;
 | |
|     t3 = t*t2;
 | |
|     u2 = u*u;
 | |
|     u3 = u*u2;
 | |
|     ht00 = 2*t3-3*t2+1;
 | |
|     ht10 = t3-2*t2+t;
 | |
|     ht01 = -2*t3+3*t2;
 | |
|     ht11 = t3-t2;
 | |
|     hu00 = 2*u3-3*u2+1;
 | |
|     hu10 = u3-2*u2+u;
 | |
|     hu01 = -2*u3+3*u2;
 | |
|     hu11 = u3-u2;
 | |
|     ht10 = ht10/dt;
 | |
|     ht11 = ht11/dt;
 | |
|     hu10 = hu10/du;
 | |
|     hu11 = hu11/du;
 | |
|     result = (double)(0);
 | |
|     result = result+c->f.ptr.p_double[s1]*ht00*hu00+c->f.ptr.p_double[s2]*ht01*hu00+c->f.ptr.p_double[s3]*ht00*hu01+c->f.ptr.p_double[s4]*ht01*hu01;
 | |
|     result = result+c->f.ptr.p_double[sfx+s1]*ht10*hu00+c->f.ptr.p_double[sfx+s2]*ht11*hu00+c->f.ptr.p_double[sfx+s3]*ht10*hu01+c->f.ptr.p_double[sfx+s4]*ht11*hu01;
 | |
|     result = result+c->f.ptr.p_double[sfy+s1]*ht00*hu10+c->f.ptr.p_double[sfy+s2]*ht01*hu10+c->f.ptr.p_double[sfy+s3]*ht00*hu11+c->f.ptr.p_double[sfy+s4]*ht01*hu11;
 | |
|     result = result+c->f.ptr.p_double[sfxy+s1]*ht10*hu10+c->f.ptr.p_double[sfxy+s2]*ht11*hu10+c->f.ptr.p_double[sfxy+s3]*ht10*hu11+c->f.ptr.p_double[sfxy+s4]*ht11*hu11;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates the value of the bilinear or bicubic spline  at
 | |
| the given point X and its derivatives.
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y-   point
 | |
| 
 | |
| Output parameters:
 | |
|     F   -   S(x,y)
 | |
|     FX  -   dS(x,y)/dX
 | |
|     FY  -   dS(x,y)/dY
 | |
|     FXY -   d2S(x,y)/dXdY
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 05.07.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2ddiff(spline2dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      double* f,
 | |
|      double* fx,
 | |
|      double* fy,
 | |
|      double* fxy,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double t;
 | |
|     double dt;
 | |
|     double u;
 | |
|     double du;
 | |
|     ae_int_t ix;
 | |
|     ae_int_t iy;
 | |
|     ae_int_t l;
 | |
|     ae_int_t r;
 | |
|     ae_int_t h;
 | |
|     ae_int_t s1;
 | |
|     ae_int_t s2;
 | |
|     ae_int_t s3;
 | |
|     ae_int_t s4;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     double y1;
 | |
|     double y2;
 | |
|     double y3;
 | |
|     double y4;
 | |
|     double v0;
 | |
|     double v1;
 | |
|     double v2;
 | |
|     double v3;
 | |
|     double t2;
 | |
|     double t3;
 | |
|     double u2;
 | |
|     double u3;
 | |
|     double ht00;
 | |
|     double ht01;
 | |
|     double ht10;
 | |
|     double ht11;
 | |
|     double hu00;
 | |
|     double hu01;
 | |
|     double hu10;
 | |
|     double hu11;
 | |
|     double dht00;
 | |
|     double dht01;
 | |
|     double dht10;
 | |
|     double dht11;
 | |
|     double dhu00;
 | |
|     double dhu01;
 | |
|     double dhu10;
 | |
|     double dhu11;
 | |
| 
 | |
|     *f = 0;
 | |
|     *fx = 0;
 | |
|     *fy = 0;
 | |
|     *fxy = 0;
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline2DDiff: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DDiff: X or Y contains NaN or Infinite value", _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare F, dF/dX, dF/dY, d2F/dXdY
 | |
|      */
 | |
|     *f = (double)(0);
 | |
|     *fx = (double)(0);
 | |
|     *fy = (double)(0);
 | |
|     *fxy = (double)(0);
 | |
|     if( c->d!=1 )
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->n-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
 | |
|     dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
 | |
|     ix = l;
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->m-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
 | |
|     du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
 | |
|     iy = l;
 | |
|     
 | |
|     /*
 | |
|      * Bilinear interpolation
 | |
|      */
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         y1 = c->f.ptr.p_double[c->n*iy+ix];
 | |
|         y2 = c->f.ptr.p_double[c->n*iy+(ix+1)];
 | |
|         y3 = c->f.ptr.p_double[c->n*(iy+1)+(ix+1)];
 | |
|         y4 = c->f.ptr.p_double[c->n*(iy+1)+ix];
 | |
|         *f = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4;
 | |
|         *fx = (-(1-u)*y1+(1-u)*y2+u*y3-u*y4)*dt;
 | |
|         *fy = (-(1-t)*y1-t*y2+t*y3+(1-t)*y4)*du;
 | |
|         *fxy = (y1-y2+y3-y4)*du*dt;
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Bicubic interpolation
 | |
|      */
 | |
|     if( c->stype==-3 )
 | |
|     {
 | |
|         sfx = c->n*c->m;
 | |
|         sfy = 2*c->n*c->m;
 | |
|         sfxy = 3*c->n*c->m;
 | |
|         s1 = c->n*iy+ix;
 | |
|         s2 = c->n*iy+(ix+1);
 | |
|         s3 = c->n*(iy+1)+ix;
 | |
|         s4 = c->n*(iy+1)+(ix+1);
 | |
|         t2 = t*t;
 | |
|         t3 = t*t2;
 | |
|         u2 = u*u;
 | |
|         u3 = u*u2;
 | |
|         ht00 = 2*t3-3*t2+1;
 | |
|         ht10 = t3-2*t2+t;
 | |
|         ht01 = -2*t3+3*t2;
 | |
|         ht11 = t3-t2;
 | |
|         hu00 = 2*u3-3*u2+1;
 | |
|         hu10 = u3-2*u2+u;
 | |
|         hu01 = -2*u3+3*u2;
 | |
|         hu11 = u3-u2;
 | |
|         ht10 = ht10/dt;
 | |
|         ht11 = ht11/dt;
 | |
|         hu10 = hu10/du;
 | |
|         hu11 = hu11/du;
 | |
|         dht00 = 6*t2-6*t;
 | |
|         dht10 = 3*t2-4*t+1;
 | |
|         dht01 = -6*t2+6*t;
 | |
|         dht11 = 3*t2-2*t;
 | |
|         dhu00 = 6*u2-6*u;
 | |
|         dhu10 = 3*u2-4*u+1;
 | |
|         dhu01 = -6*u2+6*u;
 | |
|         dhu11 = 3*u2-2*u;
 | |
|         dht00 = dht00*dt;
 | |
|         dht01 = dht01*dt;
 | |
|         dhu00 = dhu00*du;
 | |
|         dhu01 = dhu01*du;
 | |
|         *f = (double)(0);
 | |
|         *fx = (double)(0);
 | |
|         *fy = (double)(0);
 | |
|         *fxy = (double)(0);
 | |
|         v0 = c->f.ptr.p_double[s1];
 | |
|         v1 = c->f.ptr.p_double[s2];
 | |
|         v2 = c->f.ptr.p_double[s3];
 | |
|         v3 = c->f.ptr.p_double[s4];
 | |
|         *f = *f+v0*ht00*hu00+v1*ht01*hu00+v2*ht00*hu01+v3*ht01*hu01;
 | |
|         *fx = *fx+v0*dht00*hu00+v1*dht01*hu00+v2*dht00*hu01+v3*dht01*hu01;
 | |
|         *fy = *fy+v0*ht00*dhu00+v1*ht01*dhu00+v2*ht00*dhu01+v3*ht01*dhu01;
 | |
|         *fxy = *fxy+v0*dht00*dhu00+v1*dht01*dhu00+v2*dht00*dhu01+v3*dht01*dhu01;
 | |
|         v0 = c->f.ptr.p_double[sfx+s1];
 | |
|         v1 = c->f.ptr.p_double[sfx+s2];
 | |
|         v2 = c->f.ptr.p_double[sfx+s3];
 | |
|         v3 = c->f.ptr.p_double[sfx+s4];
 | |
|         *f = *f+v0*ht10*hu00+v1*ht11*hu00+v2*ht10*hu01+v3*ht11*hu01;
 | |
|         *fx = *fx+v0*dht10*hu00+v1*dht11*hu00+v2*dht10*hu01+v3*dht11*hu01;
 | |
|         *fy = *fy+v0*ht10*dhu00+v1*ht11*dhu00+v2*ht10*dhu01+v3*ht11*dhu01;
 | |
|         *fxy = *fxy+v0*dht10*dhu00+v1*dht11*dhu00+v2*dht10*dhu01+v3*dht11*dhu01;
 | |
|         v0 = c->f.ptr.p_double[sfy+s1];
 | |
|         v1 = c->f.ptr.p_double[sfy+s2];
 | |
|         v2 = c->f.ptr.p_double[sfy+s3];
 | |
|         v3 = c->f.ptr.p_double[sfy+s4];
 | |
|         *f = *f+v0*ht00*hu10+v1*ht01*hu10+v2*ht00*hu11+v3*ht01*hu11;
 | |
|         *fx = *fx+v0*dht00*hu10+v1*dht01*hu10+v2*dht00*hu11+v3*dht01*hu11;
 | |
|         *fy = *fy+v0*ht00*dhu10+v1*ht01*dhu10+v2*ht00*dhu11+v3*ht01*dhu11;
 | |
|         *fxy = *fxy+v0*dht00*dhu10+v1*dht01*dhu10+v2*dht00*dhu11+v3*dht01*dhu11;
 | |
|         v0 = c->f.ptr.p_double[sfxy+s1];
 | |
|         v1 = c->f.ptr.p_double[sfxy+s2];
 | |
|         v2 = c->f.ptr.p_double[sfxy+s3];
 | |
|         v3 = c->f.ptr.p_double[sfxy+s4];
 | |
|         *f = *f+v0*ht10*hu10+v1*ht11*hu10+v2*ht10*hu11+v3*ht11*hu11;
 | |
|         *fx = *fx+v0*dht10*hu10+v1*dht11*hu10+v2*dht10*hu11+v3*dht11*hu11;
 | |
|         *fy = *fy+v0*ht10*dhu10+v1*ht11*dhu10+v2*ht10*dhu11+v3*ht11*dhu11;
 | |
|         *fxy = *fxy+v0*dht10*dhu10+v1*dht11*dhu10+v2*dht10*dhu11+v3*dht11*dhu11;
 | |
|         return;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates bilinear or bicubic vector-valued spline at the
 | |
| given point (X,Y).
 | |
| 
 | |
| If you need just some specific component of vector-valued spline, you  can
 | |
| use spline2dcalcvi() function.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y-   point
 | |
|     F   -   output buffer, possibly preallocated array. In case array size
 | |
|             is large enough to store result, it is not reallocated.  Array
 | |
|             which is too short will be reallocated
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   array[D] (or larger) which stores function values
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dcalcvbuf(spline2dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      /* Real    */ ae_vector* f,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t ix;
 | |
|     ae_int_t iy;
 | |
|     ae_int_t l;
 | |
|     ae_int_t r;
 | |
|     ae_int_t h;
 | |
|     ae_int_t i;
 | |
|     double t;
 | |
|     double dt;
 | |
|     double u;
 | |
|     double du;
 | |
|     double y1;
 | |
|     double y2;
 | |
|     double y3;
 | |
|     double y4;
 | |
|     ae_int_t s1;
 | |
|     ae_int_t s2;
 | |
|     ae_int_t s3;
 | |
|     ae_int_t s4;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     double t2;
 | |
|     double t3;
 | |
|     double u2;
 | |
|     double u3;
 | |
|     double ht00;
 | |
|     double ht01;
 | |
|     double ht10;
 | |
|     double ht11;
 | |
|     double hu00;
 | |
|     double hu01;
 | |
|     double hu10;
 | |
|     double hu11;
 | |
| 
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcVBuf: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcVBuf: X or Y contains NaN or Infinite value", _state);
 | |
|     
 | |
|     /*
 | |
|      * Allocate place for output
 | |
|      */
 | |
|     rvectorsetlengthatleast(f, c->d, _state);
 | |
|     
 | |
|     /*
 | |
|      * Determine evaluation interval
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->n-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
 | |
|     t = (x-c->x.ptr.p_double[l])*dt;
 | |
|     ix = l;
 | |
|     l = 0;
 | |
|     r = c->m-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
 | |
|     u = (y-c->y.ptr.p_double[l])*du;
 | |
|     iy = l;
 | |
|     
 | |
|     /*
 | |
|      * Bilinear interpolation
 | |
|      */
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         for(i=0; i<=c->d-1; i++)
 | |
|         {
 | |
|             y1 = c->f.ptr.p_double[c->d*(c->n*iy+ix)+i];
 | |
|             y2 = c->f.ptr.p_double[c->d*(c->n*iy+(ix+1))+i];
 | |
|             y3 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+(ix+1))+i];
 | |
|             y4 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+ix)+i];
 | |
|             f->ptr.p_double[i] = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4;
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Bicubic interpolation:
 | |
|      * * calculate Hermite basis for dimensions X and Y (variables T and U),
 | |
|      *   here HTij means basis function whose I-th derivative has value 1 at T=J.
 | |
|      *   Same for HUij.
 | |
|      * * after initial calculation, apply scaling by DT/DU to the basis
 | |
|      * * calculate using stored table of second derivatives
 | |
|      */
 | |
|     ae_assert(c->stype==-3, "Spline2DCalc: integrity check failed", _state);
 | |
|     sfx = c->n*c->m*c->d;
 | |
|     sfy = 2*c->n*c->m*c->d;
 | |
|     sfxy = 3*c->n*c->m*c->d;
 | |
|     s1 = (c->n*iy+ix)*c->d;
 | |
|     s2 = (c->n*iy+(ix+1))*c->d;
 | |
|     s3 = (c->n*(iy+1)+ix)*c->d;
 | |
|     s4 = (c->n*(iy+1)+(ix+1))*c->d;
 | |
|     t2 = t*t;
 | |
|     t3 = t*t2;
 | |
|     u2 = u*u;
 | |
|     u3 = u*u2;
 | |
|     ht00 = 2*t3-3*t2+1;
 | |
|     ht10 = t3-2*t2+t;
 | |
|     ht01 = -2*t3+3*t2;
 | |
|     ht11 = t3-t2;
 | |
|     hu00 = 2*u3-3*u2+1;
 | |
|     hu10 = u3-2*u2+u;
 | |
|     hu01 = -2*u3+3*u2;
 | |
|     hu11 = u3-u2;
 | |
|     ht10 = ht10/dt;
 | |
|     ht11 = ht11/dt;
 | |
|     hu10 = hu10/du;
 | |
|     hu11 = hu11/du;
 | |
|     for(i=0; i<=c->d-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Calculate I-th component
 | |
|          */
 | |
|         f->ptr.p_double[i] = (double)(0);
 | |
|         f->ptr.p_double[i] = f->ptr.p_double[i]+c->f.ptr.p_double[s1]*ht00*hu00+c->f.ptr.p_double[s2]*ht01*hu00+c->f.ptr.p_double[s3]*ht00*hu01+c->f.ptr.p_double[s4]*ht01*hu01;
 | |
|         f->ptr.p_double[i] = f->ptr.p_double[i]+c->f.ptr.p_double[sfx+s1]*ht10*hu00+c->f.ptr.p_double[sfx+s2]*ht11*hu00+c->f.ptr.p_double[sfx+s3]*ht10*hu01+c->f.ptr.p_double[sfx+s4]*ht11*hu01;
 | |
|         f->ptr.p_double[i] = f->ptr.p_double[i]+c->f.ptr.p_double[sfy+s1]*ht00*hu10+c->f.ptr.p_double[sfy+s2]*ht01*hu10+c->f.ptr.p_double[sfy+s3]*ht00*hu11+c->f.ptr.p_double[sfy+s4]*ht01*hu11;
 | |
|         f->ptr.p_double[i] = f->ptr.p_double[i]+c->f.ptr.p_double[sfxy+s1]*ht10*hu10+c->f.ptr.p_double[sfxy+s2]*ht11*hu10+c->f.ptr.p_double[sfxy+s3]*ht10*hu11+c->f.ptr.p_double[sfxy+s4]*ht11*hu11;
 | |
|         
 | |
|         /*
 | |
|          * Advance source indexes
 | |
|          */
 | |
|         s1 = s1+1;
 | |
|         s2 = s2+1;
 | |
|         s3 = s3+1;
 | |
|         s4 = s4+1;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates specific component of vector-valued bilinear or
 | |
| bicubic spline at the given point (X,Y).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y-   point
 | |
|     I   -   component index, in [0,D). An exception is generated for out
 | |
|             of range values.
 | |
| 
 | |
| RESULT:
 | |
|     value of I-th component
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double spline2dcalcvi(spline2dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      ae_int_t i,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t ix;
 | |
|     ae_int_t iy;
 | |
|     ae_int_t l;
 | |
|     ae_int_t r;
 | |
|     ae_int_t h;
 | |
|     double t;
 | |
|     double dt;
 | |
|     double u;
 | |
|     double du;
 | |
|     double y1;
 | |
|     double y2;
 | |
|     double y3;
 | |
|     double y4;
 | |
|     ae_int_t s1;
 | |
|     ae_int_t s2;
 | |
|     ae_int_t s3;
 | |
|     ae_int_t s4;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     double t2;
 | |
|     double t3;
 | |
|     double u2;
 | |
|     double u3;
 | |
|     double ht00;
 | |
|     double ht01;
 | |
|     double ht10;
 | |
|     double ht11;
 | |
|     double hu00;
 | |
|     double hu01;
 | |
|     double hu10;
 | |
|     double hu11;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcVi: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcVi: X or Y contains NaN or Infinite value", _state);
 | |
|     ae_assert(i>=0&&i<c->d, "Spline2DCalcVi: incorrect I (I<0 or I>=D)", _state);
 | |
|     
 | |
|     /*
 | |
|      * Determine evaluation interval
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->n-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
 | |
|     t = (x-c->x.ptr.p_double[l])*dt;
 | |
|     ix = l;
 | |
|     l = 0;
 | |
|     r = c->m-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
 | |
|     u = (y-c->y.ptr.p_double[l])*du;
 | |
|     iy = l;
 | |
|     
 | |
|     /*
 | |
|      * Bilinear interpolation
 | |
|      */
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         y1 = c->f.ptr.p_double[c->d*(c->n*iy+ix)+i];
 | |
|         y2 = c->f.ptr.p_double[c->d*(c->n*iy+(ix+1))+i];
 | |
|         y3 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+(ix+1))+i];
 | |
|         y4 = c->f.ptr.p_double[c->d*(c->n*(iy+1)+ix)+i];
 | |
|         result = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4;
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Bicubic interpolation:
 | |
|      * * calculate Hermite basis for dimensions X and Y (variables T and U),
 | |
|      *   here HTij means basis function whose I-th derivative has value 1 at T=J.
 | |
|      *   Same for HUij.
 | |
|      * * after initial calculation, apply scaling by DT/DU to the basis
 | |
|      * * calculate using stored table of second derivatives
 | |
|      */
 | |
|     ae_assert(c->stype==-3, "Spline2DCalc: integrity check failed", _state);
 | |
|     sfx = c->n*c->m*c->d;
 | |
|     sfy = 2*c->n*c->m*c->d;
 | |
|     sfxy = 3*c->n*c->m*c->d;
 | |
|     s1 = (c->n*iy+ix)*c->d;
 | |
|     s2 = (c->n*iy+(ix+1))*c->d;
 | |
|     s3 = (c->n*(iy+1)+ix)*c->d;
 | |
|     s4 = (c->n*(iy+1)+(ix+1))*c->d;
 | |
|     t2 = t*t;
 | |
|     t3 = t*t2;
 | |
|     u2 = u*u;
 | |
|     u3 = u*u2;
 | |
|     ht00 = 2*t3-3*t2+1;
 | |
|     ht10 = t3-2*t2+t;
 | |
|     ht01 = -2*t3+3*t2;
 | |
|     ht11 = t3-t2;
 | |
|     hu00 = 2*u3-3*u2+1;
 | |
|     hu10 = u3-2*u2+u;
 | |
|     hu01 = -2*u3+3*u2;
 | |
|     hu11 = u3-u2;
 | |
|     ht10 = ht10/dt;
 | |
|     ht11 = ht11/dt;
 | |
|     hu10 = hu10/du;
 | |
|     hu11 = hu11/du;
 | |
|     
 | |
|     /*
 | |
|      * Advance source indexes to I-th position
 | |
|      */
 | |
|     s1 = s1+i;
 | |
|     s2 = s2+i;
 | |
|     s3 = s3+i;
 | |
|     s4 = s4+i;
 | |
|     
 | |
|     /*
 | |
|      * Calculate I-th component
 | |
|      */
 | |
|     result = (double)(0);
 | |
|     result = result+c->f.ptr.p_double[s1]*ht00*hu00+c->f.ptr.p_double[s2]*ht01*hu00+c->f.ptr.p_double[s3]*ht00*hu01+c->f.ptr.p_double[s4]*ht01*hu01;
 | |
|     result = result+c->f.ptr.p_double[sfx+s1]*ht10*hu00+c->f.ptr.p_double[sfx+s2]*ht11*hu00+c->f.ptr.p_double[sfx+s3]*ht10*hu01+c->f.ptr.p_double[sfx+s4]*ht11*hu01;
 | |
|     result = result+c->f.ptr.p_double[sfy+s1]*ht00*hu10+c->f.ptr.p_double[sfy+s2]*ht01*hu10+c->f.ptr.p_double[sfy+s3]*ht00*hu11+c->f.ptr.p_double[sfy+s4]*ht01*hu11;
 | |
|     result = result+c->f.ptr.p_double[sfxy+s1]*ht10*hu10+c->f.ptr.p_double[sfxy+s2]*ht11*hu10+c->f.ptr.p_double[sfxy+s3]*ht10*hu11+c->f.ptr.p_double[sfxy+s4]*ht11*hu11;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates bilinear or bicubic vector-valued spline at the
 | |
| given point (X,Y).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y-   point
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     F   -   array[D] which stores function values.  F is out-parameter and
 | |
|             it  is  reallocated  after  call to this function. In case you
 | |
|             want  to    reuse  previously  allocated  F,   you   may   use
 | |
|             Spline2DCalcVBuf(),  which  reallocates  F only when it is too
 | |
|             small.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 16.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dcalcv(spline2dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      /* Real    */ ae_vector* f,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     ae_vector_clear(f);
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline2DCalcV: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DCalcV: either X=NaN/Infinite or Y=NaN/Infinite", _state);
 | |
|     spline2dcalcvbuf(c, x, y, f, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine calculates value of  specific  component  of  bilinear  or
 | |
| bicubic vector-valued spline and its derivatives.
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   spline interpolant.
 | |
|     X, Y-   point
 | |
|     I   -   component index, in [0,D)
 | |
| 
 | |
| Output parameters:
 | |
|     F   -   S(x,y)
 | |
|     FX  -   dS(x,y)/dX
 | |
|     FY  -   dS(x,y)/dY
 | |
|     FXY -   d2S(x,y)/dXdY
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 05.07.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2ddiffvi(spline2dinterpolant* c,
 | |
|      double x,
 | |
|      double y,
 | |
|      ae_int_t i,
 | |
|      double* f,
 | |
|      double* fx,
 | |
|      double* fy,
 | |
|      double* fxy,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t d;
 | |
|     double t;
 | |
|     double dt;
 | |
|     double u;
 | |
|     double du;
 | |
|     ae_int_t ix;
 | |
|     ae_int_t iy;
 | |
|     ae_int_t l;
 | |
|     ae_int_t r;
 | |
|     ae_int_t h;
 | |
|     ae_int_t s1;
 | |
|     ae_int_t s2;
 | |
|     ae_int_t s3;
 | |
|     ae_int_t s4;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     double y1;
 | |
|     double y2;
 | |
|     double y3;
 | |
|     double y4;
 | |
|     double v0;
 | |
|     double v1;
 | |
|     double v2;
 | |
|     double v3;
 | |
|     double t2;
 | |
|     double t3;
 | |
|     double u2;
 | |
|     double u3;
 | |
|     double ht00;
 | |
|     double ht01;
 | |
|     double ht10;
 | |
|     double ht11;
 | |
|     double hu00;
 | |
|     double hu01;
 | |
|     double hu10;
 | |
|     double hu11;
 | |
|     double dht00;
 | |
|     double dht01;
 | |
|     double dht10;
 | |
|     double dht11;
 | |
|     double dhu00;
 | |
|     double dhu01;
 | |
|     double dhu10;
 | |
|     double dhu11;
 | |
| 
 | |
|     *f = 0;
 | |
|     *fx = 0;
 | |
|     *fy = 0;
 | |
|     *fxy = 0;
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline2DDiffVI: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert(ae_isfinite(x, _state)&&ae_isfinite(y, _state), "Spline2DDiffVI: X or Y contains NaN or Infinite value", _state);
 | |
|     ae_assert(i>=0&&i<c->d, "Spline2DDiffVI: I<0 or I>=D", _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare F, dF/dX, dF/dY, d2F/dXdY
 | |
|      */
 | |
|     *f = (double)(0);
 | |
|     *fx = (double)(0);
 | |
|     *fy = (double)(0);
 | |
|     *fxy = (double)(0);
 | |
|     d = c->d;
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ x[0], ..., x[n-2] ] (x[n-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->n-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->x.ptr.p_double[h],x) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     t = (x-c->x.ptr.p_double[l])/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
 | |
|     dt = 1.0/(c->x.ptr.p_double[l+1]-c->x.ptr.p_double[l]);
 | |
|     ix = l;
 | |
|     
 | |
|     /*
 | |
|      * Binary search in the [ y[0], ..., y[m-2] ] (y[m-1] is not included)
 | |
|      */
 | |
|     l = 0;
 | |
|     r = c->m-1;
 | |
|     while(l!=r-1)
 | |
|     {
 | |
|         h = (l+r)/2;
 | |
|         if( ae_fp_greater_eq(c->y.ptr.p_double[h],y) )
 | |
|         {
 | |
|             r = h;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             l = h;
 | |
|         }
 | |
|     }
 | |
|     u = (y-c->y.ptr.p_double[l])/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
 | |
|     du = 1.0/(c->y.ptr.p_double[l+1]-c->y.ptr.p_double[l]);
 | |
|     iy = l;
 | |
|     
 | |
|     /*
 | |
|      * Bilinear interpolation
 | |
|      */
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         y1 = c->f.ptr.p_double[d*(c->n*iy+ix)+i];
 | |
|         y2 = c->f.ptr.p_double[d*(c->n*iy+(ix+1))+i];
 | |
|         y3 = c->f.ptr.p_double[d*(c->n*(iy+1)+(ix+1))+i];
 | |
|         y4 = c->f.ptr.p_double[d*(c->n*(iy+1)+ix)+i];
 | |
|         *f = (1-t)*(1-u)*y1+t*(1-u)*y2+t*u*y3+(1-t)*u*y4;
 | |
|         *fx = (-(1-u)*y1+(1-u)*y2+u*y3-u*y4)*dt;
 | |
|         *fy = (-(1-t)*y1-t*y2+t*y3+(1-t)*y4)*du;
 | |
|         *fxy = (y1-y2+y3-y4)*du*dt;
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Bicubic interpolation
 | |
|      */
 | |
|     if( c->stype==-3 )
 | |
|     {
 | |
|         sfx = c->n*c->m*d;
 | |
|         sfy = 2*c->n*c->m*d;
 | |
|         sfxy = 3*c->n*c->m*d;
 | |
|         s1 = d*(c->n*iy+ix)+i;
 | |
|         s2 = d*(c->n*iy+(ix+1))+i;
 | |
|         s3 = d*(c->n*(iy+1)+ix)+i;
 | |
|         s4 = d*(c->n*(iy+1)+(ix+1))+i;
 | |
|         t2 = t*t;
 | |
|         t3 = t*t2;
 | |
|         u2 = u*u;
 | |
|         u3 = u*u2;
 | |
|         ht00 = 2*t3-3*t2+1;
 | |
|         ht10 = t3-2*t2+t;
 | |
|         ht01 = -2*t3+3*t2;
 | |
|         ht11 = t3-t2;
 | |
|         hu00 = 2*u3-3*u2+1;
 | |
|         hu10 = u3-2*u2+u;
 | |
|         hu01 = -2*u3+3*u2;
 | |
|         hu11 = u3-u2;
 | |
|         ht10 = ht10/dt;
 | |
|         ht11 = ht11/dt;
 | |
|         hu10 = hu10/du;
 | |
|         hu11 = hu11/du;
 | |
|         dht00 = 6*t2-6*t;
 | |
|         dht10 = 3*t2-4*t+1;
 | |
|         dht01 = -6*t2+6*t;
 | |
|         dht11 = 3*t2-2*t;
 | |
|         dhu00 = 6*u2-6*u;
 | |
|         dhu10 = 3*u2-4*u+1;
 | |
|         dhu01 = -6*u2+6*u;
 | |
|         dhu11 = 3*u2-2*u;
 | |
|         dht00 = dht00*dt;
 | |
|         dht01 = dht01*dt;
 | |
|         dhu00 = dhu00*du;
 | |
|         dhu01 = dhu01*du;
 | |
|         *f = (double)(0);
 | |
|         *fx = (double)(0);
 | |
|         *fy = (double)(0);
 | |
|         *fxy = (double)(0);
 | |
|         v0 = c->f.ptr.p_double[s1];
 | |
|         v1 = c->f.ptr.p_double[s2];
 | |
|         v2 = c->f.ptr.p_double[s3];
 | |
|         v3 = c->f.ptr.p_double[s4];
 | |
|         *f = *f+v0*ht00*hu00+v1*ht01*hu00+v2*ht00*hu01+v3*ht01*hu01;
 | |
|         *fx = *fx+v0*dht00*hu00+v1*dht01*hu00+v2*dht00*hu01+v3*dht01*hu01;
 | |
|         *fy = *fy+v0*ht00*dhu00+v1*ht01*dhu00+v2*ht00*dhu01+v3*ht01*dhu01;
 | |
|         *fxy = *fxy+v0*dht00*dhu00+v1*dht01*dhu00+v2*dht00*dhu01+v3*dht01*dhu01;
 | |
|         v0 = c->f.ptr.p_double[sfx+s1];
 | |
|         v1 = c->f.ptr.p_double[sfx+s2];
 | |
|         v2 = c->f.ptr.p_double[sfx+s3];
 | |
|         v3 = c->f.ptr.p_double[sfx+s4];
 | |
|         *f = *f+v0*ht10*hu00+v1*ht11*hu00+v2*ht10*hu01+v3*ht11*hu01;
 | |
|         *fx = *fx+v0*dht10*hu00+v1*dht11*hu00+v2*dht10*hu01+v3*dht11*hu01;
 | |
|         *fy = *fy+v0*ht10*dhu00+v1*ht11*dhu00+v2*ht10*dhu01+v3*ht11*dhu01;
 | |
|         *fxy = *fxy+v0*dht10*dhu00+v1*dht11*dhu00+v2*dht10*dhu01+v3*dht11*dhu01;
 | |
|         v0 = c->f.ptr.p_double[sfy+s1];
 | |
|         v1 = c->f.ptr.p_double[sfy+s2];
 | |
|         v2 = c->f.ptr.p_double[sfy+s3];
 | |
|         v3 = c->f.ptr.p_double[sfy+s4];
 | |
|         *f = *f+v0*ht00*hu10+v1*ht01*hu10+v2*ht00*hu11+v3*ht01*hu11;
 | |
|         *fx = *fx+v0*dht00*hu10+v1*dht01*hu10+v2*dht00*hu11+v3*dht01*hu11;
 | |
|         *fy = *fy+v0*ht00*dhu10+v1*ht01*dhu10+v2*ht00*dhu11+v3*ht01*dhu11;
 | |
|         *fxy = *fxy+v0*dht00*dhu10+v1*dht01*dhu10+v2*dht00*dhu11+v3*dht01*dhu11;
 | |
|         v0 = c->f.ptr.p_double[sfxy+s1];
 | |
|         v1 = c->f.ptr.p_double[sfxy+s2];
 | |
|         v2 = c->f.ptr.p_double[sfxy+s3];
 | |
|         v3 = c->f.ptr.p_double[sfxy+s4];
 | |
|         *f = *f+v0*ht10*hu10+v1*ht11*hu10+v2*ht10*hu11+v3*ht11*hu11;
 | |
|         *fx = *fx+v0*dht10*hu10+v1*dht11*hu10+v2*dht10*hu11+v3*dht11*hu11;
 | |
|         *fy = *fy+v0*ht10*dhu10+v1*ht11*dhu10+v2*ht10*dhu11+v3*ht11*dhu11;
 | |
|         *fxy = *fxy+v0*dht10*dhu10+v1*dht11*dhu10+v2*dht10*dhu11+v3*dht11*dhu11;
 | |
|         return;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline argument.
 | |
| 
 | |
| Input parameters:
 | |
|     C       -   spline interpolant
 | |
|     AX, BX  -   transformation coefficients: x = A*t + B
 | |
|     AY, BY  -   transformation coefficients: y = A*u + B
 | |
| Result:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dlintransxy(spline2dinterpolant* c,
 | |
|      double ax,
 | |
|      double bx,
 | |
|      double ay,
 | |
|      double by,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector x;
 | |
|     ae_vector y;
 | |
|     ae_vector f;
 | |
|     ae_vector v;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&x, 0, sizeof(x));
 | |
|     memset(&y, 0, sizeof(y));
 | |
|     memset(&f, 0, sizeof(f));
 | |
|     memset(&v, 0, sizeof(v));
 | |
|     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&f, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&v, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(c->stype==-3||c->stype==-1, "Spline2DLinTransXY: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_assert(ae_isfinite(ax, _state), "Spline2DLinTransXY: AX is infinite or NaN", _state);
 | |
|     ae_assert(ae_isfinite(bx, _state), "Spline2DLinTransXY: BX is infinite or NaN", _state);
 | |
|     ae_assert(ae_isfinite(ay, _state), "Spline2DLinTransXY: AY is infinite or NaN", _state);
 | |
|     ae_assert(ae_isfinite(by, _state), "Spline2DLinTransXY: BY is infinite or NaN", _state);
 | |
|     ae_vector_set_length(&x, c->n, _state);
 | |
|     ae_vector_set_length(&y, c->m, _state);
 | |
|     ae_vector_set_length(&f, c->m*c->n*c->d, _state);
 | |
|     for(j=0; j<=c->n-1; j++)
 | |
|     {
 | |
|         x.ptr.p_double[j] = c->x.ptr.p_double[j];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         y.ptr.p_double[i] = c->y.ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=c->n-1; j++)
 | |
|         {
 | |
|             for(k=0; k<=c->d-1; k++)
 | |
|             {
 | |
|                 f.ptr.p_double[c->d*(i*c->n+j)+k] = c->f.ptr.p_double[c->d*(i*c->n+j)+k];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Handle different combinations of AX/AY
 | |
|      */
 | |
|     if( ae_fp_eq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)) )
 | |
|     {
 | |
|         for(i=0; i<=c->m-1; i++)
 | |
|         {
 | |
|             spline2dcalcvbuf(c, bx, y.ptr.p_double[i], &v, _state);
 | |
|             y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay;
 | |
|             for(j=0; j<=c->n-1; j++)
 | |
|             {
 | |
|                 for(k=0; k<=c->d-1; k++)
 | |
|                 {
 | |
|                     f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if( ae_fp_neq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)) )
 | |
|     {
 | |
|         for(j=0; j<=c->n-1; j++)
 | |
|         {
 | |
|             spline2dcalcvbuf(c, x.ptr.p_double[j], by, &v, _state);
 | |
|             x.ptr.p_double[j] = (x.ptr.p_double[j]-bx)/ax;
 | |
|             for(i=0; i<=c->m-1; i++)
 | |
|             {
 | |
|                 for(k=0; k<=c->d-1; k++)
 | |
|                 {
 | |
|                     f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if( ae_fp_neq(ax,(double)(0))&&ae_fp_neq(ay,(double)(0)) )
 | |
|     {
 | |
|         for(j=0; j<=c->n-1; j++)
 | |
|         {
 | |
|             x.ptr.p_double[j] = (x.ptr.p_double[j]-bx)/ax;
 | |
|         }
 | |
|         for(i=0; i<=c->m-1; i++)
 | |
|         {
 | |
|             y.ptr.p_double[i] = (y.ptr.p_double[i]-by)/ay;
 | |
|         }
 | |
|     }
 | |
|     if( ae_fp_eq(ax,(double)(0))&&ae_fp_eq(ay,(double)(0)) )
 | |
|     {
 | |
|         spline2dcalcvbuf(c, bx, by, &v, _state);
 | |
|         for(i=0; i<=c->m-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=c->n-1; j++)
 | |
|             {
 | |
|                 for(k=0; k<=c->d-1; k++)
 | |
|                 {
 | |
|                     f.ptr.p_double[c->d*(i*c->n+j)+k] = v.ptr.p_double[k];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Rebuild spline
 | |
|      */
 | |
|     if( c->stype==-3 )
 | |
|     {
 | |
|         spline2dbuildbicubicv(&x, c->n, &y, c->m, &f, c->d, c, _state);
 | |
|     }
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         spline2dbuildbilinearv(&x, c->n, &y, c->m, &f, c->d, c, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine performs linear transformation of the spline.
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   spline interpolant.
 | |
|     A, B-   transformation coefficients: S2(x,y) = A*S(x,y) + B
 | |
|     
 | |
| Output parameters:
 | |
|     C   -   transformed spline
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 30.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dlintransf(spline2dinterpolant* c,
 | |
|      double a,
 | |
|      double b,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector x;
 | |
|     ae_vector y;
 | |
|     ae_vector f;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&x, 0, sizeof(x));
 | |
|     memset(&y, 0, sizeof(y));
 | |
|     memset(&f, 0, sizeof(f));
 | |
|     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&f, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(c->stype==-3||c->stype==-1, "Spline2DLinTransF: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     ae_vector_set_length(&x, c->n, _state);
 | |
|     ae_vector_set_length(&y, c->m, _state);
 | |
|     ae_vector_set_length(&f, c->m*c->n*c->d, _state);
 | |
|     for(j=0; j<=c->n-1; j++)
 | |
|     {
 | |
|         x.ptr.p_double[j] = c->x.ptr.p_double[j];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         y.ptr.p_double[i] = c->y.ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->m*c->n*c->d-1; i++)
 | |
|     {
 | |
|         f.ptr.p_double[i] = a*c->f.ptr.p_double[i]+b;
 | |
|     }
 | |
|     if( c->stype==-3 )
 | |
|     {
 | |
|         spline2dbuildbicubicv(&x, c->n, &y, c->m, &f, c->d, c, _state);
 | |
|     }
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         spline2dbuildbilinearv(&x, c->n, &y, c->m, &f, c->d, c, _state);
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine makes the copy of the spline model.
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
| Output parameters:
 | |
|     CC  -   spline copy
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 29.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dcopy(spline2dinterpolant* c,
 | |
|      spline2dinterpolant* cc,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t tblsize;
 | |
| 
 | |
|     _spline2dinterpolant_clear(cc);
 | |
| 
 | |
|     ae_assert(c->stype==-1||c->stype==-3, "Spline2DCopy: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     cc->n = c->n;
 | |
|     cc->m = c->m;
 | |
|     cc->d = c->d;
 | |
|     cc->stype = c->stype;
 | |
|     tblsize = -1;
 | |
|     if( c->stype==-3 )
 | |
|     {
 | |
|         tblsize = 4*c->n*c->m*c->d;
 | |
|     }
 | |
|     if( c->stype==-1 )
 | |
|     {
 | |
|         tblsize = c->n*c->m*c->d;
 | |
|     }
 | |
|     ae_assert(tblsize>0, "Spline2DCopy: internal error", _state);
 | |
|     ae_vector_set_length(&cc->x, cc->n, _state);
 | |
|     ae_vector_set_length(&cc->y, cc->m, _state);
 | |
|     ae_vector_set_length(&cc->f, tblsize, _state);
 | |
|     ae_v_move(&cc->x.ptr.p_double[0], 1, &c->x.ptr.p_double[0], 1, ae_v_len(0,cc->n-1));
 | |
|     ae_v_move(&cc->y.ptr.p_double[0], 1, &c->y.ptr.p_double[0], 1, ae_v_len(0,cc->m-1));
 | |
|     ae_v_move(&cc->f.ptr.p_double[0], 1, &c->f.ptr.p_double[0], 1, ae_v_len(0,tblsize-1));
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Bicubic spline resampling
 | |
| 
 | |
| Input parameters:
 | |
|     A           -   function values at the old grid,
 | |
|                     array[0..OldHeight-1, 0..OldWidth-1]
 | |
|     OldHeight   -   old grid height, OldHeight>1
 | |
|     OldWidth    -   old grid width, OldWidth>1
 | |
|     NewHeight   -   new grid height, NewHeight>1
 | |
|     NewWidth    -   new grid width, NewWidth>1
 | |
|     
 | |
| Output parameters:
 | |
|     B           -   function values at the new grid,
 | |
|                     array[0..NewHeight-1, 0..NewWidth-1]
 | |
| 
 | |
|   -- ALGLIB routine --
 | |
|      15 May, 2007
 | |
|      Copyright by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dresamplebicubic(/* Real    */ ae_matrix* a,
 | |
|      ae_int_t oldheight,
 | |
|      ae_int_t oldwidth,
 | |
|      /* Real    */ ae_matrix* b,
 | |
|      ae_int_t newheight,
 | |
|      ae_int_t newwidth,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_matrix buf;
 | |
|     ae_vector x;
 | |
|     ae_vector y;
 | |
|     spline1dinterpolant c;
 | |
|     ae_int_t mw;
 | |
|     ae_int_t mh;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&buf, 0, sizeof(buf));
 | |
|     memset(&x, 0, sizeof(x));
 | |
|     memset(&y, 0, sizeof(y));
 | |
|     memset(&c, 0, sizeof(c));
 | |
|     ae_matrix_clear(b);
 | |
|     ae_matrix_init(&buf, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&x, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&y, 0, DT_REAL, _state, ae_true);
 | |
|     _spline1dinterpolant_init(&c, _state, ae_true);
 | |
| 
 | |
|     ae_assert(oldwidth>1&&oldheight>1, "Spline2DResampleBicubic: width/height less than 1", _state);
 | |
|     ae_assert(newwidth>1&&newheight>1, "Spline2DResampleBicubic: width/height less than 1", _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare
 | |
|      */
 | |
|     mw = ae_maxint(oldwidth, newwidth, _state);
 | |
|     mh = ae_maxint(oldheight, newheight, _state);
 | |
|     ae_matrix_set_length(b, newheight, newwidth, _state);
 | |
|     ae_matrix_set_length(&buf, oldheight, newwidth, _state);
 | |
|     ae_vector_set_length(&x, ae_maxint(mw, mh, _state), _state);
 | |
|     ae_vector_set_length(&y, ae_maxint(mw, mh, _state), _state);
 | |
|     
 | |
|     /*
 | |
|      * Horizontal interpolation
 | |
|      */
 | |
|     for(i=0; i<=oldheight-1; i++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Fill X, Y
 | |
|          */
 | |
|         for(j=0; j<=oldwidth-1; j++)
 | |
|         {
 | |
|             x.ptr.p_double[j] = (double)j/(double)(oldwidth-1);
 | |
|             y.ptr.p_double[j] = a->ptr.pp_double[i][j];
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Interpolate and place result into temporary matrix
 | |
|          */
 | |
|         spline1dbuildcubic(&x, &y, oldwidth, 0, 0.0, 0, 0.0, &c, _state);
 | |
|         for(j=0; j<=newwidth-1; j++)
 | |
|         {
 | |
|             buf.ptr.pp_double[i][j] = spline1dcalc(&c, (double)j/(double)(newwidth-1), _state);
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Vertical interpolation
 | |
|      */
 | |
|     for(j=0; j<=newwidth-1; j++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Fill X, Y
 | |
|          */
 | |
|         for(i=0; i<=oldheight-1; i++)
 | |
|         {
 | |
|             x.ptr.p_double[i] = (double)i/(double)(oldheight-1);
 | |
|             y.ptr.p_double[i] = buf.ptr.pp_double[i][j];
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Interpolate and place result into B
 | |
|          */
 | |
|         spline1dbuildcubic(&x, &y, oldheight, 0, 0.0, 0, 0.0, &c, _state);
 | |
|         for(i=0; i<=newheight-1; i++)
 | |
|         {
 | |
|             b->ptr.pp_double[i][j] = spline1dcalc(&c, (double)i/(double)(newheight-1), _state);
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Bilinear spline resampling
 | |
| 
 | |
| Input parameters:
 | |
|     A           -   function values at the old grid,
 | |
|                     array[0..OldHeight-1, 0..OldWidth-1]
 | |
|     OldHeight   -   old grid height, OldHeight>1
 | |
|     OldWidth    -   old grid width, OldWidth>1
 | |
|     NewHeight   -   new grid height, NewHeight>1
 | |
|     NewWidth    -   new grid width, NewWidth>1
 | |
| 
 | |
| Output parameters:
 | |
|     B           -   function values at the new grid,
 | |
|                     array[0..NewHeight-1, 0..NewWidth-1]
 | |
| 
 | |
|   -- ALGLIB routine --
 | |
|      09.07.2007
 | |
|      Copyright by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dresamplebilinear(/* Real    */ ae_matrix* a,
 | |
|      ae_int_t oldheight,
 | |
|      ae_int_t oldwidth,
 | |
|      /* Real    */ ae_matrix* b,
 | |
|      ae_int_t newheight,
 | |
|      ae_int_t newwidth,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t l;
 | |
|     ae_int_t c;
 | |
|     double t;
 | |
|     double u;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     ae_matrix_clear(b);
 | |
| 
 | |
|     ae_assert(oldwidth>1&&oldheight>1, "Spline2DResampleBilinear: width/height less than 1", _state);
 | |
|     ae_assert(newwidth>1&&newheight>1, "Spline2DResampleBilinear: width/height less than 1", _state);
 | |
|     ae_matrix_set_length(b, newheight, newwidth, _state);
 | |
|     for(i=0; i<=newheight-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=newwidth-1; j++)
 | |
|         {
 | |
|             l = i*(oldheight-1)/(newheight-1);
 | |
|             if( l==oldheight-1 )
 | |
|             {
 | |
|                 l = oldheight-2;
 | |
|             }
 | |
|             u = (double)i/(double)(newheight-1)*(oldheight-1)-l;
 | |
|             c = j*(oldwidth-1)/(newwidth-1);
 | |
|             if( c==oldwidth-1 )
 | |
|             {
 | |
|                 c = oldwidth-2;
 | |
|             }
 | |
|             t = (double)(j*(oldwidth-1))/(double)(newwidth-1)-c;
 | |
|             b->ptr.pp_double[i][j] = (1-t)*(1-u)*a->ptr.pp_double[l][c]+t*(1-u)*a->ptr.pp_double[l][c+1]+t*u*a->ptr.pp_double[l+1][c+1]+(1-t)*u*a->ptr.pp_double[l+1][c];
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds bilinear vector-valued spline.
 | |
| 
 | |
| Input parameters:
 | |
|     X   -   spline abscissas, array[0..N-1]
 | |
|     Y   -   spline ordinates, array[0..M-1]
 | |
|     F   -   function values, array[0..M*N*D-1]:
 | |
|             * first D elements store D values at (X[0],Y[0])
 | |
|             * next D elements store D values at (X[1],Y[0])
 | |
|             * general form - D function values at (X[i],Y[j]) are stored
 | |
|               at F[D*(J*N+I)...D*(J*N+I)+D-1].
 | |
|     M,N -   grid size, M>=2, N>=2
 | |
|     D   -   vector dimension, D>=1
 | |
| 
 | |
| Output parameters:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 16.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildbilinearv(/* Real    */ ae_vector* x,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t m,
 | |
|      /* Real    */ ae_vector* f,
 | |
|      ae_int_t d,
 | |
|      spline2dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double t;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t i0;
 | |
| 
 | |
|     _spline2dinterpolant_clear(c);
 | |
| 
 | |
|     ae_assert(n>=2, "Spline2DBuildBilinearV: N is less then 2", _state);
 | |
|     ae_assert(m>=2, "Spline2DBuildBilinearV: M is less then 2", _state);
 | |
|     ae_assert(d>=1, "Spline2DBuildBilinearV: invalid argument D (D<1)", _state);
 | |
|     ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinearV: length of X or Y is too short (Length(X/Y)<N/M)", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state)&&isfinitevector(y, m, _state), "Spline2DBuildBilinearV: X or Y contains NaN or Infinite value", _state);
 | |
|     k = n*m*d;
 | |
|     ae_assert(f->cnt>=k, "Spline2DBuildBilinearV: length of F is too short (Length(F)<N*M*D)", _state);
 | |
|     ae_assert(isfinitevector(f, k, _state), "Spline2DBuildBilinearV: F contains NaN or Infinite value", _state);
 | |
|     
 | |
|     /*
 | |
|      * Fill interpolant
 | |
|      */
 | |
|     c->n = n;
 | |
|     c->m = m;
 | |
|     c->d = d;
 | |
|     c->stype = -1;
 | |
|     ae_vector_set_length(&c->x, c->n, _state);
 | |
|     ae_vector_set_length(&c->y, c->m, _state);
 | |
|     ae_vector_set_length(&c->f, k, _state);
 | |
|     for(i=0; i<=c->n-1; i++)
 | |
|     {
 | |
|         c->x.ptr.p_double[i] = x->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         c->y.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=k-1; i++)
 | |
|     {
 | |
|         c->f.ptr.p_double[i] = f->ptr.p_double[i];
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Sort points
 | |
|      */
 | |
|     for(j=0; j<=c->n-1; j++)
 | |
|     {
 | |
|         k = j;
 | |
|         for(i=j+1; i<=c->n-1; i++)
 | |
|         {
 | |
|             if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) )
 | |
|             {
 | |
|                 k = i;
 | |
|             }
 | |
|         }
 | |
|         if( k!=j )
 | |
|         {
 | |
|             for(i=0; i<=c->m-1; i++)
 | |
|             {
 | |
|                 for(i0=0; i0<=c->d-1; i0++)
 | |
|                 {
 | |
|                     t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0];
 | |
|                     c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(i*c->n+k)+i0];
 | |
|                     c->f.ptr.p_double[c->d*(i*c->n+k)+i0] = t;
 | |
|                 }
 | |
|             }
 | |
|             t = c->x.ptr.p_double[j];
 | |
|             c->x.ptr.p_double[j] = c->x.ptr.p_double[k];
 | |
|             c->x.ptr.p_double[k] = t;
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         k = i;
 | |
|         for(j=i+1; j<=c->m-1; j++)
 | |
|         {
 | |
|             if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) )
 | |
|             {
 | |
|                 k = j;
 | |
|             }
 | |
|         }
 | |
|         if( k!=i )
 | |
|         {
 | |
|             for(j=0; j<=c->n-1; j++)
 | |
|             {
 | |
|                 for(i0=0; i0<=c->d-1; i0++)
 | |
|                 {
 | |
|                     t = c->f.ptr.p_double[c->d*(i*c->n+j)+i0];
 | |
|                     c->f.ptr.p_double[c->d*(i*c->n+j)+i0] = c->f.ptr.p_double[c->d*(k*c->n+j)+i0];
 | |
|                     c->f.ptr.p_double[c->d*(k*c->n+j)+i0] = t;
 | |
|                 }
 | |
|             }
 | |
|             t = c->y.ptr.p_double[i];
 | |
|             c->y.ptr.p_double[i] = c->y.ptr.p_double[k];
 | |
|             c->y.ptr.p_double[k] = t;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine builds bicubic vector-valued spline.
 | |
| 
 | |
| Input parameters:
 | |
|     X   -   spline abscissas, array[0..N-1]
 | |
|     Y   -   spline ordinates, array[0..M-1]
 | |
|     F   -   function values, array[0..M*N*D-1]:
 | |
|             * first D elements store D values at (X[0],Y[0])
 | |
|             * next D elements store D values at (X[1],Y[0])
 | |
|             * general form - D function values at (X[i],Y[j]) are stored
 | |
|               at F[D*(J*N+I)...D*(J*N+I)+D-1].
 | |
|     M,N -   grid size, M>=2, N>=2
 | |
|     D   -   vector dimension, D>=1
 | |
| 
 | |
| Output parameters:
 | |
|     C   -   spline interpolant
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 16.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildbicubicv(/* Real    */ ae_vector* x,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t m,
 | |
|      /* Real    */ ae_vector* f,
 | |
|      ae_int_t d,
 | |
|      spline2dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _f;
 | |
|     ae_matrix tf;
 | |
|     ae_matrix dx;
 | |
|     ae_matrix dy;
 | |
|     ae_matrix dxy;
 | |
|     double t;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t di;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_f, 0, sizeof(_f));
 | |
|     memset(&tf, 0, sizeof(tf));
 | |
|     memset(&dx, 0, sizeof(dx));
 | |
|     memset(&dy, 0, sizeof(dy));
 | |
|     memset(&dxy, 0, sizeof(dxy));
 | |
|     ae_vector_init_copy(&_f, f, _state, ae_true);
 | |
|     f = &_f;
 | |
|     _spline2dinterpolant_clear(c);
 | |
|     ae_matrix_init(&tf, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&dx, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&dy, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=2, "Spline2DBuildBicubicV: N is less than 2", _state);
 | |
|     ae_assert(m>=2, "Spline2DBuildBicubicV: M is less than 2", _state);
 | |
|     ae_assert(d>=1, "Spline2DBuildBicubicV: invalid argument D (D<1)", _state);
 | |
|     ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubicV: length of X or Y is too short (Length(X/Y)<N/M)", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state)&&isfinitevector(y, m, _state), "Spline2DBuildBicubicV: X or Y contains NaN or Infinite value", _state);
 | |
|     k = n*m*d;
 | |
|     ae_assert(f->cnt>=k, "Spline2DBuildBicubicV: length of F is too short (Length(F)<N*M*D)", _state);
 | |
|     ae_assert(isfinitevector(f, k, _state), "Spline2DBuildBicubicV: F contains NaN or Infinite value", _state);
 | |
|     
 | |
|     /*
 | |
|      * Fill interpolant:
 | |
|      *  F[0]...F[N*M*D-1]:
 | |
|      *      f(i,j) table. f(0,0), f(0, 1), f(0,2) and so on...
 | |
|      *  F[N*M*D]...F[2*N*M*D-1]:
 | |
|      *      df(i,j)/dx table.
 | |
|      *  F[2*N*M*D]...F[3*N*M*D-1]:
 | |
|      *      df(i,j)/dy table.
 | |
|      *  F[3*N*M*D]...F[4*N*M*D-1]:
 | |
|      *      d2f(i,j)/dxdy table.
 | |
|      */
 | |
|     c->d = d;
 | |
|     c->n = n;
 | |
|     c->m = m;
 | |
|     c->stype = -3;
 | |
|     k = 4*k;
 | |
|     ae_vector_set_length(&c->x, c->n, _state);
 | |
|     ae_vector_set_length(&c->y, c->m, _state);
 | |
|     ae_vector_set_length(&c->f, k, _state);
 | |
|     ae_matrix_set_length(&tf, c->m, c->n, _state);
 | |
|     for(i=0; i<=c->n-1; i++)
 | |
|     {
 | |
|         c->x.ptr.p_double[i] = x->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         c->y.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Sort points
 | |
|      */
 | |
|     for(j=0; j<=c->n-1; j++)
 | |
|     {
 | |
|         k = j;
 | |
|         for(i=j+1; i<=c->n-1; i++)
 | |
|         {
 | |
|             if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) )
 | |
|             {
 | |
|                 k = i;
 | |
|             }
 | |
|         }
 | |
|         if( k!=j )
 | |
|         {
 | |
|             for(i=0; i<=c->m-1; i++)
 | |
|             {
 | |
|                 for(di=0; di<=c->d-1; di++)
 | |
|                 {
 | |
|                     t = f->ptr.p_double[c->d*(i*c->n+j)+di];
 | |
|                     f->ptr.p_double[c->d*(i*c->n+j)+di] = f->ptr.p_double[c->d*(i*c->n+k)+di];
 | |
|                     f->ptr.p_double[c->d*(i*c->n+k)+di] = t;
 | |
|                 }
 | |
|             }
 | |
|             t = c->x.ptr.p_double[j];
 | |
|             c->x.ptr.p_double[j] = c->x.ptr.p_double[k];
 | |
|             c->x.ptr.p_double[k] = t;
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         k = i;
 | |
|         for(j=i+1; j<=c->m-1; j++)
 | |
|         {
 | |
|             if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) )
 | |
|             {
 | |
|                 k = j;
 | |
|             }
 | |
|         }
 | |
|         if( k!=i )
 | |
|         {
 | |
|             for(j=0; j<=c->n-1; j++)
 | |
|             {
 | |
|                 for(di=0; di<=c->d-1; di++)
 | |
|                 {
 | |
|                     t = f->ptr.p_double[c->d*(i*c->n+j)+di];
 | |
|                     f->ptr.p_double[c->d*(i*c->n+j)+di] = f->ptr.p_double[c->d*(k*c->n+j)+di];
 | |
|                     f->ptr.p_double[c->d*(k*c->n+j)+di] = t;
 | |
|                 }
 | |
|             }
 | |
|             t = c->y.ptr.p_double[i];
 | |
|             c->y.ptr.p_double[i] = c->y.ptr.p_double[k];
 | |
|             c->y.ptr.p_double[k] = t;
 | |
|         }
 | |
|     }
 | |
|     for(di=0; di<=c->d-1; di++)
 | |
|     {
 | |
|         for(i=0; i<=c->m-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=c->n-1; j++)
 | |
|             {
 | |
|                 tf.ptr.pp_double[i][j] = f->ptr.p_double[c->d*(i*c->n+j)+di];
 | |
|             }
 | |
|         }
 | |
|         spline2d_bicubiccalcderivatives(&tf, &c->x, &c->y, c->m, c->n, &dx, &dy, &dxy, _state);
 | |
|         for(i=0; i<=c->m-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=c->n-1; j++)
 | |
|             {
 | |
|                 k = c->d*(i*c->n+j)+di;
 | |
|                 c->f.ptr.p_double[k] = tf.ptr.pp_double[i][j];
 | |
|                 c->f.ptr.p_double[c->n*c->m*c->d+k] = dx.ptr.pp_double[i][j];
 | |
|                 c->f.ptr.p_double[2*c->n*c->m*c->d+k] = dy.ptr.pp_double[i][j];
 | |
|                 c->f.ptr.p_double[3*c->n*c->m*c->d+k] = dxy.ptr.pp_double[i][j];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine unpacks two-dimensional spline into the coefficients table
 | |
| 
 | |
| Input parameters:
 | |
|     C   -   spline interpolant.
 | |
| 
 | |
| Result:
 | |
|     M, N-   grid size (x-axis and y-axis)
 | |
|     D   -   number of components
 | |
|     Tbl -   coefficients table, unpacked format,
 | |
|             D - components: [0..(N-1)*(M-1)*D-1, 0..19].
 | |
|             For T=0..D-1 (component index), I = 0...N-2 (x index),
 | |
|             J=0..M-2 (y index):
 | |
|                 K :=  T + I*D + J*D*(N-1)
 | |
|                 
 | |
|                 K-th row stores decomposition for T-th component of the
 | |
|                 vector-valued function
 | |
|                 
 | |
|                 Tbl[K,0] = X[i]
 | |
|                 Tbl[K,1] = X[i+1]
 | |
|                 Tbl[K,2] = Y[j]
 | |
|                 Tbl[K,3] = Y[j+1]
 | |
|                 Tbl[K,4] = C00
 | |
|                 Tbl[K,5] = C01
 | |
|                 Tbl[K,6] = C02
 | |
|                 Tbl[K,7] = C03
 | |
|                 Tbl[K,8] = C10
 | |
|                 Tbl[K,9] = C11
 | |
|                 ...
 | |
|                 Tbl[K,19] = C33
 | |
|             On each grid square spline is equals to:
 | |
|                 S(x) = SUM(c[i,j]*(t^i)*(u^j), i=0..3, j=0..3)
 | |
|                 t = x-x[j]
 | |
|                 u = y-y[i]
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 16.04.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dunpackv(spline2dinterpolant* c,
 | |
|      ae_int_t* m,
 | |
|      ae_int_t* n,
 | |
|      ae_int_t* d,
 | |
|      /* Real    */ ae_matrix* tbl,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t k;
 | |
|     ae_int_t p;
 | |
|     ae_int_t ci;
 | |
|     ae_int_t cj;
 | |
|     ae_int_t s1;
 | |
|     ae_int_t s2;
 | |
|     ae_int_t s3;
 | |
|     ae_int_t s4;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     double y1;
 | |
|     double y2;
 | |
|     double y3;
 | |
|     double y4;
 | |
|     double dt;
 | |
|     double du;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k0;
 | |
| 
 | |
|     *m = 0;
 | |
|     *n = 0;
 | |
|     *d = 0;
 | |
|     ae_matrix_clear(tbl);
 | |
| 
 | |
|     ae_assert(c->stype==-3||c->stype==-1, "Spline2DUnpackV: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     *n = c->n;
 | |
|     *m = c->m;
 | |
|     *d = c->d;
 | |
|     ae_matrix_set_length(tbl, (*n-1)*(*m-1)*(*d), 20, _state);
 | |
|     sfx = *n*(*m)*(*d);
 | |
|     sfy = 2*(*n)*(*m)*(*d);
 | |
|     sfxy = 3*(*n)*(*m)*(*d);
 | |
|     for(i=0; i<=*m-2; i++)
 | |
|     {
 | |
|         for(j=0; j<=*n-2; j++)
 | |
|         {
 | |
|             for(k=0; k<=*d-1; k++)
 | |
|             {
 | |
|                 p = *d*(i*(*n-1)+j)+k;
 | |
|                 tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[j];
 | |
|                 tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[j+1];
 | |
|                 tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[i];
 | |
|                 tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[i+1];
 | |
|                 dt = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]);
 | |
|                 du = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]);
 | |
|                 
 | |
|                 /*
 | |
|                  * Bilinear interpolation
 | |
|                  */
 | |
|                 if( c->stype==-1 )
 | |
|                 {
 | |
|                     for(k0=4; k0<=19; k0++)
 | |
|                     {
 | |
|                         tbl->ptr.pp_double[p][k0] = (double)(0);
 | |
|                     }
 | |
|                     y1 = c->f.ptr.p_double[*d*(*n*i+j)+k];
 | |
|                     y2 = c->f.ptr.p_double[*d*(*n*i+(j+1))+k];
 | |
|                     y3 = c->f.ptr.p_double[*d*(*n*(i+1)+(j+1))+k];
 | |
|                     y4 = c->f.ptr.p_double[*d*(*n*(i+1)+j)+k];
 | |
|                     tbl->ptr.pp_double[p][4] = y1;
 | |
|                     tbl->ptr.pp_double[p][4+1*4+0] = y2-y1;
 | |
|                     tbl->ptr.pp_double[p][4+0*4+1] = y4-y1;
 | |
|                     tbl->ptr.pp_double[p][4+1*4+1] = y3-y2-y4+y1;
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * Bicubic interpolation
 | |
|                  */
 | |
|                 if( c->stype==-3 )
 | |
|                 {
 | |
|                     s1 = *d*(*n*i+j)+k;
 | |
|                     s2 = *d*(*n*i+(j+1))+k;
 | |
|                     s3 = *d*(*n*(i+1)+(j+1))+k;
 | |
|                     s4 = *d*(*n*(i+1)+j)+k;
 | |
|                     tbl->ptr.pp_double[p][4+0*4+0] = c->f.ptr.p_double[s1];
 | |
|                     tbl->ptr.pp_double[p][4+0*4+1] = c->f.ptr.p_double[sfy+s1]/du;
 | |
|                     tbl->ptr.pp_double[p][4+0*4+2] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s4]-2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du;
 | |
|                     tbl->ptr.pp_double[p][4+0*4+3] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du;
 | |
|                     tbl->ptr.pp_double[p][4+1*4+0] = c->f.ptr.p_double[sfx+s1]/dt;
 | |
|                     tbl->ptr.pp_double[p][4+1*4+1] = c->f.ptr.p_double[sfxy+s1]/(dt*du);
 | |
|                     tbl->ptr.pp_double[p][4+1*4+2] = -3*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                     tbl->ptr.pp_double[p][4+1*4+3] = 2*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                     tbl->ptr.pp_double[p][4+2*4+0] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s2]-2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt;
 | |
|                     tbl->ptr.pp_double[p][4+2*4+1] = -3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du);
 | |
|                     tbl->ptr.pp_double[p][4+2*4+2] = 9*c->f.ptr.p_double[s1]-9*c->f.ptr.p_double[s2]+9*c->f.ptr.p_double[s3]-9*c->f.ptr.p_double[s4]+6*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s2]/dt-3*c->f.ptr.p_double[sfx+s3]/dt-6*c->f.ptr.p_double[sfx+s4]/dt+6*c->f.ptr.p_double[sfy+s1]/du-6*c->f.ptr.p_double[sfy+s2]/du-3*c->f.ptr.p_double[sfy+s3]/du+3*c->f.ptr.p_double[sfy+s4]/du+4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+2*c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                     tbl->ptr.pp_double[p][4+2*4+3] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-4*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s2]/dt+2*c->f.ptr.p_double[sfx+s3]/dt+4*c->f.ptr.p_double[sfx+s4]/dt-3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du+3*c->f.ptr.p_double[sfy+s3]/du-3*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-2*c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                     tbl->ptr.pp_double[p][4+3*4+0] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt;
 | |
|                     tbl->ptr.pp_double[p][4+3*4+1] = 2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du);
 | |
|                     tbl->ptr.pp_double[p][4+3*4+2] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-3*c->f.ptr.p_double[sfx+s1]/dt-3*c->f.ptr.p_double[sfx+s2]/dt+3*c->f.ptr.p_double[sfx+s3]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-4*c->f.ptr.p_double[sfy+s1]/du+4*c->f.ptr.p_double[sfy+s2]/du+2*c->f.ptr.p_double[sfy+s3]/du-2*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                     tbl->ptr.pp_double[p][4+3*4+3] = 4*c->f.ptr.p_double[s1]-4*c->f.ptr.p_double[s2]+4*c->f.ptr.p_double[s3]-4*c->f.ptr.p_double[s4]+2*c->f.ptr.p_double[sfx+s1]/dt+2*c->f.ptr.p_double[sfx+s2]/dt-2*c->f.ptr.p_double[sfx+s3]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfy+s3]/du+2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * Rescale Cij
 | |
|                  */
 | |
|                 for(ci=0; ci<=3; ci++)
 | |
|                 {
 | |
|                     for(cj=0; cj<=3; cj++)
 | |
|                     {
 | |
|                         tbl->ptr.pp_double[p][4+ci*4+cj] = tbl->ptr.pp_double[p][4+ci*4+cj]*ae_pow(dt, (double)(ci), _state)*ae_pow(du, (double)(cj), _state);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine was deprecated in ALGLIB 3.6.0
 | |
| 
 | |
| We recommend you to switch  to  Spline2DBuildBilinearV(),  which  is  more
 | |
| flexible and accepts its arguments in more convenient order.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 05.07.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildbilinear(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_matrix* f,
 | |
|      ae_int_t m,
 | |
|      ae_int_t n,
 | |
|      spline2dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double t;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
| 
 | |
|     _spline2dinterpolant_clear(c);
 | |
| 
 | |
|     ae_assert(n>=2, "Spline2DBuildBilinear: N<2", _state);
 | |
|     ae_assert(m>=2, "Spline2DBuildBilinear: M<2", _state);
 | |
|     ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBilinear: length of X or Y is too short (Length(X/Y)<N/M)", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state)&&isfinitevector(y, m, _state), "Spline2DBuildBilinear: X or Y contains NaN or Infinite value", _state);
 | |
|     ae_assert(f->rows>=m&&f->cols>=n, "Spline2DBuildBilinear: size of F is too small (rows(F)<M or cols(F)<N)", _state);
 | |
|     ae_assert(apservisfinitematrix(f, m, n, _state), "Spline2DBuildBilinear: F contains NaN or Infinite value", _state);
 | |
|     
 | |
|     /*
 | |
|      * Fill interpolant
 | |
|      */
 | |
|     c->n = n;
 | |
|     c->m = m;
 | |
|     c->d = 1;
 | |
|     c->stype = -1;
 | |
|     ae_vector_set_length(&c->x, c->n, _state);
 | |
|     ae_vector_set_length(&c->y, c->m, _state);
 | |
|     ae_vector_set_length(&c->f, c->n*c->m, _state);
 | |
|     for(i=0; i<=c->n-1; i++)
 | |
|     {
 | |
|         c->x.ptr.p_double[i] = x->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         c->y.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=c->n-1; j++)
 | |
|         {
 | |
|             c->f.ptr.p_double[i*c->n+j] = f->ptr.pp_double[i][j];
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Sort points
 | |
|      */
 | |
|     for(j=0; j<=c->n-1; j++)
 | |
|     {
 | |
|         k = j;
 | |
|         for(i=j+1; i<=c->n-1; i++)
 | |
|         {
 | |
|             if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) )
 | |
|             {
 | |
|                 k = i;
 | |
|             }
 | |
|         }
 | |
|         if( k!=j )
 | |
|         {
 | |
|             for(i=0; i<=c->m-1; i++)
 | |
|             {
 | |
|                 t = c->f.ptr.p_double[i*c->n+j];
 | |
|                 c->f.ptr.p_double[i*c->n+j] = c->f.ptr.p_double[i*c->n+k];
 | |
|                 c->f.ptr.p_double[i*c->n+k] = t;
 | |
|             }
 | |
|             t = c->x.ptr.p_double[j];
 | |
|             c->x.ptr.p_double[j] = c->x.ptr.p_double[k];
 | |
|             c->x.ptr.p_double[k] = t;
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         k = i;
 | |
|         for(j=i+1; j<=c->m-1; j++)
 | |
|         {
 | |
|             if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) )
 | |
|             {
 | |
|                 k = j;
 | |
|             }
 | |
|         }
 | |
|         if( k!=i )
 | |
|         {
 | |
|             for(j=0; j<=c->n-1; j++)
 | |
|             {
 | |
|                 t = c->f.ptr.p_double[i*c->n+j];
 | |
|                 c->f.ptr.p_double[i*c->n+j] = c->f.ptr.p_double[k*c->n+j];
 | |
|                 c->f.ptr.p_double[k*c->n+j] = t;
 | |
|             }
 | |
|             t = c->y.ptr.p_double[i];
 | |
|             c->y.ptr.p_double[i] = c->y.ptr.p_double[k];
 | |
|             c->y.ptr.p_double[k] = t;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine was deprecated in ALGLIB 3.6.0
 | |
| 
 | |
| We recommend you to switch  to  Spline2DBuildBicubicV(),  which  is  more
 | |
| flexible and accepts its arguments in more convenient order.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 05.07.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildbicubic(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_matrix* f,
 | |
|      ae_int_t m,
 | |
|      ae_int_t n,
 | |
|      spline2dinterpolant* c,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_matrix _f;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     ae_matrix dx;
 | |
|     ae_matrix dy;
 | |
|     ae_matrix dxy;
 | |
|     double t;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_f, 0, sizeof(_f));
 | |
|     memset(&dx, 0, sizeof(dx));
 | |
|     memset(&dy, 0, sizeof(dy));
 | |
|     memset(&dxy, 0, sizeof(dxy));
 | |
|     ae_matrix_init_copy(&_f, f, _state, ae_true);
 | |
|     f = &_f;
 | |
|     _spline2dinterpolant_clear(c);
 | |
|     ae_matrix_init(&dx, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&dy, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=2, "Spline2DBuildBicubicSpline: N<2", _state);
 | |
|     ae_assert(m>=2, "Spline2DBuildBicubicSpline: M<2", _state);
 | |
|     ae_assert(x->cnt>=n&&y->cnt>=m, "Spline2DBuildBicubic: length of X or Y is too short (Length(X/Y)<N/M)", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state)&&isfinitevector(y, m, _state), "Spline2DBuildBicubic: X or Y contains NaN or Infinite value", _state);
 | |
|     ae_assert(f->rows>=m&&f->cols>=n, "Spline2DBuildBicubic: size of F is too small (rows(F)<M or cols(F)<N)", _state);
 | |
|     ae_assert(apservisfinitematrix(f, m, n, _state), "Spline2DBuildBicubic: F contains NaN or Infinite value", _state);
 | |
|     
 | |
|     /*
 | |
|      * Fill interpolant:
 | |
|      *  F[0]...F[N*M-1]:
 | |
|      *      f(i,j) table. f(0,0), f(0, 1), f(0,2) and so on...
 | |
|      *  F[N*M]...F[2*N*M-1]:
 | |
|      *      df(i,j)/dx table.
 | |
|      *  F[2*N*M]...F[3*N*M-1]:
 | |
|      *      df(i,j)/dy table.
 | |
|      *  F[3*N*M]...F[4*N*M-1]:
 | |
|      *      d2f(i,j)/dxdy table.
 | |
|      */
 | |
|     c->d = 1;
 | |
|     c->n = n;
 | |
|     c->m = m;
 | |
|     c->stype = -3;
 | |
|     sfx = c->n*c->m;
 | |
|     sfy = 2*c->n*c->m;
 | |
|     sfxy = 3*c->n*c->m;
 | |
|     ae_vector_set_length(&c->x, c->n, _state);
 | |
|     ae_vector_set_length(&c->y, c->m, _state);
 | |
|     ae_vector_set_length(&c->f, 4*c->n*c->m, _state);
 | |
|     for(i=0; i<=c->n-1; i++)
 | |
|     {
 | |
|         c->x.ptr.p_double[i] = x->ptr.p_double[i];
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         c->y.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Sort points
 | |
|      */
 | |
|     for(j=0; j<=c->n-1; j++)
 | |
|     {
 | |
|         k = j;
 | |
|         for(i=j+1; i<=c->n-1; i++)
 | |
|         {
 | |
|             if( ae_fp_less(c->x.ptr.p_double[i],c->x.ptr.p_double[k]) )
 | |
|             {
 | |
|                 k = i;
 | |
|             }
 | |
|         }
 | |
|         if( k!=j )
 | |
|         {
 | |
|             for(i=0; i<=c->m-1; i++)
 | |
|             {
 | |
|                 t = f->ptr.pp_double[i][j];
 | |
|                 f->ptr.pp_double[i][j] = f->ptr.pp_double[i][k];
 | |
|                 f->ptr.pp_double[i][k] = t;
 | |
|             }
 | |
|             t = c->x.ptr.p_double[j];
 | |
|             c->x.ptr.p_double[j] = c->x.ptr.p_double[k];
 | |
|             c->x.ptr.p_double[k] = t;
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         k = i;
 | |
|         for(j=i+1; j<=c->m-1; j++)
 | |
|         {
 | |
|             if( ae_fp_less(c->y.ptr.p_double[j],c->y.ptr.p_double[k]) )
 | |
|             {
 | |
|                 k = j;
 | |
|             }
 | |
|         }
 | |
|         if( k!=i )
 | |
|         {
 | |
|             for(j=0; j<=c->n-1; j++)
 | |
|             {
 | |
|                 t = f->ptr.pp_double[i][j];
 | |
|                 f->ptr.pp_double[i][j] = f->ptr.pp_double[k][j];
 | |
|                 f->ptr.pp_double[k][j] = t;
 | |
|             }
 | |
|             t = c->y.ptr.p_double[i];
 | |
|             c->y.ptr.p_double[i] = c->y.ptr.p_double[k];
 | |
|             c->y.ptr.p_double[k] = t;
 | |
|         }
 | |
|     }
 | |
|     spline2d_bicubiccalcderivatives(f, &c->x, &c->y, c->m, c->n, &dx, &dy, &dxy, _state);
 | |
|     for(i=0; i<=c->m-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=c->n-1; j++)
 | |
|         {
 | |
|             k = i*c->n+j;
 | |
|             c->f.ptr.p_double[k] = f->ptr.pp_double[i][j];
 | |
|             c->f.ptr.p_double[sfx+k] = dx.ptr.pp_double[i][j];
 | |
|             c->f.ptr.p_double[sfy+k] = dy.ptr.pp_double[i][j];
 | |
|             c->f.ptr.p_double[sfxy+k] = dxy.ptr.pp_double[i][j];
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine was deprecated in ALGLIB 3.6.0
 | |
| 
 | |
| We recommend you to switch  to  Spline2DUnpackV(),  which is more flexible
 | |
| and accepts its arguments in more convenient order.
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 29.06.2007 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dunpack(spline2dinterpolant* c,
 | |
|      ae_int_t* m,
 | |
|      ae_int_t* n,
 | |
|      /* Real    */ ae_matrix* tbl,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t k;
 | |
|     ae_int_t p;
 | |
|     ae_int_t ci;
 | |
|     ae_int_t cj;
 | |
|     ae_int_t s1;
 | |
|     ae_int_t s2;
 | |
|     ae_int_t s3;
 | |
|     ae_int_t s4;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     double y1;
 | |
|     double y2;
 | |
|     double y3;
 | |
|     double y4;
 | |
|     double dt;
 | |
|     double du;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     *m = 0;
 | |
|     *n = 0;
 | |
|     ae_matrix_clear(tbl);
 | |
| 
 | |
|     ae_assert(c->stype==-3||c->stype==-1, "Spline2DUnpack: incorrect C (incorrect parameter C.SType)", _state);
 | |
|     if( c->d!=1 )
 | |
|     {
 | |
|         *n = 0;
 | |
|         *m = 0;
 | |
|         return;
 | |
|     }
 | |
|     *n = c->n;
 | |
|     *m = c->m;
 | |
|     ae_matrix_set_length(tbl, (*n-1)*(*m-1), 20, _state);
 | |
|     sfx = *n*(*m);
 | |
|     sfy = 2*(*n)*(*m);
 | |
|     sfxy = 3*(*n)*(*m);
 | |
|     
 | |
|     /*
 | |
|      * Fill
 | |
|      */
 | |
|     for(i=0; i<=*m-2; i++)
 | |
|     {
 | |
|         for(j=0; j<=*n-2; j++)
 | |
|         {
 | |
|             p = i*(*n-1)+j;
 | |
|             tbl->ptr.pp_double[p][0] = c->x.ptr.p_double[j];
 | |
|             tbl->ptr.pp_double[p][1] = c->x.ptr.p_double[j+1];
 | |
|             tbl->ptr.pp_double[p][2] = c->y.ptr.p_double[i];
 | |
|             tbl->ptr.pp_double[p][3] = c->y.ptr.p_double[i+1];
 | |
|             dt = 1/(tbl->ptr.pp_double[p][1]-tbl->ptr.pp_double[p][0]);
 | |
|             du = 1/(tbl->ptr.pp_double[p][3]-tbl->ptr.pp_double[p][2]);
 | |
|             
 | |
|             /*
 | |
|              * Bilinear interpolation
 | |
|              */
 | |
|             if( c->stype==-1 )
 | |
|             {
 | |
|                 for(k=4; k<=19; k++)
 | |
|                 {
 | |
|                     tbl->ptr.pp_double[p][k] = (double)(0);
 | |
|                 }
 | |
|                 y1 = c->f.ptr.p_double[*n*i+j];
 | |
|                 y2 = c->f.ptr.p_double[*n*i+(j+1)];
 | |
|                 y3 = c->f.ptr.p_double[*n*(i+1)+(j+1)];
 | |
|                 y4 = c->f.ptr.p_double[*n*(i+1)+j];
 | |
|                 tbl->ptr.pp_double[p][4] = y1;
 | |
|                 tbl->ptr.pp_double[p][4+1*4+0] = y2-y1;
 | |
|                 tbl->ptr.pp_double[p][4+0*4+1] = y4-y1;
 | |
|                 tbl->ptr.pp_double[p][4+1*4+1] = y3-y2-y4+y1;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Bicubic interpolation
 | |
|              */
 | |
|             if( c->stype==-3 )
 | |
|             {
 | |
|                 s1 = *n*i+j;
 | |
|                 s2 = *n*i+(j+1);
 | |
|                 s3 = *n*(i+1)+(j+1);
 | |
|                 s4 = *n*(i+1)+j;
 | |
|                 tbl->ptr.pp_double[p][4+0*4+0] = c->f.ptr.p_double[s1];
 | |
|                 tbl->ptr.pp_double[p][4+0*4+1] = c->f.ptr.p_double[sfy+s1]/du;
 | |
|                 tbl->ptr.pp_double[p][4+0*4+2] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s4]-2*c->f.ptr.p_double[sfy+s1]/du-c->f.ptr.p_double[sfy+s4]/du;
 | |
|                 tbl->ptr.pp_double[p][4+0*4+3] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s4]+c->f.ptr.p_double[sfy+s1]/du+c->f.ptr.p_double[sfy+s4]/du;
 | |
|                 tbl->ptr.pp_double[p][4+1*4+0] = c->f.ptr.p_double[sfx+s1]/dt;
 | |
|                 tbl->ptr.pp_double[p][4+1*4+1] = c->f.ptr.p_double[sfxy+s1]/(dt*du);
 | |
|                 tbl->ptr.pp_double[p][4+1*4+2] = -3*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                 tbl->ptr.pp_double[p][4+1*4+3] = 2*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                 tbl->ptr.pp_double[p][4+2*4+0] = -3*c->f.ptr.p_double[s1]+3*c->f.ptr.p_double[s2]-2*c->f.ptr.p_double[sfx+s1]/dt-c->f.ptr.p_double[sfx+s2]/dt;
 | |
|                 tbl->ptr.pp_double[p][4+2*4+1] = -3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du);
 | |
|                 tbl->ptr.pp_double[p][4+2*4+2] = 9*c->f.ptr.p_double[s1]-9*c->f.ptr.p_double[s2]+9*c->f.ptr.p_double[s3]-9*c->f.ptr.p_double[s4]+6*c->f.ptr.p_double[sfx+s1]/dt+3*c->f.ptr.p_double[sfx+s2]/dt-3*c->f.ptr.p_double[sfx+s3]/dt-6*c->f.ptr.p_double[sfx+s4]/dt+6*c->f.ptr.p_double[sfy+s1]/du-6*c->f.ptr.p_double[sfy+s2]/du-3*c->f.ptr.p_double[sfy+s3]/du+3*c->f.ptr.p_double[sfy+s4]/du+4*c->f.ptr.p_double[sfxy+s1]/(dt*du)+2*c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+2*c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                 tbl->ptr.pp_double[p][4+2*4+3] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-4*c->f.ptr.p_double[sfx+s1]/dt-2*c->f.ptr.p_double[sfx+s2]/dt+2*c->f.ptr.p_double[sfx+s3]/dt+4*c->f.ptr.p_double[sfx+s4]/dt-3*c->f.ptr.p_double[sfy+s1]/du+3*c->f.ptr.p_double[sfy+s2]/du+3*c->f.ptr.p_double[sfy+s3]/du-3*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-2*c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                 tbl->ptr.pp_double[p][4+3*4+0] = 2*c->f.ptr.p_double[s1]-2*c->f.ptr.p_double[s2]+c->f.ptr.p_double[sfx+s1]/dt+c->f.ptr.p_double[sfx+s2]/dt;
 | |
|                 tbl->ptr.pp_double[p][4+3*4+1] = 2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du);
 | |
|                 tbl->ptr.pp_double[p][4+3*4+2] = -6*c->f.ptr.p_double[s1]+6*c->f.ptr.p_double[s2]-6*c->f.ptr.p_double[s3]+6*c->f.ptr.p_double[s4]-3*c->f.ptr.p_double[sfx+s1]/dt-3*c->f.ptr.p_double[sfx+s2]/dt+3*c->f.ptr.p_double[sfx+s3]/dt+3*c->f.ptr.p_double[sfx+s4]/dt-4*c->f.ptr.p_double[sfy+s1]/du+4*c->f.ptr.p_double[sfy+s2]/du+2*c->f.ptr.p_double[sfy+s3]/du-2*c->f.ptr.p_double[sfy+s4]/du-2*c->f.ptr.p_double[sfxy+s1]/(dt*du)-2*c->f.ptr.p_double[sfxy+s2]/(dt*du)-c->f.ptr.p_double[sfxy+s3]/(dt*du)-c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|                 tbl->ptr.pp_double[p][4+3*4+3] = 4*c->f.ptr.p_double[s1]-4*c->f.ptr.p_double[s2]+4*c->f.ptr.p_double[s3]-4*c->f.ptr.p_double[s4]+2*c->f.ptr.p_double[sfx+s1]/dt+2*c->f.ptr.p_double[sfx+s2]/dt-2*c->f.ptr.p_double[sfx+s3]/dt-2*c->f.ptr.p_double[sfx+s4]/dt+2*c->f.ptr.p_double[sfy+s1]/du-2*c->f.ptr.p_double[sfy+s2]/du-2*c->f.ptr.p_double[sfy+s3]/du+2*c->f.ptr.p_double[sfy+s4]/du+c->f.ptr.p_double[sfxy+s1]/(dt*du)+c->f.ptr.p_double[sfxy+s2]/(dt*du)+c->f.ptr.p_double[sfxy+s3]/(dt*du)+c->f.ptr.p_double[sfxy+s4]/(dt*du);
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Rescale Cij
 | |
|              */
 | |
|             for(ci=0; ci<=3; ci++)
 | |
|             {
 | |
|                 for(cj=0; cj<=3; cj++)
 | |
|                 {
 | |
|                     tbl->ptr.pp_double[p][4+ci*4+cj] = tbl->ptr.pp_double[p][4+ci*4+cj]*ae_pow(dt, (double)(ci), _state)*ae_pow(du, (double)(cj), _state);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This subroutine creates least squares solver used to  fit  2D  splines  to
 | |
| irregularly sampled (scattered) data.
 | |
| 
 | |
| Solver object is used to perform spline fits as follows:
 | |
| * solver object is created with spline2dbuildercreate() function
 | |
| * dataset is added with spline2dbuildersetpoints() function
 | |
| * fit area is chosen:
 | |
|   * spline2dbuildersetarea()     - for user-defined area
 | |
|   * spline2dbuildersetareaauto() - for automatically chosen area
 | |
| * number of grid nodes is chosen with spline2dbuildersetgrid()
 | |
| * prior term is chosen with one of the following functions:
 | |
|   * spline2dbuildersetlinterm()   to set linear prior
 | |
|   * spline2dbuildersetconstterm() to set constant prior
 | |
|   * spline2dbuildersetzeroterm()  to set zero prior
 | |
|   * spline2dbuildersetuserterm()  to set user-defined constant prior
 | |
| * solver algorithm is chosen with either:
 | |
|   * spline2dbuildersetalgoblocklls() - BlockLLS algorithm, medium-scale problems
 | |
|   * spline2dbuildersetalgofastddm()  - FastDDM algorithm, large-scale problems
 | |
| * finally, fitting itself is performed with spline2dfit() function.
 | |
| 
 | |
| Most of the steps above can be omitted,  solver  is  configured with  good
 | |
| defaults. The minimum is to call:
 | |
| * spline2dbuildercreate() to create solver object
 | |
| * spline2dbuildersetpoints() to specify dataset
 | |
| * spline2dbuildersetgrid() to tell how many nodes you need
 | |
| * spline2dfit() to perform fit
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     D   -   positive number, number of Y-components: D=1 for simple scalar
 | |
|             fit, D>1 for vector-valued spline fitting.
 | |
|     
 | |
| OUTPUT PARAMETERS:
 | |
|     S   -   solver object
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 29.01.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildercreate(ae_int_t d,
 | |
|      spline2dbuilder* state,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _spline2dbuilder_clear(state);
 | |
| 
 | |
|     ae_assert(d>=1, "Spline2DBuilderCreate: D<=0", _state);
 | |
|     
 | |
|     /*
 | |
|      * NOTES:
 | |
|      *
 | |
|      * 1. Prior term is set to linear one (good default option)
 | |
|      * 2. Solver is set to BlockLLS - good enough for small-scale problems.
 | |
|      * 3. Refinement rounds: 5; enough to get good convergence.
 | |
|      */
 | |
|     state->priorterm = 1;
 | |
|     state->priortermval = (double)(0);
 | |
|     state->areatype = 0;
 | |
|     state->gridtype = 0;
 | |
|     state->smoothing = 0.0;
 | |
|     state->nlayers = 0;
 | |
|     state->solvertype = 1;
 | |
|     state->npoints = 0;
 | |
|     state->d = d;
 | |
|     state->sx = 1.0;
 | |
|     state->sy = 1.0;
 | |
|     state->lsqrcnt = 5;
 | |
|     
 | |
|     /*
 | |
|      * Algorithm settings
 | |
|      */
 | |
|     state->adddegreeoffreedom = ae_true;
 | |
|     state->maxcoresize = 16;
 | |
|     state->interfacesize = 5;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets constant prior term (model is a sum of  bicubic  spline
 | |
| and global prior, which can be linear, constant, user-defined  constant or
 | |
| zero).
 | |
| 
 | |
| Constant prior term is determined by least squares fitting.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
|     V       -   value for user-defined prior
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetuserterm(spline2dbuilder* state,
 | |
|      double v,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(v, _state), "Spline2DBuilderSetUserTerm: infinite/NAN value passed", _state);
 | |
|     state->priorterm = 0;
 | |
|     state->priortermval = v;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets linear prior term (model is a sum of bicubic spline and
 | |
| global  prior,  which  can  be  linear, constant, user-defined constant or
 | |
| zero).
 | |
| 
 | |
| Linear prior term is determined by least squares fitting.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetlinterm(spline2dbuilder* state, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     state->priorterm = 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets constant prior term (model is a sum of  bicubic  spline
 | |
| and global prior, which can be linear, constant, user-defined  constant or
 | |
| zero).
 | |
| 
 | |
| Constant prior term is determined by least squares fitting.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetconstterm(spline2dbuilder* state, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     state->priorterm = 2;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets zero prior term (model is a sum of bicubic  spline  and
 | |
| global  prior,  which  can  be  linear, constant, user-defined constant or
 | |
| zero).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline builder
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetzeroterm(spline2dbuilder* state, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     state->priorterm = 3;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset to the builder object.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     XY      -   points, array[N,2+D]. One  row  corresponds to  one  point
 | |
|                 in the dataset. First 2  elements  are  coordinates,  next
 | |
|                 D  elements are function values. Array may  be larger than 
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements 
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetpoints(spline2dbuilder* state,
 | |
|      /* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t ew;
 | |
| 
 | |
| 
 | |
|     ae_assert(n>0, "Spline2DBuilderSetPoints: N<0", _state);
 | |
|     ae_assert(xy->rows>=n, "Spline2DBuilderSetPoints: Rows(XY)<N", _state);
 | |
|     ae_assert(xy->cols>=2+state->d, "Spline2DBuilderSetPoints: Cols(XY)<NX+NY", _state);
 | |
|     ae_assert(apservisfinitematrix(xy, n, 2+state->d, _state), "Spline2DBuilderSetPoints: XY contains infinite or NaN values!", _state);
 | |
|     state->npoints = n;
 | |
|     ew = 2+state->d;
 | |
|     rvectorsetlengthatleast(&state->xy, n*ew, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=ew-1; j++)
 | |
|         {
 | |
|             state->xy.ptr.p_double[i*ew+j] = xy->ptr.pp_double[i][j];
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets area where 2D spline interpolant is built. "Auto" means
 | |
| that area extent is determined automatically from dataset extent.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetareaauto(spline2dbuilder* state, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     state->areatype = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  sets  area  where  2D  spline  interpolant  is   built  to
 | |
| user-defined one: [XA,XB]*[YA,YB]
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     XA,XB   -   spatial extent in the first (X) dimension, XA<XB
 | |
|     YA,YB   -   spatial extent in the second (Y) dimension, YA<YB
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetarea(spline2dbuilder* state,
 | |
|      double xa,
 | |
|      double xb,
 | |
|      double ya,
 | |
|      double yb,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(xa, _state), "Spline2DBuilderSetArea: XA is not finite", _state);
 | |
|     ae_assert(ae_isfinite(xb, _state), "Spline2DBuilderSetArea: XB is not finite", _state);
 | |
|     ae_assert(ae_isfinite(ya, _state), "Spline2DBuilderSetArea: YA is not finite", _state);
 | |
|     ae_assert(ae_isfinite(yb, _state), "Spline2DBuilderSetArea: YB is not finite", _state);
 | |
|     ae_assert(ae_fp_less(xa,xb), "Spline2DBuilderSetArea: XA>=XB", _state);
 | |
|     ae_assert(ae_fp_less(ya,yb), "Spline2DBuilderSetArea: YA>=YB", _state);
 | |
|     state->areatype = 1;
 | |
|     state->xa = xa;
 | |
|     state->xb = xb;
 | |
|     state->ya = ya;
 | |
|     state->yb = yb;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  sets  nodes  count  for  2D spline interpolant. Fitting is
 | |
| performed on area defined with one of the "setarea"  functions;  this  one
 | |
| sets number of nodes placed upon the fitting area.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     KX      -   nodes count for the first (X) dimension; fitting  interval
 | |
|                 [XA,XB] is separated into KX-1 subintervals, with KX nodes
 | |
|                 created at the boundaries.
 | |
|     KY      -   nodes count for the first (Y) dimension; fitting  interval
 | |
|                 [YA,YB] is separated into KY-1 subintervals, with KY nodes
 | |
|                 created at the boundaries.
 | |
| 
 | |
| NOTE: at  least  4  nodes  is  created in each dimension, so KX and KY are
 | |
|       silently increased if needed.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetgrid(spline2dbuilder* state,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(kx>0, "Spline2DBuilderSetGridSizePrecisely: KX<=0", _state);
 | |
|     ae_assert(ky>0, "Spline2DBuilderSetGridSizePrecisely: KY<=0", _state);
 | |
|     state->gridtype = 1;
 | |
|     state->kx = ae_maxint(kx, 4, _state);
 | |
|     state->ky = ae_maxint(ky, 4, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  allows  you to choose least squares solver used to perform
 | |
| fitting. This function sets solver algorithm to "FastDDM", which  performs
 | |
| fast parallel fitting by splitting problem into smaller chunks and merging
 | |
| results together.
 | |
| 
 | |
| This solver is optimized for large-scale problems, starting  from  256x256
 | |
| grids, and up to 10000x10000 grids. Of course, it will  work  for  smaller
 | |
| grids too.
 | |
| 
 | |
| More detailed description of the algorithm is given below:
 | |
| * algorithm generates hierarchy  of  nested  grids,  ranging  from  ~16x16
 | |
|   (topmost "layer" of the model) to ~KX*KY one (final layer). Upper layers
 | |
|   model global behavior of the function, lower layers are  used  to  model
 | |
|   fine details. Moving from layer to layer doubles grid density.
 | |
| * fitting  is  started  from  topmost  layer, subsequent layers are fitted
 | |
|   using residuals from previous ones.
 | |
| * user may choose to skip generation of upper layers and generate  only  a
 | |
|   few bottom ones, which  will  result  in  much  better  performance  and
 | |
|   parallelization efficiency, at the cost of algorithm inability to "patch"
 | |
|   large holes in the dataset.
 | |
| * every layer is regularized using progressively increasing regularization
 | |
|   coefficient; thus, increasing  LambdaV  penalizes  fine  details  first,
 | |
|   leaving lower frequencies almost intact for a while.
 | |
| * after fitting is done, all layers are merged together into  one  bicubic
 | |
|   spline
 | |
|   
 | |
| IMPORTANT: regularization coefficient used by  this  solver  is  different
 | |
|            from the one used by  BlockLLS.  Latter  utilizes  nonlinearity
 | |
|            penalty,  which  is  global  in  nature  (large  regularization
 | |
|            results in global linear trend being  extracted);  this  solver
 | |
|            uses another, localized form of penalty, which is suitable  for
 | |
|            parallel processing.
 | |
| 
 | |
| Notes on memory and performance:
 | |
| * memory requirements: most memory is consumed  during  modeling   of  the
 | |
|   higher layers; ~[512*NPoints] bytes is required for a  model  with  full
 | |
|   hierarchy of grids being generated. However, if you skip a  few  topmost
 | |
|   layers, you will get nearly constant (wrt. points count and  grid  size)
 | |
|   memory consumption.
 | |
| * serial running time: O(K*K)+O(NPoints) for a KxK grid
 | |
| * parallelism potential: good. You may get  nearly  linear  speed-up  when
 | |
|   performing fitting with just a few layers. Adding more layers results in
 | |
|   model becoming more global, which somewhat  reduces  efficiency  of  the
 | |
|   parallel code.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     NLayers -   number of layers in the model:
 | |
|                 * NLayers>=1 means that up  to  chosen  number  of  bottom
 | |
|                   layers is fitted
 | |
|                 * NLayers=0 means that maximum number of layers is  chosen
 | |
|                   (according to current grid size)
 | |
|                 * NLayers<=-1 means that up to |NLayers| topmost layers is
 | |
|                   skipped
 | |
|                 Recommendations:
 | |
|                 * good "default" value is 2 layers
 | |
|                 * you may need  more  layers,  if  your  dataset  is  very
 | |
|                   irregular and you want to "patch"  large  holes.  For  a
 | |
|                   grid step H (equal to AreaWidth/GridSize) you may expect
 | |
|                   that last layer reproduces variations at distance H (and
 | |
|                   can patch holes that wide); that higher  layers  operate
 | |
|                   at distances 2*H, 4*H, 8*H and so on.
 | |
|                 * good value for "bullletproof" mode is  NLayers=0,  which
 | |
|                   results in complete hierarchy of layers being generated.
 | |
|     LambdaV -   regularization coefficient, chosen in such a way  that  it
 | |
|                 penalizes bottom layers (fine details) first.
 | |
|                 LambdaV>=0, zero value means that no penalty is applied.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetalgofastddm(spline2dbuilder* state,
 | |
|      ae_int_t nlayers,
 | |
|      double lambdav,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(lambdav, _state), "Spline2DBuilderSetAlgoFastDDM: LambdaV is not finite value", _state);
 | |
|     ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "Spline2DBuilderSetAlgoFastDDM: LambdaV<0", _state);
 | |
|     state->solvertype = 3;
 | |
|     state->nlayers = nlayers;
 | |
|     state->smoothing = lambdav;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  allows  you to choose least squares solver used to perform
 | |
| fitting. This function sets solver algorithm to "BlockLLS", which performs
 | |
| least squares fitting  with  fast  sparse  direct  solver,  with  optional
 | |
| nonsmoothness penalty being applied.
 | |
| 
 | |
| Nonlinearity penalty has the following form:
 | |
| 
 | |
|                           [                                            ]
 | |
|     P() ~ Lambda* integral[ (d2S/dx2)^2 + 2*(d2S/dxdy)^2 + (d2S/dy2)^2 ]dxdy
 | |
|                           [                                            ]
 | |
|                   
 | |
| here integral is calculated over entire grid, and "~" means "proportional"
 | |
| because integral is normalized after calcilation. Extremely  large  values
 | |
| of Lambda result in linear fit being performed.
 | |
| 
 | |
| NOTE: this algorithm is the most robust and controllable one,  but  it  is
 | |
|       limited by 512x512 grids and (say) up to 1.000.000 points.  However,
 | |
|       ALGLIB has one more  spline  solver:  FastDDM  algorithm,  which  is
 | |
|       intended for really large-scale problems (in 10M-100M range). FastDDM
 | |
|       algorithm also has better parallelism properties.
 | |
|       
 | |
| More information on BlockLLS solver:
 | |
| * memory requirements: ~[32*K^3+256*NPoints]  bytes  for  KxK  grid   with
 | |
|   NPoints-sized dataset
 | |
| * serial running time: O(K^4+NPoints)
 | |
| * parallelism potential: limited. You may get some sublinear gain when
 | |
|   working with large grids (K's in 256..512 range)
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     LambdaNS-   non-negative value:
 | |
|                 * positive value means that some smoothing is applied
 | |
|                 * zero value means  that  no  smoothing  is  applied,  and
 | |
|                   corresponding entries of design matrix  are  numerically
 | |
|                   zero and dropped from consideration.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetalgoblocklls(spline2dbuilder* state,
 | |
|      double lambdans,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(lambdans, _state), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS is not finite value", _state);
 | |
|     ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS<0", _state);
 | |
|     state->solvertype = 1;
 | |
|     state->smoothing = lambdans;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  allows  you to choose least squares solver used to perform
 | |
| fitting. This function sets solver algorithm to "NaiveLLS".
 | |
| 
 | |
| IMPORTANT: NaiveLLS is NOT intended to be used in  real  life  code!  This
 | |
|            algorithm solves problem by generated dense (K^2)x(K^2+NPoints)
 | |
|            matrix and solves  linear  least  squares  problem  with  dense
 | |
|            solver.
 | |
|            
 | |
|            It is here just  to  test  BlockLLS  against  reference  solver
 | |
|            (and maybe for someone trying to compare well optimized  solver
 | |
|            against straightforward approach to the LLS problem).
 | |
| 
 | |
| More information on naive LLS solver:
 | |
| * memory requirements: ~[8*K^4+256*NPoints] bytes for KxK grid.
 | |
| * serial running time: O(K^6+NPoints) for KxK grid
 | |
| * when compared with BlockLLS,  NaiveLLS  has ~K  larger memory demand and
 | |
|   ~K^2  larger running time.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   spline 2D builder object
 | |
|     LambdaNS-   nonsmoothness penalty
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dbuildersetalgonaivells(spline2dbuilder* state,
 | |
|      double lambdans,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(lambdans, _state), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS is not finite value", _state);
 | |
|     ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline2DBuilderSetAlgoBlockLLS: LambdaNS<0", _state);
 | |
|     state->solvertype = 2;
 | |
|     state->smoothing = lambdans;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function fits bicubic spline to current dataset, using current  area/
 | |
| grid and current LLS solver.
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! * hardware vendor (Intel) implementations of linear algebra primitives
 | |
|   !   (C++ and C# versions, x86/x64 platform)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     State   -   spline 2D builder object
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     S       -   2D spline, fit result
 | |
|     Rep     -   fitting report, which provides some additional info  about
 | |
|                 errors, R2 coefficient and so on.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dfit(spline2dbuilder* state,
 | |
|      spline2dinterpolant* s,
 | |
|      spline2dfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     double xa;
 | |
|     double xb;
 | |
|     double ya;
 | |
|     double yb;
 | |
|     double xaraw;
 | |
|     double xbraw;
 | |
|     double yaraw;
 | |
|     double ybraw;
 | |
|     ae_int_t kx;
 | |
|     ae_int_t ky;
 | |
|     double hx;
 | |
|     double hy;
 | |
|     double invhx;
 | |
|     double invhy;
 | |
|     ae_int_t gridexpansion;
 | |
|     ae_int_t nzwidth;
 | |
|     ae_int_t bfrad;
 | |
|     ae_int_t npoints;
 | |
|     ae_int_t d;
 | |
|     ae_int_t ew;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     double v;
 | |
|     ae_int_t k0;
 | |
|     ae_int_t k1;
 | |
|     double vx;
 | |
|     double vy;
 | |
|     ae_int_t arows;
 | |
|     ae_int_t acopied;
 | |
|     ae_int_t basecasex;
 | |
|     ae_int_t basecasey;
 | |
|     double eps;
 | |
|     ae_vector xywork;
 | |
|     ae_matrix vterm;
 | |
|     ae_vector tmpx;
 | |
|     ae_vector tmpy;
 | |
|     ae_vector tmp0;
 | |
|     ae_vector tmp1;
 | |
|     ae_vector meany;
 | |
|     ae_vector xyindex;
 | |
|     ae_vector tmpi;
 | |
|     spline1dinterpolant basis1;
 | |
|     sparsematrix av;
 | |
|     sparsematrix ah;
 | |
|     spline2dxdesignmatrix xdesignmatrix;
 | |
|     ae_vector z;
 | |
|     spline2dblockllsbuf blockllsbuf;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     double tss;
 | |
|     ae_int_t dstidx;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&xywork, 0, sizeof(xywork));
 | |
|     memset(&vterm, 0, sizeof(vterm));
 | |
|     memset(&tmpx, 0, sizeof(tmpx));
 | |
|     memset(&tmpy, 0, sizeof(tmpy));
 | |
|     memset(&tmp0, 0, sizeof(tmp0));
 | |
|     memset(&tmp1, 0, sizeof(tmp1));
 | |
|     memset(&meany, 0, sizeof(meany));
 | |
|     memset(&xyindex, 0, sizeof(xyindex));
 | |
|     memset(&tmpi, 0, sizeof(tmpi));
 | |
|     memset(&basis1, 0, sizeof(basis1));
 | |
|     memset(&av, 0, sizeof(av));
 | |
|     memset(&ah, 0, sizeof(ah));
 | |
|     memset(&xdesignmatrix, 0, sizeof(xdesignmatrix));
 | |
|     memset(&z, 0, sizeof(z));
 | |
|     memset(&blockllsbuf, 0, sizeof(blockllsbuf));
 | |
|     _spline2dinterpolant_clear(s);
 | |
|     _spline2dfitreport_clear(rep);
 | |
|     ae_vector_init(&xywork, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&vterm, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&meany, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xyindex, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&tmpi, 0, DT_INT, _state, ae_true);
 | |
|     _spline1dinterpolant_init(&basis1, _state, ae_true);
 | |
|     _sparsematrix_init(&av, _state, ae_true);
 | |
|     _sparsematrix_init(&ah, _state, ae_true);
 | |
|     _spline2dxdesignmatrix_init(&xdesignmatrix, _state, ae_true);
 | |
|     ae_vector_init(&z, 0, DT_REAL, _state, ae_true);
 | |
|     _spline2dblockllsbuf_init(&blockllsbuf, _state, ae_true);
 | |
| 
 | |
|     nzwidth = 4;
 | |
|     bfrad = 2;
 | |
|     npoints = state->npoints;
 | |
|     d = state->d;
 | |
|     ew = 2+d;
 | |
|     
 | |
|     /*
 | |
|      * Integrity checks
 | |
|      */
 | |
|     ae_assert(ae_fp_eq(state->sx,(double)(1)), "Spline2DFit: integrity error", _state);
 | |
|     ae_assert(ae_fp_eq(state->sy,(double)(1)), "Spline2DFit: integrity error", _state);
 | |
|     
 | |
|     /*
 | |
|      * Determine actual area size and grid step
 | |
|      *
 | |
|      * NOTE: initialize vars by zeros in order to avoid spurious
 | |
|      *       compiler warnings.
 | |
|      */
 | |
|     xa = (double)(0);
 | |
|     xb = (double)(0);
 | |
|     ya = (double)(0);
 | |
|     yb = (double)(0);
 | |
|     if( state->areatype==0 )
 | |
|     {
 | |
|         if( npoints>0 )
 | |
|         {
 | |
|             xa = state->xy.ptr.p_double[0];
 | |
|             xb = state->xy.ptr.p_double[0];
 | |
|             ya = state->xy.ptr.p_double[1];
 | |
|             yb = state->xy.ptr.p_double[1];
 | |
|             for(i=1; i<=npoints-1; i++)
 | |
|             {
 | |
|                 xa = ae_minreal(xa, state->xy.ptr.p_double[i*ew+0], _state);
 | |
|                 xb = ae_maxreal(xb, state->xy.ptr.p_double[i*ew+0], _state);
 | |
|                 ya = ae_minreal(ya, state->xy.ptr.p_double[i*ew+1], _state);
 | |
|                 yb = ae_maxreal(yb, state->xy.ptr.p_double[i*ew+1], _state);
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             xa = (double)(-1);
 | |
|             xb = (double)(1);
 | |
|             ya = (double)(-1);
 | |
|             yb = (double)(1);
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         if( state->areatype==1 )
 | |
|         {
 | |
|             xa = state->xa;
 | |
|             xb = state->xb;
 | |
|             ya = state->ya;
 | |
|             yb = state->yb;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             ae_assert(ae_false, "Assertion failed", _state);
 | |
|         }
 | |
|     }
 | |
|     if( ae_fp_eq(xa,xb) )
 | |
|     {
 | |
|         v = xa;
 | |
|         if( ae_fp_greater_eq(v,(double)(0)) )
 | |
|         {
 | |
|             xa = v/2-1;
 | |
|             xb = v*2+1;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             xa = v*2-1;
 | |
|             xb = v/2+1;
 | |
|         }
 | |
|     }
 | |
|     if( ae_fp_eq(ya,yb) )
 | |
|     {
 | |
|         v = ya;
 | |
|         if( ae_fp_greater_eq(v,(double)(0)) )
 | |
|         {
 | |
|             ya = v/2-1;
 | |
|             yb = v*2+1;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             ya = v*2-1;
 | |
|             yb = v/2+1;
 | |
|         }
 | |
|     }
 | |
|     ae_assert(ae_fp_less(xa,xb), "Spline2DFit: integrity error", _state);
 | |
|     ae_assert(ae_fp_less(ya,yb), "Spline2DFit: integrity error", _state);
 | |
|     kx = 0;
 | |
|     ky = 0;
 | |
|     if( state->gridtype==0 )
 | |
|     {
 | |
|         kx = 4;
 | |
|         ky = 4;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         if( state->gridtype==1 )
 | |
|         {
 | |
|             kx = state->kx;
 | |
|             ky = state->ky;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             ae_assert(ae_false, "Assertion failed", _state);
 | |
|         }
 | |
|     }
 | |
|     ae_assert(kx>0, "Spline2DFit: integrity error", _state);
 | |
|     ae_assert(ky>0, "Spline2DFit: integrity error", _state);
 | |
|     basecasex = -1;
 | |
|     basecasey = -1;
 | |
|     if( state->solvertype==3 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Large-scale solver with special requirements to grid size.
 | |
|          */
 | |
|         kx = ae_maxint(kx, nzwidth, _state);
 | |
|         ky = ae_maxint(ky, nzwidth, _state);
 | |
|         k = 1;
 | |
|         while(imin2(kx, ky, _state)>state->maxcoresize+1)
 | |
|         {
 | |
|             kx = idivup(kx-1, 2, _state)+1;
 | |
|             ky = idivup(ky-1, 2, _state)+1;
 | |
|             k = k+1;
 | |
|         }
 | |
|         basecasex = kx-1;
 | |
|         k0 = 1;
 | |
|         while(kx>state->maxcoresize+1)
 | |
|         {
 | |
|             basecasex = idivup(kx-1, 2, _state);
 | |
|             kx = basecasex+1;
 | |
|             k0 = k0+1;
 | |
|         }
 | |
|         while(k0>1)
 | |
|         {
 | |
|             kx = (kx-1)*2+1;
 | |
|             k0 = k0-1;
 | |
|         }
 | |
|         basecasey = ky-1;
 | |
|         k1 = 1;
 | |
|         while(ky>state->maxcoresize+1)
 | |
|         {
 | |
|             basecasey = idivup(ky-1, 2, _state);
 | |
|             ky = basecasey+1;
 | |
|             k1 = k1+1;
 | |
|         }
 | |
|         while(k1>1)
 | |
|         {
 | |
|             ky = (ky-1)*2+1;
 | |
|             k1 = k1-1;
 | |
|         }
 | |
|         while(k>1)
 | |
|         {
 | |
|             kx = (kx-1)*2+1;
 | |
|             ky = (ky-1)*2+1;
 | |
|             k = k-1;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Grid is NOT expanded. We have very strict requirements on
 | |
|          * grid size, and we do not want to overcomplicate it by
 | |
|          * playing with grid size in order to add one more degree of
 | |
|          * freedom. It is not relevant for such large tasks.
 | |
|          */
 | |
|         gridexpansion = 0;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Medium-scale solvers which are tolerant to grid size.
 | |
|          */
 | |
|         kx = ae_maxint(kx, nzwidth, _state);
 | |
|         ky = ae_maxint(ky, nzwidth, _state);
 | |
|         
 | |
|         /*
 | |
|          * Grid is expanded by 1 in order to add one more effective degree
 | |
|          * of freedom to the spline. Having additional nodes outside of the
 | |
|          * area allows us to emulate changes in the derivative at the bound
 | |
|          * without having specialized "boundary" version of the basis function.
 | |
|          */
 | |
|         if( state->adddegreeoffreedom )
 | |
|         {
 | |
|             gridexpansion = 1;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             gridexpansion = 0;
 | |
|         }
 | |
|     }
 | |
|     hx = coalesce(xb-xa, 1.0, _state)/(kx-1);
 | |
|     hy = coalesce(yb-ya, 1.0, _state)/(ky-1);
 | |
|     invhx = 1/hx;
 | |
|     invhy = 1/hy;
 | |
|     
 | |
|     /*
 | |
|      * We determined "raw" grid size. Now perform a grid correction according
 | |
|      * to current grid expansion size.
 | |
|      */
 | |
|     xaraw = xa;
 | |
|     yaraw = ya;
 | |
|     xbraw = xb;
 | |
|     ybraw = yb;
 | |
|     xa = xa-hx*gridexpansion;
 | |
|     ya = ya-hy*gridexpansion;
 | |
|     xb = xb+hx*gridexpansion;
 | |
|     yb = yb+hy*gridexpansion;
 | |
|     kx = kx+2*gridexpansion;
 | |
|     ky = ky+2*gridexpansion;
 | |
|     
 | |
|     /*
 | |
|      * Create output spline using transformed (unit-scale)
 | |
|      * coordinates, fill by zero values
 | |
|      */
 | |
|     s->d = d;
 | |
|     s->n = kx;
 | |
|     s->m = ky;
 | |
|     s->stype = -3;
 | |
|     sfx = s->n*s->m*d;
 | |
|     sfy = 2*s->n*s->m*d;
 | |
|     sfxy = 3*s->n*s->m*d;
 | |
|     ae_vector_set_length(&s->x, s->n, _state);
 | |
|     ae_vector_set_length(&s->y, s->m, _state);
 | |
|     ae_vector_set_length(&s->f, 4*s->n*s->m*d, _state);
 | |
|     for(i=0; i<=s->n-1; i++)
 | |
|     {
 | |
|         s->x.ptr.p_double[i] = (double)(i);
 | |
|     }
 | |
|     for(i=0; i<=s->m-1; i++)
 | |
|     {
 | |
|         s->y.ptr.p_double[i] = (double)(i);
 | |
|     }
 | |
|     for(i=0; i<=4*s->n*s->m*d-1; i++)
 | |
|     {
 | |
|         s->f.ptr.p_double[i] = 0.0;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Create local copy of dataset (only points in the grid are copied;
 | |
|      * we allow small step out of the grid, by Eps*H, in order to deal
 | |
|      * with numerical rounding errors).
 | |
|      *
 | |
|      * An additional copy of Y-values is created at columns beyond 2+J;
 | |
|      * it is preserved during all transformations. This copy is used
 | |
|      * to calculate error-related metrics.
 | |
|      *
 | |
|      * Calculate mean(Y), TSS
 | |
|      */
 | |
|     ae_vector_set_length(&meany, d, _state);
 | |
|     for(j=0; j<=d-1; j++)
 | |
|     {
 | |
|         meany.ptr.p_double[j] = (double)(0);
 | |
|     }
 | |
|     rvectorsetlengthatleast(&xywork, npoints*ew, _state);
 | |
|     acopied = 0;
 | |
|     eps = 1.0E-6;
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         vx = state->xy.ptr.p_double[i*ew+0];
 | |
|         vy = state->xy.ptr.p_double[i*ew+1];
 | |
|         if( ((ae_fp_less_eq(xaraw-eps*hx,vx)&&ae_fp_less_eq(vx,xbraw+eps*hx))&&ae_fp_less_eq(yaraw-eps*hy,vy))&&ae_fp_less_eq(vy,ybraw+eps*hy) )
 | |
|         {
 | |
|             xywork.ptr.p_double[acopied*ew+0] = (vx-xa)*invhx;
 | |
|             xywork.ptr.p_double[acopied*ew+1] = (vy-ya)*invhy;
 | |
|             for(j=0; j<=d-1; j++)
 | |
|             {
 | |
|                 v = state->xy.ptr.p_double[i*ew+2+j];
 | |
|                 xywork.ptr.p_double[acopied*ew+2+j] = v;
 | |
|                 meany.ptr.p_double[j] = meany.ptr.p_double[j]+v;
 | |
|             }
 | |
|             acopied = acopied+1;
 | |
|         }
 | |
|     }
 | |
|     npoints = acopied;
 | |
|     for(j=0; j<=d-1; j++)
 | |
|     {
 | |
|         meany.ptr.p_double[j] = meany.ptr.p_double[j]/coalesce((double)(npoints), (double)(1), _state);
 | |
|     }
 | |
|     tss = 0.0;
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=d-1; j++)
 | |
|         {
 | |
|             tss = tss+ae_sqr(xywork.ptr.p_double[i*ew+2+j]-meany.ptr.p_double[j], _state);
 | |
|         }
 | |
|     }
 | |
|     tss = coalesce(tss, 1.0, _state);
 | |
|     
 | |
|     /*
 | |
|      * Handle prior term.
 | |
|      * Modify output spline.
 | |
|      * Quick exit if dataset is empty.
 | |
|      */
 | |
|     buildpriorterm1(&xywork, npoints, 2, d, state->priorterm, state->priortermval, &vterm, _state);
 | |
|     if( npoints==0 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Quick exit
 | |
|          */
 | |
|         for(k=0; k<=s->n*s->m-1; k++)
 | |
|         {
 | |
|             k0 = k%s->n;
 | |
|             k1 = k/s->n;
 | |
|             for(j=0; j<=d-1; j++)
 | |
|             {
 | |
|                 dstidx = d*(k1*s->n+k0)+j;
 | |
|                 s->f.ptr.p_double[dstidx] = s->f.ptr.p_double[dstidx]+vterm.ptr.pp_double[j][0]*s->x.ptr.p_double[k0]+vterm.ptr.pp_double[j][1]*s->y.ptr.p_double[k1]+vterm.ptr.pp_double[j][2];
 | |
|                 s->f.ptr.p_double[sfx+dstidx] = s->f.ptr.p_double[sfx+dstidx]+vterm.ptr.pp_double[j][0];
 | |
|                 s->f.ptr.p_double[sfy+dstidx] = s->f.ptr.p_double[sfy+dstidx]+vterm.ptr.pp_double[j][1];
 | |
|             }
 | |
|         }
 | |
|         for(i=0; i<=s->n-1; i++)
 | |
|         {
 | |
|             s->x.ptr.p_double[i] = s->x.ptr.p_double[i]*hx+xa;
 | |
|         }
 | |
|         for(i=0; i<=s->m-1; i++)
 | |
|         {
 | |
|             s->y.ptr.p_double[i] = s->y.ptr.p_double[i]*hy+ya;
 | |
|         }
 | |
|         for(i=0; i<=s->n*s->m*d-1; i++)
 | |
|         {
 | |
|             s->f.ptr.p_double[sfx+i] = s->f.ptr.p_double[sfx+i]*invhx;
 | |
|             s->f.ptr.p_double[sfy+i] = s->f.ptr.p_double[sfy+i]*invhy;
 | |
|             s->f.ptr.p_double[sfxy+i] = s->f.ptr.p_double[sfxy+i]*invhx*invhy;
 | |
|         }
 | |
|         rep->rmserror = (double)(0);
 | |
|         rep->avgerror = (double)(0);
 | |
|         rep->maxerror = (double)(0);
 | |
|         rep->r2 = 1.0;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Build 1D compact basis function
 | |
|      * Generate design matrix
 | |
|      */
 | |
|     ae_vector_set_length(&tmpx, 7, _state);
 | |
|     ae_vector_set_length(&tmpy, 7, _state);
 | |
|     tmpx.ptr.p_double[0] = (double)(-3);
 | |
|     tmpx.ptr.p_double[1] = (double)(-2);
 | |
|     tmpx.ptr.p_double[2] = (double)(-1);
 | |
|     tmpx.ptr.p_double[3] = (double)(0);
 | |
|     tmpx.ptr.p_double[4] = (double)(1);
 | |
|     tmpx.ptr.p_double[5] = (double)(2);
 | |
|     tmpx.ptr.p_double[6] = (double)(3);
 | |
|     tmpy.ptr.p_double[0] = (double)(0);
 | |
|     tmpy.ptr.p_double[1] = (double)(0);
 | |
|     tmpy.ptr.p_double[2] = (double)1/(double)12;
 | |
|     tmpy.ptr.p_double[3] = (double)2/(double)6;
 | |
|     tmpy.ptr.p_double[4] = (double)1/(double)12;
 | |
|     tmpy.ptr.p_double[5] = (double)(0);
 | |
|     tmpy.ptr.p_double[6] = (double)(0);
 | |
|     spline1dbuildcubic(&tmpx, &tmpy, tmpx.cnt, 2, 0.0, 2, 0.0, &basis1, _state);
 | |
|     
 | |
|     /*
 | |
|      * Solve.
 | |
|      * Update spline.
 | |
|      */
 | |
|     if( state->solvertype==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * BlockLLS
 | |
|          */
 | |
|         spline2d_reorderdatasetandbuildindex(&xywork, npoints, d, &tmp0, 0, kx, ky, &xyindex, &tmpi, _state);
 | |
|         spline2d_xdesigngenerate(&xywork, &xyindex, 0, kx, kx, 0, ky, ky, d, spline2d_lambdaregblocklls, state->smoothing, &basis1, &xdesignmatrix, _state);
 | |
|         spline2d_blockllsfit(&xdesignmatrix, state->lsqrcnt, &z, rep, tss, &blockllsbuf, _state);
 | |
|         spline2d_updatesplinetable(&z, kx, ky, d, &basis1, bfrad, &s->f, s->m, s->n, 1, _state);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         if( state->solvertype==2 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * NaiveLLS, reference implementation
 | |
|              */
 | |
|             spline2d_generatedesignmatrix(&xywork, npoints, d, kx, ky, state->smoothing, spline2d_lambdaregblocklls, &basis1, &av, &ah, &arows, _state);
 | |
|             spline2d_naivellsfit(&av, &ah, arows, &xywork, kx, ky, npoints, d, state->lsqrcnt, &z, rep, tss, _state);
 | |
|             spline2d_updatesplinetable(&z, kx, ky, d, &basis1, bfrad, &s->f, s->m, s->n, 1, _state);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if( state->solvertype==3 )
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * FastDDM method
 | |
|                  */
 | |
|                 ae_assert(basecasex>0, "Spline2DFit: integrity error", _state);
 | |
|                 ae_assert(basecasey>0, "Spline2DFit: integrity error", _state);
 | |
|                 spline2d_fastddmfit(&xywork, npoints, d, kx, ky, basecasex, basecasey, state->maxcoresize, state->interfacesize, state->nlayers, state->smoothing, state->lsqrcnt, &basis1, s, rep, tss, _state);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ae_assert(ae_false, "Spline2DFit: integrity error", _state);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Append prior term.
 | |
|      * Transform spline to original coordinates
 | |
|      */
 | |
|     for(k=0; k<=s->n*s->m-1; k++)
 | |
|     {
 | |
|         k0 = k%s->n;
 | |
|         k1 = k/s->n;
 | |
|         for(j=0; j<=d-1; j++)
 | |
|         {
 | |
|             dstidx = d*(k1*s->n+k0)+j;
 | |
|             s->f.ptr.p_double[dstidx] = s->f.ptr.p_double[dstidx]+vterm.ptr.pp_double[j][0]*s->x.ptr.p_double[k0]+vterm.ptr.pp_double[j][1]*s->y.ptr.p_double[k1]+vterm.ptr.pp_double[j][2];
 | |
|             s->f.ptr.p_double[sfx+dstidx] = s->f.ptr.p_double[sfx+dstidx]+vterm.ptr.pp_double[j][0];
 | |
|             s->f.ptr.p_double[sfy+dstidx] = s->f.ptr.p_double[sfy+dstidx]+vterm.ptr.pp_double[j][1];
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=s->n-1; i++)
 | |
|     {
 | |
|         s->x.ptr.p_double[i] = s->x.ptr.p_double[i]*hx+xa;
 | |
|     }
 | |
|     for(i=0; i<=s->m-1; i++)
 | |
|     {
 | |
|         s->y.ptr.p_double[i] = s->y.ptr.p_double[i]*hy+ya;
 | |
|     }
 | |
|     for(i=0; i<=s->n*s->m*d-1; i++)
 | |
|     {
 | |
|         s->f.ptr.p_double[sfx+i] = s->f.ptr.p_double[sfx+i]*invhx;
 | |
|         s->f.ptr.p_double[sfy+i] = s->f.ptr.p_double[sfy+i]*invhy;
 | |
|         s->f.ptr.p_double[sfxy+i] = s->f.ptr.p_double[sfxy+i]*invhx*invhy;
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: allocation
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 28.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dalloc(ae_serializer* s,
 | |
|      spline2dinterpolant* spline,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Header
 | |
|      */
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     
 | |
|     /*
 | |
|      * Data
 | |
|      */
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     allocrealarray(s, &spline->x, -1, _state);
 | |
|     allocrealarray(s, &spline->y, -1, _state);
 | |
|     allocrealarray(s, &spline->f, -1, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: serialization
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 28.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dserialize(ae_serializer* s,
 | |
|      spline2dinterpolant* spline,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Header
 | |
|      */
 | |
|     ae_serializer_serialize_int(s, getspline2dserializationcode(_state), _state);
 | |
|     
 | |
|     /*
 | |
|      * Data
 | |
|      */
 | |
|     ae_serializer_serialize_int(s, spline->stype, _state);
 | |
|     ae_serializer_serialize_int(s, spline->n, _state);
 | |
|     ae_serializer_serialize_int(s, spline->m, _state);
 | |
|     ae_serializer_serialize_int(s, spline->d, _state);
 | |
|     serializerealarray(s, &spline->x, -1, _state);
 | |
|     serializerealarray(s, &spline->y, -1, _state);
 | |
|     serializerealarray(s, &spline->f, -1, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: unserialization
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 28.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline2dunserialize(ae_serializer* s,
 | |
|      spline2dinterpolant* spline,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t scode;
 | |
| 
 | |
|     _spline2dinterpolant_clear(spline);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Header
 | |
|      */
 | |
|     ae_serializer_unserialize_int(s, &scode, _state);
 | |
|     ae_assert(scode==getspline2dserializationcode(_state), "Spline2DUnserialize: stream header corrupted", _state);
 | |
|     
 | |
|     /*
 | |
|      * Data
 | |
|      */
 | |
|     ae_serializer_unserialize_int(s, &spline->stype, _state);
 | |
|     ae_serializer_unserialize_int(s, &spline->n, _state);
 | |
|     ae_serializer_unserialize_int(s, &spline->m, _state);
 | |
|     ae_serializer_unserialize_int(s, &spline->d, _state);
 | |
|     unserializerealarray(s, &spline->x, _state);
 | |
|     unserializerealarray(s, &spline->y, _state);
 | |
|     unserializerealarray(s, &spline->f, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Internal subroutine.
 | |
| Calculation of the first derivatives and the cross-derivative.
 | |
| *************************************************************************/
 | |
| static void spline2d_bicubiccalcderivatives(/* Real    */ ae_matrix* a,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t m,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_matrix* dx,
 | |
|      /* Real    */ ae_matrix* dy,
 | |
|      /* Real    */ ae_matrix* dxy,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_vector xt;
 | |
|     ae_vector ft;
 | |
|     double s;
 | |
|     double ds;
 | |
|     double d2s;
 | |
|     spline1dinterpolant c;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&xt, 0, sizeof(xt));
 | |
|     memset(&ft, 0, sizeof(ft));
 | |
|     memset(&c, 0, sizeof(c));
 | |
|     ae_matrix_clear(dx);
 | |
|     ae_matrix_clear(dy);
 | |
|     ae_matrix_clear(dxy);
 | |
|     ae_vector_init(&xt, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ft, 0, DT_REAL, _state, ae_true);
 | |
|     _spline1dinterpolant_init(&c, _state, ae_true);
 | |
| 
 | |
|     ae_matrix_set_length(dx, m, n, _state);
 | |
|     ae_matrix_set_length(dy, m, n, _state);
 | |
|     ae_matrix_set_length(dxy, m, n, _state);
 | |
|     
 | |
|     /*
 | |
|      * dF/dX
 | |
|      */
 | |
|     ae_vector_set_length(&xt, n, _state);
 | |
|     ae_vector_set_length(&ft, n, _state);
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=n-1; j++)
 | |
|         {
 | |
|             xt.ptr.p_double[j] = x->ptr.p_double[j];
 | |
|             ft.ptr.p_double[j] = a->ptr.pp_double[i][j];
 | |
|         }
 | |
|         spline1dbuildcubic(&xt, &ft, n, 0, 0.0, 0, 0.0, &c, _state);
 | |
|         for(j=0; j<=n-1; j++)
 | |
|         {
 | |
|             spline1ddiff(&c, x->ptr.p_double[j], &s, &ds, &d2s, _state);
 | |
|             dx->ptr.pp_double[i][j] = ds;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * dF/dY
 | |
|      */
 | |
|     ae_vector_set_length(&xt, m, _state);
 | |
|     ae_vector_set_length(&ft, m, _state);
 | |
|     for(j=0; j<=n-1; j++)
 | |
|     {
 | |
|         for(i=0; i<=m-1; i++)
 | |
|         {
 | |
|             xt.ptr.p_double[i] = y->ptr.p_double[i];
 | |
|             ft.ptr.p_double[i] = a->ptr.pp_double[i][j];
 | |
|         }
 | |
|         spline1dbuildcubic(&xt, &ft, m, 0, 0.0, 0, 0.0, &c, _state);
 | |
|         for(i=0; i<=m-1; i++)
 | |
|         {
 | |
|             spline1ddiff(&c, y->ptr.p_double[i], &s, &ds, &d2s, _state);
 | |
|             dy->ptr.pp_double[i][j] = ds;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * d2F/dXdY
 | |
|      */
 | |
|     ae_vector_set_length(&xt, n, _state);
 | |
|     ae_vector_set_length(&ft, n, _state);
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=n-1; j++)
 | |
|         {
 | |
|             xt.ptr.p_double[j] = x->ptr.p_double[j];
 | |
|             ft.ptr.p_double[j] = dy->ptr.pp_double[i][j];
 | |
|         }
 | |
|         spline1dbuildcubic(&xt, &ft, n, 0, 0.0, 0, 0.0, &c, _state);
 | |
|         for(j=0; j<=n-1; j++)
 | |
|         {
 | |
|             spline1ddiff(&c, x->ptr.p_double[j], &s, &ds, &d2s, _state);
 | |
|             dxy->ptr.pp_double[i][j] = ds;
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function generates design matrix for the problem (in fact, two design
 | |
| matrices are generated: "vertical" one and transposed (horizontal) one.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY          -   array[NPoints*(2+D)]; dataset after scaling  in  such
 | |
|                     way that grid step is equal to 1.0 in both dimensions.
 | |
|     NPoints     -   dataset size, NPoints>=1
 | |
|     KX, KY      -   grid size, KX,KY>=4
 | |
|     Smoothing   -   nonlinearity penalty coefficient, >=0
 | |
|     LambdaReg   -   regularization coefficient, >=0
 | |
|     Basis1      -   basis spline, expected to be non-zero only at [-2,+2]
 | |
|     AV, AH      -   possibly preallocated buffers
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     AV          -   sparse matrix[ARows,KX*KY]; design matrix
 | |
|     AH          -   transpose of AV
 | |
|     ARows       -   number of rows in design matrix
 | |
|     
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_generatedesignmatrix(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      double smoothing,
 | |
|      double lambdareg,
 | |
|      spline1dinterpolant* basis1,
 | |
|      sparsematrix* av,
 | |
|      sparsematrix* ah,
 | |
|      ae_int_t* arows,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t nzwidth;
 | |
|     ae_int_t nzshift;
 | |
|     ae_int_t ew;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j0;
 | |
|     ae_int_t j1;
 | |
|     ae_int_t k0;
 | |
|     ae_int_t k1;
 | |
|     ae_int_t dstidx;
 | |
|     double v;
 | |
|     double v0;
 | |
|     double v1;
 | |
|     double v2;
 | |
|     double w0;
 | |
|     double w1;
 | |
|     double w2;
 | |
|     ae_vector crx;
 | |
|     ae_vector cry;
 | |
|     ae_vector nrs;
 | |
|     ae_matrix d2x;
 | |
|     ae_matrix d2y;
 | |
|     ae_matrix dxy;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&crx, 0, sizeof(crx));
 | |
|     memset(&cry, 0, sizeof(cry));
 | |
|     memset(&nrs, 0, sizeof(nrs));
 | |
|     memset(&d2x, 0, sizeof(d2x));
 | |
|     memset(&d2y, 0, sizeof(d2y));
 | |
|     memset(&dxy, 0, sizeof(dxy));
 | |
|     *arows = 0;
 | |
|     ae_vector_init(&crx, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&cry, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&nrs, 0, DT_INT, _state, ae_true);
 | |
|     ae_matrix_init(&d2x, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&d2y, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     nzwidth = 4;
 | |
|     nzshift = 1;
 | |
|     ae_assert(npoints>0, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(kx>=nzwidth, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(ky>=nzwidth, "Spline2DFit: integrity check failed", _state);
 | |
|     ew = 2+d;
 | |
|     
 | |
|     /*
 | |
|      * Determine canonical rectangle for every point. Every point of the dataset is
 | |
|      * influenced by at most NZWidth*NZWidth basis functions, which form NZWidth*NZWidth
 | |
|      * canonical rectangle.
 | |
|      *
 | |
|      * Thus, we have (KX-NZWidth+1)*(KY-NZWidth+1) overlapping canonical rectangles.
 | |
|      * Assigning every point to its rectangle simplifies creation of sparse basis
 | |
|      * matrix at the next steps.
 | |
|      */
 | |
|     ae_vector_set_length(&crx, npoints, _state);
 | |
|     ae_vector_set_length(&cry, npoints, _state);
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         crx.ptr.p_int[i] = iboundval(ae_ifloor(xy->ptr.p_double[i*ew+0], _state)-nzshift, 0, kx-nzwidth, _state);
 | |
|         cry.ptr.p_int[i] = iboundval(ae_ifloor(xy->ptr.p_double[i*ew+1], _state)-nzshift, 0, ky-nzwidth, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Create vertical and horizontal design matrices 
 | |
|      */
 | |
|     *arows = npoints+kx*ky;
 | |
|     if( ae_fp_neq(smoothing,0.0) )
 | |
|     {
 | |
|         ae_assert(ae_fp_greater(smoothing,0.0), "Spline2DFit: integrity check failed", _state);
 | |
|         *arows = *arows+3*(kx-2)*(ky-2);
 | |
|     }
 | |
|     ae_vector_set_length(&nrs, *arows, _state);
 | |
|     dstidx = 0;
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         nrs.ptr.p_int[dstidx+i] = nzwidth*nzwidth;
 | |
|     }
 | |
|     dstidx = dstidx+npoints;
 | |
|     for(i=0; i<=kx*ky-1; i++)
 | |
|     {
 | |
|         nrs.ptr.p_int[dstidx+i] = 1;
 | |
|     }
 | |
|     dstidx = dstidx+kx*ky;
 | |
|     if( ae_fp_neq(smoothing,0.0) )
 | |
|     {
 | |
|         for(i=0; i<=3*(kx-2)*(ky-2)-1; i++)
 | |
|         {
 | |
|             nrs.ptr.p_int[dstidx+i] = 3*3;
 | |
|         }
 | |
|         dstidx = dstidx+3*(kx-2)*(ky-2);
 | |
|     }
 | |
|     ae_assert(dstidx==(*arows), "Spline2DFit: integrity check failed", _state);
 | |
|     sparsecreatecrs(*arows, kx*ky, &nrs, av, _state);
 | |
|     dstidx = 0;
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         for(j1=0; j1<=nzwidth-1; j1++)
 | |
|         {
 | |
|             for(j0=0; j0<=nzwidth-1; j0++)
 | |
|             {
 | |
|                 v0 = spline1dcalc(basis1, xy->ptr.p_double[i*ew+0]-(crx.ptr.p_int[i]+j0), _state);
 | |
|                 v1 = spline1dcalc(basis1, xy->ptr.p_double[i*ew+1]-(cry.ptr.p_int[i]+j1), _state);
 | |
|                 sparseset(av, dstidx+i, (cry.ptr.p_int[i]+j1)*kx+(crx.ptr.p_int[i]+j0), v0*v1, _state);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     dstidx = dstidx+npoints;
 | |
|     for(i=0; i<=kx*ky-1; i++)
 | |
|     {
 | |
|         sparseset(av, dstidx+i, i, lambdareg, _state);
 | |
|     }
 | |
|     dstidx = dstidx+kx*ky;
 | |
|     if( ae_fp_neq(smoothing,0.0) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Smoothing is applied. Because all grid nodes are same,
 | |
|          * we apply same smoothing kernel, which is calculated only
 | |
|          * once at the beginning of design matrix generation.
 | |
|          */
 | |
|         ae_matrix_set_length(&d2x, 3, 3, _state);
 | |
|         ae_matrix_set_length(&d2y, 3, 3, _state);
 | |
|         ae_matrix_set_length(&dxy, 3, 3, _state);
 | |
|         for(j1=0; j1<=2; j1++)
 | |
|         {
 | |
|             for(j0=0; j0<=2; j0++)
 | |
|             {
 | |
|                 d2x.ptr.pp_double[j0][j1] = 0.0;
 | |
|                 d2y.ptr.pp_double[j0][j1] = 0.0;
 | |
|                 dxy.ptr.pp_double[j0][j1] = 0.0;
 | |
|             }
 | |
|         }
 | |
|         for(k1=0; k1<=2; k1++)
 | |
|         {
 | |
|             for(k0=0; k0<=2; k0++)
 | |
|             {
 | |
|                 spline1ddiff(basis1, (double)(-(k0-1)), &v0, &v1, &v2, _state);
 | |
|                 spline1ddiff(basis1, (double)(-(k1-1)), &w0, &w1, &w2, _state);
 | |
|                 d2x.ptr.pp_double[k0][k1] = d2x.ptr.pp_double[k0][k1]+v2*w0;
 | |
|                 d2y.ptr.pp_double[k0][k1] = d2y.ptr.pp_double[k0][k1]+w2*v0;
 | |
|                 dxy.ptr.pp_double[k0][k1] = dxy.ptr.pp_double[k0][k1]+v1*w1;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Now, kernel is ready - apply it to all inner nodes of the grid.
 | |
|          */
 | |
|         for(j1=1; j1<=ky-2; j1++)
 | |
|         {
 | |
|             for(j0=1; j0<=kx-2; j0++)
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * d2F/dx2 term
 | |
|                  */
 | |
|                 v = smoothing;
 | |
|                 for(k1=-1; k1<=1; k1++)
 | |
|                 {
 | |
|                     for(k0=-1; k0<=1; k0++)
 | |
|                     {
 | |
|                         sparseset(av, dstidx, (j1+k1)*kx+(j0+k0), v*d2x.ptr.pp_double[1+k0][1+k1], _state);
 | |
|                     }
 | |
|                 }
 | |
|                 dstidx = dstidx+1;
 | |
|                 
 | |
|                 /*
 | |
|                  * d2F/dy2 term
 | |
|                  */
 | |
|                 v = smoothing;
 | |
|                 for(k1=-1; k1<=1; k1++)
 | |
|                 {
 | |
|                     for(k0=-1; k0<=1; k0++)
 | |
|                     {
 | |
|                         sparseset(av, dstidx, (j1+k1)*kx+(j0+k0), v*d2y.ptr.pp_double[1+k0][1+k1], _state);
 | |
|                     }
 | |
|                 }
 | |
|                 dstidx = dstidx+1;
 | |
|                 
 | |
|                 /*
 | |
|                  * 2*d2F/dxdy term
 | |
|                  */
 | |
|                 v = ae_sqrt((double)(2), _state)*smoothing;
 | |
|                 for(k1=-1; k1<=1; k1++)
 | |
|                 {
 | |
|                     for(k0=-1; k0<=1; k0++)
 | |
|                     {
 | |
|                         sparseset(av, dstidx, (j1+k1)*kx+(j0+k0), v*dxy.ptr.pp_double[1+k0][1+k1], _state);
 | |
|                     }
 | |
|                 }
 | |
|                 dstidx = dstidx+1;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     ae_assert(dstidx==(*arows), "Spline2DFit: integrity check failed", _state);
 | |
|     sparsecopy(av, ah, _state);
 | |
|     sparsetransposecrs(ah, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function updates table of spline values/derivatives using coefficients
 | |
| for a layer of basis functions.
 | |
|     
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_updatesplinetable(/* Real    */ ae_vector* z,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t d,
 | |
|      spline1dinterpolant* basis1,
 | |
|      ae_int_t bfrad,
 | |
|      /* Real    */ ae_vector* ftbl,
 | |
|      ae_int_t m,
 | |
|      ae_int_t n,
 | |
|      ae_int_t scalexy,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t k;
 | |
|     ae_int_t k0;
 | |
|     ae_int_t k1;
 | |
|     ae_int_t j;
 | |
|     ae_int_t j0;
 | |
|     ae_int_t j1;
 | |
|     ae_int_t j0a;
 | |
|     ae_int_t j0b;
 | |
|     ae_int_t j1a;
 | |
|     ae_int_t j1b;
 | |
|     double v;
 | |
|     double v0;
 | |
|     double v1;
 | |
|     double v01;
 | |
|     double v11;
 | |
|     double rdummy;
 | |
|     ae_int_t dstidx;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     double invscalexy;
 | |
| 
 | |
| 
 | |
|     ae_assert(n==(kx-1)*scalexy+1, "Spline2DFit.UpdateSplineTable: integrity check failed", _state);
 | |
|     ae_assert(m==(ky-1)*scalexy+1, "Spline2DFit.UpdateSplineTable: integrity check failed", _state);
 | |
|     invscalexy = (double)1/(double)scalexy;
 | |
|     sfx = n*m*d;
 | |
|     sfy = 2*n*m*d;
 | |
|     sfxy = 3*n*m*d;
 | |
|     for(k=0; k<=kx*ky-1; k++)
 | |
|     {
 | |
|         k0 = k%kx;
 | |
|         k1 = k/kx;
 | |
|         j0a = iboundval(k0*scalexy-(bfrad*scalexy-1), 0, n-1, _state);
 | |
|         j0b = iboundval(k0*scalexy+(bfrad*scalexy-1), 0, n-1, _state);
 | |
|         j1a = iboundval(k1*scalexy-(bfrad*scalexy-1), 0, m-1, _state);
 | |
|         j1b = iboundval(k1*scalexy+(bfrad*scalexy-1), 0, m-1, _state);
 | |
|         for(j1=j1a; j1<=j1b; j1++)
 | |
|         {
 | |
|             spline1ddiff(basis1, (j1-k1*scalexy)*invscalexy, &v1, &v11, &rdummy, _state);
 | |
|             v11 = v11*invscalexy;
 | |
|             for(j0=j0a; j0<=j0b; j0++)
 | |
|             {
 | |
|                 spline1ddiff(basis1, (j0-k0*scalexy)*invscalexy, &v0, &v01, &rdummy, _state);
 | |
|                 v01 = v01*invscalexy;
 | |
|                 for(j=0; j<=d-1; j++)
 | |
|                 {
 | |
|                     dstidx = d*(j1*n+j0)+j;
 | |
|                     v = z->ptr.p_double[j*kx*ky+k];
 | |
|                     ftbl->ptr.p_double[dstidx] = ftbl->ptr.p_double[dstidx]+v0*v1*v;
 | |
|                     ftbl->ptr.p_double[sfx+dstidx] = ftbl->ptr.p_double[sfx+dstidx]+v01*v1*v;
 | |
|                     ftbl->ptr.p_double[sfy+dstidx] = ftbl->ptr.p_double[sfy+dstidx]+v0*v11*v;
 | |
|                     ftbl->ptr.p_double[sfxy+dstidx] = ftbl->ptr.p_double[sfxy+dstidx]+v01*v11*v;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs fitting with FastDDM solver.
 | |
| Internal function, never use it directly.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY          -   array[NPoints*(2+D)], dataset; destroyed in process
 | |
|     KX, KY      -   grid size
 | |
|     TileSize    -   tile size
 | |
|     InterfaceSize-  interface size
 | |
|     NPoints     -   points count
 | |
|     D           -   number of components in vector-valued spline, D>=1
 | |
|     LSQRCnt     -   number of iterations, non-zero:
 | |
|                     * LSQRCnt>0 means that specified amount of  preconditioned
 | |
|                       LSQR  iterations  will  be  performed  to solve problem;
 | |
|                       usually  we  need  2..5  its.  Recommended option - best
 | |
|                       convergence and stability/quality.
 | |
|                     * LSQRCnt<0 means that instead of LSQR  we  use  iterative
 | |
|                       refinement on normal equations. Again, 2..5 its is enough.
 | |
|     Basis1      -   basis spline, expected to be non-zero only at [-2,+2]
 | |
|     Z           -   possibly preallocated buffer for solution
 | |
|     Residuals   -   possibly preallocated buffer for residuals at dataset points
 | |
|     Rep         -   report structure; fields which are not set by this function
 | |
|                     are left intact
 | |
|     TSS         -   total sum of squares; used to calculate R2
 | |
|     
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     XY          -   destroyed in process
 | |
|     Z           -   array[KX*KY*D], filled by solution; KX*KY coefficients
 | |
|                     corresponding to each of D dimensions are stored contiguously.
 | |
|     Rep         -   following fields are set:
 | |
|                     * Rep.RMSError
 | |
|                     * Rep.AvgError
 | |
|                     * Rep.MaxError
 | |
|                     * Rep.R2
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_fastddmfit(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t basecasex,
 | |
|      ae_int_t basecasey,
 | |
|      ae_int_t maxcoresize,
 | |
|      ae_int_t interfacesize,
 | |
|      ae_int_t nlayers,
 | |
|      double smoothing,
 | |
|      ae_int_t lsqrcnt,
 | |
|      spline1dinterpolant* basis1,
 | |
|      spline2dinterpolant* spline,
 | |
|      spline2dfitreport* rep,
 | |
|      double tss,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t nzwidth;
 | |
|     ae_int_t xew;
 | |
|     ae_int_t ntotallayers;
 | |
|     ae_int_t scaleidx;
 | |
|     ae_int_t scalexy;
 | |
|     double invscalexy;
 | |
|     ae_int_t kxcur;
 | |
|     ae_int_t kycur;
 | |
|     ae_int_t tilescount0;
 | |
|     ae_int_t tilescount1;
 | |
|     double v;
 | |
|     double rss;
 | |
|     ae_vector yraw;
 | |
|     ae_vector xyindex;
 | |
|     ae_vector tmp0;
 | |
|     ae_vector bufi;
 | |
|     spline2dfastddmbuf seed;
 | |
|     ae_shared_pool pool;
 | |
|     spline2dxdesignmatrix xdesignmatrix;
 | |
|     spline2dblockllsbuf blockllsbuf;
 | |
|     spline2dfitreport dummyrep;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&yraw, 0, sizeof(yraw));
 | |
|     memset(&xyindex, 0, sizeof(xyindex));
 | |
|     memset(&tmp0, 0, sizeof(tmp0));
 | |
|     memset(&bufi, 0, sizeof(bufi));
 | |
|     memset(&seed, 0, sizeof(seed));
 | |
|     memset(&pool, 0, sizeof(pool));
 | |
|     memset(&xdesignmatrix, 0, sizeof(xdesignmatrix));
 | |
|     memset(&blockllsbuf, 0, sizeof(blockllsbuf));
 | |
|     memset(&dummyrep, 0, sizeof(dummyrep));
 | |
|     ae_vector_init(&yraw, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xyindex, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bufi, 0, DT_INT, _state, ae_true);
 | |
|     _spline2dfastddmbuf_init(&seed, _state, ae_true);
 | |
|     ae_shared_pool_init(&pool, _state, ae_true);
 | |
|     _spline2dxdesignmatrix_init(&xdesignmatrix, _state, ae_true);
 | |
|     _spline2dblockllsbuf_init(&blockllsbuf, _state, ae_true);
 | |
|     _spline2dfitreport_init(&dummyrep, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Dataset metrics and integrity checks
 | |
|      */
 | |
|     nzwidth = 4;
 | |
|     xew = 2+d;
 | |
|     ae_assert(maxcoresize>=2, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(interfacesize>=1, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(kx>=nzwidth, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(ky>=nzwidth, "Spline2DFit: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Verify consistency of the grid size (KX,KY) with basecase sizes.
 | |
|      * Determine full number of layers.
 | |
|      */
 | |
|     ae_assert(basecasex<=maxcoresize, "Spline2DFit: integrity error", _state);
 | |
|     ae_assert(basecasey<=maxcoresize, "Spline2DFit: integrity error", _state);
 | |
|     ntotallayers = 1;
 | |
|     scalexy = 1;
 | |
|     kxcur = kx;
 | |
|     kycur = ky;
 | |
|     while(kxcur>basecasex+1&&kycur>basecasey+1)
 | |
|     {
 | |
|         ae_assert(kxcur%2==1, "Spline2DFit: integrity error", _state);
 | |
|         ae_assert(kycur%2==1, "Spline2DFit: integrity error", _state);
 | |
|         kxcur = (kxcur-1)/2+1;
 | |
|         kycur = (kycur-1)/2+1;
 | |
|         scalexy = scalexy*2;
 | |
|         inc(&ntotallayers, _state);
 | |
|     }
 | |
|     invscalexy = (double)1/(double)scalexy;
 | |
|     ae_assert((kxcur<=maxcoresize+1&&kxcur==basecasex+1)||kxcur%basecasex==1, "Spline2DFit: integrity error", _state);
 | |
|     ae_assert((kycur<=maxcoresize+1&&kycur==basecasey+1)||kycur%basecasey==1, "Spline2DFit: integrity error", _state);
 | |
|     ae_assert(kxcur==basecasex+1||kycur==basecasey+1, "Spline2DFit: integrity error", _state);
 | |
|     
 | |
|     /*
 | |
|      * Initial scaling of dataset.
 | |
|      * Store original target values to YRaw.
 | |
|      */
 | |
|     rvectorsetlengthatleast(&yraw, npoints*d, _state);
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         xy->ptr.p_double[xew*i+0] = xy->ptr.p_double[xew*i+0]*invscalexy;
 | |
|         xy->ptr.p_double[xew*i+1] = xy->ptr.p_double[xew*i+1]*invscalexy;
 | |
|         for(j=0; j<=d-1; j++)
 | |
|         {
 | |
|             yraw.ptr.p_double[i*d+j] = xy->ptr.p_double[xew*i+2+j];
 | |
|         }
 | |
|     }
 | |
|     kxcur = (kx-1)/scalexy+1;
 | |
|     kycur = (ky-1)/scalexy+1;
 | |
|     
 | |
|     /*
 | |
|      * Build initial dataset index; area is divided into (KXCur-1)*(KYCur-1)
 | |
|      * cells, with contiguous storage of points in the same cell.
 | |
|      * Iterate over different scales
 | |
|      */
 | |
|     ae_shared_pool_set_seed(&pool, &seed, sizeof(seed), _spline2dfastddmbuf_init, _spline2dfastddmbuf_init_copy, _spline2dfastddmbuf_destroy, _state);
 | |
|     spline2d_reorderdatasetandbuildindex(xy, npoints, d, &yraw, d, kxcur, kycur, &xyindex, &bufi, _state);
 | |
|     for(scaleidx=ntotallayers-1; scaleidx>=0; scaleidx--)
 | |
|     {
 | |
|         if( (nlayers>0&&scaleidx<nlayers)||(nlayers<=0&&scaleidx<imax2(ntotallayers+nlayers, 1, _state)) )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Fit current layer
 | |
|              */
 | |
|             ae_assert(kxcur%basecasex==1, "Spline2DFit: integrity error", _state);
 | |
|             ae_assert(kycur%basecasey==1, "Spline2DFit: integrity error", _state);
 | |
|             tilescount0 = kxcur/basecasex;
 | |
|             tilescount1 = kycur/basecasey;
 | |
|             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);
 | |
|             
 | |
|             /*
 | |
|              * Compute residuals and update XY
 | |
|              */
 | |
|             spline2d_computeresidualsfromscratch(xy, &yraw, npoints, d, scalexy, spline, _state);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Move to the next level
 | |
|          */
 | |
|         if( scaleidx!=0 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Transform dataset (multply everything by 2.0) and refine grid.
 | |
|              */
 | |
|             kxcur = 2*kxcur-1;
 | |
|             kycur = 2*kycur-1;
 | |
|             scalexy = scalexy/2;
 | |
|             invscalexy = (double)1/(double)scalexy;
 | |
|             spline2d_rescaledatasetandrefineindex(xy, npoints, d, &yraw, d, kxcur, kycur, &xyindex, &bufi, _state);
 | |
|             
 | |
|             /*
 | |
|              * Clear temporaries from previous round.
 | |
|              *
 | |
|              * We have to do it because upper layer of the multilevel spline
 | |
|              * needs more memory then subsequent layers, and we want to free
 | |
|              * this memory as soon as possible.
 | |
|              */
 | |
|             ae_shared_pool_clear_recycled(&pool, _state);
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Post-check
 | |
|      */
 | |
|     ae_assert(kxcur==kx, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(kycur==ky, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(scalexy==1, "Spline2DFit: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Report
 | |
|      */
 | |
|     rep->rmserror = (double)(0);
 | |
|     rep->avgerror = (double)(0);
 | |
|     rep->maxerror = (double)(0);
 | |
|     rss = 0.0;
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=d-1; j++)
 | |
|         {
 | |
|             v = xy->ptr.p_double[i*xew+2+j];
 | |
|             rss = rss+v*v;
 | |
|             rep->rmserror = rep->rmserror+ae_sqr(v, _state);
 | |
|             rep->avgerror = rep->avgerror+ae_fabs(v, _state);
 | |
|             rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
 | |
|         }
 | |
|     }
 | |
|     rep->rmserror = ae_sqrt(rep->rmserror/coalesce((double)(npoints*d), 1.0, _state), _state);
 | |
|     rep->avgerror = rep->avgerror/coalesce((double)(npoints*d), 1.0, _state);
 | |
|     rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Recursive fitting function for FastDDM algorithm.
 | |
| 
 | |
| Works with KX*KY grid, with KX=BasecaseX*TilesCountX+1 and KY=BasecaseY*TilesCountY+1,
 | |
| which is partitioned into TilesCountX*TilesCountY tiles, each having size
 | |
| BasecaseX*BasecaseY.
 | |
| 
 | |
| This function processes tiles in range [TileX0,TileX1)x[TileY0,TileY1) and
 | |
| recursively divides this range until we move down to single tile, which
 | |
| is processed with BlockLLS solver.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_fastddmfitlayer(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t d,
 | |
|      ae_int_t scalexy,
 | |
|      /* Integer */ ae_vector* xyindex,
 | |
|      ae_int_t basecasex,
 | |
|      ae_int_t tilex0,
 | |
|      ae_int_t tilex1,
 | |
|      ae_int_t tilescountx,
 | |
|      ae_int_t basecasey,
 | |
|      ae_int_t tiley0,
 | |
|      ae_int_t tiley1,
 | |
|      ae_int_t tilescounty,
 | |
|      ae_int_t maxcoresize,
 | |
|      ae_int_t interfacesize,
 | |
|      ae_int_t lsqrcnt,
 | |
|      double lambdareg,
 | |
|      spline1dinterpolant* basis1,
 | |
|      ae_shared_pool* pool,
 | |
|      spline2dinterpolant* spline,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t kx;
 | |
|     ae_int_t ky;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t j0;
 | |
|     ae_int_t j1;
 | |
|     ae_int_t bfrad;
 | |
|     ae_int_t xa;
 | |
|     ae_int_t xb;
 | |
|     ae_int_t ya;
 | |
|     ae_int_t yb;
 | |
|     ae_int_t tile0;
 | |
|     ae_int_t tile1;
 | |
|     ae_int_t tilesize0;
 | |
|     ae_int_t tilesize1;
 | |
|     ae_int_t sfx;
 | |
|     ae_int_t sfy;
 | |
|     ae_int_t sfxy;
 | |
|     double dummytss;
 | |
|     double invscalexy;
 | |
|     ae_int_t cnt0;
 | |
|     ae_int_t cnt1;
 | |
|     ae_int_t offs;
 | |
|     double vs;
 | |
|     double vsx;
 | |
|     double vsy;
 | |
|     double vsxy;
 | |
|     spline2dfastddmbuf *buf;
 | |
|     ae_smart_ptr _buf;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_buf, 0, sizeof(_buf));
 | |
|     ae_smart_ptr_init(&_buf, (void**)&buf, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Dataset metrics and fast integrity checks;
 | |
|      * no code with side effects is allowed before parallel split.
 | |
|      */
 | |
|     bfrad = 2;
 | |
|     invscalexy = (double)1/(double)scalexy;
 | |
|     kx = basecasex*tilescountx+1;
 | |
|     ky = basecasey*tilescounty+1;
 | |
|     
 | |
|     /*
 | |
|      * Parallelism; because this function is intended for
 | |
|      * large-scale problems, we always try to:
 | |
|      * * invoke parallel execution mode
 | |
|      * * activate spawn support
 | |
|      */
 | |
|     if( _trypexec_spline2d_fastddmfitlayer(xy,d,scalexy,xyindex,basecasex,tilex0,tilex1,tilescountx,basecasey,tiley0,tiley1,tilescounty,maxcoresize,interfacesize,lsqrcnt,lambdareg,basis1,pool,spline, _state) )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     if( imax2(tiley1-tiley0, tilex1-tilex0, _state)>=2 )
 | |
|     {
 | |
|         if( tiley1-tiley0>tilex1-tilex0 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Split problem in Y dimension
 | |
|              *
 | |
|              * NOTE: recursive calls to FastDDMFitLayer() compute
 | |
|              *       residuals in the inner cells defined by XYIndex[],
 | |
|              *       but we still have to compute residuals for cells
 | |
|              *       BETWEEN two recursive subdivisions of the task.
 | |
|              */
 | |
|             tiledsplit(tiley1-tiley0, 1, &j0, &j1, _state);
 | |
|             spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0, tilex1, tilescountx, basecasey, tiley0, tiley0+j0, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state);
 | |
|             spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0, tilex1, tilescountx, basecasey, tiley0+j0, tiley1, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Split problem in X dimension
 | |
|              *
 | |
|              * NOTE: recursive calls to FastDDMFitLayer() compute
 | |
|              *       residuals in the inner cells defined by XYIndex[],
 | |
|              *       but we still have to compute residuals for cells
 | |
|              *       BETWEEN two recursive subdivisions of the task.
 | |
|              */
 | |
|             tiledsplit(tilex1-tilex0, 1, &j0, &j1, _state);
 | |
|             spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0, tilex0+j0, tilescountx, basecasey, tiley0, tiley1, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state);
 | |
|             spline2d_fastddmfitlayer(xy, d, scalexy, xyindex, basecasex, tilex0+j0, tilex1, tilescountx, basecasey, tiley0, tiley1, tilescounty, maxcoresize, interfacesize, lsqrcnt, lambdareg, basis1, pool, spline, _state);
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(tiley0==tiley1-1, "Spline2DFit.FastDDMFitLayer: integrity check failed", _state);
 | |
|     ae_assert(tilex0==tilex1-1, "Spline2DFit.FastDDMFitLayer: integrity check failed", _state);
 | |
|     tile1 = tiley0;
 | |
|     tile0 = tilex0;
 | |
|     
 | |
|     /*
 | |
|      * Retrieve temporaries
 | |
|      */
 | |
|     ae_shared_pool_retrieve(pool, &_buf, _state);
 | |
|     
 | |
|     /*
 | |
|      * Analyze dataset
 | |
|      */
 | |
|     xa = iboundval(tile0*basecasex-interfacesize, 0, kx, _state);
 | |
|     xb = iboundval((tile0+1)*basecasex+interfacesize, 0, kx, _state);
 | |
|     ya = iboundval(tile1*basecasey-interfacesize, 0, ky, _state);
 | |
|     yb = iboundval((tile1+1)*basecasey+interfacesize, 0, ky, _state);
 | |
|     tilesize0 = xb-xa;
 | |
|     tilesize1 = yb-ya;
 | |
|     
 | |
|     /*
 | |
|      * Solve current chunk with BlockLLS
 | |
|      */
 | |
|     dummytss = 1.0;
 | |
|     spline2d_xdesigngenerate(xy, xyindex, xa, xb, kx, ya, yb, ky, d, lambdareg, 0.0, basis1, &buf->xdesignmatrix, _state);
 | |
|     spline2d_blockllsfit(&buf->xdesignmatrix, lsqrcnt, &buf->tmpz, &buf->dummyrep, dummytss, &buf->blockllsbuf, _state);
 | |
|     buf->localmodel.d = d;
 | |
|     buf->localmodel.m = tilesize1;
 | |
|     buf->localmodel.n = tilesize0;
 | |
|     buf->localmodel.stype = -3;
 | |
|     rvectorsetlengthatleast(&buf->localmodel.x, tilesize0, _state);
 | |
|     rvectorsetlengthatleast(&buf->localmodel.y, tilesize1, _state);
 | |
|     rvectorsetlengthatleast(&buf->localmodel.f, tilesize0*tilesize1*d*4, _state);
 | |
|     for(i=0; i<=tilesize0-1; i++)
 | |
|     {
 | |
|         buf->localmodel.x.ptr.p_double[i] = (double)(xa+i);
 | |
|     }
 | |
|     for(i=0; i<=tilesize1-1; i++)
 | |
|     {
 | |
|         buf->localmodel.y.ptr.p_double[i] = (double)(ya+i);
 | |
|     }
 | |
|     for(i=0; i<=tilesize0*tilesize1*d*4-1; i++)
 | |
|     {
 | |
|         buf->localmodel.f.ptr.p_double[i] = 0.0;
 | |
|     }
 | |
|     spline2d_updatesplinetable(&buf->tmpz, tilesize0, tilesize1, d, basis1, bfrad, &buf->localmodel.f, tilesize1, tilesize0, 1, _state);
 | |
|     
 | |
|     /*
 | |
|      * Transform local spline to original coordinates
 | |
|      */
 | |
|     sfx = buf->localmodel.n*buf->localmodel.m*d;
 | |
|     sfy = 2*buf->localmodel.n*buf->localmodel.m*d;
 | |
|     sfxy = 3*buf->localmodel.n*buf->localmodel.m*d;
 | |
|     for(i=0; i<=tilesize0-1; i++)
 | |
|     {
 | |
|         buf->localmodel.x.ptr.p_double[i] = buf->localmodel.x.ptr.p_double[i]*scalexy;
 | |
|     }
 | |
|     for(i=0; i<=tilesize1-1; i++)
 | |
|     {
 | |
|         buf->localmodel.y.ptr.p_double[i] = buf->localmodel.y.ptr.p_double[i]*scalexy;
 | |
|     }
 | |
|     for(i=0; i<=tilesize0*tilesize1*d-1; i++)
 | |
|     {
 | |
|         buf->localmodel.f.ptr.p_double[sfx+i] = buf->localmodel.f.ptr.p_double[sfx+i]*invscalexy;
 | |
|         buf->localmodel.f.ptr.p_double[sfy+i] = buf->localmodel.f.ptr.p_double[sfy+i]*invscalexy;
 | |
|         buf->localmodel.f.ptr.p_double[sfxy+i] = buf->localmodel.f.ptr.p_double[sfxy+i]*(invscalexy*invscalexy);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Output results; for inner and topmost/leftmost tiles we output only BasecaseX*BasecaseY
 | |
|      * inner elements; for rightmost/bottom ones we also output one column/row of the interface
 | |
|      * part.
 | |
|      *
 | |
|      * Such complexity is explained by the fact that area size (by design) is not evenly divisible
 | |
|      * by the tile size; it is divisible with remainder=1, and we expect that interface size is
 | |
|      * at least 1, so we can fill the missing rightmost/bottom elements of Z by the interface
 | |
|      * values.
 | |
|      */
 | |
|     ae_assert(interfacesize>=1, "Spline2DFit: integrity check failed", _state);
 | |
|     sfx = spline->n*spline->m*d;
 | |
|     sfy = 2*spline->n*spline->m*d;
 | |
|     sfxy = 3*spline->n*spline->m*d;
 | |
|     cnt0 = basecasex*scalexy;
 | |
|     cnt1 = basecasey*scalexy;
 | |
|     if( tile0==tilescountx-1 )
 | |
|     {
 | |
|         inc(&cnt0, _state);
 | |
|     }
 | |
|     if( tile1==tilescounty-1 )
 | |
|     {
 | |
|         inc(&cnt1, _state);
 | |
|     }
 | |
|     offs = d*(spline->n*tile1*basecasey*scalexy+tile0*basecasex*scalexy);
 | |
|     for(j1=0; j1<=cnt1-1; j1++)
 | |
|     {
 | |
|         for(j0=0; j0<=cnt0-1; j0++)
 | |
|         {
 | |
|             for(j=0; j<=d-1; j++)
 | |
|             {
 | |
|                 spline2ddiffvi(&buf->localmodel, (double)(tile0*basecasex*scalexy+j0), (double)(tile1*basecasey*scalexy+j1), j, &vs, &vsx, &vsy, &vsxy, _state);
 | |
|                 spline->f.ptr.p_double[offs+d*(spline->n*j1+j0)+j] = spline->f.ptr.p_double[offs+d*(spline->n*j1+j0)+j]+vs;
 | |
|                 spline->f.ptr.p_double[sfx+offs+d*(spline->n*j1+j0)+j] = spline->f.ptr.p_double[sfx+offs+d*(spline->n*j1+j0)+j]+vsx;
 | |
|                 spline->f.ptr.p_double[sfy+offs+d*(spline->n*j1+j0)+j] = spline->f.ptr.p_double[sfy+offs+d*(spline->n*j1+j0)+j]+vsy;
 | |
|                 spline->f.ptr.p_double[sfxy+offs+d*(spline->n*j1+j0)+j] = spline->f.ptr.p_double[sfxy+offs+d*(spline->n*j1+j0)+j]+vsxy;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Recycle temporaries
 | |
|      */
 | |
|     ae_shared_pool_recycle(pool, &_buf, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serial stub for GPL edition.
 | |
| *************************************************************************/
 | |
| ae_bool _trypexec_spline2d_fastddmfitlayer(/* Real    */ ae_vector* xy,
 | |
|     ae_int_t d,
 | |
|     ae_int_t scalexy,
 | |
|     /* Integer */ ae_vector* xyindex,
 | |
|     ae_int_t basecasex,
 | |
|     ae_int_t tilex0,
 | |
|     ae_int_t tilex1,
 | |
|     ae_int_t tilescountx,
 | |
|     ae_int_t basecasey,
 | |
|     ae_int_t tiley0,
 | |
|     ae_int_t tiley1,
 | |
|     ae_int_t tilescounty,
 | |
|     ae_int_t maxcoresize,
 | |
|     ae_int_t interfacesize,
 | |
|     ae_int_t lsqrcnt,
 | |
|     double lambdareg,
 | |
|     spline1dinterpolant* basis1,
 | |
|     ae_shared_pool* pool,
 | |
|     spline2dinterpolant* spline,
 | |
|     ae_state *_state)
 | |
| {
 | |
|     return ae_false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs fitting with  BlockLLS solver.  Internal  function,
 | |
| never use it directly.
 | |
| 
 | |
| IMPORTANT: performance  and  memory  requirements  of  this  function  are
 | |
|            asymmetric w.r.t. KX and KY: it has
 | |
|            * O(KY*KX^2) memory requirements
 | |
|            * O(KY*KX^3) running time
 | |
|            Thus, if you have large KY and small KX,  simple  transposition
 | |
|            of your dataset may give you great speedup.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     AV      -   sparse matrix, [ARows,KX*KY] in size.  "Vertical"  version
 | |
|                 of design matrix, rows [0,NPoints) contain values of basis
 | |
|                 functions at dataset  points.  Other  rows  are  used  for
 | |
|                 nonlinearity penalty and other stuff like that.
 | |
|     AH      -   transpose(AV), "horizontal" version of AV
 | |
|     ARows   -   rows count
 | |
|     XY      -   array[NPoints*(2+D)], dataset
 | |
|     KX, KY  -   grid size
 | |
|     NPoints -   points count
 | |
|     D       -   number of components in vector-valued spline, D>=1
 | |
|     LSQRCnt -   number of iterations, non-zero:
 | |
|                 * LSQRCnt>0 means that specified amount of  preconditioned
 | |
|                   LSQR  iterations  will  be  performed  to solve problem;
 | |
|                   usually  we  need  2..5  its.  Recommended option - best
 | |
|                   convergence and stability/quality.
 | |
|                 * LSQRCnt<0 means that instead of LSQR  we  use  iterative
 | |
|                   refinement on normal equations. Again, 2..5 its is enough.
 | |
|     Z       -   possibly preallocated buffer for solution
 | |
|     Rep     -   report structure; fields which are not set by this function
 | |
|                 are left intact
 | |
|     TSS     -   total sum of squares; used to calculate R2
 | |
|     
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     XY      -   destroyed in process
 | |
|     Z       -   array[KX*KY*D], filled by solution; KX*KY coefficients
 | |
|                 corresponding to each of D dimensions are stored contiguously.
 | |
|     Rep         -   following fields are set:
 | |
|                     * Rep.RMSError
 | |
|                     * Rep.AvgError
 | |
|                     * Rep.MaxError
 | |
|                     * Rep.R2
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_blockllsfit(spline2dxdesignmatrix* xdesign,
 | |
|      ae_int_t lsqrcnt,
 | |
|      /* Real    */ ae_vector* z,
 | |
|      spline2dfitreport* rep,
 | |
|      double tss,
 | |
|      spline2dblockllsbuf* buf,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t blockbandwidth;
 | |
|     ae_int_t d;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double lambdachol;
 | |
|     sreal mxata;
 | |
|     double v;
 | |
|     ae_int_t celloffset;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t i1;
 | |
|     double rss;
 | |
|     ae_int_t arows;
 | |
|     ae_int_t bw2;
 | |
|     ae_int_t kx;
 | |
|     ae_int_t ky;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&mxata, 0, sizeof(mxata));
 | |
|     _sreal_init(&mxata, _state, ae_true);
 | |
| 
 | |
|     ae_assert(xdesign->blockwidth==4, "Spline2DFit: integrity check failed", _state);
 | |
|     blockbandwidth = 3;
 | |
|     d = xdesign->d;
 | |
|     arows = xdesign->nrows;
 | |
|     kx = xdesign->kx;
 | |
|     ky = xdesign->ky;
 | |
|     bw2 = xdesign->blockwidth*xdesign->blockwidth;
 | |
|     
 | |
|     /*
 | |
|      * Initial values for Z/Residuals
 | |
|      */
 | |
|     rvectorsetlengthatleast(z, kx*ky*d, _state);
 | |
|     for(i=0; i<=kx*ky*d-1; i++)
 | |
|     {
 | |
|         z->ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Create and factorize design matrix. Add regularizer if
 | |
|      * factorization failed (happens sometimes with zero
 | |
|      * smoothing and sparsely populated datasets).
 | |
|      *
 | |
|      * The algorithm below is refactoring of NaiveLLS algorithm,
 | |
|      * which uses sparsity properties and compressed block storage.
 | |
|      *
 | |
|      * Problem sparsity pattern results in block-band-diagonal
 | |
|      * matrix (block matrix with limited bandwidth, equal to 3
 | |
|      * for bicubic splines). Thus, we have KY*KY blocks, each
 | |
|      * of them is KX*KX in size. Design matrix is stored in
 | |
|      * large NROWS*KX matrix, with NROWS=(BlockBandwidth+1)*KY*KX.
 | |
|      *
 | |
|      * We use adaptation of block skyline storage format, with
 | |
|      * TOWERSIZE*KX skyline bands (towers) stored sequentially;
 | |
|      * here TOWERSIZE=(BlockBandwidth+1)*KX. So, we have KY
 | |
|      * "towers", stored one below other, in BlockATA matrix.
 | |
|      * Every "tower" is a sequence of BlockBandwidth+1 cells,
 | |
|      * each of them being KX*KX in size.
 | |
|      */
 | |
|     lambdachol = spline2d_cholreg;
 | |
|     rmatrixsetlengthatleast(&buf->blockata, (blockbandwidth+1)*ky*kx, kx, _state);
 | |
|     for(;;)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Parallel generation of squared design matrix.
 | |
|          */
 | |
|         spline2d_xdesignblockata(xdesign, &buf->blockata, &mxata.val, _state);
 | |
|         
 | |
|         /*
 | |
|          * Regularization
 | |
|          */
 | |
|         v = coalesce(mxata.val, 1.0, _state)*lambdachol;
 | |
|         for(i1=0; i1<=ky-1; i1++)
 | |
|         {
 | |
|             celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i1, _state);
 | |
|             for(i0=0; i0<=kx-1; i0++)
 | |
|             {
 | |
|                 buf->blockata.ptr.pp_double[celloffset+i0][i0] = buf->blockata.ptr.pp_double[celloffset+i0][i0]+v;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Try Cholesky factorization.
 | |
|          */
 | |
|         if( !spline2d_blockllscholesky(&buf->blockata, kx, ky, &buf->trsmbuf2, &buf->cholbuf2, &buf->cholbuf1, _state) )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Factorization failed, increase regularizer and repeat
 | |
|              */
 | |
|             lambdachol = coalesce(10*lambdachol, 1.0E-12, _state);
 | |
|             continue;
 | |
|         }
 | |
|         break;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Solve
 | |
|      */
 | |
|     rss = 0.0;
 | |
|     rep->rmserror = (double)(0);
 | |
|     rep->avgerror = (double)(0);
 | |
|     rep->maxerror = (double)(0);
 | |
|     ae_assert(lsqrcnt>0, "Spline2DFit: integrity failure", _state);
 | |
|     rvectorsetlengthatleast(&buf->tmp0, arows, _state);
 | |
|     rvectorsetlengthatleast(&buf->tmp1, kx*ky, _state);
 | |
|     linlsqrcreatebuf(arows, kx*ky, &buf->solver, _state);
 | |
|     for(j=0; j<=d-1; j++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Preconditioned LSQR:
 | |
|          *
 | |
|          * use Cholesky factor U of squared design matrix A'*A to
 | |
|          * transform min|A*x-b| to min|[A*inv(U)]*y-b| with y=U*x.
 | |
|          *
 | |
|          * Preconditioned problem is solved with LSQR solver, which
 | |
|          * gives superior results than normal equations.
 | |
|          */
 | |
|         for(i=0; i<=arows-1; i++)
 | |
|         {
 | |
|             if( i<xdesign->npoints )
 | |
|             {
 | |
|                 buf->tmp0.ptr.p_double[i] = xdesign->vals.ptr.pp_double[i][bw2+j];
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 buf->tmp0.ptr.p_double[i] = 0.0;
 | |
|             }
 | |
|         }
 | |
|         linlsqrrestart(&buf->solver, _state);
 | |
|         linlsqrsetb(&buf->solver, &buf->tmp0, _state);
 | |
|         linlsqrsetcond(&buf->solver, 1.0E-14, 1.0E-14, lsqrcnt, _state);
 | |
|         while(linlsqriteration(&buf->solver, _state))
 | |
|         {
 | |
|             if( buf->solver.needmv )
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * Use Cholesky factorization of the system matrix
 | |
|                  * as preconditioner: solve TRSV(U,Solver.X)
 | |
|                  */
 | |
|                 for(i=0; i<=kx*ky-1; i++)
 | |
|                 {
 | |
|                     buf->tmp1.ptr.p_double[i] = buf->solver.x.ptr.p_double[i];
 | |
|                 }
 | |
|                 spline2d_blockllstrsv(&buf->blockata, kx, ky, ae_false, &buf->tmp1, _state);
 | |
|                 
 | |
|                 /*
 | |
|                  * After preconditioning is done, multiply by A
 | |
|                  */
 | |
|                 spline2d_xdesignmv(xdesign, &buf->tmp1, &buf->solver.mv, _state);
 | |
|             }
 | |
|             if( buf->solver.needmtv )
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * Multiply by design matrix A
 | |
|                  */
 | |
|                 spline2d_xdesignmtv(xdesign, &buf->solver.x, &buf->solver.mtv, _state);
 | |
|                 
 | |
|                 /*
 | |
|                  * Multiply by preconditioner: solve TRSV(U',A*Solver.X)
 | |
|                  */
 | |
|                 spline2d_blockllstrsv(&buf->blockata, kx, ky, ae_true, &buf->solver.mtv, _state);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Get results and post-multiply by preconditioner to get
 | |
|          * original variables.
 | |
|          */
 | |
|         linlsqrresults(&buf->solver, &buf->tmp1, &buf->solverrep, _state);
 | |
|         spline2d_blockllstrsv(&buf->blockata, kx, ky, ae_false, &buf->tmp1, _state);
 | |
|         for(i=0; i<=kx*ky-1; i++)
 | |
|         {
 | |
|             z->ptr.p_double[kx*ky*j+i] = buf->tmp1.ptr.p_double[i];
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Calculate model values
 | |
|          */
 | |
|         spline2d_xdesignmv(xdesign, &buf->tmp1, &buf->tmp0, _state);
 | |
|         for(i=0; i<=xdesign->npoints-1; i++)
 | |
|         {
 | |
|             v = xdesign->vals.ptr.pp_double[i][bw2+j]-buf->tmp0.ptr.p_double[i];
 | |
|             rss = rss+v*v;
 | |
|             rep->rmserror = rep->rmserror+ae_sqr(v, _state);
 | |
|             rep->avgerror = rep->avgerror+ae_fabs(v, _state);
 | |
|             rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
 | |
|         }
 | |
|     }
 | |
|     rep->rmserror = ae_sqrt(rep->rmserror/coalesce((double)(xdesign->npoints*d), 1.0, _state), _state);
 | |
|     rep->avgerror = rep->avgerror/coalesce((double)(xdesign->npoints*d), 1.0, _state);
 | |
|     rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs fitting with  NaiveLLS solver.  Internal  function,
 | |
| never use it directly.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     AV      -   sparse matrix, [ARows,KX*KY] in size.  "Vertical"  version
 | |
|                 of design matrix, rows [0,NPoints] contain values of basis
 | |
|                 functions at dataset  points.  Other  rows  are  used  for
 | |
|                 nonlinearity penalty and other stuff like that.
 | |
|     AH      -   transpose(AV), "horizontal" version of AV
 | |
|     ARows   -   rows count
 | |
|     XY      -   array[NPoints*(2+D)], dataset
 | |
|     KX, KY  -   grid size
 | |
|     NPoints -   points count
 | |
|     D       -   number of components in vector-valued spline, D>=1
 | |
|     LSQRCnt -   number of iterations, non-zero:
 | |
|                 * LSQRCnt>0 means that specified amount of  preconditioned
 | |
|                   LSQR  iterations  will  be  performed  to solve problem;
 | |
|                   usually  we  need  2..5  its.  Recommended option - best
 | |
|                   convergence and stability/quality.
 | |
|                 * LSQRCnt<0 means that instead of LSQR  we  use  iterative
 | |
|                   refinement on normal equations. Again, 2..5 its is enough.
 | |
|     Z       -   possibly preallocated buffer for solution
 | |
|     Rep     -   report structure; fields which are not set by this function
 | |
|                 are left intact
 | |
|     TSS     -   total sum of squares; used to calculate R2
 | |
|     
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     XY      -   destroyed in process
 | |
|     Z       -   array[KX*KY*D], filled by solution; KX*KY coefficients
 | |
|                 corresponding to each of D dimensions are stored contiguously.
 | |
|     Rep     -   following fields are set:
 | |
|                     * Rep.RMSError
 | |
|                     * Rep.AvgError
 | |
|                     * Rep.MaxError
 | |
|                     * Rep.R2
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_naivellsfit(sparsematrix* av,
 | |
|      sparsematrix* ah,
 | |
|      ae_int_t arows,
 | |
|      /* Real    */ ae_vector* xy,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      ae_int_t lsqrcnt,
 | |
|      /* Real    */ ae_vector* z,
 | |
|      spline2dfitreport* rep,
 | |
|      double tss,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t ew;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t i1;
 | |
|     ae_int_t j0;
 | |
|     ae_int_t j1;
 | |
|     double v;
 | |
|     ae_int_t blockbandwidth;
 | |
|     double lambdareg;
 | |
|     ae_int_t srci;
 | |
|     ae_int_t srcj;
 | |
|     ae_int_t idxi;
 | |
|     ae_int_t idxj;
 | |
|     ae_int_t endi;
 | |
|     ae_int_t endj;
 | |
|     ae_int_t rfsidx;
 | |
|     ae_matrix ata;
 | |
|     ae_vector tmp0;
 | |
|     ae_vector tmp1;
 | |
|     double mxata;
 | |
|     linlsqrstate solver;
 | |
|     linlsqrreport solverrep;
 | |
|     double rss;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&ata, 0, sizeof(ata));
 | |
|     memset(&tmp0, 0, sizeof(tmp0));
 | |
|     memset(&tmp1, 0, sizeof(tmp1));
 | |
|     memset(&solver, 0, sizeof(solver));
 | |
|     memset(&solverrep, 0, sizeof(solverrep));
 | |
|     ae_matrix_init(&ata, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true);
 | |
|     _linlsqrstate_init(&solver, _state, ae_true);
 | |
|     _linlsqrreport_init(&solverrep, _state, ae_true);
 | |
| 
 | |
|     blockbandwidth = 3;
 | |
|     ew = 2+d;
 | |
|     
 | |
|     /*
 | |
|      * Initial values for Z/Residuals
 | |
|      */
 | |
|     rvectorsetlengthatleast(z, kx*ky*d, _state);
 | |
|     for(i=0; i<=kx*ky*d-1; i++)
 | |
|     {
 | |
|         z->ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Create and factorize design matrix.
 | |
|      *
 | |
|      * Add regularizer if factorization failed (happens sometimes
 | |
|      * with zero smoothing and sparsely populated datasets).
 | |
|      */
 | |
|     lambdareg = spline2d_cholreg;
 | |
|     rmatrixsetlengthatleast(&ata, kx*ky, kx*ky, _state);
 | |
|     for(;;)
 | |
|     {
 | |
|         mxata = 0.0;
 | |
|         for(i=0; i<=kx*ky-1; i++)
 | |
|         {
 | |
|             for(j=i; j<=kx*ky-1; j++)
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * Initialize by zero
 | |
|                  */
 | |
|                 ata.ptr.pp_double[i][j] = (double)(0);
 | |
|                 
 | |
|                 /*
 | |
|                  * Determine grid nodes corresponding to I and J;
 | |
|                  * skip if too far away
 | |
|                  */
 | |
|                 i0 = i%kx;
 | |
|                 i1 = i/kx;
 | |
|                 j0 = j%kx;
 | |
|                 j1 = j/kx;
 | |
|                 if( ae_iabs(i0-j0, _state)>blockbandwidth||ae_iabs(i1-j1, _state)>blockbandwidth )
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * Nodes are close enough, calculate product of columns I and J of A.
 | |
|                  */
 | |
|                 v = (double)(0);
 | |
|                 srci = ah->ridx.ptr.p_int[i];
 | |
|                 srcj = ah->ridx.ptr.p_int[j];
 | |
|                 endi = ah->ridx.ptr.p_int[i+1];
 | |
|                 endj = ah->ridx.ptr.p_int[j+1];
 | |
|                 for(;;)
 | |
|                 {
 | |
|                     if( srci>=endi||srcj>=endj )
 | |
|                     {
 | |
|                         break;
 | |
|                     }
 | |
|                     idxi = ah->idx.ptr.p_int[srci];
 | |
|                     idxj = ah->idx.ptr.p_int[srcj];
 | |
|                     if( idxi==idxj )
 | |
|                     {
 | |
|                         v = v+ah->vals.ptr.p_double[srci]*ah->vals.ptr.p_double[srcj];
 | |
|                         srci = srci+1;
 | |
|                         srcj = srcj+1;
 | |
|                         continue;
 | |
|                     }
 | |
|                     if( idxi<idxj )
 | |
|                     {
 | |
|                         srci = srci+1;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         srcj = srcj+1;
 | |
|                     }
 | |
|                 }
 | |
|                 ata.ptr.pp_double[i][j] = v;
 | |
|                 mxata = ae_maxreal(mxata, ae_fabs(v, _state), _state);
 | |
|             }
 | |
|         }
 | |
|         v = coalesce(mxata, 1.0, _state)*lambdareg;
 | |
|         for(i=0; i<=kx*ky-1; i++)
 | |
|         {
 | |
|             ata.ptr.pp_double[i][i] = ata.ptr.pp_double[i][i]+v;
 | |
|         }
 | |
|         if( spdmatrixcholesky(&ata, kx*ky, ae_true, _state) )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Success!
 | |
|              */
 | |
|             break;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Factorization failed, increase regularizer and repeat
 | |
|          */
 | |
|         lambdareg = coalesce(10*lambdareg, 1.0E-12, _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Solve
 | |
|      *
 | |
|      * NOTE: we expect that Z is zero-filled, and we treat it
 | |
|      *       like initial approximation to solution.
 | |
|      */
 | |
|     rvectorsetlengthatleast(&tmp0, arows, _state);
 | |
|     rvectorsetlengthatleast(&tmp1, kx*ky, _state);
 | |
|     if( lsqrcnt>0 )
 | |
|     {
 | |
|         linlsqrcreate(arows, kx*ky, &solver, _state);
 | |
|     }
 | |
|     for(j=0; j<=d-1; j++)
 | |
|     {
 | |
|         ae_assert(lsqrcnt!=0, "Spline2DFit: integrity failure", _state);
 | |
|         if( lsqrcnt>0 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Preconditioned LSQR:
 | |
|              *
 | |
|              * use Cholesky factor U of squared design matrix A'*A to
 | |
|              * transform min|A*x-b| to min|[A*inv(U)]*y-b| with y=U*x.
 | |
|              *
 | |
|              * Preconditioned problem is solved with LSQR solver, which
 | |
|              * gives superior results than normal equations.
 | |
|              */
 | |
|             linlsqrcreate(arows, kx*ky, &solver, _state);
 | |
|             for(i=0; i<=arows-1; i++)
 | |
|             {
 | |
|                 if( i<npoints )
 | |
|                 {
 | |
|                     tmp0.ptr.p_double[i] = xy->ptr.p_double[i*ew+2+j];
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     tmp0.ptr.p_double[i] = 0.0;
 | |
|                 }
 | |
|             }
 | |
|             linlsqrsetb(&solver, &tmp0, _state);
 | |
|             linlsqrsetcond(&solver, 1.0E-14, 1.0E-14, lsqrcnt, _state);
 | |
|             while(linlsqriteration(&solver, _state))
 | |
|             {
 | |
|                 if( solver.needmv )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      * Use Cholesky factorization of the system matrix
 | |
|                      * as preconditioner: solve TRSV(U,Solver.X)
 | |
|                      */
 | |
|                     for(i=0; i<=kx*ky-1; i++)
 | |
|                     {
 | |
|                         tmp1.ptr.p_double[i] = solver.x.ptr.p_double[i];
 | |
|                     }
 | |
|                     rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 0, &tmp1, 0, _state);
 | |
|                     
 | |
|                     /*
 | |
|                      * After preconditioning is done, multiply by A
 | |
|                      */
 | |
|                     sparsemv(av, &tmp1, &solver.mv, _state);
 | |
|                 }
 | |
|                 if( solver.needmtv )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      * Multiply by design matrix A
 | |
|                      */
 | |
|                     sparsemv(ah, &solver.x, &solver.mtv, _state);
 | |
|                     
 | |
|                     /*
 | |
|                      * Multiply by preconditioner: solve TRSV(U',A*Solver.X)
 | |
|                      */
 | |
|                     rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 1, &solver.mtv, 0, _state);
 | |
|                 }
 | |
|             }
 | |
|             linlsqrresults(&solver, &tmp1, &solverrep, _state);
 | |
|             rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 0, &tmp1, 0, _state);
 | |
|             for(i=0; i<=kx*ky-1; i++)
 | |
|             {
 | |
|                 z->ptr.p_double[kx*ky*j+i] = tmp1.ptr.p_double[i];
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Calculate model values
 | |
|              */
 | |
|             sparsemv(av, &tmp1, &tmp0, _state);
 | |
|             for(i=0; i<=npoints-1; i++)
 | |
|             {
 | |
|                 xy->ptr.p_double[i*ew+2+j] = xy->ptr.p_double[i*ew+2+j]-tmp0.ptr.p_double[i];
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Iterative refinement, inferior to LSQR
 | |
|              *
 | |
|              * For each dimension D:
 | |
|              * * fetch current estimate for solution from Z to Tmp1
 | |
|              * * calculate residual r for current estimate, store in Tmp0
 | |
|              * * calculate product of residual and design matrix A'*r, store it in Tmp1
 | |
|              * * Cholesky solver
 | |
|              * * update current estimate
 | |
|              */
 | |
|             for(rfsidx=1; rfsidx<=-lsqrcnt; rfsidx++)
 | |
|             {
 | |
|                 for(i=0; i<=kx*ky-1; i++)
 | |
|                 {
 | |
|                     tmp1.ptr.p_double[i] = z->ptr.p_double[kx*ky*j+i];
 | |
|                 }
 | |
|                 sparsemv(av, &tmp1, &tmp0, _state);
 | |
|                 for(i=0; i<=arows-1; i++)
 | |
|                 {
 | |
|                     if( i<npoints )
 | |
|                     {
 | |
|                         v = xy->ptr.p_double[i*ew+2+j];
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         v = (double)(0);
 | |
|                     }
 | |
|                     tmp0.ptr.p_double[i] = v-tmp0.ptr.p_double[i];
 | |
|                 }
 | |
|                 sparsemv(ah, &tmp0, &tmp1, _state);
 | |
|                 rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 1, &tmp1, 0, _state);
 | |
|                 rmatrixtrsv(kx*ky, &ata, 0, 0, ae_true, ae_false, 0, &tmp1, 0, _state);
 | |
|                 for(i=0; i<=kx*ky-1; i++)
 | |
|                 {
 | |
|                     z->ptr.p_double[kx*ky*j+i] = z->ptr.p_double[kx*ky*j+i]+tmp1.ptr.p_double[i];
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * Calculate model values
 | |
|              */
 | |
|             for(i=0; i<=kx*ky-1; i++)
 | |
|             {
 | |
|                 tmp1.ptr.p_double[i] = z->ptr.p_double[kx*ky*j+i];
 | |
|             }
 | |
|             sparsemv(av, &tmp1, &tmp0, _state);
 | |
|             for(i=0; i<=npoints-1; i++)
 | |
|             {
 | |
|                 xy->ptr.p_double[i*ew+2+j] = xy->ptr.p_double[i*ew+2+j]-tmp0.ptr.p_double[i];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Generate report
 | |
|      */
 | |
|     rep->rmserror = (double)(0);
 | |
|     rep->avgerror = (double)(0);
 | |
|     rep->maxerror = (double)(0);
 | |
|     rss = 0.0;
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=d-1; j++)
 | |
|         {
 | |
|             v = xy->ptr.p_double[i*ew+2+j];
 | |
|             rss = rss+v*v;
 | |
|             rep->rmserror = rep->rmserror+ae_sqr(v, _state);
 | |
|             rep->avgerror = rep->avgerror+ae_fabs(v, _state);
 | |
|             rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v, _state), _state);
 | |
|         }
 | |
|     }
 | |
|     rep->rmserror = ae_sqrt(rep->rmserror/coalesce((double)(npoints*d), 1.0, _state), _state);
 | |
|     rep->avgerror = rep->avgerror/coalesce((double)(npoints*d), 1.0, _state);
 | |
|     rep->r2 = 1.0-rss/coalesce(tss, 1.0, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  is  convenience  function  for band block storage format; it returns
 | |
| offset of KX*KX-sized block (I,J) in a compressed 2D array.
 | |
| 
 | |
| For specific offset=OFFSET,
 | |
| block (I,J) will be stored in entries BlockMatrix[OFFSET:OFFSET+KX-1,0:KX-1]
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static ae_int_t spline2d_getcelloffset(ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t blockbandwidth,
 | |
|      ae_int_t i,
 | |
|      ae_int_t j,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t result;
 | |
| 
 | |
| 
 | |
|     ae_assert(i>=0&&i<ky, "Spline2DFit: GetCellOffset() integrity error", _state);
 | |
|     ae_assert(j>=0&&j<ky, "Spline2DFit: GetCellOffset() integrity error", _state);
 | |
|     ae_assert(j>=i&&j<=i+blockbandwidth, "Spline2DFit: GetCellOffset() integrity error", _state);
 | |
|     result = j*(blockbandwidth+1)*kx;
 | |
|     result = result+(blockbandwidth-(j-i))*kx;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  is  convenience  function  for band block storage format; it  copies
 | |
| cell (I,J) from compressed format to uncompressed general matrix, at desired
 | |
| position.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_copycellto(ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t blockbandwidth,
 | |
|      /* Real    */ ae_matrix* blockata,
 | |
|      ae_int_t i,
 | |
|      ae_int_t j,
 | |
|      /* Real    */ ae_matrix* dst,
 | |
|      ae_int_t dst0,
 | |
|      ae_int_t dst1,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t celloffset;
 | |
|     ae_int_t idx0;
 | |
|     ae_int_t idx1;
 | |
| 
 | |
| 
 | |
|     celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i, j, _state);
 | |
|     for(idx0=0; idx0<=kx-1; idx0++)
 | |
|     {
 | |
|         for(idx1=0; idx1<=kx-1; idx1++)
 | |
|         {
 | |
|             dst->ptr.pp_double[dst0+idx0][dst1+idx1] = blockata->ptr.pp_double[celloffset+idx0][idx1];
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  is  convenience  function  for band block storage format; it
 | |
| truncates all elements of  cell (I,J) which are less than Eps in magnitude.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_flushtozerocell(ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_int_t blockbandwidth,
 | |
|      /* Real    */ ae_matrix* blockata,
 | |
|      ae_int_t i,
 | |
|      ae_int_t j,
 | |
|      double eps,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t celloffset;
 | |
|     ae_int_t idx0;
 | |
|     ae_int_t idx1;
 | |
|     double eps2;
 | |
|     double v;
 | |
| 
 | |
| 
 | |
|     celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i, j, _state);
 | |
|     eps2 = eps*eps;
 | |
|     for(idx0=0; idx0<=kx-1; idx0++)
 | |
|     {
 | |
|         for(idx1=0; idx1<=kx-1; idx1++)
 | |
|         {
 | |
|             v = blockata->ptr.pp_double[celloffset+idx0][idx1];
 | |
|             if( v*v<eps2 )
 | |
|             {
 | |
|                 blockata->ptr.pp_double[celloffset+idx0][idx1] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function generates squared design matrix stored in block band format.
 | |
| 
 | |
| We use adaptation of block skyline storage format, with
 | |
| TOWERSIZE*KX skyline bands (towers) stored sequentially;
 | |
| here TOWERSIZE=(BlockBandwidth+1)*KX. So, we have KY
 | |
| "towers", stored one below other, in BlockATA matrix.
 | |
| Every "tower" is a sequence of BlockBandwidth+1 cells,
 | |
| each of them being KX*KX in size.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     AH      -   sparse matrix, [KX*KY,ARows] in size. "Horizontal" version
 | |
|                 of design matrix, cols [0,NPoints] contain values of basis
 | |
|                 functions at dataset  points.  Other  cols  are  used  for
 | |
|                 nonlinearity penalty and other stuff like that.
 | |
|     KY0, KY1-   subset of output matrix bands to process; on entry it MUST
 | |
|                 be set to 0 and KY respectively.
 | |
|     KX, KY  -   grid size
 | |
|     BlockATA-   array[KY*(BlockBandwidth+1)*KX,KX],  preallocated  storage
 | |
|                 for output matrix in compressed block band format
 | |
|     MXATA   -   on entry MUST be zero
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     BlockATA-   AH*AH', stored in compressed block band format
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_blockllsgenerateata(sparsematrix* ah,
 | |
|      ae_int_t ky0,
 | |
|      ae_int_t ky1,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      /* Real    */ ae_matrix* blockata,
 | |
|      sreal* mxata,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t blockbandwidth;
 | |
|     double avgrowlen;
 | |
|     double cellcost;
 | |
|     double totalcost;
 | |
|     sreal tmpmxata;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t i1;
 | |
|     ae_int_t j0;
 | |
|     ae_int_t j1;
 | |
|     ae_int_t celloffset;
 | |
|     double v;
 | |
|     ae_int_t srci;
 | |
|     ae_int_t srcj;
 | |
|     ae_int_t idxi;
 | |
|     ae_int_t idxj;
 | |
|     ae_int_t endi;
 | |
|     ae_int_t endj;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&tmpmxata, 0, sizeof(tmpmxata));
 | |
|     _sreal_init(&tmpmxata, _state, ae_true);
 | |
| 
 | |
|     ae_assert(ae_fp_greater_eq(mxata->val,(double)(0)), "BlockLLSGenerateATA: integrity check failed", _state);
 | |
|     blockbandwidth = 3;
 | |
|     
 | |
|     /*
 | |
|      * Determine problem cost, perform recursive subdivision
 | |
|      * (with optional parallelization)
 | |
|      */
 | |
|     avgrowlen = (double)ah->ridx.ptr.p_int[kx*ky]/(double)(kx*ky);
 | |
|     cellcost = rmul3((double)(kx), (double)(1+2*blockbandwidth), avgrowlen, _state);
 | |
|     totalcost = rmul3((double)(ky1-ky0), (double)(1+2*blockbandwidth), cellcost, _state);
 | |
|     if( ky1-ky0>=2&&ae_fp_greater(totalcost,smpactivationlevel(_state)) )
 | |
|     {
 | |
|         if( _trypexec_spline2d_blockllsgenerateata(ah,ky0,ky1,kx,ky,blockata,mxata, _state) )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     if( ky1-ky0>=2 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Split X: X*A = (X1 X2)^T*A
 | |
|          */
 | |
|         j = (ky1-ky0)/2;
 | |
|         spline2d_blockllsgenerateata(ah, ky0, ky0+j, kx, ky, blockata, &tmpmxata, _state);
 | |
|         spline2d_blockllsgenerateata(ah, ky0+j, ky1, kx, ky, blockata, mxata, _state);
 | |
|         mxata->val = ae_maxreal(mxata->val, tmpmxata.val, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Splitting in Y-dimension is done, fill I1-th "tower"
 | |
|      */
 | |
|     ae_assert(ky1==ky0+1, "BlockLLSGenerateATA: integrity check failed", _state);
 | |
|     i1 = ky0;
 | |
|     for(j1=i1; j1<=ae_minint(ky-1, i1+blockbandwidth, _state); j1++)
 | |
|     {
 | |
|         celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, j1, _state);
 | |
|         
 | |
|         /*
 | |
|          * Clear cell (I1,J1)
 | |
|          */
 | |
|         for(i0=0; i0<=kx-1; i0++)
 | |
|         {
 | |
|             for(j0=0; j0<=kx-1; j0++)
 | |
|             {
 | |
|                 blockata->ptr.pp_double[celloffset+i0][j0] = 0.0;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Initialize cell internals
 | |
|          */
 | |
|         for(i0=0; i0<=kx-1; i0++)
 | |
|         {
 | |
|             for(j0=0; j0<=kx-1; j0++)
 | |
|             {
 | |
|                 if( ae_iabs(i0-j0, _state)<=blockbandwidth )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      * Nodes are close enough, calculate product of columns I and J of A.
 | |
|                      */
 | |
|                     v = (double)(0);
 | |
|                     i = i1*kx+i0;
 | |
|                     j = j1*kx+j0;
 | |
|                     srci = ah->ridx.ptr.p_int[i];
 | |
|                     srcj = ah->ridx.ptr.p_int[j];
 | |
|                     endi = ah->ridx.ptr.p_int[i+1];
 | |
|                     endj = ah->ridx.ptr.p_int[j+1];
 | |
|                     for(;;)
 | |
|                     {
 | |
|                         if( srci>=endi||srcj>=endj )
 | |
|                         {
 | |
|                             break;
 | |
|                         }
 | |
|                         idxi = ah->idx.ptr.p_int[srci];
 | |
|                         idxj = ah->idx.ptr.p_int[srcj];
 | |
|                         if( idxi==idxj )
 | |
|                         {
 | |
|                             v = v+ah->vals.ptr.p_double[srci]*ah->vals.ptr.p_double[srcj];
 | |
|                             srci = srci+1;
 | |
|                             srcj = srcj+1;
 | |
|                             continue;
 | |
|                         }
 | |
|                         if( idxi<idxj )
 | |
|                         {
 | |
|                             srci = srci+1;
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             srcj = srcj+1;
 | |
|                         }
 | |
|                     }
 | |
|                     blockata->ptr.pp_double[celloffset+i0][j0] = v;
 | |
|                     mxata->val = ae_maxreal(mxata->val, ae_fabs(v, _state), _state);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serial stub for GPL edition.
 | |
| *************************************************************************/
 | |
| ae_bool _trypexec_spline2d_blockllsgenerateata(sparsematrix* ah,
 | |
|     ae_int_t ky0,
 | |
|     ae_int_t ky1,
 | |
|     ae_int_t kx,
 | |
|     ae_int_t ky,
 | |
|     /* Real    */ ae_matrix* blockata,
 | |
|     sreal* mxata,
 | |
|     ae_state *_state)
 | |
| {
 | |
|     return ae_false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs Cholesky decomposition of squared design matrix
 | |
| stored in block band format.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     BlockATA        -   array[KY*(BlockBandwidth+1)*KX,KX], matrix in compressed
 | |
|                         block band format
 | |
|     KX, KY          -   grid size
 | |
|     TrsmBuf2,
 | |
|     CholBuf2,
 | |
|     CholBuf1        -   buffers; reused by this function on subsequent calls,
 | |
|                         automatically preallocated on the first call
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     BlockATA-   Cholesky factor, in compressed block band format
 | |
| 
 | |
| Result:
 | |
|     True on success, False on Cholesky failure
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static ae_bool spline2d_blockllscholesky(/* Real    */ ae_matrix* blockata,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      /* Real    */ ae_matrix* trsmbuf2,
 | |
|      /* Real    */ ae_matrix* cholbuf2,
 | |
|      /* Real    */ ae_vector* cholbuf1,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t blockbandwidth;
 | |
|     ae_int_t blockidx;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t celloffset;
 | |
|     ae_int_t celloffset1;
 | |
|     ae_bool result;
 | |
| 
 | |
| 
 | |
|     blockbandwidth = 3;
 | |
|     rmatrixsetlengthatleast(trsmbuf2, (blockbandwidth+1)*kx, (blockbandwidth+1)*kx, _state);
 | |
|     rmatrixsetlengthatleast(cholbuf2, kx, kx, _state);
 | |
|     rvectorsetlengthatleast(cholbuf1, kx, _state);
 | |
|     result = ae_true;
 | |
|     for(blockidx=0; blockidx<=ky-1; blockidx++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * TRSM for TRAIL*TRAIL block matrix before current cell;
 | |
|          * here TRAIL=MinInt(BlockIdx,BlockBandwidth).
 | |
|          */
 | |
|         for(i=0; i<=ae_minint(blockidx, blockbandwidth, _state)-1; i++)
 | |
|         {
 | |
|             for(j=i; j<=ae_minint(blockidx, blockbandwidth, _state)-1; j++)
 | |
|             {
 | |
|                 spline2d_copycellto(kx, ky, blockbandwidth, blockata, ae_maxint(blockidx-blockbandwidth, 0, _state)+i, ae_maxint(blockidx-blockbandwidth, 0, _state)+j, trsmbuf2, i*kx, j*kx, _state);
 | |
|             }
 | |
|         }
 | |
|         celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, ae_maxint(blockidx-blockbandwidth, 0, _state), blockidx, _state);
 | |
|         rmatrixlefttrsm(ae_minint(blockidx, blockbandwidth, _state)*kx, kx, trsmbuf2, 0, 0, ae_true, ae_false, 1, blockata, celloffset, 0, _state);
 | |
|         
 | |
|         /*
 | |
|          * SYRK for diagonal cell: MaxInt(BlockIdx-BlockBandwidth,0)
 | |
|          * cells above diagonal one are used for update.
 | |
|          */
 | |
|         celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, ae_maxint(blockidx-blockbandwidth, 0, _state), blockidx, _state);
 | |
|         celloffset1 = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state);
 | |
|         rmatrixsyrk(kx, ae_minint(blockidx, blockbandwidth, _state)*kx, -1.0, blockata, celloffset, 0, 1, 1.0, blockata, celloffset1, 0, ae_true, _state);
 | |
|         
 | |
|         /*
 | |
|          * Factorize diagonal cell
 | |
|          */
 | |
|         celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state);
 | |
|         rmatrixcopy(kx, kx, blockata, celloffset, 0, cholbuf2, 0, 0, _state);
 | |
|         if( !spdmatrixcholeskyrec(cholbuf2, 0, kx, ae_true, cholbuf1, _state) )
 | |
|         {
 | |
|             result = ae_false;
 | |
|             return result;
 | |
|         }
 | |
|         rmatrixcopy(kx, kx, cholbuf2, 0, 0, blockata, celloffset, 0, _state);
 | |
|         
 | |
|         /*
 | |
|          * PERFORMANCE TWEAK: drop nearly-denormals from last "tower".
 | |
|          *
 | |
|          * Sparse matrices like these may produce denormal numbers on
 | |
|          * sparse datasets, with significant (10x!) performance penalty
 | |
|          * on Intel chips. In order to avoid it, we manually truncate
 | |
|          * small enough numbers.
 | |
|          *
 | |
|          * We use 1.0E-50 as clipping level (not really denormal, but
 | |
|          * such small numbers are not actually important anyway).
 | |
|          */
 | |
|         for(i=ae_maxint(blockidx-blockbandwidth, 0, _state); i<=blockidx; i++)
 | |
|         {
 | |
|             spline2d_flushtozerocell(kx, ky, blockbandwidth, blockata, i, blockidx, 1.0E-50, _state);
 | |
|         }
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs TRSV on upper triangular Cholesky factor U, solving
 | |
| either U*x=b or U'*x=b.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     BlockATA        -   array[KY*(BlockBandwidth+1)*KX,KX], matrix U
 | |
|                         in compressed block band format
 | |
|     KX, KY          -   grid size
 | |
|     TransU          -   whether to transpose U or not
 | |
|     B               -   array[KX*KY], on entry - stores right part B
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     B               -   replaced by X
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_blockllstrsv(/* Real    */ ae_matrix* blockata,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      ae_bool transu,
 | |
|      /* Real    */ ae_vector* b,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t blockbandwidth;
 | |
|     ae_int_t blockidx;
 | |
|     ae_int_t blockidx1;
 | |
|     ae_int_t celloffset;
 | |
| 
 | |
| 
 | |
|     blockbandwidth = 3;
 | |
|     if( !transu )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Solve U*x=b
 | |
|          */
 | |
|         for(blockidx=ky-1; blockidx>=0; blockidx--)
 | |
|         {
 | |
|             for(blockidx1=1; blockidx1<=ae_minint(ky-(blockidx+1), blockbandwidth, _state); blockidx1++)
 | |
|             {
 | |
|                 celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx+blockidx1, _state);
 | |
|                 rmatrixgemv(kx, kx, -1.0, blockata, celloffset, 0, 0, b, (blockidx+blockidx1)*kx, 1.0, b, blockidx*kx, _state);
 | |
|             }
 | |
|             celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state);
 | |
|             rmatrixtrsv(kx, blockata, celloffset, 0, ae_true, ae_false, 0, b, blockidx*kx, _state);
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Solve U'*x=b
 | |
|          */
 | |
|         for(blockidx=0; blockidx<=ky-1; blockidx++)
 | |
|         {
 | |
|             celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx, _state);
 | |
|             rmatrixtrsv(kx, blockata, celloffset, 0, ae_true, ae_false, 1, b, blockidx*kx, _state);
 | |
|             for(blockidx1=1; blockidx1<=ae_minint(ky-(blockidx+1), blockbandwidth, _state); blockidx1++)
 | |
|             {
 | |
|                 celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, blockidx, blockidx+blockidx1, _state);
 | |
|                 rmatrixgemv(kx, kx, -1.0, blockata, celloffset, 0, 1, b, blockidx*kx, 1.0, b, (blockidx+blockidx1)*kx, _state);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function computes residuals for dataset XY[], using array of original
 | |
| values YRaw[], and loads residuals to XY.
 | |
| 
 | |
| Processing is performed in parallel manner.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_computeresidualsfromscratch(/* Real    */ ae_vector* xy,
 | |
|      /* Real    */ ae_vector* yraw,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      ae_int_t scalexy,
 | |
|      spline2dinterpolant* spline,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     srealarray seed;
 | |
|     ae_shared_pool pool;
 | |
|     ae_int_t chunksize;
 | |
|     double pointcost;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&seed, 0, sizeof(seed));
 | |
|     memset(&pool, 0, sizeof(pool));
 | |
|     _srealarray_init(&seed, _state, ae_true);
 | |
|     ae_shared_pool_init(&pool, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Setting up
 | |
|      */
 | |
|     chunksize = 1000;
 | |
|     pointcost = 100.0;
 | |
|     if( ae_fp_greater(npoints*pointcost,smpactivationlevel(_state)) )
 | |
|     {
 | |
|         if( _trypexec_spline2d_computeresidualsfromscratch(xy,yraw,npoints,d,scalexy,spline, _state) )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     ae_shared_pool_set_seed(&pool, &seed, sizeof(seed), _srealarray_init, _srealarray_init_copy, _srealarray_destroy, _state);
 | |
|     
 | |
|     /*
 | |
|      * Call compute workhorse
 | |
|      */
 | |
|     spline2d_computeresidualsfromscratchrec(xy, yraw, 0, npoints, chunksize, d, scalexy, spline, &pool, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serial stub for GPL edition.
 | |
| *************************************************************************/
 | |
| ae_bool _trypexec_spline2d_computeresidualsfromscratch(/* Real    */ ae_vector* xy,
 | |
|     /* Real    */ ae_vector* yraw,
 | |
|     ae_int_t npoints,
 | |
|     ae_int_t d,
 | |
|     ae_int_t scalexy,
 | |
|     spline2dinterpolant* spline,
 | |
|     ae_state *_state)
 | |
| {
 | |
|     return ae_false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Recursive workhorse for ComputeResidualsFromScratch.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_computeresidualsfromscratchrec(/* Real    */ ae_vector* xy,
 | |
|      /* Real    */ ae_vector* yraw,
 | |
|      ae_int_t pt0,
 | |
|      ae_int_t pt1,
 | |
|      ae_int_t chunksize,
 | |
|      ae_int_t d,
 | |
|      ae_int_t scalexy,
 | |
|      spline2dinterpolant* spline,
 | |
|      ae_shared_pool* pool,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     srealarray *pbuf;
 | |
|     ae_smart_ptr _pbuf;
 | |
|     ae_int_t xew;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_pbuf, 0, sizeof(_pbuf));
 | |
|     ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state, ae_true);
 | |
| 
 | |
|     xew = 2+d;
 | |
|     
 | |
|     /*
 | |
|      * Parallelism
 | |
|      */
 | |
|     if( pt1-pt0>chunksize )
 | |
|     {
 | |
|         tiledsplit(pt1-pt0, chunksize, &i, &j, _state);
 | |
|         spline2d_computeresidualsfromscratchrec(xy, yraw, pt0, pt0+i, chunksize, d, scalexy, spline, pool, _state);
 | |
|         spline2d_computeresidualsfromscratchrec(xy, yraw, pt0+i, pt1, chunksize, d, scalexy, spline, pool, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Serial execution
 | |
|      */
 | |
|     ae_shared_pool_retrieve(pool, &_pbuf, _state);
 | |
|     for(i=pt0; i<=pt1-1; i++)
 | |
|     {
 | |
|         spline2dcalcvbuf(spline, xy->ptr.p_double[i*xew+0]*scalexy, xy->ptr.p_double[i*xew+1]*scalexy, &pbuf->val, _state);
 | |
|         for(j=0; j<=d-1; j++)
 | |
|         {
 | |
|             xy->ptr.p_double[i*xew+2+j] = yraw->ptr.p_double[i*d+j]-pbuf->val.ptr.p_double[j];
 | |
|         }
 | |
|     }
 | |
|     ae_shared_pool_recycle(pool, &_pbuf, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serial stub for GPL edition.
 | |
| *************************************************************************/
 | |
| ae_bool _trypexec_spline2d_computeresidualsfromscratchrec(/* Real    */ ae_vector* xy,
 | |
|     /* Real    */ ae_vector* yraw,
 | |
|     ae_int_t pt0,
 | |
|     ae_int_t pt1,
 | |
|     ae_int_t chunksize,
 | |
|     ae_int_t d,
 | |
|     ae_int_t scalexy,
 | |
|     spline2dinterpolant* spline,
 | |
|     ae_shared_pool* pool,
 | |
|     ae_state *_state)
 | |
| {
 | |
|     return ae_false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function reorders dataset and builds index:
 | |
| * it is assumed that all points have X in [0,KX-1], Y in [0,KY-1]
 | |
| * area is divided into (KX-1)*(KY-1) cells
 | |
| * all points are reordered in such way that points in same cell are stored
 | |
|   contiguously
 | |
| * dataset index, array[(KX-1)*(KY-1)+1], is generated. Points of cell I
 | |
|   now have indexes XYIndex[I]..XYIndex[I+1]-1;
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY              -   array[NPoints*(2+D)], dataset
 | |
|     KX, KY, D       -   grid size and dimensionality of the outputs
 | |
|     Shadow          -   shadow array[NPoints*NS], which is sorted together
 | |
|                         with XY; if NS=0, it is not referenced at all.
 | |
|     NS              -   entry width of shadow array
 | |
|     BufI            -   possibly preallocated temporary buffer; resized if
 | |
|                         needed.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     XY              -   reordered
 | |
|     XYIndex         -   array[(KX-1)*(KY-1)+1], dataset index
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_reorderdatasetandbuildindex(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      /* Real    */ ae_vector* shadow,
 | |
|      ae_int_t ns,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      /* Integer */ ae_vector* xyindex,
 | |
|      /* Integer */ ae_vector* bufi,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t i1;
 | |
|     ae_int_t entrywidth;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Set up
 | |
|      */
 | |
|     ae_assert(kx>=2, "Spline2DFit.ReorderDatasetAndBuildIndex: integrity check failed", _state);
 | |
|     ae_assert(ky>=2, "Spline2DFit.ReorderDatasetAndBuildIndex: integrity check failed", _state);
 | |
|     entrywidth = 2+d;
 | |
|     ivectorsetlengthatleast(xyindex, (kx-1)*(ky-1)+1, _state);
 | |
|     ivectorsetlengthatleast(bufi, npoints, _state);
 | |
|     for(i=0; i<=npoints-1; i++)
 | |
|     {
 | |
|         i0 = iboundval(ae_ifloor(xy->ptr.p_double[i*entrywidth+0], _state), 0, kx-2, _state);
 | |
|         i1 = iboundval(ae_ifloor(xy->ptr.p_double[i*entrywidth+1], _state), 0, ky-2, _state);
 | |
|         bufi->ptr.p_int[i] = i1*(kx-1)+i0;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Reorder
 | |
|      */
 | |
|     spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, bufi, 0, npoints, xyindex, 0, (kx-1)*(ky-1), ae_true, _state);
 | |
|     xyindex->ptr.p_int[(kx-1)*(ky-1)] = npoints;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function multiplies all points in dataset by 2.0 and rebuilds  index,
 | |
| given previous index built for KX_prev=(KX-1)/2 and KY_prev=(KY-1)/2
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY              -   array[NPoints*(2+D)], dataset BEFORE scaling
 | |
|     NPoints, D      -   dataset size and dimensionality of the outputs
 | |
|     Shadow          -   shadow array[NPoints*NS], which is sorted together
 | |
|                         with XY; if NS=0, it is not referenced at all.
 | |
|     NS              -   entry width of shadow array
 | |
|     KX, KY          -   new grid dimensionality
 | |
|     XYIndex         -   index built for previous values of KX and KY
 | |
|     BufI            -   possibly preallocated temporary buffer; resized if
 | |
|                         needed.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     XY              -   reordered and multiplied by 2.0
 | |
|     XYIndex         -   array[(KX-1)*(KY-1)+1], dataset index
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_rescaledatasetandrefineindex(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t d,
 | |
|      /* Real    */ ae_vector* shadow,
 | |
|      ae_int_t ns,
 | |
|      ae_int_t kx,
 | |
|      ae_int_t ky,
 | |
|      /* Integer */ ae_vector* xyindex,
 | |
|      /* Integer */ ae_vector* bufi,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector xyindexprev;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&xyindexprev, 0, sizeof(xyindexprev));
 | |
|     ae_vector_init(&xyindexprev, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Set up
 | |
|      */
 | |
|     ae_assert(kx>=2, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state);
 | |
|     ae_assert(ky>=2, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state);
 | |
|     ae_assert((kx-1)%2==0, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state);
 | |
|     ae_assert((ky-1)%2==0, "Spline2DFit.RescaleDataset2AndRefineIndex: integrity check failed", _state);
 | |
|     ae_swap_vectors(xyindex, &xyindexprev);
 | |
|     ivectorsetlengthatleast(xyindex, (kx-1)*(ky-1)+1, _state);
 | |
|     ivectorsetlengthatleast(bufi, npoints, _state);
 | |
|     
 | |
|     /*
 | |
|      * Refine
 | |
|      */
 | |
|     spline2d_expandindexrows(xy, d, shadow, ns, bufi, 0, npoints, &xyindexprev, 0, (ky+1)/2-1, xyindex, kx, ky, ae_true, _state);
 | |
|     xyindex->ptr.p_int[(kx-1)*(ky-1)] = npoints;
 | |
|     
 | |
|     /*
 | |
|      * Integrity check
 | |
|      */
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Recurrent divide-and-conquer indexing function
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_expandindexrows(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t d,
 | |
|      /* Real    */ ae_vector* shadow,
 | |
|      ae_int_t ns,
 | |
|      /* Integer */ ae_vector* cidx,
 | |
|      ae_int_t pt0,
 | |
|      ae_int_t pt1,
 | |
|      /* Integer */ ae_vector* xyindexprev,
 | |
|      ae_int_t row0,
 | |
|      ae_int_t row1,
 | |
|      /* Integer */ ae_vector* xyindexnew,
 | |
|      ae_int_t kxnew,
 | |
|      ae_int_t kynew,
 | |
|      ae_bool rootcall,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t entrywidth;
 | |
|     ae_int_t kxprev;
 | |
|     double v;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t i1;
 | |
|     double efficiency;
 | |
|     double cost;
 | |
|     ae_int_t rowmid;
 | |
| 
 | |
| 
 | |
|     kxprev = (kxnew+1)/2;
 | |
|     entrywidth = 2+d;
 | |
|     efficiency = 0.1;
 | |
|     cost = d*(pt1-pt0+1)*(ae_log((double)(kxnew), _state)/ae_log((double)(2), _state))/efficiency;
 | |
|     ae_assert(xyindexprev->ptr.p_int[row0*(kxprev-1)+0]==pt0, "Spline2DFit.ExpandIndexRows: integrity check failed", _state);
 | |
|     ae_assert(xyindexprev->ptr.p_int[row1*(kxprev-1)+0]==pt1, "Spline2DFit.ExpandIndexRows: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Parallelism
 | |
|      */
 | |
|     if( ((rootcall&&pt1-pt0>10000)&&row1-row0>=2)&&ae_fp_greater(cost,smpactivationlevel(_state)) )
 | |
|     {
 | |
|         if( _trypexec_spline2d_expandindexrows(xy,d,shadow,ns,cidx,pt0,pt1,xyindexprev,row0,row1,xyindexnew,kxnew,kynew,rootcall, _state) )
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Partition
 | |
|      */
 | |
|     if( row1-row0>=2 )
 | |
|     {
 | |
|         tiledsplit(row1-row0, 1, &i0, &i1, _state);
 | |
|         rowmid = row0+i0;
 | |
|         spline2d_expandindexrows(xy, d, shadow, ns, cidx, pt0, xyindexprev->ptr.p_int[rowmid*(kxprev-1)+0], xyindexprev, row0, rowmid, xyindexnew, kxnew, kynew, ae_false, _state);
 | |
|         spline2d_expandindexrows(xy, d, shadow, ns, cidx, xyindexprev->ptr.p_int[rowmid*(kxprev-1)+0], pt1, xyindexprev, rowmid, row1, xyindexnew, kxnew, kynew, ae_false, _state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Serial execution
 | |
|      */
 | |
|     for(i=pt0; i<=pt1-1; i++)
 | |
|     {
 | |
|         v = 2*xy->ptr.p_double[i*entrywidth+0];
 | |
|         xy->ptr.p_double[i*entrywidth+0] = v;
 | |
|         i0 = iboundval(ae_ifloor(v, _state), 0, kxnew-2, _state);
 | |
|         v = 2*xy->ptr.p_double[i*entrywidth+1];
 | |
|         xy->ptr.p_double[i*entrywidth+1] = v;
 | |
|         i1 = iboundval(ae_ifloor(v, _state), 0, kynew-2, _state);
 | |
|         cidx->ptr.p_int[i] = i1*(kxnew-1)+i0;
 | |
|     }
 | |
|     spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, cidx, pt0, pt1, xyindexnew, 2*row0*(kxnew-1)+0, 2*row1*(kxnew-1)+0, ae_false, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serial stub for GPL edition.
 | |
| *************************************************************************/
 | |
| ae_bool _trypexec_spline2d_expandindexrows(/* Real    */ ae_vector* xy,
 | |
|     ae_int_t d,
 | |
|     /* Real    */ ae_vector* shadow,
 | |
|     ae_int_t ns,
 | |
|     /* Integer */ ae_vector* cidx,
 | |
|     ae_int_t pt0,
 | |
|     ae_int_t pt1,
 | |
|     /* Integer */ ae_vector* xyindexprev,
 | |
|     ae_int_t row0,
 | |
|     ae_int_t row1,
 | |
|     /* Integer */ ae_vector* xyindexnew,
 | |
|     ae_int_t kxnew,
 | |
|     ae_int_t kynew,
 | |
|     ae_bool rootcall,
 | |
|     ae_state *_state)
 | |
| {
 | |
|     return ae_false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Recurrent divide-and-conquer indexing function
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_reorderdatasetandbuildindexrec(/* Real    */ ae_vector* xy,
 | |
|      ae_int_t d,
 | |
|      /* Real    */ ae_vector* shadow,
 | |
|      ae_int_t ns,
 | |
|      /* Integer */ ae_vector* cidx,
 | |
|      ae_int_t pt0,
 | |
|      ae_int_t pt1,
 | |
|      /* Integer */ ae_vector* xyindex,
 | |
|      ae_int_t idx0,
 | |
|      ae_int_t idx1,
 | |
|      ae_bool rootcall,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t entrywidth;
 | |
|     ae_int_t idxmid;
 | |
|     ae_int_t wrk0;
 | |
|     ae_int_t wrk1;
 | |
|     double efficiency;
 | |
|     double cost;
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Efficiency - performance of the code when compared with that
 | |
|      * of linear algebra code.
 | |
|      */
 | |
|     entrywidth = 2+d;
 | |
|     efficiency = 0.1;
 | |
|     cost = d*(pt1-pt0+1)*ae_log((double)(idx1-idx0+1), _state)/ae_log((double)(2), _state)/efficiency;
 | |
|     
 | |
|     /*
 | |
|      * Parallelism
 | |
|      */
 | |
|     if( ((rootcall&&pt1-pt0>10000)&&idx1-idx0>=2)&&ae_fp_greater(cost,smpactivationlevel(_state)) )
 | |
|     {
 | |
|         if( _trypexec_spline2d_reorderdatasetandbuildindexrec(xy,d,shadow,ns,cidx,pt0,pt1,xyindex,idx0,idx1,rootcall, _state) )
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Store left bound to XYIndex
 | |
|      */
 | |
|     xyindex->ptr.p_int[idx0] = pt0;
 | |
|     
 | |
|     /*
 | |
|      * Quick exit strategies
 | |
|      */
 | |
|     if( idx1<=idx0+1 )
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
|     if( pt0==pt1 )
 | |
|     {
 | |
|         for(idxmid=idx0+1; idxmid<=idx1-1; idxmid++)
 | |
|         {
 | |
|             xyindex->ptr.p_int[idxmid] = pt1;
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Select middle element
 | |
|      */
 | |
|     idxmid = idx0+(idx1-idx0)/2;
 | |
|     ae_assert(idx0<idxmid&&idxmid<idx1, "Spline2D: integrity check failed", _state);
 | |
|     wrk0 = pt0;
 | |
|     wrk1 = pt1-1;
 | |
|     for(;;)
 | |
|     {
 | |
|         while(wrk0<pt1&&cidx->ptr.p_int[wrk0]<idxmid)
 | |
|         {
 | |
|             wrk0 = wrk0+1;
 | |
|         }
 | |
|         while(wrk1>=pt0&&cidx->ptr.p_int[wrk1]>=idxmid)
 | |
|         {
 | |
|             wrk1 = wrk1-1;
 | |
|         }
 | |
|         if( wrk1<=wrk0 )
 | |
|         {
 | |
|             break;
 | |
|         }
 | |
|         swapentries(xy, wrk0, wrk1, entrywidth, _state);
 | |
|         if( ns>0 )
 | |
|         {
 | |
|             swapentries(shadow, wrk0, wrk1, ns, _state);
 | |
|         }
 | |
|         swapelementsi(cidx, wrk0, wrk1, _state);
 | |
|     }
 | |
|     spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, cidx, pt0, wrk0, xyindex, idx0, idxmid, ae_false, _state);
 | |
|     spline2d_reorderdatasetandbuildindexrec(xy, d, shadow, ns, cidx, wrk0, pt1, xyindex, idxmid, idx1, ae_false, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serial stub for GPL edition.
 | |
| *************************************************************************/
 | |
| ae_bool _trypexec_spline2d_reorderdatasetandbuildindexrec(/* Real    */ ae_vector* xy,
 | |
|     ae_int_t d,
 | |
|     /* Real    */ ae_vector* shadow,
 | |
|     ae_int_t ns,
 | |
|     /* Integer */ ae_vector* cidx,
 | |
|     ae_int_t pt0,
 | |
|     ae_int_t pt1,
 | |
|     /* Integer */ ae_vector* xyindex,
 | |
|     ae_int_t idx0,
 | |
|     ae_int_t idx1,
 | |
|     ae_bool rootcall,
 | |
|     ae_state *_state)
 | |
| {
 | |
|     return ae_false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs fitting with  BlockLLS solver.  Internal  function,
 | |
| never use it directly.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     XY      -   dataset, array[NPoints,2+D]
 | |
|     XYIndex -   dataset index, see ReorderDatasetAndBuildIndex() for more info
 | |
|     KX0, KX1-   X-indices of basis functions to select and fit;
 | |
|                 range [KX0,KX1) is processed
 | |
|     KXTotal -   total number of indexes in the entire grid
 | |
|     KY0, KY1-   Y-indices of basis functions to select and fit;
 | |
|                 range [KY0,KY1) is processed
 | |
|     KYTotal -   total number of indexes in the entire grid
 | |
|     D       -   number of components in vector-valued spline, D>=1
 | |
|     LambdaReg-  regularization coefficient
 | |
|     LambdaNS-   nonlinearity penalty, exactly zero value is specially handled
 | |
|                 (entire set of rows is not added to the matrix)
 | |
|     Basis1  -   single-dimensional B-spline
 | |
|     
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     A       -   design matrix
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_xdesigngenerate(/* Real    */ ae_vector* xy,
 | |
|      /* Integer */ ae_vector* xyindex,
 | |
|      ae_int_t kx0,
 | |
|      ae_int_t kx1,
 | |
|      ae_int_t kxtotal,
 | |
|      ae_int_t ky0,
 | |
|      ae_int_t ky1,
 | |
|      ae_int_t kytotal,
 | |
|      ae_int_t d,
 | |
|      double lambdareg,
 | |
|      double lambdans,
 | |
|      spline1dinterpolant* basis1,
 | |
|      spline2dxdesignmatrix* a,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t entrywidth;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t j0;
 | |
|     ae_int_t j1;
 | |
|     ae_int_t k0;
 | |
|     ae_int_t k1;
 | |
|     ae_int_t kx;
 | |
|     ae_int_t ky;
 | |
|     ae_int_t rowsdone;
 | |
|     ae_int_t batchesdone;
 | |
|     ae_int_t pt0;
 | |
|     ae_int_t pt1;
 | |
|     ae_int_t base0;
 | |
|     ae_int_t base1;
 | |
|     ae_int_t baseidx;
 | |
|     ae_int_t nzshift;
 | |
|     ae_int_t nzwidth;
 | |
|     ae_matrix d2x;
 | |
|     ae_matrix d2y;
 | |
|     ae_matrix dxy;
 | |
|     double v;
 | |
|     double v0;
 | |
|     double v1;
 | |
|     double v2;
 | |
|     double w0;
 | |
|     double w1;
 | |
|     double w2;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&d2x, 0, sizeof(d2x));
 | |
|     memset(&d2y, 0, sizeof(d2y));
 | |
|     memset(&dxy, 0, sizeof(dxy));
 | |
|     ae_matrix_init(&d2x, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&d2y, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&dxy, 0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     nzshift = 1;
 | |
|     nzwidth = 4;
 | |
|     entrywidth = 2+d;
 | |
|     kx = kx1-kx0;
 | |
|     ky = ky1-ky0;
 | |
|     a->lambdareg = lambdareg;
 | |
|     a->blockwidth = 4;
 | |
|     a->kx = kx;
 | |
|     a->ky = ky;
 | |
|     a->d = d;
 | |
|     a->npoints = 0;
 | |
|     a->ndenserows = 0;
 | |
|     a->ndensebatches = 0;
 | |
|     a->maxbatch = 0;
 | |
|     for(j1=ky0; j1<=ky1-2; j1++)
 | |
|     {
 | |
|         for(j0=kx0; j0<=kx1-2; j0++)
 | |
|         {
 | |
|             i = xyindex->ptr.p_int[j1*(kxtotal-1)+j0+1]-xyindex->ptr.p_int[j1*(kxtotal-1)+j0];
 | |
|             a->npoints = a->npoints+i;
 | |
|             a->ndenserows = a->ndenserows+i;
 | |
|             a->ndensebatches = a->ndensebatches+1;
 | |
|             a->maxbatch = ae_maxint(a->maxbatch, i, _state);
 | |
|         }
 | |
|     }
 | |
|     if( ae_fp_neq(lambdans,(double)(0)) )
 | |
|     {
 | |
|         ae_assert(ae_fp_greater_eq(lambdans,(double)(0)), "Spline2DFit: integrity check failed", _state);
 | |
|         a->ndenserows = a->ndenserows+3*(kx-2)*(ky-2);
 | |
|         a->ndensebatches = a->ndensebatches+(kx-2)*(ky-2);
 | |
|         a->maxbatch = ae_maxint(a->maxbatch, 3, _state);
 | |
|     }
 | |
|     a->nrows = a->ndenserows+kx*ky;
 | |
|     rmatrixsetlengthatleast(&a->vals, a->ndenserows, a->blockwidth*a->blockwidth+d, _state);
 | |
|     ivectorsetlengthatleast(&a->batches, a->ndensebatches+1, _state);
 | |
|     ivectorsetlengthatleast(&a->batchbases, a->ndensebatches, _state);
 | |
|     
 | |
|     /*
 | |
|      * Setup output counters
 | |
|      */
 | |
|     batchesdone = 0;
 | |
|     rowsdone = 0;
 | |
|     
 | |
|     /*
 | |
|      * Generate rows corresponding to dataset points
 | |
|      */
 | |
|     ae_assert(kx>=nzwidth, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(ky>=nzwidth, "Spline2DFit: integrity check failed", _state);
 | |
|     rvectorsetlengthatleast(&a->tmp0, nzwidth, _state);
 | |
|     rvectorsetlengthatleast(&a->tmp1, nzwidth, _state);
 | |
|     a->batches.ptr.p_int[batchesdone] = 0;
 | |
|     for(j1=ky0; j1<=ky1-2; j1++)
 | |
|     {
 | |
|         for(j0=kx0; j0<=kx1-2; j0++)
 | |
|         {
 | |
|             pt0 = xyindex->ptr.p_int[j1*(kxtotal-1)+j0];
 | |
|             pt1 = xyindex->ptr.p_int[j1*(kxtotal-1)+j0+1];
 | |
|             base0 = iboundval(j0-kx0-nzshift, 0, kx-nzwidth, _state);
 | |
|             base1 = iboundval(j1-ky0-nzshift, 0, ky-nzwidth, _state);
 | |
|             baseidx = base1*kx+base0;
 | |
|             a->batchbases.ptr.p_int[batchesdone] = baseidx;
 | |
|             for(i=pt0; i<=pt1-1; i++)
 | |
|             {
 | |
|                 for(k0=0; k0<=nzwidth-1; k0++)
 | |
|                 {
 | |
|                     a->tmp0.ptr.p_double[k0] = spline1dcalc(basis1, xy->ptr.p_double[i*entrywidth+0]-(base0+kx0+k0), _state);
 | |
|                 }
 | |
|                 for(k1=0; k1<=nzwidth-1; k1++)
 | |
|                 {
 | |
|                     a->tmp1.ptr.p_double[k1] = spline1dcalc(basis1, xy->ptr.p_double[i*entrywidth+1]-(base1+ky0+k1), _state);
 | |
|                 }
 | |
|                 for(k1=0; k1<=nzwidth-1; k1++)
 | |
|                 {
 | |
|                     for(k0=0; k0<=nzwidth-1; k0++)
 | |
|                     {
 | |
|                         a->vals.ptr.pp_double[rowsdone][k1*nzwidth+k0] = a->tmp0.ptr.p_double[k0]*a->tmp1.ptr.p_double[k1];
 | |
|                     }
 | |
|                 }
 | |
|                 for(j=0; j<=d-1; j++)
 | |
|                 {
 | |
|                     a->vals.ptr.pp_double[rowsdone][nzwidth*nzwidth+j] = xy->ptr.p_double[i*entrywidth+2+j];
 | |
|                 }
 | |
|                 rowsdone = rowsdone+1;
 | |
|             }
 | |
|             batchesdone = batchesdone+1;
 | |
|             a->batches.ptr.p_int[batchesdone] = rowsdone;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Generate rows corresponding to nonlinearity penalty
 | |
|      */
 | |
|     if( ae_fp_greater(lambdans,(double)(0)) )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Smoothing is applied. Because all grid nodes are same,
 | |
|          * we apply same smoothing kernel, which is calculated only
 | |
|          * once at the beginning of design matrix generation.
 | |
|          */
 | |
|         ae_matrix_set_length(&d2x, 3, 3, _state);
 | |
|         ae_matrix_set_length(&d2y, 3, 3, _state);
 | |
|         ae_matrix_set_length(&dxy, 3, 3, _state);
 | |
|         for(j1=0; j1<=2; j1++)
 | |
|         {
 | |
|             for(j0=0; j0<=2; j0++)
 | |
|             {
 | |
|                 d2x.ptr.pp_double[j0][j1] = 0.0;
 | |
|                 d2y.ptr.pp_double[j0][j1] = 0.0;
 | |
|                 dxy.ptr.pp_double[j0][j1] = 0.0;
 | |
|             }
 | |
|         }
 | |
|         for(k1=0; k1<=2; k1++)
 | |
|         {
 | |
|             for(k0=0; k0<=2; k0++)
 | |
|             {
 | |
|                 spline1ddiff(basis1, (double)(-(k0-1)), &v0, &v1, &v2, _state);
 | |
|                 spline1ddiff(basis1, (double)(-(k1-1)), &w0, &w1, &w2, _state);
 | |
|                 d2x.ptr.pp_double[k0][k1] = d2x.ptr.pp_double[k0][k1]+v2*w0;
 | |
|                 d2y.ptr.pp_double[k0][k1] = d2y.ptr.pp_double[k0][k1]+w2*v0;
 | |
|                 dxy.ptr.pp_double[k0][k1] = dxy.ptr.pp_double[k0][k1]+v1*w1;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Now, kernel is ready - apply it to all inner nodes of the grid.
 | |
|          */
 | |
|         for(j1=1; j1<=ky-2; j1++)
 | |
|         {
 | |
|             for(j0=1; j0<=kx-2; j0++)
 | |
|             {
 | |
|                 base0 = imax2(j0-2, 0, _state);
 | |
|                 base1 = imax2(j1-2, 0, _state);
 | |
|                 baseidx = base1*kx+base0;
 | |
|                 a->batchbases.ptr.p_int[batchesdone] = baseidx;
 | |
|                 
 | |
|                 /*
 | |
|                  * d2F/dx2 term
 | |
|                  */
 | |
|                 v = lambdans;
 | |
|                 for(j=0; j<=nzwidth*nzwidth+d-1; j++)
 | |
|                 {
 | |
|                     a->vals.ptr.pp_double[rowsdone][j] = (double)(0);
 | |
|                 }
 | |
|                 for(k1=j1-1; k1<=j1+1; k1++)
 | |
|                 {
 | |
|                     for(k0=j0-1; k0<=j0+1; k0++)
 | |
|                     {
 | |
|                         a->vals.ptr.pp_double[rowsdone][nzwidth*(k1-base1)+(k0-base0)] = v*d2x.ptr.pp_double[1+(k0-j0)][1+(k1-j1)];
 | |
|                     }
 | |
|                 }
 | |
|                 rowsdone = rowsdone+1;
 | |
|                 
 | |
|                 /*
 | |
|                  * d2F/dy2 term
 | |
|                  */
 | |
|                 v = lambdans;
 | |
|                 for(j=0; j<=nzwidth*nzwidth+d-1; j++)
 | |
|                 {
 | |
|                     a->vals.ptr.pp_double[rowsdone][j] = (double)(0);
 | |
|                 }
 | |
|                 for(k1=j1-1; k1<=j1+1; k1++)
 | |
|                 {
 | |
|                     for(k0=j0-1; k0<=j0+1; k0++)
 | |
|                     {
 | |
|                         a->vals.ptr.pp_double[rowsdone][nzwidth*(k1-base1)+(k0-base0)] = v*d2y.ptr.pp_double[1+(k0-j0)][1+(k1-j1)];
 | |
|                     }
 | |
|                 }
 | |
|                 rowsdone = rowsdone+1;
 | |
|                 
 | |
|                 /*
 | |
|                  * 2*d2F/dxdy term
 | |
|                  */
 | |
|                 v = ae_sqrt((double)(2), _state)*lambdans;
 | |
|                 for(j=0; j<=nzwidth*nzwidth+d-1; j++)
 | |
|                 {
 | |
|                     a->vals.ptr.pp_double[rowsdone][j] = (double)(0);
 | |
|                 }
 | |
|                 for(k1=j1-1; k1<=j1+1; k1++)
 | |
|                 {
 | |
|                     for(k0=j0-1; k0<=j0+1; k0++)
 | |
|                     {
 | |
|                         a->vals.ptr.pp_double[rowsdone][nzwidth*(k1-base1)+(k0-base0)] = v*dxy.ptr.pp_double[1+(k0-j0)][1+(k1-j1)];
 | |
|                     }
 | |
|                 }
 | |
|                 rowsdone = rowsdone+1;
 | |
|                 batchesdone = batchesdone+1;
 | |
|                 a->batches.ptr.p_int[batchesdone] = rowsdone;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Integrity post-check
 | |
|      */
 | |
|     ae_assert(batchesdone==a->ndensebatches, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(rowsdone==a->ndenserows, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs matrix-vector product of design matrix and dense
 | |
| vector.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A       -   design matrix, (a.nrows) X (a.kx*a.ky);
 | |
|                 some fields of A are used for temporaries,
 | |
|                 so it is non-constant.
 | |
|     X       -   array[A.KX*A.KY]
 | |
|     
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   product, array[A.NRows], automatically allocated
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_xdesignmv(spline2dxdesignmatrix* a,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t bidx;
 | |
|     ae_int_t i;
 | |
|     ae_int_t cnt;
 | |
|     double v;
 | |
|     ae_int_t baseidx;
 | |
|     ae_int_t outidx;
 | |
|     ae_int_t batchsize;
 | |
|     ae_int_t kx;
 | |
|     ae_int_t k0;
 | |
|     ae_int_t k1;
 | |
|     ae_int_t nzwidth;
 | |
| 
 | |
| 
 | |
|     nzwidth = 4;
 | |
|     ae_assert(a->blockwidth==nzwidth, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(x->cnt>=a->kx*a->ky, "Spline2DFit: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare
 | |
|      */
 | |
|     rvectorsetlengthatleast(y, a->nrows, _state);
 | |
|     rvectorsetlengthatleast(&a->tmp0, nzwidth*nzwidth, _state);
 | |
|     rvectorsetlengthatleast(&a->tmp1, a->maxbatch, _state);
 | |
|     kx = a->kx;
 | |
|     outidx = 0;
 | |
|     
 | |
|     /*
 | |
|      * Process dense part
 | |
|      */
 | |
|     for(bidx=0; bidx<=a->ndensebatches-1; bidx++)
 | |
|     {
 | |
|         if( a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]>0 )
 | |
|         {
 | |
|             batchsize = a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx];
 | |
|             baseidx = a->batchbases.ptr.p_int[bidx];
 | |
|             for(k1=0; k1<=nzwidth-1; k1++)
 | |
|             {
 | |
|                 for(k0=0; k0<=nzwidth-1; k0++)
 | |
|                 {
 | |
|                     a->tmp0.ptr.p_double[k1*nzwidth+k0] = x->ptr.p_double[baseidx+k1*kx+k0];
 | |
|                 }
 | |
|             }
 | |
|             rmatrixgemv(batchsize, nzwidth*nzwidth, 1.0, &a->vals, a->batches.ptr.p_int[bidx], 0, 0, &a->tmp0, 0, 0.0, &a->tmp1, 0, _state);
 | |
|             for(i=0; i<=batchsize-1; i++)
 | |
|             {
 | |
|                 y->ptr.p_double[outidx+i] = a->tmp1.ptr.p_double[i];
 | |
|             }
 | |
|             outidx = outidx+batchsize;
 | |
|         }
 | |
|     }
 | |
|     ae_assert(outidx==a->ndenserows, "Spline2DFit: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Process regularizer 
 | |
|      */
 | |
|     v = a->lambdareg;
 | |
|     cnt = a->kx*a->ky;
 | |
|     for(i=0; i<=cnt-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[outidx+i] = v*x->ptr.p_double[i];
 | |
|     }
 | |
|     outidx = outidx+cnt;
 | |
|     
 | |
|     /*
 | |
|      * Post-check
 | |
|      */
 | |
|     ae_assert(outidx==a->nrows, "Spline2DFit: integrity check failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function performs matrix-vector product of transposed design matrix and dense
 | |
| vector.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A       -   design matrix, (a.nrows) X (a.kx*a.ky);
 | |
|                 some fields of A are used for temporaries,
 | |
|                 so it is non-constant.
 | |
|     X       -   array[A.NRows]
 | |
|     
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   product, array[A.KX*A.KY], automatically allocated
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_xdesignmtv(spline2dxdesignmatrix* a,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t bidx;
 | |
|     ae_int_t i;
 | |
|     ae_int_t cnt;
 | |
|     double v;
 | |
|     ae_int_t baseidx;
 | |
|     ae_int_t inidx;
 | |
|     ae_int_t batchsize;
 | |
|     ae_int_t kx;
 | |
|     ae_int_t k0;
 | |
|     ae_int_t k1;
 | |
|     ae_int_t nzwidth;
 | |
| 
 | |
| 
 | |
|     nzwidth = 4;
 | |
|     ae_assert(a->blockwidth==nzwidth, "Spline2DFit: integrity check failed", _state);
 | |
|     ae_assert(x->cnt>=a->nrows, "Spline2DFit: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare
 | |
|      */
 | |
|     rvectorsetlengthatleast(y, a->kx*a->ky, _state);
 | |
|     rvectorsetlengthatleast(&a->tmp0, nzwidth*nzwidth, _state);
 | |
|     rvectorsetlengthatleast(&a->tmp1, a->maxbatch, _state);
 | |
|     kx = a->kx;
 | |
|     inidx = 0;
 | |
|     cnt = a->kx*a->ky;
 | |
|     for(i=0; i<=cnt-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Process dense part
 | |
|      */
 | |
|     for(bidx=0; bidx<=a->ndensebatches-1; bidx++)
 | |
|     {
 | |
|         if( a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]>0 )
 | |
|         {
 | |
|             batchsize = a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx];
 | |
|             baseidx = a->batchbases.ptr.p_int[bidx];
 | |
|             for(i=0; i<=batchsize-1; i++)
 | |
|             {
 | |
|                 a->tmp1.ptr.p_double[i] = x->ptr.p_double[inidx+i];
 | |
|             }
 | |
|             rmatrixgemv(nzwidth*nzwidth, batchsize, 1.0, &a->vals, a->batches.ptr.p_int[bidx], 0, 1, &a->tmp1, 0, 0.0, &a->tmp0, 0, _state);
 | |
|             for(k1=0; k1<=nzwidth-1; k1++)
 | |
|             {
 | |
|                 for(k0=0; k0<=nzwidth-1; k0++)
 | |
|                 {
 | |
|                     y->ptr.p_double[baseidx+k1*kx+k0] = y->ptr.p_double[baseidx+k1*kx+k0]+a->tmp0.ptr.p_double[k1*nzwidth+k0];
 | |
|                 }
 | |
|             }
 | |
|             inidx = inidx+batchsize;
 | |
|         }
 | |
|     }
 | |
|     ae_assert(inidx==a->ndenserows, "Spline2DFit: integrity check failed", _state);
 | |
|     
 | |
|     /*
 | |
|      * Process regularizer 
 | |
|      */
 | |
|     v = a->lambdareg;
 | |
|     cnt = a->kx*a->ky;
 | |
|     for(i=0; i<=cnt-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[i] = y->ptr.p_double[i]+v*x->ptr.p_double[inidx+i];
 | |
|     }
 | |
|     inidx = inidx+cnt;
 | |
|     
 | |
|     /*
 | |
|      * Post-check
 | |
|      */
 | |
|     ae_assert(inidx==a->nrows, "Spline2DFit: integrity check failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function generates squared design matrix stored in block band format.
 | |
| 
 | |
| We  use  an   adaptation   of   block   skyline   storage   format,   with
 | |
| TOWERSIZE*KX   skyline    bands   (towers)   stored   sequentially;   here
 | |
| TOWERSIZE=(BlockBandwidth+1)*KX. So, we have KY "towers", stored one below
 | |
| other, in BlockATA matrix. Every "tower" is a sequence of BlockBandwidth+1
 | |
| cells, each of them being KX*KX in size.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     A       -   design matrix; some of its fields are used for temporaries
 | |
|     BlockATA-   array[KY*(BlockBandwidth+1)*KX,KX],  preallocated  storage
 | |
|                 for output matrix in compressed block band format
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     BlockATA-   AH*AH', stored in compressed block band format
 | |
|     MXATA   -   max(|AH*AH'|), elementwise
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 05.02.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void spline2d_xdesignblockata(spline2dxdesignmatrix* a,
 | |
|      /* Real    */ ae_matrix* blockata,
 | |
|      double* mxata,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t blockbandwidth;
 | |
|     ae_int_t nzwidth;
 | |
|     ae_int_t kx;
 | |
|     ae_int_t ky;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t i1;
 | |
|     ae_int_t j0;
 | |
|     ae_int_t j1;
 | |
|     ae_int_t celloffset;
 | |
|     ae_int_t bidx;
 | |
|     ae_int_t baseidx;
 | |
|     ae_int_t batchsize;
 | |
|     ae_int_t offs0;
 | |
|     ae_int_t offs1;
 | |
|     double v;
 | |
| 
 | |
| 
 | |
|     blockbandwidth = 3;
 | |
|     nzwidth = 4;
 | |
|     kx = a->kx;
 | |
|     ky = a->ky;
 | |
|     ae_assert(a->blockwidth==nzwidth, "Spline2DFit: integrity check failed", _state);
 | |
|     rmatrixsetlengthatleast(&a->tmp2, nzwidth*nzwidth, nzwidth*nzwidth, _state);
 | |
|     
 | |
|     /*
 | |
|      * Initial zero-fill:
 | |
|      * * zero-fill ALL elements of BlockATA
 | |
|      * * zero-fill ALL elements of Tmp2
 | |
|      *
 | |
|      * Filling ALL elements, including unused ones, is essential for the
 | |
|      * purposes of calculating max(BlockATA).
 | |
|      */
 | |
|     for(i1=0; i1<=ky-1; i1++)
 | |
|     {
 | |
|         for(i0=i1; i0<=ae_minint(ky-1, i1+blockbandwidth, _state); i0++)
 | |
|         {
 | |
|             celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i0, _state);
 | |
|             for(j1=0; j1<=kx-1; j1++)
 | |
|             {
 | |
|                 for(j0=0; j0<=kx-1; j0++)
 | |
|                 {
 | |
|                     blockata->ptr.pp_double[celloffset+j1][j0] = 0.0;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     for(j1=0; j1<=nzwidth*nzwidth-1; j1++)
 | |
|     {
 | |
|         for(j0=0; j0<=nzwidth*nzwidth-1; j0++)
 | |
|         {
 | |
|             a->tmp2.ptr.pp_double[j1][j0] = 0.0;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Process dense part of A
 | |
|      */
 | |
|     for(bidx=0; bidx<=a->ndensebatches-1; bidx++)
 | |
|     {
 | |
|         if( a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx]>0 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Generate 16x16 U = BATCH'*BATCH and add it to ATA.
 | |
|              *
 | |
|              * NOTE: it is essential that lower triangle of Tmp2 is
 | |
|              *       filled by zeros.
 | |
|              */
 | |
|             batchsize = a->batches.ptr.p_int[bidx+1]-a->batches.ptr.p_int[bidx];
 | |
|             rmatrixsyrk(nzwidth*nzwidth, batchsize, 1.0, &a->vals, a->batches.ptr.p_int[bidx], 0, 2, 0.0, &a->tmp2, 0, 0, ae_true, _state);
 | |
|             baseidx = a->batchbases.ptr.p_int[bidx];
 | |
|             for(i1=0; i1<=nzwidth-1; i1++)
 | |
|             {
 | |
|                 for(j1=i1; j1<=nzwidth-1; j1++)
 | |
|                 {
 | |
|                     celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, baseidx/kx+i1, baseidx/kx+j1, _state);
 | |
|                     offs0 = baseidx%kx;
 | |
|                     offs1 = baseidx%kx;
 | |
|                     for(i0=0; i0<=nzwidth-1; i0++)
 | |
|                     {
 | |
|                         for(j0=0; j0<=nzwidth-1; j0++)
 | |
|                         {
 | |
|                             v = a->tmp2.ptr.pp_double[i1*nzwidth+i0][j1*nzwidth+j0];
 | |
|                             blockata->ptr.pp_double[celloffset+offs1+i0][offs0+j0] = blockata->ptr.pp_double[celloffset+offs1+i0][offs0+j0]+v;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Process regularizer term
 | |
|      */
 | |
|     for(i1=0; i1<=ky-1; i1++)
 | |
|     {
 | |
|         celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i1, _state);
 | |
|         for(j1=0; j1<=kx-1; j1++)
 | |
|         {
 | |
|             blockata->ptr.pp_double[celloffset+j1][j1] = blockata->ptr.pp_double[celloffset+j1][j1]+ae_sqr(a->lambdareg, _state);
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Calculate max(ATA)
 | |
|      *
 | |
|      * NOTE: here we rely on zero initialization of unused parts of
 | |
|      *       BlockATA and Tmp2.
 | |
|      */
 | |
|     *mxata = 0.0;
 | |
|     for(i1=0; i1<=ky-1; i1++)
 | |
|     {
 | |
|         for(i0=i1; i0<=ae_minint(ky-1, i1+blockbandwidth, _state); i0++)
 | |
|         {
 | |
|             celloffset = spline2d_getcelloffset(kx, ky, blockbandwidth, i1, i0, _state);
 | |
|             for(j1=0; j1<=kx-1; j1++)
 | |
|             {
 | |
|                 for(j0=0; j0<=kx-1; j0++)
 | |
|                 {
 | |
|                     *mxata = ae_maxreal(*mxata, ae_fabs(blockata->ptr.pp_double[celloffset+j1][j0], _state), _state);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dinterpolant_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dinterpolant *p = (spline2dinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->x, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->y, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->f, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dinterpolant_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dinterpolant *dst = (spline2dinterpolant*)_dst;
 | |
|     spline2dinterpolant *src = (spline2dinterpolant*)_src;
 | |
|     dst->stype = src->stype;
 | |
|     dst->n = src->n;
 | |
|     dst->m = src->m;
 | |
|     dst->d = src->d;
 | |
|     ae_vector_init_copy(&dst->x, &src->x, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->y, &src->y, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->f, &src->f, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dinterpolant_clear(void* _p)
 | |
| {
 | |
|     spline2dinterpolant *p = (spline2dinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->x);
 | |
|     ae_vector_clear(&p->y);
 | |
|     ae_vector_clear(&p->f);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dinterpolant_destroy(void* _p)
 | |
| {
 | |
|     spline2dinterpolant *p = (spline2dinterpolant*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->x);
 | |
|     ae_vector_destroy(&p->y);
 | |
|     ae_vector_destroy(&p->f);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dbuilder_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dbuilder *p = (spline2dbuilder*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->xy, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dbuilder_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dbuilder *dst = (spline2dbuilder*)_dst;
 | |
|     spline2dbuilder *src = (spline2dbuilder*)_src;
 | |
|     dst->priorterm = src->priorterm;
 | |
|     dst->priortermval = src->priortermval;
 | |
|     dst->areatype = src->areatype;
 | |
|     dst->xa = src->xa;
 | |
|     dst->xb = src->xb;
 | |
|     dst->ya = src->ya;
 | |
|     dst->yb = src->yb;
 | |
|     dst->gridtype = src->gridtype;
 | |
|     dst->kx = src->kx;
 | |
|     dst->ky = src->ky;
 | |
|     dst->smoothing = src->smoothing;
 | |
|     dst->nlayers = src->nlayers;
 | |
|     dst->solvertype = src->solvertype;
 | |
|     dst->lambdabase = src->lambdabase;
 | |
|     ae_vector_init_copy(&dst->xy, &src->xy, _state, make_automatic);
 | |
|     dst->npoints = src->npoints;
 | |
|     dst->d = src->d;
 | |
|     dst->sx = src->sx;
 | |
|     dst->sy = src->sy;
 | |
|     dst->adddegreeoffreedom = src->adddegreeoffreedom;
 | |
|     dst->interfacesize = src->interfacesize;
 | |
|     dst->lsqrcnt = src->lsqrcnt;
 | |
|     dst->maxcoresize = src->maxcoresize;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dbuilder_clear(void* _p)
 | |
| {
 | |
|     spline2dbuilder *p = (spline2dbuilder*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->xy);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dbuilder_destroy(void* _p)
 | |
| {
 | |
|     spline2dbuilder *p = (spline2dbuilder*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->xy);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dfitreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dfitreport *p = (spline2dfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dfitreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dfitreport *dst = (spline2dfitreport*)_dst;
 | |
|     spline2dfitreport *src = (spline2dfitreport*)_src;
 | |
|     dst->rmserror = src->rmserror;
 | |
|     dst->avgerror = src->avgerror;
 | |
|     dst->maxerror = src->maxerror;
 | |
|     dst->r2 = src->r2;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dfitreport_clear(void* _p)
 | |
| {
 | |
|     spline2dfitreport *p = (spline2dfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dfitreport_destroy(void* _p)
 | |
| {
 | |
|     spline2dfitreport *p = (spline2dfitreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dxdesignmatrix_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dxdesignmatrix *p = (spline2dxdesignmatrix*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_matrix_init(&p->vals, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->batches, 0, DT_INT, _state, make_automatic);
 | |
|     ae_vector_init(&p->batchbases, 0, DT_INT, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->tmp2, 0, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dxdesignmatrix_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dxdesignmatrix *dst = (spline2dxdesignmatrix*)_dst;
 | |
|     spline2dxdesignmatrix *src = (spline2dxdesignmatrix*)_src;
 | |
|     dst->blockwidth = src->blockwidth;
 | |
|     dst->kx = src->kx;
 | |
|     dst->ky = src->ky;
 | |
|     dst->npoints = src->npoints;
 | |
|     dst->nrows = src->nrows;
 | |
|     dst->ndenserows = src->ndenserows;
 | |
|     dst->ndensebatches = src->ndensebatches;
 | |
|     dst->d = src->d;
 | |
|     dst->maxbatch = src->maxbatch;
 | |
|     ae_matrix_init_copy(&dst->vals, &src->vals, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->batches, &src->batches, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->batchbases, &src->batchbases, _state, make_automatic);
 | |
|     dst->lambdareg = src->lambdareg;
 | |
|     ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->tmp2, &src->tmp2, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dxdesignmatrix_clear(void* _p)
 | |
| {
 | |
|     spline2dxdesignmatrix *p = (spline2dxdesignmatrix*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_matrix_clear(&p->vals);
 | |
|     ae_vector_clear(&p->batches);
 | |
|     ae_vector_clear(&p->batchbases);
 | |
|     ae_vector_clear(&p->tmp0);
 | |
|     ae_vector_clear(&p->tmp1);
 | |
|     ae_matrix_clear(&p->tmp2);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dxdesignmatrix_destroy(void* _p)
 | |
| {
 | |
|     spline2dxdesignmatrix *p = (spline2dxdesignmatrix*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_matrix_destroy(&p->vals);
 | |
|     ae_vector_destroy(&p->batches);
 | |
|     ae_vector_destroy(&p->batchbases);
 | |
|     ae_vector_destroy(&p->tmp0);
 | |
|     ae_vector_destroy(&p->tmp1);
 | |
|     ae_matrix_destroy(&p->tmp2);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dblockllsbuf_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dblockllsbuf *p = (spline2dblockllsbuf*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _linlsqrstate_init(&p->solver, _state, make_automatic);
 | |
|     _linlsqrreport_init(&p->solverrep, _state, make_automatic);
 | |
|     ae_matrix_init(&p->blockata, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->trsmbuf2, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->cholbuf2, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->cholbuf1, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmp1, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dblockllsbuf_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dblockllsbuf *dst = (spline2dblockllsbuf*)_dst;
 | |
|     spline2dblockllsbuf *src = (spline2dblockllsbuf*)_src;
 | |
|     _linlsqrstate_init_copy(&dst->solver, &src->solver, _state, make_automatic);
 | |
|     _linlsqrreport_init_copy(&dst->solverrep, &src->solverrep, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->blockata, &src->blockata, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->trsmbuf2, &src->trsmbuf2, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->cholbuf2, &src->cholbuf2, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->cholbuf1, &src->cholbuf1, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmp1, &src->tmp1, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dblockllsbuf_clear(void* _p)
 | |
| {
 | |
|     spline2dblockllsbuf *p = (spline2dblockllsbuf*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _linlsqrstate_clear(&p->solver);
 | |
|     _linlsqrreport_clear(&p->solverrep);
 | |
|     ae_matrix_clear(&p->blockata);
 | |
|     ae_matrix_clear(&p->trsmbuf2);
 | |
|     ae_matrix_clear(&p->cholbuf2);
 | |
|     ae_vector_clear(&p->cholbuf1);
 | |
|     ae_vector_clear(&p->tmp0);
 | |
|     ae_vector_clear(&p->tmp1);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dblockllsbuf_destroy(void* _p)
 | |
| {
 | |
|     spline2dblockllsbuf *p = (spline2dblockllsbuf*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _linlsqrstate_destroy(&p->solver);
 | |
|     _linlsqrreport_destroy(&p->solverrep);
 | |
|     ae_matrix_destroy(&p->blockata);
 | |
|     ae_matrix_destroy(&p->trsmbuf2);
 | |
|     ae_matrix_destroy(&p->cholbuf2);
 | |
|     ae_vector_destroy(&p->cholbuf1);
 | |
|     ae_vector_destroy(&p->tmp0);
 | |
|     ae_vector_destroy(&p->tmp1);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dfastddmbuf_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dfastddmbuf *p = (spline2dfastddmbuf*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _spline2dxdesignmatrix_init(&p->xdesignmatrix, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmp0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->tmpz, 0, DT_REAL, _state, make_automatic);
 | |
|     _spline2dfitreport_init(&p->dummyrep, _state, make_automatic);
 | |
|     _spline2dinterpolant_init(&p->localmodel, _state, make_automatic);
 | |
|     _spline2dblockllsbuf_init(&p->blockllsbuf, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dfastddmbuf_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     spline2dfastddmbuf *dst = (spline2dfastddmbuf*)_dst;
 | |
|     spline2dfastddmbuf *src = (spline2dfastddmbuf*)_src;
 | |
|     _spline2dxdesignmatrix_init_copy(&dst->xdesignmatrix, &src->xdesignmatrix, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmp0, &src->tmp0, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->tmpz, &src->tmpz, _state, make_automatic);
 | |
|     _spline2dfitreport_init_copy(&dst->dummyrep, &src->dummyrep, _state, make_automatic);
 | |
|     _spline2dinterpolant_init_copy(&dst->localmodel, &src->localmodel, _state, make_automatic);
 | |
|     _spline2dblockllsbuf_init_copy(&dst->blockllsbuf, &src->blockllsbuf, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dfastddmbuf_clear(void* _p)
 | |
| {
 | |
|     spline2dfastddmbuf *p = (spline2dfastddmbuf*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _spline2dxdesignmatrix_clear(&p->xdesignmatrix);
 | |
|     ae_vector_clear(&p->tmp0);
 | |
|     ae_vector_clear(&p->tmpz);
 | |
|     _spline2dfitreport_clear(&p->dummyrep);
 | |
|     _spline2dinterpolant_clear(&p->localmodel);
 | |
|     _spline2dblockllsbuf_clear(&p->blockllsbuf);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _spline2dfastddmbuf_destroy(void* _p)
 | |
| {
 | |
|     spline2dfastddmbuf *p = (spline2dfastddmbuf*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _spline2dxdesignmatrix_destroy(&p->xdesignmatrix);
 | |
|     ae_vector_destroy(&p->tmp0);
 | |
|     ae_vector_destroy(&p->tmpz);
 | |
|     _spline2dfitreport_destroy(&p->dummyrep);
 | |
|     _spline2dinterpolant_destroy(&p->localmodel);
 | |
|     _spline2dblockllsbuf_destroy(&p->blockllsbuf);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_RBFV1) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function creates RBF  model  for  a  scalar (NY=1)  or  vector (NY>1)
 | |
| function in a NX-dimensional space (NX=2 or NX=3).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     NX      -   dimension of the space, NX=2 or NX=3
 | |
|     NY      -   function dimension, NY>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     S       -   RBF model (initially equals to zero)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv1create(ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      rbfv1model* s,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
|     _rbfv1model_clear(s);
 | |
| 
 | |
|     ae_assert(nx==2||nx==3, "RBFCreate: NX<>2 and NX<>3", _state);
 | |
|     ae_assert(ny>=1, "RBFCreate: NY<1", _state);
 | |
|     s->nx = nx;
 | |
|     s->ny = ny;
 | |
|     s->nl = 0;
 | |
|     s->nc = 0;
 | |
|     ae_matrix_set_length(&s->v, ny, rbfv1_mxnx+1, _state);
 | |
|     for(i=0; i<=ny-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=rbfv1_mxnx; j++)
 | |
|         {
 | |
|             s->v.ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     s->rmax = (double)(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function creates buffer  structure  which  can  be  used  to  perform
 | |
| parallel  RBF  model  evaluations  (with  one  RBF  model  instance  being
 | |
| used from multiple threads, as long as  different  threads  use  different
 | |
| instances of buffer).
 | |
| 
 | |
| This buffer object can be used with  rbftscalcbuf()  function  (here  "ts"
 | |
| stands for "thread-safe", "buf" is a suffix which denotes  function  which
 | |
| reuses previously allocated output space).
 | |
| 
 | |
| How to use it:
 | |
| * create RBF model structure with rbfcreate()
 | |
| * load data, tune parameters
 | |
| * call rbfbuildmodel()
 | |
| * call rbfcreatecalcbuffer(), once per thread working with RBF model  (you
 | |
|   should call this function only AFTER call to rbfbuildmodel(), see  below
 | |
|   for more information)
 | |
| * call rbftscalcbuf() from different threads,  with  each  thread  working
 | |
|   with its own copy of buffer object.
 | |
| 
 | |
| INPUT PARAMETERS
 | |
|     S           -   RBF model
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     Buf         -   external buffer.
 | |
|     
 | |
|     
 | |
| IMPORTANT: buffer object should be used only with  RBF model object  which
 | |
|            was used to initialize buffer. Any attempt to use buffer   with
 | |
|            different object is dangerous - you may  get  memory  violation
 | |
|            error because sizes of internal arrays do not fit to dimensions
 | |
|            of RBF structure.
 | |
|            
 | |
| IMPORTANT: you  should  call  this function only for model which was built
 | |
|            with rbfbuildmodel() function, after successful  invocation  of
 | |
|            rbfbuildmodel().  Sizes   of   some   internal  structures  are
 | |
|            determined only after model is built, so buffer object  created
 | |
|            before model  construction  stage  will  be  useless  (and  any
 | |
|            attempt to use it will result in exception).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.04.2016 by Sergey Bochkanov
 | |
| *************************************************************************/
 | |
| void rbfv1createcalcbuffer(rbfv1model* s,
 | |
|      rbfv1calcbuffer* buf,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _rbfv1calcbuffer_clear(buf);
 | |
| 
 | |
|     kdtreecreaterequestbuffer(&s->tree, &buf->requestbuffer, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This   function  builds  RBF  model  and  returns  report  (contains  some 
 | |
| information which can be used for evaluation of the algorithm properties).
 | |
| 
 | |
| Call to this function modifies RBF model by calculating its centers/radii/
 | |
| weights  and  saving  them  into  RBFModel  structure.  Initially RBFModel 
 | |
| contain zero coefficients, but after call to this function  we  will  have
 | |
| coefficients which were calculated in order to fit our dataset.
 | |
| 
 | |
| After you called this function you can call RBFCalc(),  RBFGridCalc()  and
 | |
| other model calculation functions.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     Rep     -   report:
 | |
|                 * Rep.TerminationType:
 | |
|                   * -5 - non-distinct basis function centers were detected,
 | |
|                          interpolation aborted
 | |
|                   * -4 - nonconvergence of the internal SVD solver
 | |
|                   *  1 - successful termination
 | |
|                 Fields are used for debugging purposes:
 | |
|                 * Rep.IterationsCount - iterations count of the LSQR solver
 | |
|                 * Rep.NMV - number of matrix-vector products
 | |
|                 * Rep.ARows - rows count for the system matrix
 | |
|                 * Rep.ACols - columns count for the system matrix
 | |
|                 * Rep.ANNZ - number of significantly non-zero elements
 | |
|                   (elements above some algorithm-determined threshold)
 | |
| 
 | |
| NOTE:  failure  to  build  model will leave current state of the structure
 | |
| unchanged.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv1buildmodel(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t aterm,
 | |
|      ae_int_t algorithmtype,
 | |
|      ae_int_t nlayers,
 | |
|      double radvalue,
 | |
|      double radzvalue,
 | |
|      double lambdav,
 | |
|      double epsort,
 | |
|      double epserr,
 | |
|      ae_int_t maxits,
 | |
|      rbfv1model* s,
 | |
|      rbfv1report* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     kdtree tree;
 | |
|     kdtree ctree;
 | |
|     ae_vector dist;
 | |
|     ae_vector xcx;
 | |
|     ae_matrix a;
 | |
|     ae_matrix v;
 | |
|     ae_matrix omega;
 | |
|     ae_matrix residualy;
 | |
|     ae_vector radius;
 | |
|     ae_matrix xc;
 | |
|     ae_int_t nc;
 | |
|     double rmax;
 | |
|     ae_vector tags;
 | |
|     ae_vector ctags;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t snnz;
 | |
|     ae_vector tmp0;
 | |
|     ae_vector tmp1;
 | |
|     ae_int_t layerscnt;
 | |
|     ae_bool modelstatus;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&tree, 0, sizeof(tree));
 | |
|     memset(&ctree, 0, sizeof(ctree));
 | |
|     memset(&dist, 0, sizeof(dist));
 | |
|     memset(&xcx, 0, sizeof(xcx));
 | |
|     memset(&a, 0, sizeof(a));
 | |
|     memset(&v, 0, sizeof(v));
 | |
|     memset(&omega, 0, sizeof(omega));
 | |
|     memset(&residualy, 0, sizeof(residualy));
 | |
|     memset(&radius, 0, sizeof(radius));
 | |
|     memset(&xc, 0, sizeof(xc));
 | |
|     memset(&tags, 0, sizeof(tags));
 | |
|     memset(&ctags, 0, sizeof(ctags));
 | |
|     memset(&tmp0, 0, sizeof(tmp0));
 | |
|     memset(&tmp1, 0, sizeof(tmp1));
 | |
|     _rbfv1report_clear(rep);
 | |
|     _kdtree_init(&tree, _state, ae_true);
 | |
|     _kdtree_init(&ctree, _state, ae_true);
 | |
|     ae_vector_init(&dist, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xcx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&v, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&omega, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&residualy, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&radius, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&xc, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tags, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&ctags, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(s->nx==2||s->nx==3, "RBFBuildModel: S.NX<>2 or S.NX<>3!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Quick exit when we have no points
 | |
|      */
 | |
|     if( n==0 )
 | |
|     {
 | |
|         rep->terminationtype = 1;
 | |
|         rep->iterationscount = 0;
 | |
|         rep->nmv = 0;
 | |
|         rep->arows = 0;
 | |
|         rep->acols = 0;
 | |
|         kdtreebuildtagged(&s->xc, &tags, 0, rbfv1_mxnx, 0, 2, &s->tree, _state);
 | |
|         ae_matrix_set_length(&s->xc, 0, 0, _state);
 | |
|         ae_matrix_set_length(&s->wr, 0, 0, _state);
 | |
|         s->nc = 0;
 | |
|         s->rmax = (double)(0);
 | |
|         ae_matrix_set_length(&s->v, s->ny, rbfv1_mxnx+1, _state);
 | |
|         for(i=0; i<=s->ny-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=rbfv1_mxnx; j++)
 | |
|             {
 | |
|                 s->v.ptr.pp_double[i][j] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * General case, N>0
 | |
|      */
 | |
|     rep->annz = 0;
 | |
|     rep->iterationscount = 0;
 | |
|     rep->nmv = 0;
 | |
|     ae_vector_set_length(&xcx, rbfv1_mxnx, _state);
 | |
|     
 | |
|     /*
 | |
|      * First model in a sequence - linear model.
 | |
|      * Residuals from linear regression are stored in the ResidualY variable
 | |
|      * (used later to build RBF models).
 | |
|      */
 | |
|     ae_matrix_set_length(&residualy, n, s->ny, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=s->ny-1; j++)
 | |
|         {
 | |
|             residualy.ptr.pp_double[i][j] = y->ptr.pp_double[i][j];
 | |
|         }
 | |
|     }
 | |
|     if( !rbfv1_rbfv1buildlinearmodel(x, &residualy, n, s->ny, aterm, &v, _state) )
 | |
|     {
 | |
|         rep->terminationtype = -5;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Handle special case: multilayer model with NLayers=0.
 | |
|      * Quick exit.
 | |
|      */
 | |
|     if( algorithmtype==2&&nlayers==0 )
 | |
|     {
 | |
|         rep->terminationtype = 1;
 | |
|         rep->iterationscount = 0;
 | |
|         rep->nmv = 0;
 | |
|         rep->arows = 0;
 | |
|         rep->acols = 0;
 | |
|         kdtreebuildtagged(&s->xc, &tags, 0, rbfv1_mxnx, 0, 2, &s->tree, _state);
 | |
|         ae_matrix_set_length(&s->xc, 0, 0, _state);
 | |
|         ae_matrix_set_length(&s->wr, 0, 0, _state);
 | |
|         s->nc = 0;
 | |
|         s->rmax = (double)(0);
 | |
|         ae_matrix_set_length(&s->v, s->ny, rbfv1_mxnx+1, _state);
 | |
|         for(i=0; i<=s->ny-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=rbfv1_mxnx; j++)
 | |
|             {
 | |
|                 s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j];
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Second model in a sequence - RBF term.
 | |
|      *
 | |
|      * NOTE: assignments below are not necessary, but without them
 | |
|      *       MSVC complains about unitialized variables.
 | |
|      */
 | |
|     nc = 0;
 | |
|     rmax = (double)(0);
 | |
|     layerscnt = 0;
 | |
|     modelstatus = ae_false;
 | |
|     if( algorithmtype==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Add RBF model.
 | |
|          * This model uses local KD-trees to speed-up nearest neighbor searches.
 | |
|          */
 | |
|         nc = n;
 | |
|         ae_matrix_set_length(&xc, nc, rbfv1_mxnx, _state);
 | |
|         for(i=0; i<=nc-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|             {
 | |
|                 xc.ptr.pp_double[i][j] = x->ptr.pp_double[i][j];
 | |
|             }
 | |
|         }
 | |
|         rmax = (double)(0);
 | |
|         ae_vector_set_length(&radius, nc, _state);
 | |
|         ae_vector_set_length(&ctags, nc, _state);
 | |
|         for(i=0; i<=nc-1; i++)
 | |
|         {
 | |
|             ctags.ptr.p_int[i] = i;
 | |
|         }
 | |
|         kdtreebuildtagged(&xc, &ctags, nc, rbfv1_mxnx, 0, 2, &ctree, _state);
 | |
|         if( nc==0 )
 | |
|         {
 | |
|             rmax = (double)(1);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if( nc==1 )
 | |
|             {
 | |
|                 radius.ptr.p_double[0] = radvalue;
 | |
|                 rmax = radius.ptr.p_double[0];
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * NC>1, calculate radii using distances to nearest neigbors
 | |
|                  */
 | |
|                 for(i=0; i<=nc-1; i++)
 | |
|                 {
 | |
|                     for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|                     {
 | |
|                         xcx.ptr.p_double[j] = xc.ptr.pp_double[i][j];
 | |
|                     }
 | |
|                     if( kdtreequeryknn(&ctree, &xcx, 1, ae_false, _state)>0 )
 | |
|                     {
 | |
|                         kdtreequeryresultsdistances(&ctree, &dist, _state);
 | |
|                         radius.ptr.p_double[i] = radvalue*dist.ptr.p_double[0];
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         
 | |
|                         /*
 | |
|                          * No neighbors found (it will happen when we have only one center).
 | |
|                          * Initialize radius with default value.
 | |
|                          */
 | |
|                         radius.ptr.p_double[i] = 1.0;
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * Apply filtering
 | |
|                  */
 | |
|                 rvectorsetlengthatleast(&tmp0, nc, _state);
 | |
|                 for(i=0; i<=nc-1; i++)
 | |
|                 {
 | |
|                     tmp0.ptr.p_double[i] = radius.ptr.p_double[i];
 | |
|                 }
 | |
|                 tagsortfast(&tmp0, &tmp1, nc, _state);
 | |
|                 for(i=0; i<=nc-1; i++)
 | |
|                 {
 | |
|                     radius.ptr.p_double[i] = ae_minreal(radius.ptr.p_double[i], radzvalue*tmp0.ptr.p_double[nc/2], _state);
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * Calculate RMax, check that all radii are non-zero
 | |
|                  */
 | |
|                 for(i=0; i<=nc-1; i++)
 | |
|                 {
 | |
|                     rmax = ae_maxreal(rmax, radius.ptr.p_double[i], _state);
 | |
|                 }
 | |
|                 for(i=0; i<=nc-1; i++)
 | |
|                 {
 | |
|                     if( ae_fp_eq(radius.ptr.p_double[i],(double)(0)) )
 | |
|                     {
 | |
|                         rep->terminationtype = -5;
 | |
|                         ae_frame_leave(_state);
 | |
|                         return;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         ivectorsetlengthatleast(&tags, n, _state);
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             tags.ptr.p_int[i] = i;
 | |
|         }
 | |
|         kdtreebuildtagged(x, &tags, n, rbfv1_mxnx, 0, 2, &tree, _state);
 | |
|         rbfv1_buildrbfmodellsqr(x, &residualy, &xc, &radius, n, nc, s->ny, &tree, &ctree, epsort, epserr, maxits, &rep->annz, &snnz, &omega, &rep->terminationtype, &rep->iterationscount, &rep->nmv, _state);
 | |
|         layerscnt = 1;
 | |
|         modelstatus = ae_true;
 | |
|     }
 | |
|     if( algorithmtype==2 )
 | |
|     {
 | |
|         rmax = radvalue;
 | |
|         rbfv1_buildrbfmlayersmodellsqr(x, &residualy, &xc, radvalue, &radius, n, &nc, s->ny, nlayers, &ctree, 1.0E-6, 1.0E-6, 50, lambdav, &rep->annz, &omega, &rep->terminationtype, &rep->iterationscount, &rep->nmv, _state);
 | |
|         layerscnt = nlayers;
 | |
|         modelstatus = ae_true;
 | |
|     }
 | |
|     ae_assert(modelstatus, "RBFBuildModel: integrity error", _state);
 | |
|     if( rep->terminationtype<=0 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Model is built
 | |
|      */
 | |
|     s->nc = nc/layerscnt;
 | |
|     s->rmax = rmax;
 | |
|     s->nl = layerscnt;
 | |
|     ae_matrix_set_length(&s->xc, s->nc, rbfv1_mxnx, _state);
 | |
|     ae_matrix_set_length(&s->wr, s->nc, 1+s->nl*s->ny, _state);
 | |
|     ae_matrix_set_length(&s->v, s->ny, rbfv1_mxnx+1, _state);
 | |
|     for(i=0; i<=s->nc-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|         {
 | |
|             s->xc.ptr.pp_double[i][j] = xc.ptr.pp_double[i][j];
 | |
|         }
 | |
|     }
 | |
|     ivectorsetlengthatleast(&tags, s->nc, _state);
 | |
|     for(i=0; i<=s->nc-1; i++)
 | |
|     {
 | |
|         tags.ptr.p_int[i] = i;
 | |
|     }
 | |
|     kdtreebuildtagged(&s->xc, &tags, s->nc, rbfv1_mxnx, 0, 2, &s->tree, _state);
 | |
|     for(i=0; i<=s->nc-1; i++)
 | |
|     {
 | |
|         s->wr.ptr.pp_double[i][0] = radius.ptr.p_double[i];
 | |
|         for(k=0; k<=layerscnt-1; k++)
 | |
|         {
 | |
|             for(j=0; j<=s->ny-1; j++)
 | |
|             {
 | |
|                 s->wr.ptr.pp_double[i][1+k*s->ny+j] = omega.ptr.pp_double[k*s->nc+i][j];
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=s->ny-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=rbfv1_mxnx; j++)
 | |
|         {
 | |
|             s->v.ptr.pp_double[i][j] = v.ptr.pp_double[i][j];
 | |
|         }
 | |
|     }
 | |
|     rep->terminationtype = 1;
 | |
|     rep->arows = n;
 | |
|     rep->acols = s->nc;
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: allocation
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.02.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv1alloc(ae_serializer* s, rbfv1model* model, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Data
 | |
|      */
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     kdtreealloc(s, &model->tree, _state);
 | |
|     allocrealmatrix(s, &model->xc, -1, -1, _state);
 | |
|     allocrealmatrix(s, &model->wr, -1, -1, _state);
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     allocrealmatrix(s, &model->v, -1, -1, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: serialization
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.02.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv1serialize(ae_serializer* s, rbfv1model* model, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Data
 | |
|      */
 | |
|     ae_serializer_serialize_int(s, model->nx, _state);
 | |
|     ae_serializer_serialize_int(s, model->ny, _state);
 | |
|     ae_serializer_serialize_int(s, model->nc, _state);
 | |
|     ae_serializer_serialize_int(s, model->nl, _state);
 | |
|     kdtreeserialize(s, &model->tree, _state);
 | |
|     serializerealmatrix(s, &model->xc, -1, -1, _state);
 | |
|     serializerealmatrix(s, &model->wr, -1, -1, _state);
 | |
|     ae_serializer_serialize_double(s, model->rmax, _state);
 | |
|     serializerealmatrix(s, &model->v, -1, -1, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: unserialization
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.02.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv1unserialize(ae_serializer* s,
 | |
|      rbfv1model* model,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
| 
 | |
|     _rbfv1model_clear(model);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Unserialize primary model parameters, initialize model.
 | |
|      *
 | |
|      * It is necessary to call RBFCreate() because some internal fields
 | |
|      * which are NOT unserialized will need initialization.
 | |
|      */
 | |
|     ae_serializer_unserialize_int(s, &nx, _state);
 | |
|     ae_serializer_unserialize_int(s, &ny, _state);
 | |
|     rbfv1create(nx, ny, model, _state);
 | |
|     ae_serializer_unserialize_int(s, &model->nc, _state);
 | |
|     ae_serializer_unserialize_int(s, &model->nl, _state);
 | |
|     kdtreeunserialize(s, &model->tree, _state);
 | |
|     unserializerealmatrix(s, &model->xc, _state);
 | |
|     unserializerealmatrix(s, &model->wr, _state);
 | |
|     ae_serializer_unserialize_double(s, &model->rmax, _state);
 | |
|     unserializerealmatrix(s, &model->v, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model in the given point.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=2
 | |
| (2-dimensional space). If you have 3-dimensional space, use RBFCalc3(). If
 | |
| you have general situation (NX-dimensional space, NY-dimensional function)
 | |
| you should use general, less efficient implementation RBFCalc().
 | |
| 
 | |
| If  you  want  to  calculate  function  values  many times, consider using 
 | |
| RBFGridCalc2(), which is far more efficient than many subsequent calls  to
 | |
| RBFCalc2().
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>2
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   first coordinate, finite number
 | |
|     X1      -   second coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfv1calc2(rbfv1model* s, double x0, double x1, ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t lx;
 | |
|     ae_int_t tg;
 | |
|     double d2;
 | |
|     double t;
 | |
|     double bfcur;
 | |
|     double rcur;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state);
 | |
|     ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state);
 | |
|     if( s->ny!=1||s->nx!=2 )
 | |
|     {
 | |
|         result = (double)(0);
 | |
|         return result;
 | |
|     }
 | |
|     result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][rbfv1_mxnx];
 | |
|     if( s->nc==0 )
 | |
|     {
 | |
|         return result;
 | |
|     }
 | |
|     rvectorsetlengthatleast(&s->calcbufxcx, rbfv1_mxnx, _state);
 | |
|     for(i=0; i<=rbfv1_mxnx-1; i++)
 | |
|     {
 | |
|         s->calcbufxcx.ptr.p_double[i] = 0.0;
 | |
|     }
 | |
|     s->calcbufxcx.ptr.p_double[0] = x0;
 | |
|     s->calcbufxcx.ptr.p_double[1] = x1;
 | |
|     lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state);
 | |
|     kdtreequeryresultsx(&s->tree, &s->calcbufx, _state);
 | |
|     kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state);
 | |
|     for(i=0; i<=lx-1; i++)
 | |
|     {
 | |
|         tg = s->calcbuftags.ptr.p_int[i];
 | |
|         d2 = ae_sqr(x0-s->calcbufx.ptr.pp_double[i][0], _state)+ae_sqr(x1-s->calcbufx.ptr.pp_double[i][1], _state);
 | |
|         rcur = s->wr.ptr.pp_double[tg][0];
 | |
|         bfcur = ae_exp(-d2/(rcur*rcur), _state);
 | |
|         for(j=0; j<=s->nl-1; j++)
 | |
|         {
 | |
|             result = result+bfcur*s->wr.ptr.pp_double[tg][1+j];
 | |
|             rcur = 0.5*rcur;
 | |
|             t = bfcur*bfcur;
 | |
|             bfcur = t*t;
 | |
|         }
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model in the given point.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=3
 | |
| (3-dimensional space). If you have 2-dimensional space, use RBFCalc2(). If
 | |
| you have general situation (NX-dimensional space, NY-dimensional function)
 | |
| you should use general, less efficient implementation RBFCalc().
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>3
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   first coordinate, finite number
 | |
|     X1      -   second coordinate, finite number
 | |
|     X2      -   third coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfv1calc3(rbfv1model* s,
 | |
|      double x0,
 | |
|      double x1,
 | |
|      double x2,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t lx;
 | |
|     ae_int_t tg;
 | |
|     double t;
 | |
|     double rcur;
 | |
|     double bf;
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state);
 | |
|     ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state);
 | |
|     ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state);
 | |
|     if( s->ny!=1||s->nx!=3 )
 | |
|     {
 | |
|         result = (double)(0);
 | |
|         return result;
 | |
|     }
 | |
|     result = s->v.ptr.pp_double[0][0]*x0+s->v.ptr.pp_double[0][1]*x1+s->v.ptr.pp_double[0][2]*x2+s->v.ptr.pp_double[0][rbfv1_mxnx];
 | |
|     if( s->nc==0 )
 | |
|     {
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * calculating value for F(X)
 | |
|      */
 | |
|     rvectorsetlengthatleast(&s->calcbufxcx, rbfv1_mxnx, _state);
 | |
|     for(i=0; i<=rbfv1_mxnx-1; i++)
 | |
|     {
 | |
|         s->calcbufxcx.ptr.p_double[i] = 0.0;
 | |
|     }
 | |
|     s->calcbufxcx.ptr.p_double[0] = x0;
 | |
|     s->calcbufxcx.ptr.p_double[1] = x1;
 | |
|     s->calcbufxcx.ptr.p_double[2] = x2;
 | |
|     lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state);
 | |
|     kdtreequeryresultsx(&s->tree, &s->calcbufx, _state);
 | |
|     kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state);
 | |
|     for(i=0; i<=lx-1; i++)
 | |
|     {
 | |
|         tg = s->calcbuftags.ptr.p_int[i];
 | |
|         rcur = s->wr.ptr.pp_double[tg][0];
 | |
|         bf = ae_exp(-(ae_sqr(x0-s->calcbufx.ptr.pp_double[i][0], _state)+ae_sqr(x1-s->calcbufx.ptr.pp_double[i][1], _state)+ae_sqr(x2-s->calcbufx.ptr.pp_double[i][2], _state))/ae_sqr(rcur, _state), _state);
 | |
|         for(j=0; j<=s->nl-1; j++)
 | |
|         {
 | |
|             result = result+bf*s->wr.ptr.pp_double[tg][1+j];
 | |
|             t = bf*bf;
 | |
|             bf = t*t;
 | |
|         }
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the given point.
 | |
| 
 | |
| Same as RBFCalc(), but does not reallocate Y when in is large enough to 
 | |
| store function values.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X       -   coordinates, array[NX].
 | |
|                 X may have more than NX elements, in this case only 
 | |
|                 leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv1calcbuf(rbfv1model* s,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t lx;
 | |
|     ae_int_t tg;
 | |
|     double t;
 | |
|     double rcur;
 | |
|     double bf;
 | |
| 
 | |
| 
 | |
|     ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)<NX", _state);
 | |
|     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state);
 | |
|     if( y->cnt<s->ny )
 | |
|     {
 | |
|         ae_vector_set_length(y, s->ny, _state);
 | |
|     }
 | |
|     for(i=0; i<=s->ny-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[i] = s->v.ptr.pp_double[i][rbfv1_mxnx];
 | |
|         for(j=0; j<=s->nx-1; j++)
 | |
|         {
 | |
|             y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j];
 | |
|         }
 | |
|     }
 | |
|     if( s->nc==0 )
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
|     rvectorsetlengthatleast(&s->calcbufxcx, rbfv1_mxnx, _state);
 | |
|     for(i=0; i<=rbfv1_mxnx-1; i++)
 | |
|     {
 | |
|         s->calcbufxcx.ptr.p_double[i] = 0.0;
 | |
|     }
 | |
|     for(i=0; i<=s->nx-1; i++)
 | |
|     {
 | |
|         s->calcbufxcx.ptr.p_double[i] = x->ptr.p_double[i];
 | |
|     }
 | |
|     lx = kdtreequeryrnn(&s->tree, &s->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state);
 | |
|     kdtreequeryresultsx(&s->tree, &s->calcbufx, _state);
 | |
|     kdtreequeryresultstags(&s->tree, &s->calcbuftags, _state);
 | |
|     for(i=0; i<=s->ny-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=lx-1; j++)
 | |
|         {
 | |
|             tg = s->calcbuftags.ptr.p_int[j];
 | |
|             rcur = s->wr.ptr.pp_double[tg][0];
 | |
|             bf = ae_exp(-(ae_sqr(s->calcbufxcx.ptr.p_double[0]-s->calcbufx.ptr.pp_double[j][0], _state)+ae_sqr(s->calcbufxcx.ptr.p_double[1]-s->calcbufx.ptr.pp_double[j][1], _state)+ae_sqr(s->calcbufxcx.ptr.p_double[2]-s->calcbufx.ptr.pp_double[j][2], _state))/ae_sqr(rcur, _state), _state);
 | |
|             for(k=0; k<=s->nl-1; k++)
 | |
|             {
 | |
|                 y->ptr.p_double[i] = y->ptr.p_double[i]+bf*s->wr.ptr.pp_double[tg][1+k*s->ny+i];
 | |
|                 t = bf*bf;
 | |
|                 bf = t*t;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the given point, using
 | |
| external  buffer  object  (internal  temporaries  of  RBF  model  are  not
 | |
| modified).
 | |
| 
 | |
| This function allows to use same RBF model object  in  different  threads,
 | |
| assuming  that  different   threads  use  different  instances  of  buffer
 | |
| structure.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, may be shared between different threads
 | |
|     Buf     -   buffer object created for this particular instance of  RBF
 | |
|                 model with rbfcreatecalcbuffer().
 | |
|     X       -   coordinates, array[NX].
 | |
|                 X may have more than NX elements, in this case only 
 | |
|                 leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv1tscalcbuf(rbfv1model* s,
 | |
|      rbfv1calcbuffer* buf,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t lx;
 | |
|     ae_int_t tg;
 | |
|     double t;
 | |
|     double rcur;
 | |
|     double bf;
 | |
| 
 | |
| 
 | |
|     ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)<NX", _state);
 | |
|     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state);
 | |
|     if( y->cnt<s->ny )
 | |
|     {
 | |
|         ae_vector_set_length(y, s->ny, _state);
 | |
|     }
 | |
|     for(i=0; i<=s->ny-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[i] = s->v.ptr.pp_double[i][rbfv1_mxnx];
 | |
|         for(j=0; j<=s->nx-1; j++)
 | |
|         {
 | |
|             y->ptr.p_double[i] = y->ptr.p_double[i]+s->v.ptr.pp_double[i][j]*x->ptr.p_double[j];
 | |
|         }
 | |
|     }
 | |
|     if( s->nc==0 )
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
|     rvectorsetlengthatleast(&buf->calcbufxcx, rbfv1_mxnx, _state);
 | |
|     for(i=0; i<=rbfv1_mxnx-1; i++)
 | |
|     {
 | |
|         buf->calcbufxcx.ptr.p_double[i] = 0.0;
 | |
|     }
 | |
|     for(i=0; i<=s->nx-1; i++)
 | |
|     {
 | |
|         buf->calcbufxcx.ptr.p_double[i] = x->ptr.p_double[i];
 | |
|     }
 | |
|     lx = kdtreetsqueryrnn(&s->tree, &buf->requestbuffer, &buf->calcbufxcx, s->rmax*rbfv1_rbffarradius, ae_true, _state);
 | |
|     kdtreetsqueryresultsx(&s->tree, &buf->requestbuffer, &buf->calcbufx, _state);
 | |
|     kdtreetsqueryresultstags(&s->tree, &buf->requestbuffer, &buf->calcbuftags, _state);
 | |
|     for(i=0; i<=s->ny-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=lx-1; j++)
 | |
|         {
 | |
|             tg = buf->calcbuftags.ptr.p_int[j];
 | |
|             rcur = s->wr.ptr.pp_double[tg][0];
 | |
|             bf = ae_exp(-(ae_sqr(buf->calcbufxcx.ptr.p_double[0]-buf->calcbufx.ptr.pp_double[j][0], _state)+ae_sqr(buf->calcbufxcx.ptr.p_double[1]-buf->calcbufx.ptr.pp_double[j][1], _state)+ae_sqr(buf->calcbufxcx.ptr.p_double[2]-buf->calcbufx.ptr.pp_double[j][2], _state))/ae_sqr(rcur, _state), _state);
 | |
|             for(k=0; k<=s->nl-1; k++)
 | |
|             {
 | |
|                 y->ptr.p_double[i] = y->ptr.p_double[i]+bf*s->wr.ptr.pp_double[tg][1+k*s->ny+i];
 | |
|                 t = bf*bf;
 | |
|                 bf = t*t;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the regular grid.
 | |
| 
 | |
| Grid have N0*N1 points, with Point[I,J] = (X0[I], X1[J])
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>2
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   array of grid nodes, first coordinates, array[N0]
 | |
|     N0      -   grid size (number of nodes) in the first dimension
 | |
|     X1      -   array of grid nodes, second coordinates, array[N1]
 | |
|     N1      -   grid size (number of nodes) in the second dimension
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function values, array[N0,N1]. Y is out-variable and 
 | |
|                 is reallocated by this function.
 | |
|                 
 | |
| NOTE: as a special exception, this function supports unordered  arrays  X0
 | |
|       and X1. However, future versions may be  more  efficient  for  X0/X1
 | |
|       ordered by ascending.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv1gridcalc2(rbfv1model* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector cpx0;
 | |
|     ae_vector cpx1;
 | |
|     ae_vector p01;
 | |
|     ae_vector p11;
 | |
|     ae_vector p2;
 | |
|     double rlimit;
 | |
|     double xcnorm2;
 | |
|     ae_int_t hp01;
 | |
|     double hcpx0;
 | |
|     double xc0;
 | |
|     double xc1;
 | |
|     double omega;
 | |
|     double radius;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t d;
 | |
|     ae_int_t i00;
 | |
|     ae_int_t i01;
 | |
|     ae_int_t i10;
 | |
|     ae_int_t i11;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&cpx0, 0, sizeof(cpx0));
 | |
|     memset(&cpx1, 0, sizeof(cpx1));
 | |
|     memset(&p01, 0, sizeof(p01));
 | |
|     memset(&p11, 0, sizeof(p11));
 | |
|     memset(&p2, 0, sizeof(p2));
 | |
|     ae_matrix_clear(y);
 | |
|     ae_vector_init(&cpx0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&cpx1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p01, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&p11, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state);
 | |
|     ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state);
 | |
|     ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)<N0", _state);
 | |
|     ae_assert(x1->cnt>=n1, "RBFGridCalc2: Length(X1)<N1", _state);
 | |
|     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2: X0 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2: X1 contains infinite or NaN values!", _state);
 | |
|     ae_matrix_set_length(y, n0, n1, _state);
 | |
|     for(i=0; i<=n0-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=n1-1; j++)
 | |
|         {
 | |
|             y->ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     if( (s->ny!=1||s->nx!=2)||s->nc==0 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      *create and sort arrays
 | |
|      */
 | |
|     ae_vector_set_length(&cpx0, n0, _state);
 | |
|     for(i=0; i<=n0-1; i++)
 | |
|     {
 | |
|         cpx0.ptr.p_double[i] = x0->ptr.p_double[i];
 | |
|     }
 | |
|     tagsort(&cpx0, n0, &p01, &p2, _state);
 | |
|     ae_vector_set_length(&cpx1, n1, _state);
 | |
|     for(i=0; i<=n1-1; i++)
 | |
|     {
 | |
|         cpx1.ptr.p_double[i] = x1->ptr.p_double[i];
 | |
|     }
 | |
|     tagsort(&cpx1, n1, &p11, &p2, _state);
 | |
|     
 | |
|     /*
 | |
|      *calculate function's value
 | |
|      */
 | |
|     for(i=0; i<=s->nc-1; i++)
 | |
|     {
 | |
|         radius = s->wr.ptr.pp_double[i][0];
 | |
|         for(d=0; d<=s->nl-1; d++)
 | |
|         {
 | |
|             omega = s->wr.ptr.pp_double[i][1+d];
 | |
|             rlimit = radius*rbfv1_rbffarradius;
 | |
|             
 | |
|             /*
 | |
|              *search lower and upper indexes
 | |
|              */
 | |
|             i00 = lowerbound(&cpx0, n0, s->xc.ptr.pp_double[i][0]-rlimit, _state);
 | |
|             i01 = upperbound(&cpx0, n0, s->xc.ptr.pp_double[i][0]+rlimit, _state);
 | |
|             i10 = lowerbound(&cpx1, n1, s->xc.ptr.pp_double[i][1]-rlimit, _state);
 | |
|             i11 = upperbound(&cpx1, n1, s->xc.ptr.pp_double[i][1]+rlimit, _state);
 | |
|             xc0 = s->xc.ptr.pp_double[i][0];
 | |
|             xc1 = s->xc.ptr.pp_double[i][1];
 | |
|             for(j=i00; j<=i01-1; j++)
 | |
|             {
 | |
|                 hcpx0 = cpx0.ptr.p_double[j];
 | |
|                 hp01 = p01.ptr.p_int[j];
 | |
|                 for(k=i10; k<=i11-1; k++)
 | |
|                 {
 | |
|                     xcnorm2 = ae_sqr(hcpx0-xc0, _state)+ae_sqr(cpx1.ptr.p_double[k]-xc1, _state);
 | |
|                     if( ae_fp_less_eq(xcnorm2,rlimit*rlimit) )
 | |
|                     {
 | |
|                         y->ptr.pp_double[hp01][p11.ptr.p_int[k]] = y->ptr.pp_double[hp01][p11.ptr.p_int[k]]+ae_exp(-xcnorm2/ae_sqr(radius, _state), _state)*omega;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             radius = 0.5*radius;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      *add linear term
 | |
|      */
 | |
|     for(i=0; i<=n0-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=n1-1; j++)
 | |
|         {
 | |
|             y->ptr.pp_double[i][j] = y->ptr.pp_double[i][j]+s->v.ptr.pp_double[0][0]*x0->ptr.p_double[i]+s->v.ptr.pp_double[0][1]*x1->ptr.p_double[j]+s->v.ptr.pp_double[0][rbfv1_mxnx];
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| void rbfv1gridcalc3vrec(rbfv1model* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      ae_int_t n2,
 | |
|      /* Integer */ ae_vector* blocks0,
 | |
|      ae_int_t block0a,
 | |
|      ae_int_t block0b,
 | |
|      /* Integer */ ae_vector* blocks1,
 | |
|      ae_int_t block1a,
 | |
|      ae_int_t block1b,
 | |
|      /* Integer */ ae_vector* blocks2,
 | |
|      ae_int_t block2a,
 | |
|      ae_int_t block2b,
 | |
|      /* Boolean */ ae_vector* flagy,
 | |
|      ae_bool sparsey,
 | |
|      double searchradius,
 | |
|      double avgfuncpernode,
 | |
|      ae_shared_pool* bufpool,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t t;
 | |
|     ae_int_t l;
 | |
|     ae_int_t i0;
 | |
|     ae_int_t i1;
 | |
|     ae_int_t i2;
 | |
|     ae_int_t ic;
 | |
|     gridcalc3v1buf *pbuf;
 | |
|     ae_smart_ptr _pbuf;
 | |
|     ae_int_t flag12dim1;
 | |
|     ae_int_t flag12dim2;
 | |
|     double problemcost;
 | |
|     ae_int_t maxbs;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
|     double v;
 | |
|     ae_int_t kc;
 | |
|     ae_int_t tg;
 | |
|     double rcur;
 | |
|     double rcur2;
 | |
|     double basisfuncval;
 | |
|     ae_int_t dstoffs;
 | |
|     ae_int_t srcoffs;
 | |
|     ae_int_t ubnd;
 | |
|     double w0;
 | |
|     double w1;
 | |
|     double w2;
 | |
|     ae_bool allnodes;
 | |
|     ae_bool somenodes;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_pbuf, 0, sizeof(_pbuf));
 | |
|     ae_smart_ptr_init(&_pbuf, (void**)&pbuf, _state, ae_true);
 | |
| 
 | |
|     nx = s->nx;
 | |
|     ny = s->ny;
 | |
|     
 | |
|     /*
 | |
|      * Try to split large problem
 | |
|      */
 | |
|     problemcost = (s->nl+1)*s->ny*2*(avgfuncpernode+1);
 | |
|     problemcost = problemcost*(blocks0->ptr.p_int[block0b]-blocks0->ptr.p_int[block0a]);
 | |
|     problemcost = problemcost*(blocks1->ptr.p_int[block1b]-blocks1->ptr.p_int[block1a]);
 | |
|     problemcost = problemcost*(blocks2->ptr.p_int[block2b]-blocks2->ptr.p_int[block2a]);
 | |
|     maxbs = 0;
 | |
|     maxbs = ae_maxint(maxbs, block0b-block0a, _state);
 | |
|     maxbs = ae_maxint(maxbs, block1b-block1a, _state);
 | |
|     maxbs = ae_maxint(maxbs, block2b-block2a, _state);
 | |
|     if( ae_fp_greater_eq(problemcost,rbfv1_minbasecasecost)&&maxbs>=2 )
 | |
|     {
 | |
|         if( block0b-block0a==maxbs )
 | |
|         {
 | |
|             rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a, block0a+maxbs/2, blocks1, block1a, block1b, blocks2, block2a, block2b, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state);
 | |
|             rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a+maxbs/2, block0b, blocks1, block1a, block1b, blocks2, block2a, block2b, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state);
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( block1b-block1a==maxbs )
 | |
|         {
 | |
|             rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a, block0b, blocks1, block1a, block1a+maxbs/2, blocks2, block2a, block2b, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state);
 | |
|             rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a, block0b, blocks1, block1a+maxbs/2, block1b, blocks2, block2a, block2b, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state);
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         if( block2b-block2a==maxbs )
 | |
|         {
 | |
|             rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, block2a, block2a+maxbs/2, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state);
 | |
|             rbfv1gridcalc3vrec(s, x0, n0, x1, n1, x2, n2, blocks0, block0a, block0b, blocks1, block1a, block1b, blocks2, block2a+maxbs/2, block2b, flagy, sparsey, searchradius, avgfuncpernode, bufpool, y, _state);
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Retrieve buffer object from pool (it will be returned later)
 | |
|      */
 | |
|     ae_shared_pool_retrieve(bufpool, &_pbuf, _state);
 | |
|     
 | |
|     /*
 | |
|      * Calculate RBF model
 | |
|      */
 | |
|     for(i2=block2a; i2<=block2b-1; i2++)
 | |
|     {
 | |
|         for(i1=block1a; i1<=block1b-1; i1++)
 | |
|         {
 | |
|             for(i0=block0a; i0<=block0b-1; i0++)
 | |
|             {
 | |
|                 
 | |
|                 /*
 | |
|                  * Analyze block - determine what elements are needed and what are not.
 | |
|                  *
 | |
|                  * After this block is done, two flag variables can be used:
 | |
|                  * * SomeNodes, which is True when there are at least one node which have
 | |
|                  *   to be calculated
 | |
|                  * * AllNodes, which is True when all nodes are required
 | |
|                  */
 | |
|                 somenodes = ae_true;
 | |
|                 allnodes = ae_true;
 | |
|                 flag12dim1 = blocks1->ptr.p_int[i1+1]-blocks1->ptr.p_int[i1];
 | |
|                 flag12dim2 = blocks2->ptr.p_int[i2+1]-blocks2->ptr.p_int[i2];
 | |
|                 if( sparsey )
 | |
|                 {
 | |
|                     
 | |
|                     /*
 | |
|                      * Use FlagY to determine what is required.
 | |
|                      */
 | |
|                     bvectorsetlengthatleast(&pbuf->flag0, n0, _state);
 | |
|                     bvectorsetlengthatleast(&pbuf->flag1, n1, _state);
 | |
|                     bvectorsetlengthatleast(&pbuf->flag2, n2, _state);
 | |
|                     bvectorsetlengthatleast(&pbuf->flag12, flag12dim1*flag12dim2, _state);
 | |
|                     for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++)
 | |
|                     {
 | |
|                         pbuf->flag0.ptr.p_bool[i] = ae_false;
 | |
|                     }
 | |
|                     for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++)
 | |
|                     {
 | |
|                         pbuf->flag1.ptr.p_bool[j] = ae_false;
 | |
|                     }
 | |
|                     for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++)
 | |
|                     {
 | |
|                         pbuf->flag2.ptr.p_bool[k] = ae_false;
 | |
|                     }
 | |
|                     for(i=0; i<=flag12dim1*flag12dim2-1; i++)
 | |
|                     {
 | |
|                         pbuf->flag12.ptr.p_bool[i] = ae_false;
 | |
|                     }
 | |
|                     somenodes = ae_false;
 | |
|                     allnodes = ae_true;
 | |
|                     for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++)
 | |
|                     {
 | |
|                         for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++)
 | |
|                         {
 | |
|                             dstoffs = j-blocks1->ptr.p_int[i1]+flag12dim1*(k-blocks2->ptr.p_int[i2]);
 | |
|                             srcoffs = j*n0+k*n0*n1;
 | |
|                             for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++)
 | |
|                             {
 | |
|                                 if( flagy->ptr.p_bool[srcoffs+i] )
 | |
|                                 {
 | |
|                                     pbuf->flag0.ptr.p_bool[i] = ae_true;
 | |
|                                     pbuf->flag1.ptr.p_bool[j] = ae_true;
 | |
|                                     pbuf->flag2.ptr.p_bool[k] = ae_true;
 | |
|                                     pbuf->flag12.ptr.p_bool[dstoffs] = ae_true;
 | |
|                                     somenodes = ae_true;
 | |
|                                 }
 | |
|                                 else
 | |
|                                 {
 | |
|                                     allnodes = ae_false;
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * Skip block if it is completely empty.
 | |
|                  */
 | |
|                 if( !somenodes )
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * compute linear term for block (I0,I1,I2)
 | |
|                  */
 | |
|                 for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++)
 | |
|                 {
 | |
|                     for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++)
 | |
|                     {
 | |
|                         
 | |
|                         /*
 | |
|                          * do we need this micro-row?
 | |
|                          */
 | |
|                         if( !allnodes&&!pbuf->flag12.ptr.p_bool[j-blocks1->ptr.p_int[i1]+flag12dim1*(k-blocks2->ptr.p_int[i2])] )
 | |
|                         {
 | |
|                             continue;
 | |
|                         }
 | |
|                         
 | |
|                         /*
 | |
|                          * Compute linear term
 | |
|                          */
 | |
|                         for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++)
 | |
|                         {
 | |
|                             pbuf->tx.ptr.p_double[0] = x0->ptr.p_double[i];
 | |
|                             pbuf->tx.ptr.p_double[1] = x1->ptr.p_double[j];
 | |
|                             pbuf->tx.ptr.p_double[2] = x2->ptr.p_double[k];
 | |
|                             for(l=0; l<=s->ny-1; l++)
 | |
|                             {
 | |
|                                 v = s->v.ptr.pp_double[l][rbfv1_mxnx];
 | |
|                                 for(t=0; t<=nx-1; t++)
 | |
|                                 {
 | |
|                                     v = v+s->v.ptr.pp_double[l][t]*pbuf->tx.ptr.p_double[t];
 | |
|                                 }
 | |
|                                 y->ptr.p_double[l+ny*(i+j*n0+k*n0*n1)] = v;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 /*
 | |
|                  * compute RBF term for block (I0,I1,I2)
 | |
|                  */
 | |
|                 pbuf->tx.ptr.p_double[0] = 0.5*(x0->ptr.p_double[blocks0->ptr.p_int[i0]]+x0->ptr.p_double[blocks0->ptr.p_int[i0+1]-1]);
 | |
|                 pbuf->tx.ptr.p_double[1] = 0.5*(x1->ptr.p_double[blocks1->ptr.p_int[i1]]+x1->ptr.p_double[blocks1->ptr.p_int[i1+1]-1]);
 | |
|                 pbuf->tx.ptr.p_double[2] = 0.5*(x2->ptr.p_double[blocks2->ptr.p_int[i2]]+x2->ptr.p_double[blocks2->ptr.p_int[i2+1]-1]);
 | |
|                 kc = kdtreetsqueryrnn(&s->tree, &pbuf->requestbuf, &pbuf->tx, searchradius, ae_true, _state);
 | |
|                 kdtreetsqueryresultsx(&s->tree, &pbuf->requestbuf, &pbuf->calcbufx, _state);
 | |
|                 kdtreetsqueryresultstags(&s->tree, &pbuf->requestbuf, &pbuf->calcbuftags, _state);
 | |
|                 for(ic=0; ic<=kc-1; ic++)
 | |
|                 {
 | |
|                     pbuf->cx.ptr.p_double[0] = pbuf->calcbufx.ptr.pp_double[ic][0];
 | |
|                     pbuf->cx.ptr.p_double[1] = pbuf->calcbufx.ptr.pp_double[ic][1];
 | |
|                     pbuf->cx.ptr.p_double[2] = pbuf->calcbufx.ptr.pp_double[ic][2];
 | |
|                     tg = pbuf->calcbuftags.ptr.p_int[ic];
 | |
|                     rcur = s->wr.ptr.pp_double[tg][0];
 | |
|                     rcur2 = rcur*rcur;
 | |
|                     for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++)
 | |
|                     {
 | |
|                         if( allnodes||pbuf->flag0.ptr.p_bool[i] )
 | |
|                         {
 | |
|                             pbuf->expbuf0.ptr.p_double[i] = ae_exp(-ae_sqr(x0->ptr.p_double[i]-pbuf->cx.ptr.p_double[0], _state)/rcur2, _state);
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             pbuf->expbuf0.ptr.p_double[i] = 0.0;
 | |
|                         }
 | |
|                     }
 | |
|                     for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++)
 | |
|                     {
 | |
|                         if( allnodes||pbuf->flag1.ptr.p_bool[j] )
 | |
|                         {
 | |
|                             pbuf->expbuf1.ptr.p_double[j] = ae_exp(-ae_sqr(x1->ptr.p_double[j]-pbuf->cx.ptr.p_double[1], _state)/rcur2, _state);
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             pbuf->expbuf1.ptr.p_double[j] = 0.0;
 | |
|                         }
 | |
|                     }
 | |
|                     for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++)
 | |
|                     {
 | |
|                         if( allnodes||pbuf->flag2.ptr.p_bool[k] )
 | |
|                         {
 | |
|                             pbuf->expbuf2.ptr.p_double[k] = ae_exp(-ae_sqr(x2->ptr.p_double[k]-pbuf->cx.ptr.p_double[2], _state)/rcur2, _state);
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             pbuf->expbuf2.ptr.p_double[k] = 0.0;
 | |
|                         }
 | |
|                     }
 | |
|                     for(t=0; t<=s->nl-1; t++)
 | |
|                     {
 | |
|                         
 | |
|                         /*
 | |
|                          * Calculate
 | |
|                          */
 | |
|                         for(k=blocks2->ptr.p_int[i2]; k<=blocks2->ptr.p_int[i2+1]-1; k++)
 | |
|                         {
 | |
|                             for(j=blocks1->ptr.p_int[i1]; j<=blocks1->ptr.p_int[i1+1]-1; j++)
 | |
|                             {
 | |
|                                 
 | |
|                                 /*
 | |
|                                  * do we need this micro-row?
 | |
|                                  */
 | |
|                                 if( !allnodes&&!pbuf->flag12.ptr.p_bool[j-blocks1->ptr.p_int[i1]+flag12dim1*(k-blocks2->ptr.p_int[i2])] )
 | |
|                                 {
 | |
|                                     continue;
 | |
|                                 }
 | |
|                                 
 | |
|                                 /*
 | |
|                                  * Prepare local variables
 | |
|                                  */
 | |
|                                 dstoffs = ny*(blocks0->ptr.p_int[i0]+j*n0+k*n0*n1);
 | |
|                                 v = pbuf->expbuf1.ptr.p_double[j]*pbuf->expbuf2.ptr.p_double[k];
 | |
|                                 
 | |
|                                 /*
 | |
|                                  * Optimized for NY=1
 | |
|                                  */
 | |
|                                 if( s->ny==1 )
 | |
|                                 {
 | |
|                                     w0 = s->wr.ptr.pp_double[tg][1+t*s->ny+0];
 | |
|                                     ubnd = blocks0->ptr.p_int[i0+1]-1;
 | |
|                                     for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++)
 | |
|                                     {
 | |
|                                         basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v;
 | |
|                                         y->ptr.p_double[dstoffs] = y->ptr.p_double[dstoffs]+basisfuncval*w0;
 | |
|                                         dstoffs = dstoffs+1;
 | |
|                                     }
 | |
|                                     continue;
 | |
|                                 }
 | |
|                                 
 | |
|                                 /*
 | |
|                                  * Optimized for NY=2
 | |
|                                  */
 | |
|                                 if( s->ny==2 )
 | |
|                                 {
 | |
|                                     w0 = s->wr.ptr.pp_double[tg][1+t*s->ny+0];
 | |
|                                     w1 = s->wr.ptr.pp_double[tg][1+t*s->ny+1];
 | |
|                                     ubnd = blocks0->ptr.p_int[i0+1]-1;
 | |
|                                     for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++)
 | |
|                                     {
 | |
|                                         basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v;
 | |
|                                         y->ptr.p_double[dstoffs+0] = y->ptr.p_double[dstoffs+0]+basisfuncval*w0;
 | |
|                                         y->ptr.p_double[dstoffs+1] = y->ptr.p_double[dstoffs+1]+basisfuncval*w1;
 | |
|                                         dstoffs = dstoffs+2;
 | |
|                                     }
 | |
|                                     continue;
 | |
|                                 }
 | |
|                                 
 | |
|                                 /*
 | |
|                                  * Optimized for NY=3
 | |
|                                  */
 | |
|                                 if( s->ny==3 )
 | |
|                                 {
 | |
|                                     w0 = s->wr.ptr.pp_double[tg][1+t*s->ny+0];
 | |
|                                     w1 = s->wr.ptr.pp_double[tg][1+t*s->ny+1];
 | |
|                                     w2 = s->wr.ptr.pp_double[tg][1+t*s->ny+2];
 | |
|                                     ubnd = blocks0->ptr.p_int[i0+1]-1;
 | |
|                                     for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++)
 | |
|                                     {
 | |
|                                         basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v;
 | |
|                                         y->ptr.p_double[dstoffs+0] = y->ptr.p_double[dstoffs+0]+basisfuncval*w0;
 | |
|                                         y->ptr.p_double[dstoffs+1] = y->ptr.p_double[dstoffs+1]+basisfuncval*w1;
 | |
|                                         y->ptr.p_double[dstoffs+2] = y->ptr.p_double[dstoffs+2]+basisfuncval*w2;
 | |
|                                         dstoffs = dstoffs+3;
 | |
|                                     }
 | |
|                                     continue;
 | |
|                                 }
 | |
|                                 
 | |
|                                 /*
 | |
|                                  * General case
 | |
|                                  */
 | |
|                                 for(i=blocks0->ptr.p_int[i0]; i<=blocks0->ptr.p_int[i0+1]-1; i++)
 | |
|                                 {
 | |
|                                     basisfuncval = pbuf->expbuf0.ptr.p_double[i]*v;
 | |
|                                     for(l=0; l<=s->ny-1; l++)
 | |
|                                     {
 | |
|                                         y->ptr.p_double[l+dstoffs] = y->ptr.p_double[l+dstoffs]+basisfuncval*s->wr.ptr.pp_double[tg][1+t*s->ny+l];
 | |
|                                     }
 | |
|                                     dstoffs = dstoffs+ny;
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                         
 | |
|                         /*
 | |
|                          * Update basis functions
 | |
|                          */
 | |
|                         if( t!=s->nl-1 )
 | |
|                         {
 | |
|                             ubnd = blocks0->ptr.p_int[i0+1]-1;
 | |
|                             for(i=blocks0->ptr.p_int[i0]; i<=ubnd; i++)
 | |
|                             {
 | |
|                                 if( allnodes||pbuf->flag0.ptr.p_bool[i] )
 | |
|                                 {
 | |
|                                     v = pbuf->expbuf0.ptr.p_double[i]*pbuf->expbuf0.ptr.p_double[i];
 | |
|                                     pbuf->expbuf0.ptr.p_double[i] = v*v;
 | |
|                                 }
 | |
|                             }
 | |
|                             ubnd = blocks1->ptr.p_int[i1+1]-1;
 | |
|                             for(j=blocks1->ptr.p_int[i1]; j<=ubnd; j++)
 | |
|                             {
 | |
|                                 if( allnodes||pbuf->flag1.ptr.p_bool[j] )
 | |
|                                 {
 | |
|                                     v = pbuf->expbuf1.ptr.p_double[j]*pbuf->expbuf1.ptr.p_double[j];
 | |
|                                     pbuf->expbuf1.ptr.p_double[j] = v*v;
 | |
|                                 }
 | |
|                             }
 | |
|                             ubnd = blocks2->ptr.p_int[i2+1]-1;
 | |
|                             for(k=blocks2->ptr.p_int[i2]; k<=ubnd; k++)
 | |
|                             {
 | |
|                                 if( allnodes||pbuf->flag2.ptr.p_bool[k] )
 | |
|                                 {
 | |
|                                     v = pbuf->expbuf2.ptr.p_double[k]*pbuf->expbuf2.ptr.p_double[k];
 | |
|                                     pbuf->expbuf2.ptr.p_double[k] = v*v;
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Recycle buffer object back to pool
 | |
|      */
 | |
|     ae_shared_pool_recycle(bufpool, &_pbuf, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serial stub for GPL edition.
 | |
| *************************************************************************/
 | |
| ae_bool _trypexec_rbfv1gridcalc3vrec(rbfv1model* s,
 | |
|     /* Real    */ ae_vector* x0,
 | |
|     ae_int_t n0,
 | |
|     /* Real    */ ae_vector* x1,
 | |
|     ae_int_t n1,
 | |
|     /* Real    */ ae_vector* x2,
 | |
|     ae_int_t n2,
 | |
|     /* Integer */ ae_vector* blocks0,
 | |
|     ae_int_t block0a,
 | |
|     ae_int_t block0b,
 | |
|     /* Integer */ ae_vector* blocks1,
 | |
|     ae_int_t block1a,
 | |
|     ae_int_t block1b,
 | |
|     /* Integer */ ae_vector* blocks2,
 | |
|     ae_int_t block2a,
 | |
|     ae_int_t block2b,
 | |
|     /* Boolean */ ae_vector* flagy,
 | |
|     ae_bool sparsey,
 | |
|     double searchradius,
 | |
|     double avgfuncpernode,
 | |
|     ae_shared_pool* bufpool,
 | |
|     /* Real    */ ae_vector* y,
 | |
|     ae_state *_state)
 | |
| {
 | |
|     return ae_false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function "unpacks" RBF model by extracting its coefficients.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     NX      -   dimensionality of argument
 | |
|     NY      -   dimensionality of the target function
 | |
|     XWR     -   model information, array[NC,NX+NY+1].
 | |
|                 One row of the array corresponds to one basis function:
 | |
|                 * first NX columns  - coordinates of the center 
 | |
|                 * next NY columns   - weights, one per dimension of the 
 | |
|                                       function being modelled
 | |
|                 * last column       - radius, same for all dimensions of
 | |
|                                       the function being modelled
 | |
|     NC      -   number of the centers
 | |
|     V       -   polynomial  term , array[NY,NX+1]. One row per one 
 | |
|                 dimension of the function being modelled. First NX 
 | |
|                 elements are linear coefficients, V[NX] is equal to the 
 | |
|                 constant part.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfv1unpack(rbfv1model* s,
 | |
|      ae_int_t* nx,
 | |
|      ae_int_t* ny,
 | |
|      /* Real    */ ae_matrix* xwr,
 | |
|      ae_int_t* nc,
 | |
|      /* Real    */ ae_matrix* v,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     double rcur;
 | |
| 
 | |
|     *nx = 0;
 | |
|     *ny = 0;
 | |
|     ae_matrix_clear(xwr);
 | |
|     *nc = 0;
 | |
|     ae_matrix_clear(v);
 | |
| 
 | |
|     *nx = s->nx;
 | |
|     *ny = s->ny;
 | |
|     *nc = s->nc;
 | |
|     
 | |
|     /*
 | |
|      * Fill V
 | |
|      */
 | |
|     ae_matrix_set_length(v, s->ny, s->nx+1, _state);
 | |
|     for(i=0; i<=s->ny-1; i++)
 | |
|     {
 | |
|         ae_v_move(&v->ptr.pp_double[i][0], 1, &s->v.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx-1));
 | |
|         v->ptr.pp_double[i][s->nx] = s->v.ptr.pp_double[i][rbfv1_mxnx];
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Fill XWR and V
 | |
|      */
 | |
|     if( *nc*s->nl>0 )
 | |
|     {
 | |
|         ae_matrix_set_length(xwr, s->nc*s->nl, s->nx+s->ny+1, _state);
 | |
|         for(i=0; i<=s->nc-1; i++)
 | |
|         {
 | |
|             rcur = s->wr.ptr.pp_double[i][0];
 | |
|             for(j=0; j<=s->nl-1; j++)
 | |
|             {
 | |
|                 ae_v_move(&xwr->ptr.pp_double[i*s->nl+j][0], 1, &s->xc.ptr.pp_double[i][0], 1, ae_v_len(0,s->nx-1));
 | |
|                 ae_v_move(&xwr->ptr.pp_double[i*s->nl+j][s->nx], 1, &s->wr.ptr.pp_double[i][1+j*s->ny], 1, ae_v_len(s->nx,s->nx+s->ny-1));
 | |
|                 xwr->ptr.pp_double[i*s->nl+j][s->nx+s->ny] = rcur;
 | |
|                 rcur = 0.5*rcur;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| static ae_bool rbfv1_rbfv1buildlinearmodel(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t modeltype,
 | |
|      /* Real    */ ae_matrix* v,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector tmpy;
 | |
|     ae_matrix a;
 | |
|     double scaling;
 | |
|     ae_vector shifting;
 | |
|     double mn;
 | |
|     double mx;
 | |
|     ae_vector c;
 | |
|     lsfitreport rep;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t info;
 | |
|     ae_bool result;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&tmpy, 0, sizeof(tmpy));
 | |
|     memset(&a, 0, sizeof(a));
 | |
|     memset(&shifting, 0, sizeof(shifting));
 | |
|     memset(&c, 0, sizeof(c));
 | |
|     memset(&rep, 0, sizeof(rep));
 | |
|     ae_matrix_clear(v);
 | |
|     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&shifting, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&c, 0, DT_REAL, _state, ae_true);
 | |
|     _lsfitreport_init(&rep, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=0, "BuildLinearModel: N<0", _state);
 | |
|     ae_assert(ny>0, "BuildLinearModel: NY<=0", _state);
 | |
|     
 | |
|     /*
 | |
|      * Handle degenerate case (N=0)
 | |
|      */
 | |
|     result = ae_true;
 | |
|     ae_matrix_set_length(v, ny, rbfv1_mxnx+1, _state);
 | |
|     if( n==0 )
 | |
|     {
 | |
|         for(j=0; j<=rbfv1_mxnx; j++)
 | |
|         {
 | |
|             for(i=0; i<=ny-1; i++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][j] = (double)(0);
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Allocate temporaries
 | |
|      */
 | |
|     ae_vector_set_length(&tmpy, n, _state);
 | |
|     
 | |
|     /*
 | |
|      * General linear model.
 | |
|      */
 | |
|     if( modeltype==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Calculate scaling/shifting, transform variables, prepare LLS problem
 | |
|          */
 | |
|         ae_matrix_set_length(&a, n, rbfv1_mxnx+1, _state);
 | |
|         ae_vector_set_length(&shifting, rbfv1_mxnx, _state);
 | |
|         scaling = (double)(0);
 | |
|         for(i=0; i<=rbfv1_mxnx-1; i++)
 | |
|         {
 | |
|             mn = x->ptr.pp_double[0][i];
 | |
|             mx = mn;
 | |
|             for(j=1; j<=n-1; j++)
 | |
|             {
 | |
|                 if( ae_fp_greater(mn,x->ptr.pp_double[j][i]) )
 | |
|                 {
 | |
|                     mn = x->ptr.pp_double[j][i];
 | |
|                 }
 | |
|                 if( ae_fp_less(mx,x->ptr.pp_double[j][i]) )
 | |
|                 {
 | |
|                     mx = x->ptr.pp_double[j][i];
 | |
|                 }
 | |
|             }
 | |
|             scaling = ae_maxreal(scaling, mx-mn, _state);
 | |
|             shifting.ptr.p_double[i] = 0.5*(mx+mn);
 | |
|         }
 | |
|         if( ae_fp_eq(scaling,(double)(0)) )
 | |
|         {
 | |
|             scaling = (double)(1);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             scaling = 0.5*scaling;
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|             {
 | |
|                 a.ptr.pp_double[i][j] = (x->ptr.pp_double[i][j]-shifting.ptr.p_double[j])/scaling;
 | |
|             }
 | |
|         }
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             a.ptr.pp_double[i][rbfv1_mxnx] = (double)(1);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Solve linear system in transformed variables, make backward 
 | |
|          */
 | |
|         for(i=0; i<=ny-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i];
 | |
|             }
 | |
|             lsfitlinear(&tmpy, &a, n, rbfv1_mxnx+1, &info, &c, &rep, _state);
 | |
|             if( info<=0 )
 | |
|             {
 | |
|                 result = ae_false;
 | |
|                 ae_frame_leave(_state);
 | |
|                 return result;
 | |
|             }
 | |
|             for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][j] = c.ptr.p_double[j]/scaling;
 | |
|             }
 | |
|             v->ptr.pp_double[i][rbfv1_mxnx] = c.ptr.p_double[rbfv1_mxnx];
 | |
|             for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][rbfv1_mxnx] = v->ptr.pp_double[i][rbfv1_mxnx]-shifting.ptr.p_double[j]*v->ptr.pp_double[i][j];
 | |
|             }
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 for(k=0; k<=rbfv1_mxnx-1; k++)
 | |
|                 {
 | |
|                     y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-x->ptr.pp_double[j][k]*v->ptr.pp_double[i][k];
 | |
|                 }
 | |
|                 y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][rbfv1_mxnx];
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Constant model, very simple
 | |
|      */
 | |
|     if( modeltype==2 )
 | |
|     {
 | |
|         for(i=0; i<=ny-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=rbfv1_mxnx; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][j] = (double)(0);
 | |
|             }
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 v->ptr.pp_double[i][rbfv1_mxnx] = v->ptr.pp_double[i][rbfv1_mxnx]+y->ptr.pp_double[j][i];
 | |
|             }
 | |
|             if( n>0 )
 | |
|             {
 | |
|                 v->ptr.pp_double[i][rbfv1_mxnx] = v->ptr.pp_double[i][rbfv1_mxnx]/n;
 | |
|             }
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-v->ptr.pp_double[i][rbfv1_mxnx];
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return result;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Zero model
 | |
|      */
 | |
|     ae_assert(modeltype==3, "BuildLinearModel: unknown model type", _state);
 | |
|     for(i=0; i<=ny-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=rbfv1_mxnx; j++)
 | |
|         {
 | |
|             v->ptr.pp_double[i][j] = (double)(0);
 | |
|         }
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void rbfv1_buildrbfmodellsqr(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      /* Real    */ ae_matrix* xc,
 | |
|      /* Real    */ ae_vector* r,
 | |
|      ae_int_t n,
 | |
|      ae_int_t nc,
 | |
|      ae_int_t ny,
 | |
|      kdtree* pointstree,
 | |
|      kdtree* centerstree,
 | |
|      double epsort,
 | |
|      double epserr,
 | |
|      ae_int_t maxits,
 | |
|      ae_int_t* gnnz,
 | |
|      ae_int_t* snnz,
 | |
|      /* Real    */ ae_matrix* w,
 | |
|      ae_int_t* info,
 | |
|      ae_int_t* iterationscount,
 | |
|      ae_int_t* nmv,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     linlsqrstate state;
 | |
|     linlsqrreport lsqrrep;
 | |
|     sparsematrix spg;
 | |
|     sparsematrix sps;
 | |
|     ae_vector nearcenterscnt;
 | |
|     ae_vector nearpointscnt;
 | |
|     ae_vector skipnearpointscnt;
 | |
|     ae_vector farpointscnt;
 | |
|     ae_int_t maxnearcenterscnt;
 | |
|     ae_int_t maxnearpointscnt;
 | |
|     ae_int_t maxfarpointscnt;
 | |
|     ae_int_t sumnearcenterscnt;
 | |
|     ae_int_t sumnearpointscnt;
 | |
|     ae_int_t sumfarpointscnt;
 | |
|     double maxrad;
 | |
|     ae_vector pointstags;
 | |
|     ae_vector centerstags;
 | |
|     ae_matrix nearpoints;
 | |
|     ae_matrix nearcenters;
 | |
|     ae_matrix farpoints;
 | |
|     ae_int_t tmpi;
 | |
|     ae_int_t pointscnt;
 | |
|     ae_int_t centerscnt;
 | |
|     ae_vector xcx;
 | |
|     ae_vector tmpy;
 | |
|     ae_vector tc;
 | |
|     ae_vector g;
 | |
|     ae_vector c;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t sind;
 | |
|     ae_matrix a;
 | |
|     double vv;
 | |
|     double vx;
 | |
|     double vy;
 | |
|     double vz;
 | |
|     double vr;
 | |
|     double gnorm2;
 | |
|     ae_vector tmp0;
 | |
|     ae_vector tmp1;
 | |
|     ae_vector tmp2;
 | |
|     double fx;
 | |
|     ae_matrix xx;
 | |
|     ae_matrix cx;
 | |
|     double mrad;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&state, 0, sizeof(state));
 | |
|     memset(&lsqrrep, 0, sizeof(lsqrrep));
 | |
|     memset(&spg, 0, sizeof(spg));
 | |
|     memset(&sps, 0, sizeof(sps));
 | |
|     memset(&nearcenterscnt, 0, sizeof(nearcenterscnt));
 | |
|     memset(&nearpointscnt, 0, sizeof(nearpointscnt));
 | |
|     memset(&skipnearpointscnt, 0, sizeof(skipnearpointscnt));
 | |
|     memset(&farpointscnt, 0, sizeof(farpointscnt));
 | |
|     memset(&pointstags, 0, sizeof(pointstags));
 | |
|     memset(¢erstags, 0, sizeof(centerstags));
 | |
|     memset(&nearpoints, 0, sizeof(nearpoints));
 | |
|     memset(&nearcenters, 0, sizeof(nearcenters));
 | |
|     memset(&farpoints, 0, sizeof(farpoints));
 | |
|     memset(&xcx, 0, sizeof(xcx));
 | |
|     memset(&tmpy, 0, sizeof(tmpy));
 | |
|     memset(&tc, 0, sizeof(tc));
 | |
|     memset(&g, 0, sizeof(g));
 | |
|     memset(&c, 0, sizeof(c));
 | |
|     memset(&a, 0, sizeof(a));
 | |
|     memset(&tmp0, 0, sizeof(tmp0));
 | |
|     memset(&tmp1, 0, sizeof(tmp1));
 | |
|     memset(&tmp2, 0, sizeof(tmp2));
 | |
|     memset(&xx, 0, sizeof(xx));
 | |
|     memset(&cx, 0, sizeof(cx));
 | |
|     *gnnz = 0;
 | |
|     *snnz = 0;
 | |
|     ae_matrix_clear(w);
 | |
|     *info = 0;
 | |
|     *iterationscount = 0;
 | |
|     *nmv = 0;
 | |
|     _linlsqrstate_init(&state, _state, ae_true);
 | |
|     _linlsqrreport_init(&lsqrrep, _state, ae_true);
 | |
|     _sparsematrix_init(&spg, _state, ae_true);
 | |
|     _sparsematrix_init(&sps, _state, ae_true);
 | |
|     ae_vector_init(&nearcenterscnt, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&nearpointscnt, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&skipnearpointscnt, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&farpointscnt, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&pointstags, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(¢erstags, 0, DT_INT, _state, ae_true);
 | |
|     ae_matrix_init(&nearpoints, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&nearcenters, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&farpoints, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xcx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&g, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&c, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&a, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&xx, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&cx, 0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Handle special cases: NC=0
 | |
|      */
 | |
|     if( nc==0 )
 | |
|     {
 | |
|         *info = 1;
 | |
|         *iterationscount = 0;
 | |
|         *nmv = 0;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare for general case, NC>0
 | |
|      */
 | |
|     ae_vector_set_length(&xcx, rbfv1_mxnx, _state);
 | |
|     ae_vector_set_length(&pointstags, n, _state);
 | |
|     ae_vector_set_length(¢erstags, nc, _state);
 | |
|     *info = -1;
 | |
|     *iterationscount = 0;
 | |
|     *nmv = 0;
 | |
|     
 | |
|     /*
 | |
|      * This block prepares quantities used to compute approximate cardinal basis functions (ACBFs):
 | |
|      * * NearCentersCnt[]   -   array[NC], whose elements store number of near centers used to build ACBF
 | |
|      * * NearPointsCnt[]    -   array[NC], number of near points used to build ACBF
 | |
|      * * FarPointsCnt[]     -   array[NC], number of far points (ones where ACBF is nonzero)
 | |
|      * * MaxNearCentersCnt  -   max(NearCentersCnt)
 | |
|      * * MaxNearPointsCnt   -   max(NearPointsCnt)
 | |
|      * * SumNearCentersCnt  -   sum(NearCentersCnt)
 | |
|      * * SumNearPointsCnt   -   sum(NearPointsCnt)
 | |
|      * * SumFarPointsCnt    -   sum(FarPointsCnt)
 | |
|      */
 | |
|     ae_vector_set_length(&nearcenterscnt, nc, _state);
 | |
|     ae_vector_set_length(&nearpointscnt, nc, _state);
 | |
|     ae_vector_set_length(&skipnearpointscnt, nc, _state);
 | |
|     ae_vector_set_length(&farpointscnt, nc, _state);
 | |
|     maxnearcenterscnt = 0;
 | |
|     maxnearpointscnt = 0;
 | |
|     maxfarpointscnt = 0;
 | |
|     sumnearcenterscnt = 0;
 | |
|     sumnearpointscnt = 0;
 | |
|     sumfarpointscnt = 0;
 | |
|     for(i=0; i<=nc-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|         {
 | |
|             xcx.ptr.p_double[j] = xc->ptr.pp_double[i][j];
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Determine number of near centers and maximum radius of near centers
 | |
|          */
 | |
|         nearcenterscnt.ptr.p_int[i] = kdtreequeryrnn(centerstree, &xcx, r->ptr.p_double[i]*rbfv1_rbfnearradius, ae_true, _state);
 | |
|         kdtreequeryresultstags(centerstree, ¢erstags, _state);
 | |
|         maxrad = (double)(0);
 | |
|         for(j=0; j<=nearcenterscnt.ptr.p_int[i]-1; j++)
 | |
|         {
 | |
|             maxrad = ae_maxreal(maxrad, ae_fabs(r->ptr.p_double[centerstags.ptr.p_int[j]], _state), _state);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Determine number of near points (ones which used to build ACBF)
 | |
|          * and skipped points (the most near points which are NOT used to build ACBF
 | |
|          * and are NOT included in the near points count
 | |
|          */
 | |
|         skipnearpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, 0.1*r->ptr.p_double[i], ae_true, _state);
 | |
|         nearpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, (r->ptr.p_double[i]+maxrad)*rbfv1_rbfnearradius, ae_true, _state)-skipnearpointscnt.ptr.p_int[i];
 | |
|         ae_assert(nearpointscnt.ptr.p_int[i]>=0, "BuildRBFModelLSQR: internal error", _state);
 | |
|         
 | |
|         /*
 | |
|          * Determine number of far points
 | |
|          */
 | |
|         farpointscnt.ptr.p_int[i] = kdtreequeryrnn(pointstree, &xcx, ae_maxreal(r->ptr.p_double[i]*rbfv1_rbfnearradius+maxrad*rbfv1_rbffarradius, r->ptr.p_double[i]*rbfv1_rbffarradius, _state), ae_true, _state);
 | |
|         
 | |
|         /*
 | |
|          * calculate sum and max, make some basic checks
 | |
|          */
 | |
|         ae_assert(nearcenterscnt.ptr.p_int[i]>0, "BuildRBFModelLSQR: internal error", _state);
 | |
|         maxnearcenterscnt = ae_maxint(maxnearcenterscnt, nearcenterscnt.ptr.p_int[i], _state);
 | |
|         maxnearpointscnt = ae_maxint(maxnearpointscnt, nearpointscnt.ptr.p_int[i], _state);
 | |
|         maxfarpointscnt = ae_maxint(maxfarpointscnt, farpointscnt.ptr.p_int[i], _state);
 | |
|         sumnearcenterscnt = sumnearcenterscnt+nearcenterscnt.ptr.p_int[i];
 | |
|         sumnearpointscnt = sumnearpointscnt+nearpointscnt.ptr.p_int[i];
 | |
|         sumfarpointscnt = sumfarpointscnt+farpointscnt.ptr.p_int[i];
 | |
|     }
 | |
|     *snnz = sumnearcenterscnt;
 | |
|     *gnnz = sumfarpointscnt;
 | |
|     ae_assert(maxnearcenterscnt>0, "BuildRBFModelLSQR: internal error", _state);
 | |
|     
 | |
|     /*
 | |
|      * Allocate temporaries.
 | |
|      *
 | |
|      * NOTE: we want to avoid allocation of zero-size arrays, so we
 | |
|      *       use max(desired_size,1) instead of desired_size when performing
 | |
|      *       memory allocation.
 | |
|      */
 | |
|     ae_matrix_set_length(&a, maxnearpointscnt+maxnearcenterscnt, maxnearcenterscnt, _state);
 | |
|     ae_vector_set_length(&tmpy, maxnearpointscnt+maxnearcenterscnt, _state);
 | |
|     ae_vector_set_length(&g, maxnearcenterscnt, _state);
 | |
|     ae_vector_set_length(&c, maxnearcenterscnt, _state);
 | |
|     ae_matrix_set_length(&nearcenters, maxnearcenterscnt, rbfv1_mxnx, _state);
 | |
|     ae_matrix_set_length(&nearpoints, ae_maxint(maxnearpointscnt, 1, _state), rbfv1_mxnx, _state);
 | |
|     ae_matrix_set_length(&farpoints, ae_maxint(maxfarpointscnt, 1, _state), rbfv1_mxnx, _state);
 | |
|     
 | |
|     /*
 | |
|      * fill matrix SpG
 | |
|      */
 | |
|     sparsecreate(n, nc, *gnnz, &spg, _state);
 | |
|     sparsecreate(nc, nc, *snnz, &sps, _state);
 | |
|     for(i=0; i<=nc-1; i++)
 | |
|     {
 | |
|         centerscnt = nearcenterscnt.ptr.p_int[i];
 | |
|         
 | |
|         /*
 | |
|          * main center
 | |
|          */
 | |
|         for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|         {
 | |
|             xcx.ptr.p_double[j] = xc->ptr.pp_double[i][j];
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * center's tree
 | |
|          */
 | |
|         tmpi = kdtreequeryknn(centerstree, &xcx, centerscnt, ae_true, _state);
 | |
|         ae_assert(tmpi==centerscnt, "BuildRBFModelLSQR: internal error", _state);
 | |
|         kdtreequeryresultsx(centerstree, &cx, _state);
 | |
|         kdtreequeryresultstags(centerstree, ¢erstags, _state);
 | |
|         
 | |
|         /*
 | |
|          * point's tree
 | |
|          */
 | |
|         mrad = (double)(0);
 | |
|         for(j=0; j<=centerscnt-1; j++)
 | |
|         {
 | |
|             mrad = ae_maxreal(mrad, r->ptr.p_double[centerstags.ptr.p_int[j]], _state);
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * we need to be sure that 'CTree' contains
 | |
|          * at least one side center
 | |
|          */
 | |
|         sparseset(&sps, i, i, (double)(1), _state);
 | |
|         c.ptr.p_double[0] = 1.0;
 | |
|         for(j=1; j<=centerscnt-1; j++)
 | |
|         {
 | |
|             c.ptr.p_double[j] = 0.0;
 | |
|         }
 | |
|         if( centerscnt>1&&nearpointscnt.ptr.p_int[i]>0 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * first KDTree request for points
 | |
|              */
 | |
|             pointscnt = nearpointscnt.ptr.p_int[i];
 | |
|             tmpi = kdtreequeryknn(pointstree, &xcx, skipnearpointscnt.ptr.p_int[i]+nearpointscnt.ptr.p_int[i], ae_true, _state);
 | |
|             ae_assert(tmpi==skipnearpointscnt.ptr.p_int[i]+nearpointscnt.ptr.p_int[i], "BuildRBFModelLSQR: internal error", _state);
 | |
|             kdtreequeryresultsx(pointstree, &xx, _state);
 | |
|             sind = skipnearpointscnt.ptr.p_int[i];
 | |
|             for(j=0; j<=pointscnt-1; j++)
 | |
|             {
 | |
|                 vx = xx.ptr.pp_double[sind+j][0];
 | |
|                 vy = xx.ptr.pp_double[sind+j][1];
 | |
|                 vz = xx.ptr.pp_double[sind+j][2];
 | |
|                 for(k=0; k<=centerscnt-1; k++)
 | |
|                 {
 | |
|                     vr = 0.0;
 | |
|                     vv = vx-cx.ptr.pp_double[k][0];
 | |
|                     vr = vr+vv*vv;
 | |
|                     vv = vy-cx.ptr.pp_double[k][1];
 | |
|                     vr = vr+vv*vv;
 | |
|                     vv = vz-cx.ptr.pp_double[k][2];
 | |
|                     vr = vr+vv*vv;
 | |
|                     vv = r->ptr.p_double[centerstags.ptr.p_int[k]];
 | |
|                     a.ptr.pp_double[j][k] = ae_exp(-vr/(vv*vv), _state);
 | |
|                 }
 | |
|             }
 | |
|             for(j=0; j<=centerscnt-1; j++)
 | |
|             {
 | |
|                 g.ptr.p_double[j] = ae_exp(-(ae_sqr(xcx.ptr.p_double[0]-cx.ptr.pp_double[j][0], _state)+ae_sqr(xcx.ptr.p_double[1]-cx.ptr.pp_double[j][1], _state)+ae_sqr(xcx.ptr.p_double[2]-cx.ptr.pp_double[j][2], _state))/ae_sqr(r->ptr.p_double[centerstags.ptr.p_int[j]], _state), _state);
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * calculate the problem
 | |
|              */
 | |
|             gnorm2 = ae_v_dotproduct(&g.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1));
 | |
|             for(j=0; j<=pointscnt-1; j++)
 | |
|             {
 | |
|                 vv = ae_v_dotproduct(&a.ptr.pp_double[j][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1));
 | |
|                 vv = vv/gnorm2;
 | |
|                 tmpy.ptr.p_double[j] = -vv;
 | |
|                 ae_v_subd(&a.ptr.pp_double[j][0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv);
 | |
|             }
 | |
|             for(j=pointscnt; j<=pointscnt+centerscnt-1; j++)
 | |
|             {
 | |
|                 for(k=0; k<=centerscnt-1; k++)
 | |
|                 {
 | |
|                     a.ptr.pp_double[j][k] = 0.0;
 | |
|                 }
 | |
|                 a.ptr.pp_double[j][j-pointscnt] = 1.0E-6;
 | |
|                 tmpy.ptr.p_double[j] = 0.0;
 | |
|             }
 | |
|             fblssolvels(&a, &tmpy, pointscnt+centerscnt, centerscnt, &tmp0, &tmp1, &tmp2, _state);
 | |
|             ae_v_move(&c.ptr.p_double[0], 1, &tmpy.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1));
 | |
|             vv = ae_v_dotproduct(&g.ptr.p_double[0], 1, &c.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1));
 | |
|             vv = vv/gnorm2;
 | |
|             ae_v_subd(&c.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv);
 | |
|             vv = 1/gnorm2;
 | |
|             ae_v_addd(&c.ptr.p_double[0], 1, &g.ptr.p_double[0], 1, ae_v_len(0,centerscnt-1), vv);
 | |
|             for(j=0; j<=centerscnt-1; j++)
 | |
|             {
 | |
|                 sparseset(&sps, i, centerstags.ptr.p_int[j], c.ptr.p_double[j], _state);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * second KDTree request for points
 | |
|          */
 | |
|         pointscnt = farpointscnt.ptr.p_int[i];
 | |
|         tmpi = kdtreequeryknn(pointstree, &xcx, pointscnt, ae_true, _state);
 | |
|         ae_assert(tmpi==pointscnt, "BuildRBFModelLSQR: internal error", _state);
 | |
|         kdtreequeryresultsx(pointstree, &xx, _state);
 | |
|         kdtreequeryresultstags(pointstree, &pointstags, _state);
 | |
|         
 | |
|         /*
 | |
|          *fill SpG matrix
 | |
|          */
 | |
|         for(j=0; j<=pointscnt-1; j++)
 | |
|         {
 | |
|             fx = (double)(0);
 | |
|             vx = xx.ptr.pp_double[j][0];
 | |
|             vy = xx.ptr.pp_double[j][1];
 | |
|             vz = xx.ptr.pp_double[j][2];
 | |
|             for(k=0; k<=centerscnt-1; k++)
 | |
|             {
 | |
|                 vr = 0.0;
 | |
|                 vv = vx-cx.ptr.pp_double[k][0];
 | |
|                 vr = vr+vv*vv;
 | |
|                 vv = vy-cx.ptr.pp_double[k][1];
 | |
|                 vr = vr+vv*vv;
 | |
|                 vv = vz-cx.ptr.pp_double[k][2];
 | |
|                 vr = vr+vv*vv;
 | |
|                 vv = r->ptr.p_double[centerstags.ptr.p_int[k]];
 | |
|                 vv = vv*vv;
 | |
|                 fx = fx+c.ptr.p_double[k]*ae_exp(-vr/vv, _state);
 | |
|             }
 | |
|             sparseset(&spg, pointstags.ptr.p_int[j], i, fx, _state);
 | |
|         }
 | |
|     }
 | |
|     sparseconverttocrs(&spg, _state);
 | |
|     sparseconverttocrs(&sps, _state);
 | |
|     
 | |
|     /*
 | |
|      * solve by LSQR method
 | |
|      */
 | |
|     ae_vector_set_length(&tmpy, n, _state);
 | |
|     ae_vector_set_length(&tc, nc, _state);
 | |
|     ae_matrix_set_length(w, nc, ny, _state);
 | |
|     linlsqrcreate(n, nc, &state, _state);
 | |
|     linlsqrsetcond(&state, epsort, epserr, maxits, _state);
 | |
|     for(i=0; i<=ny-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=n-1; j++)
 | |
|         {
 | |
|             tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i];
 | |
|         }
 | |
|         linlsqrsolvesparse(&state, &spg, &tmpy, _state);
 | |
|         linlsqrresults(&state, &c, &lsqrrep, _state);
 | |
|         if( lsqrrep.terminationtype<=0 )
 | |
|         {
 | |
|             *info = -4;
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         sparsemtv(&sps, &c, &tc, _state);
 | |
|         for(j=0; j<=nc-1; j++)
 | |
|         {
 | |
|             w->ptr.pp_double[j][i] = tc.ptr.p_double[j];
 | |
|         }
 | |
|         *iterationscount = *iterationscount+lsqrrep.iterationscount;
 | |
|         *nmv = *nmv+lsqrrep.nmv;
 | |
|     }
 | |
|     *info = 1;
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void rbfv1_buildrbfmlayersmodellsqr(/* Real    */ ae_matrix* x,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      /* Real    */ ae_matrix* xc,
 | |
|      double rval,
 | |
|      /* Real    */ ae_vector* r,
 | |
|      ae_int_t n,
 | |
|      ae_int_t* nc,
 | |
|      ae_int_t ny,
 | |
|      ae_int_t nlayers,
 | |
|      kdtree* centerstree,
 | |
|      double epsort,
 | |
|      double epserr,
 | |
|      ae_int_t maxits,
 | |
|      double lambdav,
 | |
|      ae_int_t* annz,
 | |
|      /* Real    */ ae_matrix* w,
 | |
|      ae_int_t* info,
 | |
|      ae_int_t* iterationscount,
 | |
|      ae_int_t* nmv,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     linlsqrstate state;
 | |
|     linlsqrreport lsqrrep;
 | |
|     sparsematrix spa;
 | |
|     double anorm;
 | |
|     ae_vector omega;
 | |
|     ae_vector xx;
 | |
|     ae_vector tmpy;
 | |
|     ae_matrix cx;
 | |
|     double yval;
 | |
|     ae_int_t nec;
 | |
|     ae_vector centerstags;
 | |
|     ae_int_t layer;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     double v;
 | |
|     double rmaxbefore;
 | |
|     double rmaxafter;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&state, 0, sizeof(state));
 | |
|     memset(&lsqrrep, 0, sizeof(lsqrrep));
 | |
|     memset(&spa, 0, sizeof(spa));
 | |
|     memset(&omega, 0, sizeof(omega));
 | |
|     memset(&xx, 0, sizeof(xx));
 | |
|     memset(&tmpy, 0, sizeof(tmpy));
 | |
|     memset(&cx, 0, sizeof(cx));
 | |
|     memset(¢erstags, 0, sizeof(centerstags));
 | |
|     ae_matrix_clear(xc);
 | |
|     ae_vector_clear(r);
 | |
|     *nc = 0;
 | |
|     *annz = 0;
 | |
|     ae_matrix_clear(w);
 | |
|     *info = 0;
 | |
|     *iterationscount = 0;
 | |
|     *nmv = 0;
 | |
|     _linlsqrstate_init(&state, _state, ae_true);
 | |
|     _linlsqrreport_init(&lsqrrep, _state, ae_true);
 | |
|     _sparsematrix_init(&spa, _state, ae_true);
 | |
|     ae_vector_init(&omega, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmpy, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&cx, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(¢erstags, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     ae_assert(nlayers>=0, "BuildRBFMLayersModelLSQR: invalid argument(NLayers<0)", _state);
 | |
|     ae_assert(n>=0, "BuildRBFMLayersModelLSQR: invalid argument(N<0)", _state);
 | |
|     ae_assert(rbfv1_mxnx>0&&rbfv1_mxnx<=3, "BuildRBFMLayersModelLSQR: internal error(invalid global const MxNX: either MxNX<=0 or MxNX>3)", _state);
 | |
|     *annz = 0;
 | |
|     if( n==0||nlayers==0 )
 | |
|     {
 | |
|         *info = 1;
 | |
|         *iterationscount = 0;
 | |
|         *nmv = 0;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     *nc = n*nlayers;
 | |
|     ae_vector_set_length(&xx, rbfv1_mxnx, _state);
 | |
|     ae_vector_set_length(¢erstags, n, _state);
 | |
|     ae_matrix_set_length(xc, *nc, rbfv1_mxnx, _state);
 | |
|     ae_vector_set_length(r, *nc, _state);
 | |
|     for(i=0; i<=*nc-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|         {
 | |
|             xc->ptr.pp_double[i][j] = x->ptr.pp_double[i%n][j];
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=*nc-1; i++)
 | |
|     {
 | |
|         r->ptr.p_double[i] = rval/ae_pow((double)(2), (double)(i/n), _state);
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         centerstags.ptr.p_int[i] = i;
 | |
|     }
 | |
|     kdtreebuildtagged(xc, ¢erstags, n, rbfv1_mxnx, 0, 2, centerstree, _state);
 | |
|     ae_vector_set_length(&omega, n, _state);
 | |
|     ae_vector_set_length(&tmpy, n, _state);
 | |
|     ae_matrix_set_length(w, *nc, ny, _state);
 | |
|     *info = -1;
 | |
|     *iterationscount = 0;
 | |
|     *nmv = 0;
 | |
|     linlsqrcreate(n, n, &state, _state);
 | |
|     linlsqrsetcond(&state, epsort, epserr, maxits, _state);
 | |
|     linlsqrsetlambdai(&state, 1.0E-6, _state);
 | |
|     
 | |
|     /*
 | |
|      * calculate number of non-zero elements for sparse matrix
 | |
|      */
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|         {
 | |
|             xx.ptr.p_double[j] = x->ptr.pp_double[i][j];
 | |
|         }
 | |
|         *annz = *annz+kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[0]*rbfv1_rbfmlradius, ae_true, _state);
 | |
|     }
 | |
|     for(layer=0; layer<=nlayers-1; layer++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Fill sparse matrix, calculate norm(A)
 | |
|          */
 | |
|         anorm = 0.0;
 | |
|         sparsecreate(n, n, *annz, &spa, _state);
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=rbfv1_mxnx-1; j++)
 | |
|             {
 | |
|                 xx.ptr.p_double[j] = x->ptr.pp_double[i][j];
 | |
|             }
 | |
|             nec = kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[layer*n]*rbfv1_rbfmlradius, ae_true, _state);
 | |
|             kdtreequeryresultsx(centerstree, &cx, _state);
 | |
|             kdtreequeryresultstags(centerstree, ¢erstags, _state);
 | |
|             for(j=0; j<=nec-1; j++)
 | |
|             {
 | |
|                 v = ae_exp(-(ae_sqr(xx.ptr.p_double[0]-cx.ptr.pp_double[j][0], _state)+ae_sqr(xx.ptr.p_double[1]-cx.ptr.pp_double[j][1], _state)+ae_sqr(xx.ptr.p_double[2]-cx.ptr.pp_double[j][2], _state))/ae_sqr(r->ptr.p_double[layer*n+centerstags.ptr.p_int[j]], _state), _state);
 | |
|                 sparseset(&spa, i, centerstags.ptr.p_int[j], v, _state);
 | |
|                 anorm = anorm+ae_sqr(v, _state);
 | |
|             }
 | |
|         }
 | |
|         anorm = ae_sqrt(anorm, _state);
 | |
|         sparseconverttocrs(&spa, _state);
 | |
|         
 | |
|         /*
 | |
|          * Calculate maximum residual before adding new layer.
 | |
|          * This value is not used by algorithm, the only purpose is to make debugging easier.
 | |
|          */
 | |
|         rmaxbefore = 0.0;
 | |
|         for(j=0; j<=n-1; j++)
 | |
|         {
 | |
|             for(i=0; i<=ny-1; i++)
 | |
|             {
 | |
|                 rmaxbefore = ae_maxreal(rmaxbefore, ae_fabs(y->ptr.pp_double[j][i], _state), _state);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Process NY dimensions of the target function
 | |
|          */
 | |
|         for(i=0; i<=ny-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 tmpy.ptr.p_double[j] = y->ptr.pp_double[j][i];
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * calculate Omega for current layer
 | |
|              */
 | |
|             linlsqrsetlambdai(&state, lambdav*anorm/n, _state);
 | |
|             linlsqrsolvesparse(&state, &spa, &tmpy, _state);
 | |
|             linlsqrresults(&state, &omega, &lsqrrep, _state);
 | |
|             if( lsqrrep.terminationtype<=0 )
 | |
|             {
 | |
|                 *info = -4;
 | |
|                 ae_frame_leave(_state);
 | |
|                 return;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * calculate error for current layer
 | |
|              */
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 yval = (double)(0);
 | |
|                 for(k=0; k<=rbfv1_mxnx-1; k++)
 | |
|                 {
 | |
|                     xx.ptr.p_double[k] = x->ptr.pp_double[j][k];
 | |
|                 }
 | |
|                 nec = kdtreequeryrnn(centerstree, &xx, r->ptr.p_double[layer*n]*rbfv1_rbffarradius, ae_true, _state);
 | |
|                 kdtreequeryresultsx(centerstree, &cx, _state);
 | |
|                 kdtreequeryresultstags(centerstree, ¢erstags, _state);
 | |
|                 for(k=0; k<=nec-1; k++)
 | |
|                 {
 | |
|                     yval = yval+omega.ptr.p_double[centerstags.ptr.p_int[k]]*ae_exp(-(ae_sqr(xx.ptr.p_double[0]-cx.ptr.pp_double[k][0], _state)+ae_sqr(xx.ptr.p_double[1]-cx.ptr.pp_double[k][1], _state)+ae_sqr(xx.ptr.p_double[2]-cx.ptr.pp_double[k][2], _state))/ae_sqr(r->ptr.p_double[layer*n+centerstags.ptr.p_int[k]], _state), _state);
 | |
|                 }
 | |
|                 y->ptr.pp_double[j][i] = y->ptr.pp_double[j][i]-yval;
 | |
|             }
 | |
|             
 | |
|             /*
 | |
|              * write Omega in out parameter W
 | |
|              */
 | |
|             for(j=0; j<=n-1; j++)
 | |
|             {
 | |
|                 w->ptr.pp_double[layer*n+j][i] = omega.ptr.p_double[j];
 | |
|             }
 | |
|             *iterationscount = *iterationscount+lsqrrep.iterationscount;
 | |
|             *nmv = *nmv+lsqrrep.nmv;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Calculate maximum residual before adding new layer.
 | |
|          * This value is not used by algorithm, the only purpose is to make debugging easier.
 | |
|          */
 | |
|         rmaxafter = 0.0;
 | |
|         for(j=0; j<=n-1; j++)
 | |
|         {
 | |
|             for(i=0; i<=ny-1; i++)
 | |
|             {
 | |
|                 rmaxafter = ae_maxreal(rmaxafter, ae_fabs(y->ptr.pp_double[j][i], _state), _state);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     *info = 1;
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1calcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv1calcbuffer *p = (rbfv1calcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->calcbufxcx, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->calcbuftags, 0, DT_INT, _state, make_automatic);
 | |
|     _kdtreerequestbuffer_init(&p->requestbuffer, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1calcbuffer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv1calcbuffer *dst = (rbfv1calcbuffer*)_dst;
 | |
|     rbfv1calcbuffer *src = (rbfv1calcbuffer*)_src;
 | |
|     ae_vector_init_copy(&dst->calcbufxcx, &src->calcbufxcx, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state, make_automatic);
 | |
|     _kdtreerequestbuffer_init_copy(&dst->requestbuffer, &src->requestbuffer, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1calcbuffer_clear(void* _p)
 | |
| {
 | |
|     rbfv1calcbuffer *p = (rbfv1calcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->calcbufxcx);
 | |
|     ae_matrix_clear(&p->calcbufx);
 | |
|     ae_vector_clear(&p->calcbuftags);
 | |
|     _kdtreerequestbuffer_clear(&p->requestbuffer);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1calcbuffer_destroy(void* _p)
 | |
| {
 | |
|     rbfv1calcbuffer *p = (rbfv1calcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->calcbufxcx);
 | |
|     ae_matrix_destroy(&p->calcbufx);
 | |
|     ae_vector_destroy(&p->calcbuftags);
 | |
|     _kdtreerequestbuffer_destroy(&p->requestbuffer);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1model_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv1model *p = (rbfv1model*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _kdtree_init(&p->tree, _state, make_automatic);
 | |
|     ae_matrix_init(&p->xc, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->wr, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->v, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->calcbufxcx, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->calcbuftags, 0, DT_INT, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1model_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv1model *dst = (rbfv1model*)_dst;
 | |
|     rbfv1model *src = (rbfv1model*)_src;
 | |
|     dst->ny = src->ny;
 | |
|     dst->nx = src->nx;
 | |
|     dst->nc = src->nc;
 | |
|     dst->nl = src->nl;
 | |
|     _kdtree_init_copy(&dst->tree, &src->tree, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->xc, &src->xc, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->wr, &src->wr, _state, make_automatic);
 | |
|     dst->rmax = src->rmax;
 | |
|     ae_matrix_init_copy(&dst->v, &src->v, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->calcbufxcx, &src->calcbufxcx, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1model_clear(void* _p)
 | |
| {
 | |
|     rbfv1model *p = (rbfv1model*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _kdtree_clear(&p->tree);
 | |
|     ae_matrix_clear(&p->xc);
 | |
|     ae_matrix_clear(&p->wr);
 | |
|     ae_matrix_clear(&p->v);
 | |
|     ae_vector_clear(&p->calcbufxcx);
 | |
|     ae_matrix_clear(&p->calcbufx);
 | |
|     ae_vector_clear(&p->calcbuftags);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1model_destroy(void* _p)
 | |
| {
 | |
|     rbfv1model *p = (rbfv1model*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _kdtree_destroy(&p->tree);
 | |
|     ae_matrix_destroy(&p->xc);
 | |
|     ae_matrix_destroy(&p->wr);
 | |
|     ae_matrix_destroy(&p->v);
 | |
|     ae_vector_destroy(&p->calcbufxcx);
 | |
|     ae_matrix_destroy(&p->calcbufx);
 | |
|     ae_vector_destroy(&p->calcbuftags);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _gridcalc3v1buf_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     gridcalc3v1buf *p = (gridcalc3v1buf*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_init(&p->tx, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->cx, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->ty, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->flag0, 0, DT_BOOL, _state, make_automatic);
 | |
|     ae_vector_init(&p->flag1, 0, DT_BOOL, _state, make_automatic);
 | |
|     ae_vector_init(&p->flag2, 0, DT_BOOL, _state, make_automatic);
 | |
|     ae_vector_init(&p->flag12, 0, DT_BOOL, _state, make_automatic);
 | |
|     ae_vector_init(&p->expbuf0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->expbuf1, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->expbuf2, 0, DT_REAL, _state, make_automatic);
 | |
|     _kdtreerequestbuffer_init(&p->requestbuf, _state, make_automatic);
 | |
|     ae_matrix_init(&p->calcbufx, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->calcbuftags, 0, DT_INT, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _gridcalc3v1buf_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     gridcalc3v1buf *dst = (gridcalc3v1buf*)_dst;
 | |
|     gridcalc3v1buf *src = (gridcalc3v1buf*)_src;
 | |
|     ae_vector_init_copy(&dst->tx, &src->tx, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->cx, &src->cx, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->ty, &src->ty, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->flag0, &src->flag0, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->flag1, &src->flag1, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->flag2, &src->flag2, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->flag12, &src->flag12, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->expbuf0, &src->expbuf0, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->expbuf1, &src->expbuf1, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->expbuf2, &src->expbuf2, _state, make_automatic);
 | |
|     _kdtreerequestbuffer_init_copy(&dst->requestbuf, &src->requestbuf, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->calcbufx, &src->calcbufx, _state, make_automatic);
 | |
|     ae_vector_init_copy(&dst->calcbuftags, &src->calcbuftags, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _gridcalc3v1buf_clear(void* _p)
 | |
| {
 | |
|     gridcalc3v1buf *p = (gridcalc3v1buf*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_clear(&p->tx);
 | |
|     ae_vector_clear(&p->cx);
 | |
|     ae_vector_clear(&p->ty);
 | |
|     ae_vector_clear(&p->flag0);
 | |
|     ae_vector_clear(&p->flag1);
 | |
|     ae_vector_clear(&p->flag2);
 | |
|     ae_vector_clear(&p->flag12);
 | |
|     ae_vector_clear(&p->expbuf0);
 | |
|     ae_vector_clear(&p->expbuf1);
 | |
|     ae_vector_clear(&p->expbuf2);
 | |
|     _kdtreerequestbuffer_clear(&p->requestbuf);
 | |
|     ae_matrix_clear(&p->calcbufx);
 | |
|     ae_vector_clear(&p->calcbuftags);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _gridcalc3v1buf_destroy(void* _p)
 | |
| {
 | |
|     gridcalc3v1buf *p = (gridcalc3v1buf*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     ae_vector_destroy(&p->tx);
 | |
|     ae_vector_destroy(&p->cx);
 | |
|     ae_vector_destroy(&p->ty);
 | |
|     ae_vector_destroy(&p->flag0);
 | |
|     ae_vector_destroy(&p->flag1);
 | |
|     ae_vector_destroy(&p->flag2);
 | |
|     ae_vector_destroy(&p->flag12);
 | |
|     ae_vector_destroy(&p->expbuf0);
 | |
|     ae_vector_destroy(&p->expbuf1);
 | |
|     ae_vector_destroy(&p->expbuf2);
 | |
|     _kdtreerequestbuffer_destroy(&p->requestbuf);
 | |
|     ae_matrix_destroy(&p->calcbufx);
 | |
|     ae_vector_destroy(&p->calcbuftags);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1report_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv1report *p = (rbfv1report*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1report_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfv1report *dst = (rbfv1report*)_dst;
 | |
|     rbfv1report *src = (rbfv1report*)_src;
 | |
|     dst->arows = src->arows;
 | |
|     dst->acols = src->acols;
 | |
|     dst->annz = src->annz;
 | |
|     dst->iterationscount = src->iterationscount;
 | |
|     dst->nmv = src->nmv;
 | |
|     dst->terminationtype = src->terminationtype;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1report_clear(void* _p)
 | |
| {
 | |
|     rbfv1report *p = (rbfv1report*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfv1report_destroy(void* _p)
 | |
| {
 | |
|     rbfv1report *p = (rbfv1report*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_RBF) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function creates RBF  model  for  a  scalar (NY=1)  or  vector (NY>1)
 | |
| function in a NX-dimensional space (NX>=1).
 | |
| 
 | |
| Newly created model is empty. It can be used for interpolation right after
 | |
| creation, but it just returns zeros. You have to add points to the  model,
 | |
| tune interpolation settings, and then  call  model  construction  function
 | |
| rbfbuildmodel() which will update model according to your specification.
 | |
| 
 | |
| USAGE:
 | |
| 1. User creates model with rbfcreate()
 | |
| 2. User adds dataset with rbfsetpoints() (points do NOT have to  be  on  a
 | |
|    regular grid) or rbfsetpointsandscales().
 | |
| 3. (OPTIONAL) User chooses polynomial term by calling:
 | |
|    * rbflinterm() to set linear term
 | |
|    * rbfconstterm() to set constant term
 | |
|    * rbfzeroterm() to set zero term
 | |
|    By default, linear term is used.
 | |
| 4. User tweaks algorithm properties with  rbfsetalgohierarchical()  method
 | |
|    (or chooses one of the legacy algorithms - QNN  (rbfsetalgoqnn)  or  ML
 | |
|    (rbfsetalgomultilayer)).
 | |
| 5. User calls rbfbuildmodel() function which rebuilds model  according  to
 | |
|    the specification
 | |
| 6. User may call rbfcalc() to calculate model value at the specified point,
 | |
|    rbfgridcalc() to  calculate   model  values at the points of the regular
 | |
|    grid. User may extract model coefficients with rbfunpack() call.
 | |
|    
 | |
| IMPORTANT: we recommend you to use latest model construction  algorithm  -
 | |
|            hierarchical RBFs, which is activated by rbfsetalgohierarchical()
 | |
|            function. This algorithm is the fastest one, and  most  memory-
 | |
|            efficient.
 | |
|            However,  it  is  incompatible  with older versions  of  ALGLIB
 | |
|            (pre-3.11). So, if you serialize hierarchical model,  you  will
 | |
|            be unable to load it in pre-3.11 ALGLIB. Other model types (QNN
 | |
|            and RBF-ML) are still backward-compatible.
 | |
|    
 | |
| INPUT PARAMETERS:
 | |
|     NX      -   dimension of the space, NX>=1
 | |
|     NY      -   function dimension, NY>=1
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     S       -   RBF model (initially equals to zero)
 | |
| 
 | |
| NOTE 1: memory requirements. RBF models require amount of memory  which is
 | |
|         proportional  to the number of data points. Some additional memory
 | |
|         is allocated during model construction, but most of this memory is
 | |
|         freed after model coefficients  are  calculated.  Amount  of  this
 | |
|         additional memory depends on model  construction  algorithm  being
 | |
|         used.
 | |
|         
 | |
| NOTE 2: prior to ALGLIB version 3.11, RBF models supported  only  NX=2  or
 | |
|         NX=3. Any  attempt  to  create  single-dimensional  or  more  than
 | |
|         3-dimensional RBF model resulted in exception.
 | |
|         
 | |
|         ALGLIB 3.11 supports any NX>0, but models created with  NX!=2  and
 | |
|         NX!=3 are incompatible with (a) older versions of ALGLIB, (b)  old
 | |
|         model construction algorithms (QNN or RBF-ML).
 | |
|         
 | |
|         So, if you create a model with NX=2 or NX=3,  then,  depending  on
 | |
|         specific  model construction algorithm being chosen, you will (QNN
 | |
|         and RBF-ML) or will not (HierarchicalRBF) get backward compatibility
 | |
|         with older versions of ALGLIB. You have a choice here.
 | |
|         
 | |
|         However, if you create a model with NX neither 2 nor 3,  you  have
 | |
|         no backward compatibility from the start, and you  are  forced  to
 | |
|         use hierarchical RBFs and ALGLIB 3.11 or later.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011, 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfcreate(ae_int_t nx, ae_int_t ny, rbfmodel* s, ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _rbfmodel_clear(s);
 | |
| 
 | |
|     ae_assert(nx>=1, "RBFCreate: NX<1", _state);
 | |
|     ae_assert(ny>=1, "RBFCreate: NY<1", _state);
 | |
|     s->nx = nx;
 | |
|     s->ny = ny;
 | |
|     rbf_rbfpreparenonserializablefields(s, _state);
 | |
|     
 | |
|     /*
 | |
|      * Select default model version according to NX.
 | |
|      *
 | |
|      * The idea is that when we call this function with NX=2 or NX=3, backward
 | |
|      * compatible dummy (zero) V1 model is created, so serialization produces
 | |
|      * model which are compatible with pre-3.11 ALGLIB.
 | |
|      */
 | |
|     rbf_initializev1(nx, ny, &s->model1, _state);
 | |
|     rbf_initializev2(nx, ny, &s->model2, _state);
 | |
|     if( nx==2||nx==3 )
 | |
|     {
 | |
|         s->modelversion = 1;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         s->modelversion = 2;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Report fields
 | |
|      */
 | |
|     s->progress10000 = 0;
 | |
|     s->terminationrequest = ae_false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function creates buffer  structure  which  can  be  used  to  perform
 | |
| parallel  RBF  model  evaluations  (with  one  RBF  model  instance  being
 | |
| used from multiple threads, as long as  different  threads  use  different
 | |
| instances of buffer).
 | |
| 
 | |
| This buffer object can be used with  rbftscalcbuf()  function  (here  "ts"
 | |
| stands for "thread-safe", "buf" is a suffix which denotes  function  which
 | |
| reuses previously allocated output space).
 | |
| 
 | |
| How to use it:
 | |
| * create RBF model structure with rbfcreate()
 | |
| * load data, tune parameters
 | |
| * call rbfbuildmodel()
 | |
| * call rbfcreatecalcbuffer(), once per thread working with RBF model  (you
 | |
|   should call this function only AFTER call to rbfbuildmodel(), see  below
 | |
|   for more information)
 | |
| * call rbftscalcbuf() from different threads,  with  each  thread  working
 | |
|   with its own copy of buffer object.
 | |
| 
 | |
| INPUT PARAMETERS
 | |
|     S           -   RBF model
 | |
| 
 | |
| OUTPUT PARAMETERS
 | |
|     Buf         -   external buffer.
 | |
|     
 | |
|     
 | |
| IMPORTANT: buffer object should be used only with  RBF model object  which
 | |
|            was used to initialize buffer. Any attempt to use buffer   with
 | |
|            different object is dangerous - you may  get  memory  violation
 | |
|            error because sizes of internal arrays do not fit to dimensions
 | |
|            of RBF structure.
 | |
|            
 | |
| IMPORTANT: you  should  call  this function only for model which was built
 | |
|            with rbfbuildmodel() function, after successful  invocation  of
 | |
|            rbfbuildmodel().  Sizes   of   some   internal  structures  are
 | |
|            determined only after model is built, so buffer object  created
 | |
|            before model  construction  stage  will  be  useless  (and  any
 | |
|            attempt to use it will result in exception).
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.04.2016 by Sergey Bochkanov
 | |
| *************************************************************************/
 | |
| void rbfcreatecalcbuffer(rbfmodel* s,
 | |
|      rbfcalcbuffer* buf,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _rbfcalcbuffer_clear(buf);
 | |
| 
 | |
|     if( s->modelversion==1 )
 | |
|     {
 | |
|         buf->modelversion = 1;
 | |
|         rbfv1createcalcbuffer(&s->model1, &buf->bufv1, _state);
 | |
|         return;
 | |
|     }
 | |
|     if( s->modelversion==2 )
 | |
|     {
 | |
|         buf->modelversion = 2;
 | |
|         rbfv2createcalcbuffer(&s->model2, &buf->bufv2, _state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(ae_false, "RBFCreateCalcBuffer: integrity check failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| IMPORTANT: ALGLIB version 3.11 and later allows you to specify  a  set  of
 | |
|            per-dimension scales. Interpolation radii are multiplied by the
 | |
|            scale vector. It may be useful if you have mixed spatio-temporal
 | |
|            data (say, a set of 3D slices recorded at different times).
 | |
|            You should call rbfsetpointsandscales() function  to  use  this
 | |
|            feature.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by rbfcreate() call.
 | |
|     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
 | |
|                 in the dataset. First NX elements  are  coordinates,  next
 | |
|                 NY elements are function values. Array may  be larger than 
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements 
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset
 | |
| 
 | |
| After you've added dataset and (optionally) tuned algorithm  settings  you
 | |
| should call rbfbuildmodel() in order to build a model for you.
 | |
| 
 | |
| NOTE: dataset added by this function is not saved during model serialization.
 | |
|       MODEL ITSELF is serialized, but data used to build it are not.
 | |
|       
 | |
|       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
 | |
|       unserialize it, then you will get an empty RBF model with no dataset
 | |
|       being attached.
 | |
|       
 | |
|       From the other side, if you call rbfbuildmodel() between (1) and (2),
 | |
|       then after (2) you will get your fully constructed RBF model  -  but
 | |
|       again with no dataset attached, so subsequent calls to rbfbuildmodel()
 | |
|       will produce empty model.
 | |
|       
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetpoints(rbfmodel* s,
 | |
|      /* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
| 
 | |
|     ae_assert(n>0, "RBFSetPoints: N<0", _state);
 | |
|     ae_assert(xy->rows>=n, "RBFSetPoints: Rows(XY)<N", _state);
 | |
|     ae_assert(xy->cols>=s->nx+s->ny, "RBFSetPoints: Cols(XY)<NX+NY", _state);
 | |
|     ae_assert(apservisfinitematrix(xy, n, s->nx+s->ny, _state), "RBFSetPoints: XY contains infinite or NaN values!", _state);
 | |
|     s->n = n;
 | |
|     s->hasscale = ae_false;
 | |
|     ae_matrix_set_length(&s->x, s->n, s->nx, _state);
 | |
|     ae_matrix_set_length(&s->y, s->n, s->ny, _state);
 | |
|     for(i=0; i<=s->n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=s->nx-1; j++)
 | |
|         {
 | |
|             s->x.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j];
 | |
|         }
 | |
|         for(j=0; j<=s->ny-1; j++)
 | |
|         {
 | |
|             s->y.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j+s->nx];
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function adds dataset and a vector of per-dimension scales.
 | |
| 
 | |
| It may be useful if you have mixed spatio-temporal data - say, a set of 3D
 | |
| slices recorded at different times. Such data typically require  different
 | |
| RBF radii for spatial and temporal dimensions. ALGLIB solves this  problem
 | |
| by specifying single RBF radius, which is (optionally) multiplied  by  the
 | |
| scale vector.
 | |
| 
 | |
| This function overrides results of the previous calls, i.e. multiple calls
 | |
| of this function will result in only the last set being added.
 | |
| 
 | |
| IMPORTANT: only HierarchicalRBF algorithm can work with scaled points. So,
 | |
|            using this function results in RBF models which can be used  in
 | |
|            ALGLIB 3.11 or later. Previous versions of the library will  be
 | |
|            unable  to unserialize models produced by HierarchicalRBF algo.
 | |
|            
 | |
|            Any attempt to use this function with RBF-ML or QNN  algorithms
 | |
|            will result  in  -3  error  code   being   returned  (incorrect
 | |
|            algorithm).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     R       -   RBF model, initialized by rbfcreate() call.
 | |
|     XY      -   points, array[N,NX+NY]. One row corresponds to  one  point
 | |
|                 in the dataset. First NX elements  are  coordinates,  next
 | |
|                 NY elements are function values. Array may  be larger than 
 | |
|                 specified, in  this  case  only leading [N,NX+NY] elements 
 | |
|                 will be used.
 | |
|     N       -   number of points in the dataset
 | |
|     S       -   array[NX], scale vector, S[i]>0.
 | |
| 
 | |
| After you've added dataset and (optionally) tuned algorithm  settings  you
 | |
| should call rbfbuildmodel() in order to build a model for you.
 | |
| 
 | |
| NOTE: dataset added by this function is not saved during model serialization.
 | |
|       MODEL ITSELF is serialized, but data used to build it are not.
 | |
|       
 | |
|       So, if you 1) add dataset to  empty  RBF  model,  2)  serialize  and
 | |
|       unserialize it, then you will get an empty RBF model with no dataset
 | |
|       being attached.
 | |
|       
 | |
|       From the other side, if you call rbfbuildmodel() between (1) and (2),
 | |
|       then after (2) you will get your fully constructed RBF model  -  but
 | |
|       again with no dataset attached, so subsequent calls to rbfbuildmodel()
 | |
|       will produce empty model.
 | |
|       
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetpointsandscales(rbfmodel* r,
 | |
|      /* Real    */ ae_matrix* xy,
 | |
|      ae_int_t n,
 | |
|      /* Real    */ ae_vector* s,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
| 
 | |
| 
 | |
|     ae_assert(n>0, "RBFSetPointsAndScales: N<0", _state);
 | |
|     ae_assert(xy->rows>=n, "RBFSetPointsAndScales: Rows(XY)<N", _state);
 | |
|     ae_assert(xy->cols>=r->nx+r->ny, "RBFSetPointsAndScales: Cols(XY)<NX+NY", _state);
 | |
|     ae_assert(s->cnt>=r->nx, "RBFSetPointsAndScales: Length(S)<NX", _state);
 | |
|     r->n = n;
 | |
|     r->hasscale = ae_true;
 | |
|     ae_matrix_set_length(&r->x, r->n, r->nx, _state);
 | |
|     ae_matrix_set_length(&r->y, r->n, r->ny, _state);
 | |
|     for(i=0; i<=r->n-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=r->nx-1; j++)
 | |
|         {
 | |
|             r->x.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j];
 | |
|         }
 | |
|         for(j=0; j<=r->ny-1; j++)
 | |
|         {
 | |
|             r->y.ptr.pp_double[i][j] = xy->ptr.pp_double[i][j+r->nx];
 | |
|         }
 | |
|     }
 | |
|     ae_vector_set_length(&r->s, r->nx, _state);
 | |
|     for(i=0; i<=r->nx-1; i++)
 | |
|     {
 | |
|         ae_assert(ae_isfinite(s->ptr.p_double[i], _state), "RBFSetPointsAndScales: S[i] is not finite number", _state);
 | |
|         ae_assert(ae_fp_greater(s->ptr.p_double[i],(double)(0)), "RBFSetPointsAndScales: S[i]<=0", _state);
 | |
|         r->s.ptr.p_double[i] = s->ptr.p_double[i];
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
 | |
|            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
 | |
|            requires less memory than QNN and RBF-ML. It is especially good
 | |
|            for large-scale interpolation problems. So, we recommend you to
 | |
|            consider Hierarchical RBF as default option.
 | |
|            
 | |
| ==========================================================================
 | |
| 
 | |
| This  function  sets  RBF interpolation algorithm. ALGLIB supports several
 | |
| RBF algorithms with different properties.
 | |
| 
 | |
| This algorithm is called RBF-QNN and  it  is  good  for  point  sets  with
 | |
| following properties:
 | |
| a) all points are distinct
 | |
| b) all points are well separated.
 | |
| c) points  distribution  is  approximately  uniform.  There is no "contour
 | |
|    lines", clusters of points, or other small-scale structures.
 | |
| 
 | |
| Algorithm description:
 | |
| 1) interpolation centers are allocated to data points
 | |
| 2) interpolation radii are calculated as distances to the  nearest centers
 | |
|    times Q coefficient (where Q is a value from [0.75,1.50]).
 | |
| 3) after  performing (2) radii are transformed in order to avoid situation
 | |
|    when single outlier has very large radius and  influences  many  points
 | |
|    across all dataset. Transformation has following form:
 | |
|        new_r[i] = min(r[i],Z*median(r[]))
 | |
|    where r[i] is I-th radius, median()  is a median  radius across  entire
 | |
|    dataset, Z is user-specified value which controls amount  of  deviation
 | |
|    from median radius.
 | |
| 
 | |
| When (a) is violated,  we  will  be unable to build RBF model. When (b) or
 | |
| (c) are violated, model will be built, but interpolation quality  will  be
 | |
| low. See http://www.alglib.net/interpolation/ for more information on this
 | |
| subject.
 | |
| 
 | |
| This algorithm is used by default.
 | |
| 
 | |
| Additional Q parameter controls smoothness properties of the RBF basis:
 | |
| * Q<0.75 will give perfectly conditioned basis,  but  terrible  smoothness
 | |
|   properties (RBF interpolant will have sharp peaks around function values)
 | |
| * Q around 1.0 gives good balance between smoothness and condition number
 | |
| * Q>1.5 will lead to badly conditioned systems and slow convergence of the
 | |
|   underlying linear solver (although smoothness will be very good)
 | |
| * Q>2.0 will effectively make optimizer useless because it won't  converge
 | |
|   within reasonable amount of iterations. It is possible to set such large
 | |
|   Q, but it is advised not to do so.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     Q       -   Q parameter, Q>0, recommended value - 1.0
 | |
|     Z       -   Z parameter, Z>0, recommended value - 5.0
 | |
| 
 | |
| NOTE: this   function  has   some   serialization-related  subtleties.  We
 | |
|       recommend you to study serialization examples from ALGLIB  Reference
 | |
|       Manual if you want to perform serialization of your models.
 | |
| 
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetalgoqnn(rbfmodel* s, double q, double z, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(q, _state), "RBFSetAlgoQNN: Q is infinite or NAN", _state);
 | |
|     ae_assert(ae_fp_greater(q,(double)(0)), "RBFSetAlgoQNN: Q<=0", _state);
 | |
|     ae_assert(ae_isfinite(z, _state), "RBFSetAlgoQNN: Z is infinite or NAN", _state);
 | |
|     ae_assert(ae_fp_greater(z,(double)(0)), "RBFSetAlgoQNN: Z<=0", _state);
 | |
|     s->radvalue = q;
 | |
|     s->radzvalue = z;
 | |
|     s->algorithmtype = 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| DEPRECATED:since version 3.11 ALGLIB includes new RBF  model  construction
 | |
|            algorithm, Hierarchical  RBF.  This  algorithm  is  faster  and
 | |
|            requires less memory than QNN and RBF-ML. It is especially good
 | |
|            for large-scale interpolation problems. So, we recommend you to
 | |
|            consider Hierarchical RBF as default option.
 | |
|            
 | |
| ==========================================================================
 | |
| 
 | |
| This  function  sets  RBF interpolation algorithm. ALGLIB supports several
 | |
| RBF algorithms with different properties.
 | |
| 
 | |
| This  algorithm is called RBF-ML. It builds  multilayer  RBF  model,  i.e.
 | |
| model with subsequently decreasing  radii,  which  allows  us  to  combine
 | |
| smoothness (due to  large radii of  the first layers) with  exactness (due
 | |
| to small radii of the last layers) and fast convergence.
 | |
| 
 | |
| Internally RBF-ML uses many different  means  of acceleration, from sparse
 | |
| matrices  to  KD-trees,  which  results in algorithm whose working time is
 | |
| roughly proportional to N*log(N)*Density*RBase^2*NLayers,  where  N  is  a
 | |
| number of points, Density is an average density if points per unit of  the
 | |
| interpolation space, RBase is an initial radius, NLayers is  a  number  of
 | |
| layers.
 | |
| 
 | |
| RBF-ML is good for following kinds of interpolation problems:
 | |
| 1. "exact" problems (perfect fit) with well separated points
 | |
| 2. least squares problems with arbitrary distribution of points (algorithm
 | |
|    gives  perfect  fit  where it is possible, and resorts to least squares
 | |
|    fit in the hard areas).
 | |
| 3. noisy problems where  we  want  to  apply  some  controlled  amount  of
 | |
|    smoothing.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     RBase   -   RBase parameter, RBase>0
 | |
|     NLayers -   NLayers parameter, NLayers>0, recommended value  to  start
 | |
|                 with - about 5.
 | |
|     LambdaV -   regularization value, can be useful when  solving  problem
 | |
|                 in the least squares sense.  Optimal  lambda  is  problem-
 | |
|                 dependent and require trial and error. In our  experience,
 | |
|                 good lambda can be as large as 0.1, and you can use  0.001
 | |
|                 as initial guess.
 | |
|                 Default  value  - 0.01, which is used when LambdaV is  not
 | |
|                 given.  You  can  specify  zero  value,  but  it  is   not
 | |
|                 recommended to do so.
 | |
| 
 | |
| TUNING ALGORITHM
 | |
| 
 | |
| In order to use this algorithm you have to choose three parameters:
 | |
| * initial radius RBase
 | |
| * number of layers in the model NLayers
 | |
| * regularization coefficient LambdaV
 | |
| 
 | |
| Initial radius is easy to choose - you can pick any number  several  times
 | |
| larger  than  the  average  distance between points. Algorithm won't break
 | |
| down if you choose radius which is too large (model construction time will
 | |
| increase, but model will be built correctly).
 | |
| 
 | |
| Choose such number of layers that RLast=RBase/2^(NLayers-1)  (radius  used
 | |
| by  the  last  layer)  will  be  smaller than the typical distance between
 | |
| points.  In  case  model  error  is  too large, you can increase number of
 | |
| layers.  Having  more  layers  will make model construction and evaluation
 | |
| proportionally slower, but it will allow you to have model which precisely
 | |
| fits your data. From the other side, if you want to  suppress  noise,  you
 | |
| can DECREASE number of layers to make your model less flexible.
 | |
| 
 | |
| Regularization coefficient LambdaV controls smoothness of  the  individual
 | |
| models built for each layer. We recommend you to use default value in case
 | |
| you don't want to tune this parameter,  because  having  non-zero  LambdaV
 | |
| accelerates and stabilizes internal iterative algorithm. In case you  want
 | |
| to suppress noise you can use  LambdaV  as  additional  parameter  (larger
 | |
| value = more smoothness) to tune.
 | |
| 
 | |
| TYPICAL ERRORS
 | |
| 
 | |
| 1. Using  initial  radius  which is too large. Memory requirements  of the
 | |
|    RBF-ML are roughly proportional to N*Density*RBase^2 (where Density  is
 | |
|    an average density of points per unit of the interpolation  space).  In
 | |
|    the extreme case of the very large RBase we will need O(N^2)  units  of
 | |
|    memory - and many layers in order to decrease radius to some reasonably
 | |
|    small value.
 | |
| 
 | |
| 2. Using too small number of layers - RBF models with large radius are not
 | |
|    flexible enough to reproduce small variations in the  target  function.
 | |
|    You  need  many  layers  with  different radii, from large to small, in
 | |
|    order to have good model.
 | |
| 
 | |
| 3. Using  initial  radius  which  is  too  small.  You will get model with
 | |
|    "holes" in the areas which are too far away from interpolation centers.
 | |
|    However, algorithm will work correctly (and quickly) in this case.
 | |
| 
 | |
| 4. Using too many layers - you will get too large and too slow model. This
 | |
|    model  will  perfectly  reproduce  your function, but maybe you will be
 | |
|    able to achieve similar results with less layers (and less memory).
 | |
|    
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.03.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetalgomultilayer(rbfmodel* s,
 | |
|      double rbase,
 | |
|      ae_int_t nlayers,
 | |
|      double lambdav,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(rbase, _state), "RBFSetAlgoMultiLayer: RBase is infinite or NaN", _state);
 | |
|     ae_assert(ae_fp_greater(rbase,(double)(0)), "RBFSetAlgoMultiLayer: RBase<=0", _state);
 | |
|     ae_assert(nlayers>=0, "RBFSetAlgoMultiLayer: NLayers<0", _state);
 | |
|     ae_assert(ae_isfinite(lambdav, _state), "RBFSetAlgoMultiLayer: LambdaV is infinite or NAN", _state);
 | |
|     ae_assert(ae_fp_greater_eq(lambdav,(double)(0)), "RBFSetAlgoMultiLayer: LambdaV<0", _state);
 | |
|     s->radvalue = rbase;
 | |
|     s->nlayers = nlayers;
 | |
|     s->algorithmtype = 2;
 | |
|     s->lambdav = lambdav;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  sets  RBF interpolation algorithm. ALGLIB supports several
 | |
| RBF algorithms with different properties.
 | |
| 
 | |
| This  algorithm is called Hierarchical RBF. It  similar  to  its  previous
 | |
| incarnation, RBF-ML, i.e.  it  also  builds  a  sequence  of  models  with
 | |
| decreasing radii. However, it uses more economical way of  building  upper
 | |
| layers (ones with large radii), which results in faster model construction
 | |
| and evaluation, as well as smaller memory footprint during construction.
 | |
| 
 | |
| This algorithm has following important features:
 | |
| * ability to handle millions of points
 | |
| * controllable smoothing via nonlinearity penalization
 | |
| * support for NX-dimensional models with NX=1 or NX>3 (unlike QNN or RBF-ML)
 | |
| * support for specification of per-dimensional  radii  via  scale  vector,
 | |
|   which is set by means of rbfsetpointsandscales() function. This  feature
 | |
|   is useful if you solve  spatio-temporal  interpolation  problems,  where
 | |
|   different radii are required for spatial and temporal dimensions.
 | |
| 
 | |
| Running times are roughly proportional to:
 | |
| * N*log(N)*NLayers - for model construction
 | |
| * N*NLayers - for model evaluation
 | |
| You may see that running time does not depend on search radius  or  points
 | |
| density, just on number of layers in the hierarchy.
 | |
| 
 | |
| IMPORTANT: this model construction algorithm was introduced in ALGLIB 3.11
 | |
|            and  produces  models  which  are  INCOMPATIBLE  with  previous
 | |
|            versions of ALGLIB. You can  not  unserialize  models  produced
 | |
|            with this function in ALGLIB 3.10 or earlier.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by rbfcreate() call
 | |
|     RBase   -   RBase parameter, RBase>0
 | |
|     NLayers -   NLayers parameter, NLayers>0, recommended value  to  start
 | |
|                 with - about 5.
 | |
|     LambdaNS-   >=0, nonlinearity penalty coefficient, negative values are
 | |
|                 not allowed. This parameter adds controllable smoothing to
 | |
|                 the problem, which may reduce noise. Specification of non-
 | |
|                 zero lambda means that in addition to fitting error solver
 | |
|                 will  also  minimize   LambdaNS*|S''(x)|^2  (appropriately
 | |
|                 generalized to multiple dimensions.
 | |
|                 
 | |
|                 Specification of exactly zero value means that no  penalty
 | |
|                 is added  (we  do  not  even  evaluate  matrix  of  second
 | |
|                 derivatives which is necessary for smoothing).
 | |
|                 
 | |
|                 Calculation of nonlinearity penalty is costly - it results
 | |
|                 in  several-fold  increase  of  model  construction  time.
 | |
|                 Evaluation time remains the same.
 | |
|                 
 | |
|                 Optimal  lambda  is  problem-dependent and requires  trial
 | |
|                 and  error.  Good  value to  start  from  is  1e-5...1e-6,
 | |
|                 which corresponds to slightly noticeable smoothing  of the
 | |
|                 function.  Value  1e-2  usually  means  that  quite  heavy
 | |
|                 smoothing is applied.
 | |
| 
 | |
| TUNING ALGORITHM
 | |
| 
 | |
| In order to use this algorithm you have to choose three parameters:
 | |
| * initial radius RBase
 | |
| * number of layers in the model NLayers
 | |
| * penalty coefficient LambdaNS
 | |
| 
 | |
| Initial radius is easy to choose - you can pick any number  several  times
 | |
| larger  than  the  average  distance between points. Algorithm won't break
 | |
| down if you choose radius which is too large (model construction time will
 | |
| increase, but model will be built correctly).
 | |
| 
 | |
| Choose such number of layers that RLast=RBase/2^(NLayers-1)  (radius  used
 | |
| by  the  last  layer)  will  be  smaller than the typical distance between
 | |
| points.  In  case  model  error  is  too large, you can increase number of
 | |
| layers.  Having  more  layers  will make model construction and evaluation
 | |
| proportionally slower, but it will allow you to have model which precisely
 | |
| fits your data. From the other side, if you want to  suppress  noise,  you
 | |
| can DECREASE number of layers to make your model less flexible (or specify
 | |
| non-zero LambdaNS).
 | |
| 
 | |
| TYPICAL ERRORS
 | |
| 
 | |
| 1. Using too small number of layers - RBF models with large radius are not
 | |
|    flexible enough to reproduce small variations in the  target  function.
 | |
|    You  need  many  layers  with  different radii, from large to small, in
 | |
|    order to have good model.
 | |
| 
 | |
| 2. Using  initial  radius  which  is  too  small.  You will get model with
 | |
|    "holes" in the areas which are too far away from interpolation centers.
 | |
|    However, algorithm will work correctly (and quickly) in this case.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 20.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetalgohierarchical(rbfmodel* s,
 | |
|      double rbase,
 | |
|      ae_int_t nlayers,
 | |
|      double lambdans,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(rbase, _state), "RBFSetAlgoHierarchical: RBase is infinite or NaN", _state);
 | |
|     ae_assert(ae_fp_greater(rbase,(double)(0)), "RBFSetAlgoHierarchical: RBase<=0", _state);
 | |
|     ae_assert(nlayers>=0, "RBFSetAlgoHierarchical: NLayers<0", _state);
 | |
|     ae_assert(ae_isfinite(lambdans, _state)&&ae_fp_greater_eq(lambdans,(double)(0)), "RBFSetAlgoHierarchical: LambdaNS<0 or infinite", _state);
 | |
|     s->radvalue = rbase;
 | |
|     s->nlayers = nlayers;
 | |
|     s->algorithmtype = 3;
 | |
|     s->lambdav = lambdans;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets linear term (model is a sum of radial  basis  functions
 | |
| plus linear polynomial). This function won't have effect until  next  call 
 | |
| to RBFBuildModel().
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
| 
 | |
| NOTE: this   function  has   some   serialization-related  subtleties.  We
 | |
|       recommend you to study serialization examples from ALGLIB  Reference
 | |
|       Manual if you want to perform serialization of your models.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetlinterm(rbfmodel* s, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     s->aterm = 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets constant term (model is a sum of radial basis functions
 | |
| plus constant).  This  function  won't  have  effect  until  next  call to 
 | |
| RBFBuildModel().
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
| 
 | |
| NOTE: this   function  has   some   serialization-related  subtleties.  We
 | |
|       recommend you to study serialization examples from ALGLIB  Reference
 | |
|       Manual if you want to perform serialization of your models.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetconstterm(rbfmodel* s, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     s->aterm = 2;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This  function  sets  zero  term (model is a sum of radial basis functions 
 | |
| without polynomial term). This function won't have effect until next  call
 | |
| to RBFBuildModel().
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
| 
 | |
| NOTE: this   function  has   some   serialization-related  subtleties.  We
 | |
|       recommend you to study serialization examples from ALGLIB  Reference
 | |
|       Manual if you want to perform serialization of your models.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetzeroterm(rbfmodel* s, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     s->aterm = 3;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets basis function type, which can be:
 | |
| * 0 for classic Gaussian
 | |
| * 1 for fast and compact bell-like basis function, which  becomes  exactly
 | |
|   zero at distance equal to 3*R (default option).
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     BF      -   basis function type:
 | |
|                 * 0 - classic Gaussian
 | |
|                 * 1 - fast and compact one
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetv2bf(rbfmodel* s, ae_int_t bf, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(bf==0||bf==1, "RBFSetV2Its: BF<>0 and BF<>1", _state);
 | |
|     s->model2.basisfunction = bf;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets stopping criteria of the underlying linear  solver  for
 | |
| hierarchical (version 2) RBF constructor.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     MaxIts  -   this criterion will stop algorithm after MaxIts iterations.
 | |
|                 Typically a few hundreds iterations is required,  with 400
 | |
|                 being a good default value to start experimentation.
 | |
|                 Zero value means that default value will be selected.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetv2its(rbfmodel* s, ae_int_t maxits, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(maxits>=0, "RBFSetV2Its: MaxIts is negative", _state);
 | |
|     s->model2.maxits = maxits;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets support radius parameter  of  hierarchical  (version 2)
 | |
| RBF constructor.
 | |
| 
 | |
| Hierarchical RBF model achieves great speed-up  by removing from the model
 | |
| excessive (too dense) nodes. Say, if you have RBF radius equal to 1 meter,
 | |
| and two nodes are just 1 millimeter apart, you  may  remove  one  of  them
 | |
| without reducing model quality.
 | |
| 
 | |
| Support radius parameter is used to justify which points need removal, and
 | |
| which do not. If two points are less than  SUPPORT_R*CUR_RADIUS  units  of
 | |
| distance apart, one of them is removed from the model. The larger  support
 | |
| radius  is, the faster model  construction  AND  evaluation are.  However,
 | |
| too large values result in "bumpy" models.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     R       -   support radius coefficient, >=0.
 | |
|                 Recommended values are [0.1,0.4] range, with 0.1 being
 | |
|                 default value.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 01.02.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetv2supportr(rbfmodel* s, double r, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(r, _state), "RBFSetV2SupportR: R is not finite", _state);
 | |
|     ae_assert(ae_fp_greater_eq(r,(double)(0)), "RBFSetV2SupportR: R<0", _state);
 | |
|     s->model2.supportr = r;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function sets stopping criteria of the underlying linear solver.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     EpsOrt  -   orthogonality stopping criterion, EpsOrt>=0. Algorithm will
 | |
|                 stop when ||A'*r||<=EpsOrt where A' is a transpose of  the 
 | |
|                 system matrix, r is a residual vector.
 | |
|                 Recommended value of EpsOrt is equal to 1E-6.
 | |
|                 This criterion will stop algorithm when we have "bad fit"
 | |
|                 situation, i.e. when we should stop in a point with large,
 | |
|                 nonzero residual.
 | |
|     EpsErr  -   residual stopping  criterion.  Algorithm  will  stop  when
 | |
|                 ||r||<=EpsErr*||b||, where r is a residual vector, b is  a
 | |
|                 right part of the system (function values).
 | |
|                 Recommended value of EpsErr is equal to 1E-3 or 1E-6.
 | |
|                 This  criterion  will  stop  algorithm  in  a  "good  fit" 
 | |
|                 situation when we have near-zero residual near the desired
 | |
|                 solution.
 | |
|     MaxIts  -   this criterion will stop algorithm after MaxIts iterations.
 | |
|                 It should be used for debugging purposes only!
 | |
|                 Zero MaxIts means that no limit is placed on the number of
 | |
|                 iterations.
 | |
| 
 | |
| We  recommend  to  set  moderate  non-zero  values   EpsOrt   and   EpsErr 
 | |
| simultaneously. Values equal to 10E-6 are good to start with. In case  you
 | |
| need high performance and do not need high precision ,  you  may  decrease
 | |
| EpsErr down to 0.001. However, we do not recommend decreasing EpsOrt.
 | |
| 
 | |
| As for MaxIts, we recommend to leave it zero unless you know what you do.
 | |
| 
 | |
| NOTE: this   function  has   some   serialization-related  subtleties.  We
 | |
|       recommend you to study serialization examples from ALGLIB  Reference
 | |
|       Manual if you want to perform serialization of your models.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfsetcond(rbfmodel* s,
 | |
|      double epsort,
 | |
|      double epserr,
 | |
|      ae_int_t maxits,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(epsort, _state)&&ae_fp_greater_eq(epsort,(double)(0)), "RBFSetCond: EpsOrt is negative, INF or NAN", _state);
 | |
|     ae_assert(ae_isfinite(epserr, _state)&&ae_fp_greater_eq(epserr,(double)(0)), "RBFSetCond: EpsB is negative, INF or NAN", _state);
 | |
|     ae_assert(maxits>=0, "RBFSetCond: MaxIts is negative", _state);
 | |
|     if( (ae_fp_eq(epsort,(double)(0))&&ae_fp_eq(epserr,(double)(0)))&&maxits==0 )
 | |
|     {
 | |
|         s->epsort = rbf_eps;
 | |
|         s->epserr = rbf_eps;
 | |
|         s->maxits = 0;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         s->epsort = epsort;
 | |
|         s->epserr = epserr;
 | |
|         s->maxits = maxits;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This   function  builds  RBF  model  and  returns  report  (contains  some 
 | |
| information which can be used for evaluation of the algorithm properties).
 | |
| 
 | |
| Call to this function modifies RBF model by calculating its centers/radii/
 | |
| weights  and  saving  them  into  RBFModel  structure.  Initially RBFModel 
 | |
| contain zero coefficients, but after call to this function  we  will  have
 | |
| coefficients which were calculated in order to fit our dataset.
 | |
| 
 | |
| After you called this function you can call RBFCalc(),  RBFGridCalc()  and
 | |
| other model calculation functions.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, initialized by RBFCreate() call
 | |
|     Rep     -   report:
 | |
|                 * Rep.TerminationType:
 | |
|                   * -5 - non-distinct basis function centers were detected,
 | |
|                          interpolation  aborted;  only  QNN  returns  this
 | |
|                          error   code, other  algorithms  can  handle non-
 | |
|                          distinct nodes.
 | |
|                   * -4 - nonconvergence of the internal SVD solver
 | |
|                   * -3   incorrect model construction algorithm was chosen:
 | |
|                          QNN or RBF-ML, combined with one of the incompatible
 | |
|                          features - NX=1 or NX>3; points with per-dimension
 | |
|                          scales.
 | |
|                   *  1 - successful termination
 | |
|                   *  8 - a termination request was submitted via
 | |
|                          rbfrequesttermination() function.
 | |
|                 
 | |
|                 Fields which are set only by modern RBF solvers (hierarchical
 | |
|                 or nonnegative; older solvers like QNN and ML initialize these
 | |
|                 fields by NANs):
 | |
|                 * rep.rmserror - root-mean-square error at nodes
 | |
|                 * rep.maxerror - maximum error at nodes
 | |
|                 
 | |
|                 Fields are used for debugging purposes:
 | |
|                 * Rep.IterationsCount - iterations count of the LSQR solver
 | |
|                 * Rep.NMV - number of matrix-vector products
 | |
|                 * Rep.ARows - rows count for the system matrix
 | |
|                 * Rep.ACols - columns count for the system matrix
 | |
|                 * Rep.ANNZ - number of significantly non-zero elements
 | |
|                   (elements above some algorithm-determined threshold)
 | |
| 
 | |
| NOTE:  failure  to  build  model will leave current state of the structure
 | |
| unchanged.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfbuildmodel(rbfmodel* s, rbfreport* rep, ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     rbfv1report rep1;
 | |
|     rbfv2report rep2;
 | |
|     ae_matrix x3;
 | |
|     ae_vector scalevec;
 | |
|     ae_int_t i;
 | |
|     ae_int_t curalgorithmtype;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&rep1, 0, sizeof(rep1));
 | |
|     memset(&rep2, 0, sizeof(rep2));
 | |
|     memset(&x3, 0, sizeof(x3));
 | |
|     memset(&scalevec, 0, sizeof(scalevec));
 | |
|     _rbfreport_clear(rep);
 | |
|     _rbfv1report_init(&rep1, _state, ae_true);
 | |
|     _rbfv2report_init(&rep2, _state, ae_true);
 | |
|     ae_matrix_init(&x3, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&scalevec, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Clean fields prior to processing
 | |
|      */
 | |
|     rbf_clearreportfields(rep, _state);
 | |
|     s->progress10000 = 0;
 | |
|     s->terminationrequest = ae_false;
 | |
|     
 | |
|     /*
 | |
|      * Autoselect algorithm
 | |
|      */
 | |
|     if( s->algorithmtype==0 )
 | |
|     {
 | |
|         if( (s->nx<2||s->nx>3)||s->hasscale )
 | |
|         {
 | |
|             curalgorithmtype = 3;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             curalgorithmtype = 1;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         curalgorithmtype = s->algorithmtype;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Algorithms which generate V1 models
 | |
|      */
 | |
|     if( curalgorithmtype==1||curalgorithmtype==2 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Perform compatibility checks
 | |
|          */
 | |
|         if( (s->nx<2||s->nx>3)||s->hasscale )
 | |
|         {
 | |
|             rep->terminationtype = -3;
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Try to build model.
 | |
|          *
 | |
|          * NOTE: due to historical reasons RBFV1BuildModel() accepts points
 | |
|          *       cast to 3-dimensional space, even if they are really 2-dimensional.
 | |
|          *       So, for 2D data we have to explicitly convert them to 3D.
 | |
|          */
 | |
|         if( s->nx==2 )
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Convert data to 3D
 | |
|              */
 | |
|             rmatrixsetlengthatleast(&x3, s->n, 3, _state);
 | |
|             for(i=0; i<=s->n-1; i++)
 | |
|             {
 | |
|                 x3.ptr.pp_double[i][0] = s->x.ptr.pp_double[i][0];
 | |
|                 x3.ptr.pp_double[i][1] = s->x.ptr.pp_double[i][1];
 | |
|                 x3.ptr.pp_double[i][2] = (double)(0);
 | |
|             }
 | |
|             rbfv1buildmodel(&x3, &s->y, s->n, s->aterm, curalgorithmtype, s->nlayers, s->radvalue, s->radzvalue, s->lambdav, s->epsort, s->epserr, s->maxits, &s->model1, &rep1, _state);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * Work with raw data
 | |
|              */
 | |
|             rbfv1buildmodel(&s->x, &s->y, s->n, s->aterm, curalgorithmtype, s->nlayers, s->radvalue, s->radzvalue, s->lambdav, s->epsort, s->epserr, s->maxits, &s->model1, &rep1, _state);
 | |
|         }
 | |
|         s->modelversion = 1;
 | |
|         
 | |
|         /*
 | |
|          * Convert report fields
 | |
|          */
 | |
|         rep->arows = rep1.arows;
 | |
|         rep->acols = rep1.acols;
 | |
|         rep->annz = rep1.annz;
 | |
|         rep->iterationscount = rep1.iterationscount;
 | |
|         rep->nmv = rep1.nmv;
 | |
|         rep->terminationtype = rep1.terminationtype;
 | |
|         
 | |
|         /*
 | |
|          * Done
 | |
|          */
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Algorithms which generate V2 models
 | |
|      */
 | |
|     if( curalgorithmtype==3 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Prepare scale vector - use unit values or user supplied ones
 | |
|          */
 | |
|         ae_vector_set_length(&scalevec, s->nx, _state);
 | |
|         for(i=0; i<=s->nx-1; i++)
 | |
|         {
 | |
|             if( s->hasscale )
 | |
|             {
 | |
|                 scalevec.ptr.p_double[i] = s->s.ptr.p_double[i];
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 scalevec.ptr.p_double[i] = (double)(1);
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Build model
 | |
|          */
 | |
|         rbfv2buildhierarchical(&s->x, &s->y, s->n, &scalevec, s->aterm, s->nlayers, s->radvalue, s->lambdav, &s->model2, &s->progress10000, &s->terminationrequest, &rep2, _state);
 | |
|         s->modelversion = 2;
 | |
|         
 | |
|         /*
 | |
|          * Convert report fields
 | |
|          */
 | |
|         rep->terminationtype = rep2.terminationtype;
 | |
|         rep->rmserror = rep2.rmserror;
 | |
|         rep->maxerror = rep2.maxerror;
 | |
|         
 | |
|         /*
 | |
|          * Done
 | |
|          */
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Critical error
 | |
|      */
 | |
|     ae_assert(ae_false, "RBFBuildModel: integrity check failure", _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model in the given point.
 | |
| 
 | |
| IMPORTANT: this function works only with modern  (hierarchical)  RBFs.  It 
 | |
|            can not be used with legacy (version 1) RBFs because older  RBF
 | |
|            code does not support 1-dimensional models.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=1
 | |
| (1-dimensional space). If you have 3-dimensional space, use rbfcalc3(). If
 | |
| you  have  2-dimensional  space,  use  rbfcalc3().  If  you  have  general
 | |
| situation (NX-dimensional space, NY-dimensional function)  you  should use
 | |
| generic rbfcalc().
 | |
| 
 | |
| If you want to perform parallel model evaluation  from  multiple  threads,
 | |
| use rbftscalcbuf() with per-thread buffer object.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>1
 | |
| * NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   X-coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfcalc1(rbfmodel* s, double x0, ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(x0, _state), "RBFCalc1: invalid value for X0 (X0 is Inf)!", _state);
 | |
|     result = (double)(0);
 | |
|     if( s->ny!=1||s->nx!=1 )
 | |
|     {
 | |
|         return result;
 | |
|     }
 | |
|     if( s->modelversion==1 )
 | |
|     {
 | |
|         result = (double)(0);
 | |
|         return result;
 | |
|     }
 | |
|     if( s->modelversion==2 )
 | |
|     {
 | |
|         result = rbfv2calc1(&s->model2, x0, _state);
 | |
|         return result;
 | |
|     }
 | |
|     ae_assert(ae_false, "RBFCalc1: integrity check failed", _state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model in the given point.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=2
 | |
| (2-dimensional space). If you have 3-dimensional space, use rbfcalc3(). If
 | |
| you have general situation (NX-dimensional space, NY-dimensional function)
 | |
| you should use generic rbfcalc().
 | |
| 
 | |
| If  you  want  to  calculate  function  values  many times, consider using 
 | |
| rbfgridcalc2v(), which is far more efficient than many subsequent calls to
 | |
| rbfcalc2().
 | |
| 
 | |
| If you want to perform parallel model evaluation  from  multiple  threads,
 | |
| use rbftscalcbuf() with per-thread buffer object.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>2
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   first coordinate, finite number
 | |
|     X1      -   second coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfcalc2(rbfmodel* s, double x0, double x1, ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(x0, _state), "RBFCalc2: invalid value for X0 (X0 is Inf)!", _state);
 | |
|     ae_assert(ae_isfinite(x1, _state), "RBFCalc2: invalid value for X1 (X1 is Inf)!", _state);
 | |
|     result = (double)(0);
 | |
|     if( s->ny!=1||s->nx!=2 )
 | |
|     {
 | |
|         return result;
 | |
|     }
 | |
|     if( s->modelversion==1 )
 | |
|     {
 | |
|         result = rbfv1calc2(&s->model1, x0, x1, _state);
 | |
|         return result;
 | |
|     }
 | |
|     if( s->modelversion==2 )
 | |
|     {
 | |
|         result = rbfv2calc2(&s->model2, x0, x1, _state);
 | |
|         return result;
 | |
|     }
 | |
|     ae_assert(ae_false, "RBFCalc2: integrity check failed", _state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates value of the RBF model in the given point.
 | |
| 
 | |
| This function should be used when we have NY=1 (scalar function) and  NX=3
 | |
| (3-dimensional space). If you have 2-dimensional space, use rbfcalc2(). If
 | |
| you have general situation (NX-dimensional space, NY-dimensional function)
 | |
| you should use generic rbfcalc().
 | |
| 
 | |
| If  you  want  to  calculate  function  values  many times, consider using 
 | |
| rbfgridcalc3v(), which is far more efficient than many subsequent calls to
 | |
| rbfcalc3().
 | |
| 
 | |
| If you want to perform parallel model evaluation  from  multiple  threads,
 | |
| use rbftscalcbuf() with per-thread buffer object.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>3
 | |
|  *NY<>1
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X0      -   first coordinate, finite number
 | |
|     X1      -   second coordinate, finite number
 | |
|     X2      -   third coordinate, finite number
 | |
| 
 | |
| RESULT:
 | |
|     value of the model or 0.0 (as defined above)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfcalc3(rbfmodel* s,
 | |
|      double x0,
 | |
|      double x1,
 | |
|      double x2,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     ae_assert(ae_isfinite(x0, _state), "RBFCalc3: invalid value for X0 (X0 is Inf or NaN)!", _state);
 | |
|     ae_assert(ae_isfinite(x1, _state), "RBFCalc3: invalid value for X1 (X1 is Inf or NaN)!", _state);
 | |
|     ae_assert(ae_isfinite(x2, _state), "RBFCalc3: invalid value for X2 (X2 is Inf or NaN)!", _state);
 | |
|     result = (double)(0);
 | |
|     if( s->ny!=1||s->nx!=3 )
 | |
|     {
 | |
|         return result;
 | |
|     }
 | |
|     if( s->modelversion==1 )
 | |
|     {
 | |
|         result = rbfv1calc3(&s->model1, x0, x1, x2, _state);
 | |
|         return result;
 | |
|     }
 | |
|     if( s->modelversion==2 )
 | |
|     {
 | |
|         result = rbfv2calc3(&s->model2, x0, x1, x2, _state);
 | |
|         return result;
 | |
|     }
 | |
|     ae_assert(ae_false, "RBFCalc3: integrity check failed", _state);
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the given point.
 | |
| 
 | |
| This is general function which can be used for arbitrary NX (dimension  of 
 | |
| the space of arguments) and NY (dimension of the function itself). However
 | |
| when  you  have  NY=1  you  may  find more convenient to use rbfcalc2() or 
 | |
| rbfcalc3().
 | |
| 
 | |
| If you want to perform parallel model evaluation  from  multiple  threads,
 | |
| use rbftscalcbuf() with per-thread buffer object.
 | |
| 
 | |
| This function returns 0.0 when model is not initialized.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X       -   coordinates, array[NX].
 | |
|                 X may have more than NX elements, in this case only 
 | |
|                 leading NX will be used.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is out-parameter and 
 | |
|                 reallocated after call to this function. In case you  want
 | |
|                 to reuse previously allocated Y, you may use RBFCalcBuf(),
 | |
|                 which reallocates Y only when it is too small.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfcalc(rbfmodel* s,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     ae_vector_clear(y);
 | |
| 
 | |
|     ae_assert(x->cnt>=s->nx, "RBFCalc: Length(X)<NX", _state);
 | |
|     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalc: X contains infinite or NaN values", _state);
 | |
|     rbfcalcbuf(s, x, y, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the given point.
 | |
| 
 | |
| Same as rbfcalc(), but does not reallocate Y when in is large enough to 
 | |
| store function values.
 | |
| 
 | |
| If you want to perform parallel model evaluation  from  multiple  threads,
 | |
| use rbftscalcbuf() with per-thread buffer object.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
|     X       -   coordinates, array[NX].
 | |
|                 X may have more than NX elements, in this case only 
 | |
|                 leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfcalcbuf(rbfmodel* s,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
| 
 | |
|     ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)<NX", _state);
 | |
|     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state);
 | |
|     if( y->cnt<s->ny )
 | |
|     {
 | |
|         ae_vector_set_length(y, s->ny, _state);
 | |
|     }
 | |
|     for(i=0; i<=s->ny-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     if( s->modelversion==1 )
 | |
|     {
 | |
|         rbfv1calcbuf(&s->model1, x, y, _state);
 | |
|         return;
 | |
|     }
 | |
|     if( s->modelversion==2 )
 | |
|     {
 | |
|         rbfv2calcbuf(&s->model2, x, y, _state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(ae_false, "RBFCalcBuf: integrity check failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at the given point, using
 | |
| external  buffer  object  (internal  temporaries  of  RBF  model  are  not
 | |
| modified).
 | |
| 
 | |
| This function allows to use same RBF model object  in  different  threads,
 | |
| assuming  that  different   threads  use  different  instances  of  buffer
 | |
| structure.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, may be shared between different threads
 | |
|     Buf     -   buffer object created for this particular instance of  RBF
 | |
|                 model with rbfcreatecalcbuffer().
 | |
|     X       -   coordinates, array[NX].
 | |
|                 X may have more than NX elements, in this case only 
 | |
|                 leading NX will be used.
 | |
|     Y       -   possibly preallocated array
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function value, array[NY]. Y is not reallocated when it
 | |
|                 is larger than NY.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbftscalcbuf(rbfmodel* s,
 | |
|      rbfcalcbuffer* buf,
 | |
|      /* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
| 
 | |
|     ae_assert(x->cnt>=s->nx, "RBFCalcBuf: Length(X)<NX", _state);
 | |
|     ae_assert(isfinitevector(x, s->nx, _state), "RBFCalcBuf: X contains infinite or NaN values", _state);
 | |
|     ae_assert(s->modelversion==buf->modelversion, "RBFCalcBuf: buffer object is not compatible with RBF model", _state);
 | |
|     if( y->cnt<s->ny )
 | |
|     {
 | |
|         ae_vector_set_length(y, s->ny, _state);
 | |
|     }
 | |
|     for(i=0; i<=s->ny-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     if( s->modelversion==1 )
 | |
|     {
 | |
|         rbfv1tscalcbuf(&s->model1, &buf->bufv1, x, y, _state);
 | |
|         return;
 | |
|     }
 | |
|     if( s->modelversion==2 )
 | |
|     {
 | |
|         rbfv2tscalcbuf(&s->model2, &buf->bufv2, x, y, _state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(ae_false, "RBFTsCalcBuf: integrity check failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This is legacy function for gridded calculation of RBF model.
 | |
| 
 | |
| It is superseded by rbfgridcalc2v() and  rbfgridcalc2vsubset()  functions.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc2(rbfmodel* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Real    */ ae_matrix* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector cpx0;
 | |
|     ae_vector cpx1;
 | |
|     ae_vector p01;
 | |
|     ae_vector p11;
 | |
|     ae_vector p2;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&cpx0, 0, sizeof(cpx0));
 | |
|     memset(&cpx1, 0, sizeof(cpx1));
 | |
|     memset(&p01, 0, sizeof(p01));
 | |
|     memset(&p11, 0, sizeof(p11));
 | |
|     memset(&p2, 0, sizeof(p2));
 | |
|     ae_matrix_clear(y);
 | |
|     ae_vector_init(&cpx0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&cpx1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&p01, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&p11, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&p2, 0, DT_INT, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n0>0, "RBFGridCalc2: invalid value for N0 (N0<=0)!", _state);
 | |
|     ae_assert(n1>0, "RBFGridCalc2: invalid value for N1 (N1<=0)!", _state);
 | |
|     ae_assert(x0->cnt>=n0, "RBFGridCalc2: Length(X0)<N0", _state);
 | |
|     ae_assert(x1->cnt>=n1, "RBFGridCalc2: Length(X1)<N1", _state);
 | |
|     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2: X0 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2: X1 contains infinite or NaN values!", _state);
 | |
|     if( s->modelversion==1 )
 | |
|     {
 | |
|         rbfv1gridcalc2(&s->model1, x0, n0, x1, n1, y, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     if( s->modelversion==2 )
 | |
|     {
 | |
|         rbfv2gridcalc2(&s->model2, x0, n0, x1, n1, y, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(ae_false, "RBFGridCalc2: integrity check failed", _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF  model  at  the  regular  grid,
 | |
| which  has  N0*N1 points, with Point[I,J] = (X0[I], X1[J]).  Vector-valued
 | |
| RBF models are supported.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>2
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
 | |
|       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
 | |
|       processed serially.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, used in read-only mode, can be  shared  between
 | |
|                 multiple   invocations  of  this  function  from  multiple
 | |
|                 threads.
 | |
|     
 | |
|     X0      -   array of grid nodes, first coordinates, array[N0].
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N0      -   grid size (number of nodes) in the first dimension
 | |
|     
 | |
|     X1      -   array of grid nodes, second coordinates, array[N1]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N1      -   grid size (number of nodes) in the second dimension
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function values, array[NY*N0*N1], where NY is a  number of
 | |
|                 "output" vector values (this  function   supports  vector-
 | |
|                 valued RBF models). Y is out-variable and  is  reallocated
 | |
|                 by this function.
 | |
|                 Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]), for:
 | |
|                 *  K=0...NY-1
 | |
|                 * I0=0...N0-1
 | |
|                 * I1=0...N1-1
 | |
| 
 | |
| NOTE: this function supports weakly ordered grid nodes, i.e. you may  have                
 | |
|       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
 | |
|       benefits  due  to   duplication  of  points,  just  convenience  and
 | |
|       flexibility.
 | |
|       
 | |
| NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
 | |
|       structure in multiple threads calling  this function  for  different
 | |
|       grids.
 | |
|       
 | |
| NOTE: if you need function values on some subset  of  regular  grid, which
 | |
|       may be described as "several compact and  dense  islands",  you  may
 | |
|       use rbfgridcalc2vsubset().
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 27.01.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc2v(rbfmodel* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_vector dummy;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&dummy, 0, sizeof(dummy));
 | |
|     ae_vector_clear(y);
 | |
|     ae_vector_init(&dummy, 0, DT_BOOL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n0>0, "RBFGridCalc2V: invalid value for N0 (N0<=0)!", _state);
 | |
|     ae_assert(n1>0, "RBFGridCalc2V: invalid value for N1 (N1<=0)!", _state);
 | |
|     ae_assert(x0->cnt>=n0, "RBFGridCalc2V: Length(X0)<N0", _state);
 | |
|     ae_assert(x1->cnt>=n1, "RBFGridCalc2V: Length(X1)<N1", _state);
 | |
|     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2V: X0 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2V: X1 contains infinite or NaN values!", _state);
 | |
|     for(i=0; i<=n0-2; i++)
 | |
|     {
 | |
|         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);
 | |
|     }
 | |
|     for(i=0; i<=n1-2; i++)
 | |
|     {
 | |
|         ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc2V: X1 is not ordered by ascending", _state);
 | |
|     }
 | |
|     rbfgridcalc2vx(s, x0, n0, x1, n1, &dummy, ae_false, y, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at some subset of regular
 | |
| grid:
 | |
| * grid has N0*N1 points, with Point[I,J] = (X0[I], X1[J])
 | |
| * only values at some subset of this grid are required
 | |
| Vector-valued RBF models are supported.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>2
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
 | |
|       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
 | |
|       processed serially.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, used in read-only mode, can be  shared  between
 | |
|                 multiple   invocations  of  this  function  from  multiple
 | |
|                 threads.
 | |
|     
 | |
|     X0      -   array of grid nodes, first coordinates, array[N0].
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N0      -   grid size (number of nodes) in the first dimension
 | |
|     
 | |
|     X1      -   array of grid nodes, second coordinates, array[N1]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N1      -   grid size (number of nodes) in the second dimension
 | |
|     
 | |
|     FlagY   -   array[N0*N1]:
 | |
|                 * Y[I0+I1*N0] corresponds to node (X0[I0],X1[I1])
 | |
|                 * it is a "bitmap" array which contains  False  for  nodes
 | |
|                   which are NOT calculated, and True for nodes  which  are
 | |
|                   required.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
 | |
|                 of "output" vector values (this function  supports vector-
 | |
|                 valued RBF models):
 | |
|                 * Y[K+NY*(I0+I1*N0)]=F_k(X0[I0],X1[I1]),
 | |
|                   for K=0...NY-1, I0=0...N0-1, I1=0...N1-1.
 | |
|                 * elements of Y[] which correspond  to  FlagY[]=True   are
 | |
|                   loaded by model values (which may be  exactly  zero  for
 | |
|                   some nodes).
 | |
|                 * elements of Y[] which correspond to FlagY[]=False MAY be
 | |
|                   initialized by zeros OR may be calculated. This function
 | |
|                   processes  grid  as  a  hierarchy  of  nested blocks and
 | |
|                   micro-rows. If just one element of micro-row is required,
 | |
|                   entire micro-row (up to 8 nodes in the current  version,
 | |
|                   but no promises) is calculated.
 | |
| 
 | |
| NOTE: this function supports weakly ordered grid nodes, i.e. you may  have                
 | |
|       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
 | |
|       benefits  due  to   duplication  of  points,  just  convenience  and
 | |
|       flexibility.
 | |
|       
 | |
| NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
 | |
|       structure in multiple threads calling  this function  for  different
 | |
|       grids.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 04.03.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc2vsubset(rbfmodel* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Boolean */ ae_vector* flagy,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_vector_clear(y);
 | |
| 
 | |
|     ae_assert(n0>0, "RBFGridCalc2VSubset: invalid value for N0 (N0<=0)!", _state);
 | |
|     ae_assert(n1>0, "RBFGridCalc2VSubset: invalid value for N1 (N1<=0)!", _state);
 | |
|     ae_assert(x0->cnt>=n0, "RBFGridCalc2VSubset: Length(X0)<N0", _state);
 | |
|     ae_assert(x1->cnt>=n1, "RBFGridCalc2VSubset: Length(X1)<N1", _state);
 | |
|     ae_assert(flagy->cnt>=n0*n1, "RBFGridCalc2VSubset: Length(FlagY)<N0*N1*N2", _state);
 | |
|     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2VSubset: X0 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2VSubset: X1 contains infinite or NaN values!", _state);
 | |
|     for(i=0; i<=n0-2; i++)
 | |
|     {
 | |
|         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);
 | |
|     }
 | |
|     for(i=0; i<=n1-2; i++)
 | |
|     {
 | |
|         ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc2VSubset: X1 is not ordered by ascending", _state);
 | |
|     }
 | |
|     rbfgridcalc2vx(s, x0, n0, x1, n1, flagy, ae_true, y, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF  model  at  the  regular  grid,
 | |
| which  has  N0*N1*N2  points,  with  Point[I,J,K] = (X0[I], X1[J], X2[K]).
 | |
| Vector-valued RBF models are supported.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>3
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
 | |
|       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
 | |
|       processed serially.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, used in read-only mode, can be  shared  between
 | |
|                 multiple   invocations  of  this  function  from  multiple
 | |
|                 threads.
 | |
|     
 | |
|     X0      -   array of grid nodes, first coordinates, array[N0].
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N0      -   grid size (number of nodes) in the first dimension
 | |
|     
 | |
|     X1      -   array of grid nodes, second coordinates, array[N1]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N1      -   grid size (number of nodes) in the second dimension
 | |
|     
 | |
|     X2      -   array of grid nodes, third coordinates, array[N2]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N2      -   grid size (number of nodes) in the third dimension
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
 | |
|                 of "output" vector values (this function  supports vector-
 | |
|                 valued RBF models). Y is out-variable and  is  reallocated
 | |
|                 by this function.
 | |
|                 Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]), for:
 | |
|                 *  K=0...NY-1
 | |
|                 * I0=0...N0-1
 | |
|                 * I1=0...N1-1
 | |
|                 * I2=0...N2-1
 | |
| 
 | |
| NOTE: this function supports weakly ordered grid nodes, i.e. you may  have                
 | |
|       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
 | |
|       benefits  due  to   duplication  of  points,  just  convenience  and
 | |
|       flexibility.
 | |
|       
 | |
| NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
 | |
|       structure in multiple threads calling  this function  for  different
 | |
|       grids.
 | |
|       
 | |
| NOTE: if you need function values on some subset  of  regular  grid, which
 | |
|       may be described as "several compact and  dense  islands",  you  may
 | |
|       use rbfgridcalc3vsubset().
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 04.03.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc3v(rbfmodel* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      ae_int_t n2,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_vector dummy;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&dummy, 0, sizeof(dummy));
 | |
|     ae_vector_clear(y);
 | |
|     ae_vector_init(&dummy, 0, DT_BOOL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n0>0, "RBFGridCalc3V: invalid value for N0 (N0<=0)!", _state);
 | |
|     ae_assert(n1>0, "RBFGridCalc3V: invalid value for N1 (N1<=0)!", _state);
 | |
|     ae_assert(n2>0, "RBFGridCalc3V: invalid value for N2 (N2<=0)!", _state);
 | |
|     ae_assert(x0->cnt>=n0, "RBFGridCalc3V: Length(X0)<N0", _state);
 | |
|     ae_assert(x1->cnt>=n1, "RBFGridCalc3V: Length(X1)<N1", _state);
 | |
|     ae_assert(x2->cnt>=n2, "RBFGridCalc3V: Length(X2)<N2", _state);
 | |
|     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc3V: X0 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc3V: X1 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x2, n2, _state), "RBFGridCalc3V: X2 contains infinite or NaN values!", _state);
 | |
|     for(i=0; i<=n0-2; i++)
 | |
|     {
 | |
|         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);
 | |
|     }
 | |
|     for(i=0; i<=n1-2; i++)
 | |
|     {
 | |
|         ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc3V: X1 is not ordered by ascending", _state);
 | |
|     }
 | |
|     for(i=0; i<=n2-2; i++)
 | |
|     {
 | |
|         ae_assert(ae_fp_less_eq(x2->ptr.p_double[i],x2->ptr.p_double[i+1]), "RBFGridCalc3V: X2 is not ordered by ascending", _state);
 | |
|     }
 | |
|     rbfgridcalc3vx(s, x0, n0, x1, n1, x2, n2, &dummy, ae_false, y, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function calculates values of the RBF model at some subset of regular
 | |
| grid:
 | |
| * grid has N0*N1*N2 points, with Point[I,J,K] = (X0[I], X1[J], X2[K])
 | |
| * only values at some subset of this grid are required
 | |
| Vector-valued RBF models are supported.
 | |
| 
 | |
| This function returns 0.0 when:
 | |
| * model is not initialized
 | |
| * NX<>3
 | |
| 
 | |
|   ! COMMERCIAL EDITION OF ALGLIB:
 | |
|   ! 
 | |
|   ! Commercial Edition of ALGLIB includes following important improvements
 | |
|   ! of this function:
 | |
|   ! * high-performance native backend with same C# interface (C# version)
 | |
|   ! * multithreading support (C++ and C# versions)
 | |
|   ! 
 | |
|   ! We recommend you to read 'Working with commercial version' section  of
 | |
|   ! ALGLIB Reference Manual in order to find out how to  use  performance-
 | |
|   ! related features provided by commercial edition of ALGLIB.
 | |
| 
 | |
| NOTE: Parallel  processing  is  implemented only for modern (hierarchical)
 | |
|       RBFs. Legacy version 1 RBFs (created  by  QNN  or  RBF-ML) are still
 | |
|       processed serially.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model, used in read-only mode, can be  shared  between
 | |
|                 multiple   invocations  of  this  function  from  multiple
 | |
|                 threads.
 | |
|     
 | |
|     X0      -   array of grid nodes, first coordinates, array[N0].
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N0      -   grid size (number of nodes) in the first dimension
 | |
|     
 | |
|     X1      -   array of grid nodes, second coordinates, array[N1]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N1      -   grid size (number of nodes) in the second dimension
 | |
|     
 | |
|     X2      -   array of grid nodes, third coordinates, array[N2]
 | |
|                 Must be ordered by ascending. Exception is generated
 | |
|                 if the array is not correctly ordered.
 | |
|     N2      -   grid size (number of nodes) in the third dimension
 | |
|     
 | |
|     FlagY   -   array[N0*N1*N2]:
 | |
|                 * Y[I0+I1*N0+I2*N0*N1] corresponds to node (X0[I0],X1[I1],X2[I2])
 | |
|                 * it is a "bitmap" array which contains  False  for  nodes
 | |
|                   which are NOT calculated, and True for nodes  which  are
 | |
|                   required.
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     Y       -   function values, array[NY*N0*N1*N2], where NY is a  number
 | |
|                 of "output" vector values (this function  supports vector-
 | |
|                 valued RBF models):
 | |
|                 * Y[K+NY*(I0+I1*N0+I2*N0*N1)]=F_k(X0[I0],X1[I1],X2[I2]),
 | |
|                   for K=0...NY-1, I0=0...N0-1, I1=0...N1-1, I2=0...N2-1.
 | |
|                 * elements of Y[] which correspond  to  FlagY[]=True   are
 | |
|                   loaded by model values (which may be  exactly  zero  for
 | |
|                   some nodes).
 | |
|                 * elements of Y[] which correspond to FlagY[]=False MAY be
 | |
|                   initialized by zeros OR may be calculated. This function
 | |
|                   processes  grid  as  a  hierarchy  of  nested blocks and
 | |
|                   micro-rows. If just one element of micro-row is required,
 | |
|                   entire micro-row (up to 8 nodes in the current  version,
 | |
|                   but no promises) is calculated.
 | |
| 
 | |
| NOTE: this function supports weakly ordered grid nodes, i.e. you may  have                
 | |
|       X[i]=X[i+1] for some i. It does  not  provide  you  any  performance
 | |
|       benefits  due  to   duplication  of  points,  just  convenience  and
 | |
|       flexibility.
 | |
|       
 | |
| NOTE: this  function  is  re-entrant,  i.e.  you  may  use  same  rbfmodel
 | |
|       structure in multiple threads calling  this function  for  different
 | |
|       grids.
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 04.03.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc3vsubset(rbfmodel* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      ae_int_t n2,
 | |
|      /* Boolean */ ae_vector* flagy,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_vector_clear(y);
 | |
| 
 | |
|     ae_assert(n0>0, "RBFGridCalc3VSubset: invalid value for N0 (N0<=0)!", _state);
 | |
|     ae_assert(n1>0, "RBFGridCalc3VSubset: invalid value for N1 (N1<=0)!", _state);
 | |
|     ae_assert(n2>0, "RBFGridCalc3VSubset: invalid value for N2 (N2<=0)!", _state);
 | |
|     ae_assert(x0->cnt>=n0, "RBFGridCalc3VSubset: Length(X0)<N0", _state);
 | |
|     ae_assert(x1->cnt>=n1, "RBFGridCalc3VSubset: Length(X1)<N1", _state);
 | |
|     ae_assert(x2->cnt>=n2, "RBFGridCalc3VSubset: Length(X2)<N2", _state);
 | |
|     ae_assert(flagy->cnt>=n0*n1*n2, "RBFGridCalc3VSubset: Length(FlagY)<N0*N1*N2", _state);
 | |
|     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc3VSubset: X0 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc3VSubset: X1 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x2, n2, _state), "RBFGridCalc3VSubset: X2 contains infinite or NaN values!", _state);
 | |
|     for(i=0; i<=n0-2; i++)
 | |
|     {
 | |
|         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);
 | |
|     }
 | |
|     for(i=0; i<=n1-2; i++)
 | |
|     {
 | |
|         ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc3VSubset: X1 is not ordered by ascending", _state);
 | |
|     }
 | |
|     for(i=0; i<=n2-2; i++)
 | |
|     {
 | |
|         ae_assert(ae_fp_less_eq(x2->ptr.p_double[i],x2->ptr.p_double[i+1]), "RBFGridCalc3VSubset: X2 is not ordered by ascending", _state);
 | |
|     }
 | |
|     rbfgridcalc3vx(s, x0, n0, x1, n1, x2, n2, flagy, ae_true, y, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function, depending on SparseY, acts as RBFGridCalc2V (SparseY=False)
 | |
| or RBFGridCalc2VSubset (SparseY=True) function.  See  comments  for  these
 | |
| functions for more information
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 04.03.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc2vx(rbfmodel* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Boolean */ ae_vector* flagy,
 | |
|      ae_bool sparsey,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
|     ae_int_t ylen;
 | |
|     hqrndstate rs;
 | |
|     ae_vector dummyx2;
 | |
|     ae_vector dummyx3;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t k;
 | |
|     ae_int_t l;
 | |
|     ae_vector tx;
 | |
|     ae_vector ty;
 | |
|     ae_int_t dstoffs;
 | |
|     rbfcalcbuffer calcbuf;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&rs, 0, sizeof(rs));
 | |
|     memset(&dummyx2, 0, sizeof(dummyx2));
 | |
|     memset(&dummyx3, 0, sizeof(dummyx3));
 | |
|     memset(&tx, 0, sizeof(tx));
 | |
|     memset(&ty, 0, sizeof(ty));
 | |
|     memset(&calcbuf, 0, sizeof(calcbuf));
 | |
|     _hqrndstate_init(&rs, _state, ae_true);
 | |
|     ae_vector_init(&dummyx2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dummyx3, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ty, 0, DT_REAL, _state, ae_true);
 | |
|     _rbfcalcbuffer_init(&calcbuf, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n0>0, "RBFGridCalc2VX: invalid value for N0 (N0<=0)!", _state);
 | |
|     ae_assert(n1>0, "RBFGridCalc2VX: invalid value for N1 (N1<=0)!", _state);
 | |
|     ae_assert(x0->cnt>=n0, "RBFGridCalc2VX: Length(X0)<N0", _state);
 | |
|     ae_assert(x1->cnt>=n1, "RBFGridCalc2VX: Length(X1)<N1", _state);
 | |
|     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc2VX: X0 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc2VX: X1 contains infinite or NaN values!", _state);
 | |
|     for(i=0; i<=n0-2; i++)
 | |
|     {
 | |
|         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);
 | |
|     }
 | |
|     for(i=0; i<=n1-2; i++)
 | |
|     {
 | |
|         ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc2VX: X1 is not ordered by ascending", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare local variables
 | |
|      */
 | |
|     nx = s->nx;
 | |
|     ny = s->ny;
 | |
|     hqrndseed(325, 46345, &rs, _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare output array
 | |
|      */
 | |
|     ylen = ny*n0*n1;
 | |
|     ae_vector_set_length(y, ylen, _state);
 | |
|     for(i=0; i<=ylen-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     if( s->nx!=2 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Process V2 model
 | |
|      */
 | |
|     if( s->modelversion==2 )
 | |
|     {
 | |
|         ae_vector_set_length(&dummyx2, 1, _state);
 | |
|         dummyx2.ptr.p_double[0] = (double)(0);
 | |
|         ae_vector_set_length(&dummyx3, 1, _state);
 | |
|         dummyx3.ptr.p_double[0] = (double)(0);
 | |
|         rbfv2gridcalcvx(&s->model2, x0, n0, x1, n1, &dummyx2, 1, &dummyx3, 1, flagy, sparsey, y, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Reference code for V1 models
 | |
|      */
 | |
|     if( s->modelversion==1 )
 | |
|     {
 | |
|         ae_vector_set_length(&tx, nx, _state);
 | |
|         rbfcreatecalcbuffer(s, &calcbuf, _state);
 | |
|         for(i=0; i<=n0-1; i++)
 | |
|         {
 | |
|             for(j=0; j<=n1-1; j++)
 | |
|             {
 | |
|                 k = i+j*n0;
 | |
|                 dstoffs = ny*k;
 | |
|                 if( sparsey&&!flagy->ptr.p_bool[k] )
 | |
|                 {
 | |
|                     for(l=0; l<=ny-1; l++)
 | |
|                     {
 | |
|                         y->ptr.p_double[l+dstoffs] = (double)(0);
 | |
|                     }
 | |
|                     continue;
 | |
|                 }
 | |
|                 tx.ptr.p_double[0] = x0->ptr.p_double[i];
 | |
|                 tx.ptr.p_double[1] = x1->ptr.p_double[j];
 | |
|                 rbftscalcbuf(s, &calcbuf, &tx, &ty, _state);
 | |
|                 for(l=0; l<=ny-1; l++)
 | |
|                 {
 | |
|                     y->ptr.p_double[l+dstoffs] = ty.ptr.p_double[l];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Unknown model
 | |
|      */
 | |
|     ae_assert(ae_false, "RBFGradCalc3VX: integrity check failed", _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function, depending on SparseY, acts as RBFGridCalc3V (SparseY=False)
 | |
| or RBFGridCalc3VSubset (SparseY=True) function.  See  comments  for  these
 | |
| functions for more information
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 04.03.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfgridcalc3vx(rbfmodel* s,
 | |
|      /* Real    */ ae_vector* x0,
 | |
|      ae_int_t n0,
 | |
|      /* Real    */ ae_vector* x1,
 | |
|      ae_int_t n1,
 | |
|      /* Real    */ ae_vector* x2,
 | |
|      ae_int_t n2,
 | |
|      /* Boolean */ ae_vector* flagy,
 | |
|      ae_bool sparsey,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_int_t i;
 | |
|     ae_int_t ylen;
 | |
|     ae_int_t nx;
 | |
|     ae_int_t ny;
 | |
|     double rmax;
 | |
|     ae_vector blocks0;
 | |
|     ae_vector blocks1;
 | |
|     ae_vector blocks2;
 | |
|     ae_int_t blockscnt0;
 | |
|     ae_int_t blockscnt1;
 | |
|     ae_int_t blockscnt2;
 | |
|     double blockwidth;
 | |
|     double searchradius;
 | |
|     double avgfuncpernode;
 | |
|     ae_int_t ntrials;
 | |
|     ae_int_t maxblocksize;
 | |
|     gridcalc3v1buf bufseedv1;
 | |
|     ae_shared_pool bufpool;
 | |
|     hqrndstate rs;
 | |
|     ae_vector dummyx3;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&blocks0, 0, sizeof(blocks0));
 | |
|     memset(&blocks1, 0, sizeof(blocks1));
 | |
|     memset(&blocks2, 0, sizeof(blocks2));
 | |
|     memset(&bufseedv1, 0, sizeof(bufseedv1));
 | |
|     memset(&bufpool, 0, sizeof(bufpool));
 | |
|     memset(&rs, 0, sizeof(rs));
 | |
|     memset(&dummyx3, 0, sizeof(dummyx3));
 | |
|     ae_vector_init(&blocks0, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&blocks1, 0, DT_INT, _state, ae_true);
 | |
|     ae_vector_init(&blocks2, 0, DT_INT, _state, ae_true);
 | |
|     _gridcalc3v1buf_init(&bufseedv1, _state, ae_true);
 | |
|     ae_shared_pool_init(&bufpool, _state, ae_true);
 | |
|     _hqrndstate_init(&rs, _state, ae_true);
 | |
|     ae_vector_init(&dummyx3, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n0>0, "RBFGridCalc3V: invalid value for N0 (N0<=0)!", _state);
 | |
|     ae_assert(n1>0, "RBFGridCalc3V: invalid value for N1 (N1<=0)!", _state);
 | |
|     ae_assert(n2>0, "RBFGridCalc3V: invalid value for N2 (N2<=0)!", _state);
 | |
|     ae_assert(x0->cnt>=n0, "RBFGridCalc3V: Length(X0)<N0", _state);
 | |
|     ae_assert(x1->cnt>=n1, "RBFGridCalc3V: Length(X1)<N1", _state);
 | |
|     ae_assert(x2->cnt>=n2, "RBFGridCalc3V: Length(X2)<N2", _state);
 | |
|     ae_assert(isfinitevector(x0, n0, _state), "RBFGridCalc3V: X0 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x1, n1, _state), "RBFGridCalc3V: X1 contains infinite or NaN values!", _state);
 | |
|     ae_assert(isfinitevector(x2, n2, _state), "RBFGridCalc3V: X2 contains infinite or NaN values!", _state);
 | |
|     for(i=0; i<=n0-2; i++)
 | |
|     {
 | |
|         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);
 | |
|     }
 | |
|     for(i=0; i<=n1-2; i++)
 | |
|     {
 | |
|         ae_assert(ae_fp_less_eq(x1->ptr.p_double[i],x1->ptr.p_double[i+1]), "RBFGridCalc3V: X1 is not ordered by ascending", _state);
 | |
|     }
 | |
|     for(i=0; i<=n2-2; i++)
 | |
|     {
 | |
|         ae_assert(ae_fp_less_eq(x2->ptr.p_double[i],x2->ptr.p_double[i+1]), "RBFGridCalc3V: X2 is not ordered by ascending", _state);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Prepare local variables
 | |
|      */
 | |
|     nx = s->nx;
 | |
|     ny = s->ny;
 | |
|     hqrndseed(325, 46345, &rs, _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare output array
 | |
|      */
 | |
|     ylen = ny*n0*n1*n2;
 | |
|     ae_vector_set_length(y, ylen, _state);
 | |
|     for(i=0; i<=ylen-1; i++)
 | |
|     {
 | |
|         y->ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     if( s->nx!=3 )
 | |
|     {
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Process V1 model
 | |
|      */
 | |
|     if( s->modelversion==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Fast exit for models without centers
 | |
|          */
 | |
|         if( s->model1.nc==0 )
 | |
|         {
 | |
|             ae_frame_leave(_state);
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         /*
 | |
|          * Prepare seed, create shared pool of temporary buffers
 | |
|          */
 | |
|         ae_vector_set_length(&bufseedv1.cx, nx, _state);
 | |
|         ae_vector_set_length(&bufseedv1.tx, nx, _state);
 | |
|         ae_vector_set_length(&bufseedv1.ty, ny, _state);
 | |
|         ae_vector_set_length(&bufseedv1.expbuf0, n0, _state);
 | |
|         ae_vector_set_length(&bufseedv1.expbuf1, n1, _state);
 | |
|         ae_vector_set_length(&bufseedv1.expbuf2, n2, _state);
 | |
|         kdtreecreaterequestbuffer(&s->model1.tree, &bufseedv1.requestbuf, _state);
 | |
|         ae_shared_pool_set_seed(&bufpool, &bufseedv1, sizeof(bufseedv1), _gridcalc3v1buf_init, _gridcalc3v1buf_init_copy, _gridcalc3v1buf_destroy, _state);
 | |
|         
 | |
|         /*
 | |
|          * Analyze input grid:
 | |
|          * * analyze average number of basis functions per grid node
 | |
|          * * partition grid in into blocks
 | |
|          */
 | |
|         rmax = s->model1.rmax;
 | |
|         blockwidth = 2*rmax;
 | |
|         maxblocksize = 8;
 | |
|         searchradius = rmax*rbf_rbffarradius+0.5*ae_sqrt((double)(s->nx), _state)*blockwidth;
 | |
|         ntrials = 100;
 | |
|         avgfuncpernode = 0.0;
 | |
|         for(i=0; i<=ntrials-1; i++)
 | |
|         {
 | |
|             bufseedv1.tx.ptr.p_double[0] = x0->ptr.p_double[hqrnduniformi(&rs, n0, _state)];
 | |
|             bufseedv1.tx.ptr.p_double[1] = x1->ptr.p_double[hqrnduniformi(&rs, n1, _state)];
 | |
|             bufseedv1.tx.ptr.p_double[2] = x2->ptr.p_double[hqrnduniformi(&rs, n2, _state)];
 | |
|             avgfuncpernode = avgfuncpernode+(double)kdtreetsqueryrnn(&s->model1.tree, &bufseedv1.requestbuf, &bufseedv1.tx, searchradius, ae_true, _state)/(double)ntrials;
 | |
|         }
 | |
|         ae_vector_set_length(&blocks0, n0+1, _state);
 | |
|         blockscnt0 = 0;
 | |
|         blocks0.ptr.p_int[0] = 0;
 | |
|         for(i=1; i<=n0-1; i++)
 | |
|         {
 | |
|             if( ae_fp_greater(x0->ptr.p_double[i]-x0->ptr.p_double[blocks0.ptr.p_int[blockscnt0]],blockwidth)||i-blocks0.ptr.p_int[blockscnt0]>=maxblocksize )
 | |
|             {
 | |
|                 inc(&blockscnt0, _state);
 | |
|                 blocks0.ptr.p_int[blockscnt0] = i;
 | |
|             }
 | |
|         }
 | |
|         inc(&blockscnt0, _state);
 | |
|         blocks0.ptr.p_int[blockscnt0] = n0;
 | |
|         ae_vector_set_length(&blocks1, n1+1, _state);
 | |
|         blockscnt1 = 0;
 | |
|         blocks1.ptr.p_int[0] = 0;
 | |
|         for(i=1; i<=n1-1; i++)
 | |
|         {
 | |
|             if( ae_fp_greater(x1->ptr.p_double[i]-x1->ptr.p_double[blocks1.ptr.p_int[blockscnt1]],blockwidth)||i-blocks1.ptr.p_int[blockscnt1]>=maxblocksize )
 | |
|             {
 | |
|                 inc(&blockscnt1, _state);
 | |
|                 blocks1.ptr.p_int[blockscnt1] = i;
 | |
|             }
 | |
|         }
 | |
|         inc(&blockscnt1, _state);
 | |
|         blocks1.ptr.p_int[blockscnt1] = n1;
 | |
|         ae_vector_set_length(&blocks2, n2+1, _state);
 | |
|         blockscnt2 = 0;
 | |
|         blocks2.ptr.p_int[0] = 0;
 | |
|         for(i=1; i<=n2-1; i++)
 | |
|         {
 | |
|             if( ae_fp_greater(x2->ptr.p_double[i]-x2->ptr.p_double[blocks2.ptr.p_int[blockscnt2]],blockwidth)||i-blocks2.ptr.p_int[blockscnt2]>=maxblocksize )
 | |
|             {
 | |
|                 inc(&blockscnt2, _state);
 | |
|                 blocks2.ptr.p_int[blockscnt2] = i;
 | |
|             }
 | |
|         }
 | |
|         inc(&blockscnt2, _state);
 | |
|         blocks2.ptr.p_int[blockscnt2] = n2;
 | |
|         
 | |
|         /*
 | |
|          * Perform calculation in multithreaded mode
 | |
|          */
 | |
|         rbfv1gridcalc3vrec(&s->model1, x0, n0, x1, n1, x2, n2, &blocks0, 0, blockscnt0, &blocks1, 0, blockscnt1, &blocks2, 0, blockscnt2, flagy, sparsey, searchradius, avgfuncpernode, &bufpool, y, _state);
 | |
|         
 | |
|         /*
 | |
|          * Done
 | |
|          */
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Process V2 model
 | |
|      */
 | |
|     if( s->modelversion==2 )
 | |
|     {
 | |
|         ae_vector_set_length(&dummyx3, 1, _state);
 | |
|         dummyx3.ptr.p_double[0] = (double)(0);
 | |
|         rbfv2gridcalcvx(&s->model2, x0, n0, x1, n1, x2, n2, &dummyx3, 1, flagy, sparsey, y, _state);
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Unknown model
 | |
|      */
 | |
|     ae_assert(ae_false, "RBFGradCalc3VX: integrity check failed", _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function "unpacks" RBF model by extracting its coefficients.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
| 
 | |
| OUTPUT PARAMETERS:
 | |
|     NX      -   dimensionality of argument
 | |
|     NY      -   dimensionality of the target function
 | |
|     XWR     -   model information, array[NC,NX+NY+1].
 | |
|                 One row of the array corresponds to one basis function:
 | |
|                 * first NX columns  - coordinates of the center 
 | |
|                 * next NY columns   - weights, one per dimension of the 
 | |
|                                       function being modelled
 | |
|                 For ModelVersion=1:
 | |
|                 * last column       - radius, same for all dimensions of
 | |
|                                       the function being modelled
 | |
|                 For ModelVersion=2:
 | |
|                 * last NX columns   - radii, one per dimension
 | |
|     NC      -   number of the centers
 | |
|     V       -   polynomial  term , array[NY,NX+1]. One row per one 
 | |
|                 dimension of the function being modelled. First NX 
 | |
|                 elements are linear coefficients, V[NX] is equal to the 
 | |
|                 constant part.
 | |
|     ModelVersion-version of the RBF model:
 | |
|                 * 1 - for models created by QNN and RBF-ML algorithms,
 | |
|                   compatible with ALGLIB 3.10 or earlier.
 | |
|                 * 2 - for models created by HierarchicalRBF, requires
 | |
|                   ALGLIB 3.11 or later
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 13.12.2011 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfunpack(rbfmodel* s,
 | |
|      ae_int_t* nx,
 | |
|      ae_int_t* ny,
 | |
|      /* Real    */ ae_matrix* xwr,
 | |
|      ae_int_t* nc,
 | |
|      /* Real    */ ae_matrix* v,
 | |
|      ae_int_t* modelversion,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     *nx = 0;
 | |
|     *ny = 0;
 | |
|     ae_matrix_clear(xwr);
 | |
|     *nc = 0;
 | |
|     ae_matrix_clear(v);
 | |
|     *modelversion = 0;
 | |
| 
 | |
|     if( s->modelversion==1 )
 | |
|     {
 | |
|         *modelversion = 1;
 | |
|         rbfv1unpack(&s->model1, nx, ny, xwr, nc, v, _state);
 | |
|         return;
 | |
|     }
 | |
|     if( s->modelversion==2 )
 | |
|     {
 | |
|         *modelversion = 2;
 | |
|         rbfv2unpack(&s->model2, nx, ny, xwr, nc, v, _state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(ae_false, "RBFUnpack: integrity check failure", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function returns model version.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S       -   RBF model
 | |
| 
 | |
| RESULT:
 | |
|     * 1 - for models created by QNN and RBF-ML algorithms,
 | |
|       compatible with ALGLIB 3.10 or earlier.
 | |
|     * 2 - for models created by HierarchicalRBF, requires
 | |
|       ALGLIB 3.11 or later
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 06.07.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| ae_int_t rbfgetmodelversion(rbfmodel* s, ae_state *_state)
 | |
| {
 | |
|     ae_int_t result;
 | |
| 
 | |
| 
 | |
|     result = s->modelversion;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is used to peek into hierarchical RBF  construction  process
 | |
| from  some  other  thread  and  get current progress indicator. It returns
 | |
| value in [0,1].
 | |
| 
 | |
| IMPORTANT: only HRBFs (hierarchical RBFs) support  peeking  into  progress
 | |
|            indicator. Legacy RBF-ML and RBF-QNN do  not  support  it.  You
 | |
|            will always get 0 value.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S           -   RBF model object
 | |
| 
 | |
| RESULT:
 | |
|     progress value, in [0,1]
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.11.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| double rbfpeekprogress(rbfmodel* s, ae_state *_state)
 | |
| {
 | |
|     double result;
 | |
| 
 | |
| 
 | |
|     result = (double)s->progress10000/(double)10000;
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function  is  used  to  submit  a  request  for  termination  of  the
 | |
| hierarchical RBF construction process from some other thread.  As  result,
 | |
| RBF construction is terminated smoothly (with proper deallocation  of  all
 | |
| necessary resources) and resultant model is filled by zeros.
 | |
| 
 | |
| A rep.terminationtype=8 will be returned upon receiving such request.
 | |
| 
 | |
| IMPORTANT: only  HRBFs  (hierarchical  RBFs) support termination requests.
 | |
|            Legacy RBF-ML and RBF-QNN do not  support  it.  An  attempt  to
 | |
|            terminate their construction will be ignored.
 | |
| 
 | |
| IMPORTANT: termination request flag is cleared when the model construction
 | |
|            starts. Thus, any pre-construction termination requests will be
 | |
|            silently ignored - only ones submitted AFTER  construction  has
 | |
|            actually began will be handled.
 | |
| 
 | |
| INPUT PARAMETERS:
 | |
|     S           -   RBF model object
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 17.11.2018 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfrequesttermination(rbfmodel* s, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     s->terminationrequest = ae_true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: allocation
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.02.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfalloc(ae_serializer* s, rbfmodel* model, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Header
 | |
|      */
 | |
|     ae_serializer_alloc_entry(s);
 | |
|     
 | |
|     /*
 | |
|      * V1 model
 | |
|      */
 | |
|     if( model->modelversion==1 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Header
 | |
|          */
 | |
|         ae_serializer_alloc_entry(s);
 | |
|         rbfv1alloc(s, &model->model1, _state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * V2 model
 | |
|      */
 | |
|     if( model->modelversion==2 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Header
 | |
|          */
 | |
|         ae_serializer_alloc_entry(s);
 | |
|         rbfv2alloc(s, &model->model2, _state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(ae_false, "Assertion failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: serialization
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.02.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfserialize(ae_serializer* s, rbfmodel* model, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     
 | |
|     /*
 | |
|      * Header
 | |
|      */
 | |
|     ae_serializer_serialize_int(s, getrbfserializationcode(_state), _state);
 | |
|     
 | |
|     /*
 | |
|      * V1 model
 | |
|      */
 | |
|     if( model->modelversion==1 )
 | |
|     {
 | |
|         ae_serializer_serialize_int(s, rbf_rbffirstversion, _state);
 | |
|         rbfv1serialize(s, &model->model1, _state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * V2 model
 | |
|      */
 | |
|     if( model->modelversion==2 )
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Header
 | |
|          */
 | |
|         ae_serializer_serialize_int(s, rbf_rbfversion2, _state);
 | |
|         rbfv2serialize(s, &model->model2, _state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(ae_false, "Assertion failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Serializer: unserialization
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 02.02.2012 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void rbfunserialize(ae_serializer* s, rbfmodel* model, ae_state *_state)
 | |
| {
 | |
|     ae_int_t i0;
 | |
|     ae_int_t i1;
 | |
| 
 | |
|     _rbfmodel_clear(model);
 | |
| 
 | |
|     rbf_rbfpreparenonserializablefields(model, _state);
 | |
|     
 | |
|     /*
 | |
|      * Header
 | |
|      */
 | |
|     ae_serializer_unserialize_int(s, &i0, _state);
 | |
|     ae_assert(i0==getrbfserializationcode(_state), "RBFUnserialize: stream header corrupted", _state);
 | |
|     ae_serializer_unserialize_int(s, &i1, _state);
 | |
|     ae_assert(i1==rbf_rbffirstversion||i1==rbf_rbfversion2, "RBFUnserialize: stream header corrupted", _state);
 | |
|     
 | |
|     /*
 | |
|      * V1 model
 | |
|      */
 | |
|     if( i1==rbf_rbffirstversion )
 | |
|     {
 | |
|         rbfv1unserialize(s, &model->model1, _state);
 | |
|         model->modelversion = 1;
 | |
|         model->ny = model->model1.ny;
 | |
|         model->nx = model->model1.nx;
 | |
|         rbf_initializev2(model->nx, model->ny, &model->model2, _state);
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * V2 model
 | |
|      */
 | |
|     if( i1==rbf_rbfversion2 )
 | |
|     {
 | |
|         rbfv2unserialize(s, &model->model2, _state);
 | |
|         model->modelversion = 2;
 | |
|         model->ny = model->model2.ny;
 | |
|         model->nx = model->model2.nx;
 | |
|         rbf_initializev1(model->nx, model->ny, &model->model1, _state);
 | |
|         return;
 | |
|     }
 | |
|     ae_assert(ae_false, "Assertion failed", _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Initialize empty model
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 12.05.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbf_rbfpreparenonserializablefields(rbfmodel* s,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     s->n = 0;
 | |
|     s->hasscale = ae_false;
 | |
|     s->radvalue = (double)(1);
 | |
|     s->radzvalue = (double)(5);
 | |
|     s->nlayers = 0;
 | |
|     s->lambdav = (double)(0);
 | |
|     s->aterm = 1;
 | |
|     s->algorithmtype = 0;
 | |
|     s->epsort = rbf_eps;
 | |
|     s->epserr = rbf_eps;
 | |
|     s->maxits = 0;
 | |
|     s->nnmaxits = 100;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Initialize V1 model (skip initialization for NX=1 or NX>3)
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 12.05.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbf_initializev1(ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      rbfv1model* s,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _rbfv1model_clear(s);
 | |
| 
 | |
|     if( nx==2||nx==3 )
 | |
|     {
 | |
|         rbfv1create(nx, ny, s, _state);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Initialize V2 model
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 12.05.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbf_initializev2(ae_int_t nx,
 | |
|      ae_int_t ny,
 | |
|      rbfv2model* s,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     _rbfv2model_clear(s);
 | |
| 
 | |
|     rbfv2create(nx, ny, s, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| Cleans report fields
 | |
| 
 | |
|   -- ALGLIB --
 | |
|      Copyright 16.06.2016 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| static void rbf_clearreportfields(rbfreport* rep, ae_state *_state)
 | |
| {
 | |
| 
 | |
| 
 | |
|     rep->rmserror = _state->v_nan;
 | |
|     rep->maxerror = _state->v_nan;
 | |
|     rep->arows = 0;
 | |
|     rep->acols = 0;
 | |
|     rep->annz = 0;
 | |
|     rep->iterationscount = 0;
 | |
|     rep->nmv = 0;
 | |
|     rep->terminationtype = 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfcalcbuffer_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfcalcbuffer *p = (rbfcalcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _rbfv1calcbuffer_init(&p->bufv1, _state, make_automatic);
 | |
|     _rbfv2calcbuffer_init(&p->bufv2, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfcalcbuffer_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfcalcbuffer *dst = (rbfcalcbuffer*)_dst;
 | |
|     rbfcalcbuffer *src = (rbfcalcbuffer*)_src;
 | |
|     dst->modelversion = src->modelversion;
 | |
|     _rbfv1calcbuffer_init_copy(&dst->bufv1, &src->bufv1, _state, make_automatic);
 | |
|     _rbfv2calcbuffer_init_copy(&dst->bufv2, &src->bufv2, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfcalcbuffer_clear(void* _p)
 | |
| {
 | |
|     rbfcalcbuffer *p = (rbfcalcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _rbfv1calcbuffer_clear(&p->bufv1);
 | |
|     _rbfv2calcbuffer_clear(&p->bufv2);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfcalcbuffer_destroy(void* _p)
 | |
| {
 | |
|     rbfcalcbuffer *p = (rbfcalcbuffer*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _rbfv1calcbuffer_destroy(&p->bufv1);
 | |
|     _rbfv2calcbuffer_destroy(&p->bufv2);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfmodel_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfmodel *p = (rbfmodel*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _rbfv1model_init(&p->model1, _state, make_automatic);
 | |
|     _rbfv2model_init(&p->model2, _state, make_automatic);
 | |
|     ae_matrix_init(&p->x, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_matrix_init(&p->y, 0, 0, DT_REAL, _state, make_automatic);
 | |
|     ae_vector_init(&p->s, 0, DT_REAL, _state, make_automatic);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfmodel_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfmodel *dst = (rbfmodel*)_dst;
 | |
|     rbfmodel *src = (rbfmodel*)_src;
 | |
|     dst->nx = src->nx;
 | |
|     dst->ny = src->ny;
 | |
|     dst->modelversion = src->modelversion;
 | |
|     _rbfv1model_init_copy(&dst->model1, &src->model1, _state, make_automatic);
 | |
|     _rbfv2model_init_copy(&dst->model2, &src->model2, _state, make_automatic);
 | |
|     dst->lambdav = src->lambdav;
 | |
|     dst->radvalue = src->radvalue;
 | |
|     dst->radzvalue = src->radzvalue;
 | |
|     dst->nlayers = src->nlayers;
 | |
|     dst->aterm = src->aterm;
 | |
|     dst->algorithmtype = src->algorithmtype;
 | |
|     dst->epsort = src->epsort;
 | |
|     dst->epserr = src->epserr;
 | |
|     dst->maxits = src->maxits;
 | |
|     dst->nnmaxits = src->nnmaxits;
 | |
|     dst->n = src->n;
 | |
|     ae_matrix_init_copy(&dst->x, &src->x, _state, make_automatic);
 | |
|     ae_matrix_init_copy(&dst->y, &src->y, _state, make_automatic);
 | |
|     dst->hasscale = src->hasscale;
 | |
|     ae_vector_init_copy(&dst->s, &src->s, _state, make_automatic);
 | |
|     dst->progress10000 = src->progress10000;
 | |
|     dst->terminationrequest = src->terminationrequest;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfmodel_clear(void* _p)
 | |
| {
 | |
|     rbfmodel *p = (rbfmodel*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _rbfv1model_clear(&p->model1);
 | |
|     _rbfv2model_clear(&p->model2);
 | |
|     ae_matrix_clear(&p->x);
 | |
|     ae_matrix_clear(&p->y);
 | |
|     ae_vector_clear(&p->s);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfmodel_destroy(void* _p)
 | |
| {
 | |
|     rbfmodel *p = (rbfmodel*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
|     _rbfv1model_destroy(&p->model1);
 | |
|     _rbfv2model_destroy(&p->model2);
 | |
|     ae_matrix_destroy(&p->x);
 | |
|     ae_matrix_destroy(&p->y);
 | |
|     ae_vector_destroy(&p->s);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfreport_init(void* _p, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfreport *p = (rbfreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfreport_init_copy(void* _dst, void* _src, ae_state *_state, ae_bool make_automatic)
 | |
| {
 | |
|     rbfreport *dst = (rbfreport*)_dst;
 | |
|     rbfreport *src = (rbfreport*)_src;
 | |
|     dst->rmserror = src->rmserror;
 | |
|     dst->maxerror = src->maxerror;
 | |
|     dst->arows = src->arows;
 | |
|     dst->acols = src->acols;
 | |
|     dst->annz = src->annz;
 | |
|     dst->iterationscount = src->iterationscount;
 | |
|     dst->nmv = src->nmv;
 | |
|     dst->terminationtype = src->terminationtype;
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfreport_clear(void* _p)
 | |
| {
 | |
|     rbfreport *p = (rbfreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| void _rbfreport_destroy(void* _p)
 | |
| {
 | |
|     rbfreport *p = (rbfreport*)_p;
 | |
|     ae_touch_ptr((void*)p);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| #if defined(AE_COMPILE_INTCOMP) || !defined(AE_PARTIAL_BUILD)
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is left for backward compatibility.
 | |
| Use fitspheremc() instead.
 | |
| 
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void nsfitspheremcc(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t nx,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      double* rhi,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double dummy;
 | |
| 
 | |
|     ae_vector_clear(cx);
 | |
|     *rhi = 0;
 | |
| 
 | |
|     nsfitspherex(xy, npoints, nx, 1, 0.0, 0, 0.0, cx, &dummy, rhi, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is left for backward compatibility.
 | |
| Use fitspheremi() instead.
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void nsfitspheremic(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t nx,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      double* rlo,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     double dummy;
 | |
| 
 | |
|     ae_vector_clear(cx);
 | |
|     *rlo = 0;
 | |
| 
 | |
|     nsfitspherex(xy, npoints, nx, 2, 0.0, 0, 0.0, cx, rlo, &dummy, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is left for backward compatibility.
 | |
| Use fitspheremz() instead.
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void nsfitspheremzc(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t nx,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      double* rlo,
 | |
|      double* rhi,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     ae_vector_clear(cx);
 | |
|     *rlo = 0;
 | |
|     *rhi = 0;
 | |
| 
 | |
|     nsfitspherex(xy, npoints, nx, 3, 0.0, 0, 0.0, cx, rlo, rhi, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is left for backward compatibility.
 | |
| Use fitspherex() instead.
 | |
|                                     
 | |
|   -- ALGLIB --
 | |
|      Copyright 14.04.2017 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void nsfitspherex(/* Real    */ ae_matrix* xy,
 | |
|      ae_int_t npoints,
 | |
|      ae_int_t nx,
 | |
|      ae_int_t problemtype,
 | |
|      double epsx,
 | |
|      ae_int_t aulits,
 | |
|      double penalty,
 | |
|      /* Real    */ ae_vector* cx,
 | |
|      double* rlo,
 | |
|      double* rhi,
 | |
|      ae_state *_state)
 | |
| {
 | |
| 
 | |
|     ae_vector_clear(cx);
 | |
|     *rlo = 0;
 | |
|     *rhi = 0;
 | |
| 
 | |
|     fitspherex(xy, npoints, nx, problemtype, epsx, aulits, penalty, cx, rlo, rhi, _state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is an obsolete and deprecated version of fitting by
 | |
| penalized cubic spline.
 | |
| 
 | |
| It was superseded by spline1dfit(), which is an orders of magnitude faster
 | |
| and more memory-efficient implementation.
 | |
| 
 | |
| Do NOT use this function in the new code!
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 18.08.2009 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfitpenalized(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      double rho,
 | |
|      ae_int_t* info,
 | |
|      spline1dinterpolant* s,
 | |
|      spline1dfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector w;
 | |
|     ae_int_t i;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&w, 0, sizeof(w));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     *info = 0;
 | |
|     _spline1dinterpolant_clear(s);
 | |
|     _spline1dfitreport_clear(rep);
 | |
|     ae_vector_init(&w, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=1, "Spline1DFitPenalized: N<1!", _state);
 | |
|     ae_assert(m>=4, "Spline1DFitPenalized: M<4!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DFitPenalized: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DFitPenalized: Length(Y)<N!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DFitPenalized: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DFitPenalized: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(ae_isfinite(rho, _state), "Spline1DFitPenalized: Rho is infinite!", _state);
 | |
|     ae_vector_set_length(&w, n, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         w.ptr.p_double[i] = (double)(1);
 | |
|     }
 | |
|     spline1dfitpenalizedw(x, y, &w, n, m, rho, info, s, rep, _state);
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*************************************************************************
 | |
| This function is an obsolete and deprecated version of fitting by
 | |
| penalized cubic spline.
 | |
| 
 | |
| It was superseded by spline1dfit(), which is an orders of magnitude faster
 | |
| and more memory-efficient implementation.
 | |
| 
 | |
| Do NOT use this function in the new code!
 | |
| 
 | |
|   -- ALGLIB PROJECT --
 | |
|      Copyright 19.10.2010 by Bochkanov Sergey
 | |
| *************************************************************************/
 | |
| void spline1dfitpenalizedw(/* Real    */ ae_vector* x,
 | |
|      /* Real    */ ae_vector* y,
 | |
|      /* Real    */ ae_vector* w,
 | |
|      ae_int_t n,
 | |
|      ae_int_t m,
 | |
|      double rho,
 | |
|      ae_int_t* info,
 | |
|      spline1dinterpolant* s,
 | |
|      spline1dfitreport* rep,
 | |
|      ae_state *_state)
 | |
| {
 | |
|     ae_frame _frame_block;
 | |
|     ae_vector _x;
 | |
|     ae_vector _y;
 | |
|     ae_vector _w;
 | |
|     ae_int_t i;
 | |
|     ae_int_t j;
 | |
|     ae_int_t b;
 | |
|     double v;
 | |
|     double relcnt;
 | |
|     double xa;
 | |
|     double xb;
 | |
|     double sa;
 | |
|     double sb;
 | |
|     ae_vector xoriginal;
 | |
|     ae_vector yoriginal;
 | |
|     double pdecay;
 | |
|     double tdecay;
 | |
|     ae_matrix fmatrix;
 | |
|     ae_vector fcolumn;
 | |
|     ae_vector y2;
 | |
|     ae_vector w2;
 | |
|     ae_vector xc;
 | |
|     ae_vector yc;
 | |
|     ae_vector dc;
 | |
|     double fdmax;
 | |
|     double admax;
 | |
|     ae_matrix amatrix;
 | |
|     ae_matrix d2matrix;
 | |
|     double fa;
 | |
|     double ga;
 | |
|     double fb;
 | |
|     double gb;
 | |
|     double lambdav;
 | |
|     ae_vector bx;
 | |
|     ae_vector by;
 | |
|     ae_vector bd1;
 | |
|     ae_vector bd2;
 | |
|     ae_vector tx;
 | |
|     ae_vector ty;
 | |
|     ae_vector td;
 | |
|     spline1dinterpolant bs;
 | |
|     ae_matrix nmatrix;
 | |
|     ae_vector rightpart;
 | |
|     fblslincgstate cgstate;
 | |
|     ae_vector c;
 | |
|     ae_vector tmp0;
 | |
| 
 | |
|     ae_frame_make(_state, &_frame_block);
 | |
|     memset(&_x, 0, sizeof(_x));
 | |
|     memset(&_y, 0, sizeof(_y));
 | |
|     memset(&_w, 0, sizeof(_w));
 | |
|     memset(&xoriginal, 0, sizeof(xoriginal));
 | |
|     memset(&yoriginal, 0, sizeof(yoriginal));
 | |
|     memset(&fmatrix, 0, sizeof(fmatrix));
 | |
|     memset(&fcolumn, 0, sizeof(fcolumn));
 | |
|     memset(&y2, 0, sizeof(y2));
 | |
|     memset(&w2, 0, sizeof(w2));
 | |
|     memset(&xc, 0, sizeof(xc));
 | |
|     memset(&yc, 0, sizeof(yc));
 | |
|     memset(&dc, 0, sizeof(dc));
 | |
|     memset(&amatrix, 0, sizeof(amatrix));
 | |
|     memset(&d2matrix, 0, sizeof(d2matrix));
 | |
|     memset(&bx, 0, sizeof(bx));
 | |
|     memset(&by, 0, sizeof(by));
 | |
|     memset(&bd1, 0, sizeof(bd1));
 | |
|     memset(&bd2, 0, sizeof(bd2));
 | |
|     memset(&tx, 0, sizeof(tx));
 | |
|     memset(&ty, 0, sizeof(ty));
 | |
|     memset(&td, 0, sizeof(td));
 | |
|     memset(&bs, 0, sizeof(bs));
 | |
|     memset(&nmatrix, 0, sizeof(nmatrix));
 | |
|     memset(&rightpart, 0, sizeof(rightpart));
 | |
|     memset(&cgstate, 0, sizeof(cgstate));
 | |
|     memset(&c, 0, sizeof(c));
 | |
|     memset(&tmp0, 0, sizeof(tmp0));
 | |
|     ae_vector_init_copy(&_x, x, _state, ae_true);
 | |
|     x = &_x;
 | |
|     ae_vector_init_copy(&_y, y, _state, ae_true);
 | |
|     y = &_y;
 | |
|     ae_vector_init_copy(&_w, w, _state, ae_true);
 | |
|     w = &_w;
 | |
|     *info = 0;
 | |
|     _spline1dinterpolant_clear(s);
 | |
|     _spline1dfitreport_clear(rep);
 | |
|     ae_vector_init(&xoriginal, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&yoriginal, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&fmatrix, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&fcolumn, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&y2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&w2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&xc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&yc, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&dc, 0, DT_INT, _state, ae_true);
 | |
|     ae_matrix_init(&amatrix, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_matrix_init(&d2matrix, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&by, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bd1, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&bd2, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tx, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&ty, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&td, 0, DT_REAL, _state, ae_true);
 | |
|     _spline1dinterpolant_init(&bs, _state, ae_true);
 | |
|     ae_matrix_init(&nmatrix, 0, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&rightpart, 0, DT_REAL, _state, ae_true);
 | |
|     _fblslincgstate_init(&cgstate, _state, ae_true);
 | |
|     ae_vector_init(&c, 0, DT_REAL, _state, ae_true);
 | |
|     ae_vector_init(&tmp0, 0, DT_REAL, _state, ae_true);
 | |
| 
 | |
|     ae_assert(n>=1, "Spline1DFitPenalizedW: N<1!", _state);
 | |
|     ae_assert(m>=4, "Spline1DFitPenalizedW: M<4!", _state);
 | |
|     ae_assert(x->cnt>=n, "Spline1DFitPenalizedW: Length(X)<N!", _state);
 | |
|     ae_assert(y->cnt>=n, "Spline1DFitPenalizedW: Length(Y)<N!", _state);
 | |
|     ae_assert(w->cnt>=n, "Spline1DFitPenalizedW: Length(W)<N!", _state);
 | |
|     ae_assert(isfinitevector(x, n, _state), "Spline1DFitPenalizedW: X contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(y, n, _state), "Spline1DFitPenalizedW: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(isfinitevector(w, n, _state), "Spline1DFitPenalizedW: Y contains infinite or NAN values!", _state);
 | |
|     ae_assert(ae_isfinite(rho, _state), "Spline1DFitPenalizedW: Rho is infinite!", _state);
 | |
|     
 | |
|     /*
 | |
|      * Prepare LambdaV
 | |
|      */
 | |
|     v = -ae_log(ae_machineepsilon, _state)/ae_log((double)(10), _state);
 | |
|     if( ae_fp_less(rho,-v) )
 | |
|     {
 | |
|         rho = -v;
 | |
|     }
 | |
|     if( ae_fp_greater(rho,v) )
 | |
|     {
 | |
|         rho = v;
 | |
|     }
 | |
|     lambdav = ae_pow((double)(10), rho, _state);
 | |
|     
 | |
|     /*
 | |
|      * Sort X, Y, W
 | |
|      */
 | |
|     heapsortdpoints(x, y, w, n, _state);
 | |
|     
 | |
|     /*
 | |
|      * Scale X, Y, XC, YC
 | |
|      */
 | |
|     lsfitscalexy(x, y, w, n, &xc, &yc, &dc, 0, &xa, &xb, &sa, &sb, &xoriginal, &yoriginal, _state);
 | |
|     
 | |
|     /*
 | |
|      * Allocate space
 | |
|      */
 | |
|     ae_matrix_set_length(&fmatrix, n, m, _state);
 | |
|     ae_matrix_set_length(&amatrix, m, m, _state);
 | |
|     ae_matrix_set_length(&d2matrix, m, m, _state);
 | |
|     ae_vector_set_length(&bx, m, _state);
 | |
|     ae_vector_set_length(&by, m, _state);
 | |
|     ae_vector_set_length(&fcolumn, n, _state);
 | |
|     ae_matrix_set_length(&nmatrix, m, m, _state);
 | |
|     ae_vector_set_length(&rightpart, m, _state);
 | |
|     ae_vector_set_length(&tmp0, ae_maxint(m, n, _state), _state);
 | |
|     ae_vector_set_length(&c, m, _state);
 | |
|     
 | |
|     /*
 | |
|      * Fill:
 | |
|      * * FMatrix by values of basis functions
 | |
|      * * TmpAMatrix by second derivatives of I-th function at J-th point
 | |
|      * * CMatrix by constraints
 | |
|      */
 | |
|     fdmax = (double)(0);
 | |
|     for(b=0; b<=m-1; b++)
 | |
|     {
 | |
|         
 | |
|         /*
 | |
|          * Prepare I-th basis function
 | |
|          */
 | |
|         for(j=0; j<=m-1; j++)
 | |
|         {
 | |
|             bx.ptr.p_double[j] = (double)(2*j)/(double)(m-1)-1;
 | |
|             by.ptr.p_double[j] = (double)(0);
 | |
|         }
 | |
|         by.ptr.p_double[b] = (double)(1);
 | |
|         spline1dgriddiff2cubic(&bx, &by, m, 2, 0.0, 2, 0.0, &bd1, &bd2, _state);
 | |
|         spline1dbuildcubic(&bx, &by, m, 2, 0.0, 2, 0.0, &bs, _state);
 | |
|         
 | |
|         /*
 | |
|          * Calculate B-th column of FMatrix
 | |
|          * Update FDMax (maximum column norm)
 | |
|          */
 | |
|         spline1dconvcubic(&bx, &by, m, 2, 0.0, 2, 0.0, x, n, &fcolumn, _state);
 | |
|         ae_v_move(&fmatrix.ptr.pp_double[0][b], fmatrix.stride, &fcolumn.ptr.p_double[0], 1, ae_v_len(0,n-1));
 | |
|         v = (double)(0);
 | |
|         for(i=0; i<=n-1; i++)
 | |
|         {
 | |
|             v = v+ae_sqr(w->ptr.p_double[i]*fcolumn.ptr.p_double[i], _state);
 | |
|         }
 | |
|         fdmax = ae_maxreal(fdmax, v, _state);
 | |
|         
 | |
|         /*
 | |
|          * Fill temporary with second derivatives of basis function
 | |
|          */
 | |
|         ae_v_move(&d2matrix.ptr.pp_double[b][0], 1, &bd2.ptr.p_double[0], 1, ae_v_len(0,m-1));
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * * calculate penalty matrix A
 | |
|      * * calculate max of diagonal elements of A
 | |
|      * * calculate PDecay - coefficient before penalty matrix
 | |
|      */
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         for(j=i; j<=m-1; j++)
 | |
|         {
 | |
|             
 | |
|             /*
 | |
|              * calculate integral(B_i''*B_j'') where B_i and B_j are
 | |
|              * i-th and j-th basis splines.
 | |
|              * B_i and B_j are piecewise linear functions.
 | |
|              */
 | |
|             v = (double)(0);
 | |
|             for(b=0; b<=m-2; b++)
 | |
|             {
 | |
|                 fa = d2matrix.ptr.pp_double[i][b];
 | |
|                 fb = d2matrix.ptr.pp_double[i][b+1];
 | |
|                 ga = d2matrix.ptr.pp_double[j][b];
 | |
|                 gb = d2matrix.ptr.pp_double[j][b+1];
 | |
|                 v = v+(bx.ptr.p_double[b+1]-bx.ptr.p_double[b])*(fa*ga+(fa*(gb-ga)+ga*(fb-fa))/2+(fb-fa)*(gb-ga)/3);
 | |
|             }
 | |
|             amatrix.ptr.pp_double[i][j] = v;
 | |
|             amatrix.ptr.pp_double[j][i] = v;
 | |
|         }
 | |
|     }
 | |
|     admax = (double)(0);
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         admax = ae_maxreal(admax, ae_fabs(amatrix.ptr.pp_double[i][i], _state), _state);
 | |
|     }
 | |
|     pdecay = lambdav*fdmax/admax;
 | |
|     
 | |
|     /*
 | |
|      * Calculate TDecay for Tikhonov regularization
 | |
|      */
 | |
|     tdecay = fdmax*(1+pdecay)*10*ae_machineepsilon;
 | |
|     
 | |
|     /*
 | |
|      * Prepare system
 | |
|      *
 | |
|      * NOTE: FMatrix is spoiled during this process
 | |
|      */
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         v = w->ptr.p_double[i];
 | |
|         ae_v_muld(&fmatrix.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
 | |
|     }
 | |
|     rmatrixgemm(m, m, n, 1.0, &fmatrix, 0, 0, 1, &fmatrix, 0, 0, 0, 0.0, &nmatrix, 0, 0, _state);
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         for(j=0; j<=m-1; j++)
 | |
|         {
 | |
|             nmatrix.ptr.pp_double[i][j] = nmatrix.ptr.pp_double[i][j]+pdecay*amatrix.ptr.pp_double[i][j];
 | |
|         }
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         nmatrix.ptr.pp_double[i][i] = nmatrix.ptr.pp_double[i][i]+tdecay;
 | |
|     }
 | |
|     for(i=0; i<=m-1; i++)
 | |
|     {
 | |
|         rightpart.ptr.p_double[i] = (double)(0);
 | |
|     }
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         v = y->ptr.p_double[i]*w->ptr.p_double[i];
 | |
|         ae_v_addd(&rightpart.ptr.p_double[0], 1, &fmatrix.ptr.pp_double[i][0], 1, ae_v_len(0,m-1), v);
 | |
|     }
 | |
|     
 | |
|     /*
 | |
|      * Solve system
 | |
|      */
 | |
|     if( !spdmatrixcholesky(&nmatrix, m, ae_true, _state) )
 | |
|     {
 | |
|         *info = -4;
 | |
|         ae_frame_leave(_state);
 | |
|         return;
 | |
|     }
 | |
|     fblscholeskysolve(&nmatrix, 1.0, m, ae_true, &rightpart, &tmp0, _state);
 | |
|     ae_v_move(&c.ptr.p_double[0], 1, &rightpart.ptr.p_double[0], 1, ae_v_len(0,m-1));
 | |
|     
 | |
|     /*
 | |
|      * add nodes to force linearity outside of the fitting interval
 | |
|      */
 | |
|     spline1dgriddiffcubic(&bx, &c, m, 2, 0.0, 2, 0.0, &bd1, _state);
 | |
|     ae_vector_set_length(&tx, m+2, _state);
 | |
|     ae_vector_set_length(&ty, m+2, _state);
 | |
|     ae_vector_set_length(&td, m+2, _state);
 | |
|     ae_v_move(&tx.ptr.p_double[1], 1, &bx.ptr.p_double[0], 1, ae_v_len(1,m));
 | |
|     ae_v_move(&ty.ptr.p_double[1], 1, &rightpart.ptr.p_double[0], 1, ae_v_len(1,m));
 | |
|     ae_v_move(&td.ptr.p_double[1], 1, &bd1.ptr.p_double[0], 1, ae_v_len(1,m));
 | |
|     tx.ptr.p_double[0] = tx.ptr.p_double[1]-(tx.ptr.p_double[2]-tx.ptr.p_double[1]);
 | |
|     ty.ptr.p_double[0] = ty.ptr.p_double[1]-td.ptr.p_double[1]*(tx.ptr.p_double[2]-tx.ptr.p_double[1]);
 | |
|     td.ptr.p_double[0] = td.ptr.p_double[1];
 | |
|     tx.ptr.p_double[m+1] = tx.ptr.p_double[m]+(tx.ptr.p_double[m]-tx.ptr.p_double[m-1]);
 | |
|     ty.ptr.p_double[m+1] = ty.ptr.p_double[m]+td.ptr.p_double[m]*(tx.ptr.p_double[m]-tx.ptr.p_double[m-1]);
 | |
|     td.ptr.p_double[m+1] = td.ptr.p_double[m];
 | |
|     spline1dbuildhermite(&tx, &ty, &td, m+2, s, _state);
 | |
|     spline1dlintransx(s, 2/(xb-xa), -(xa+xb)/(xb-xa), _state);
 | |
|     spline1dlintransy(s, sb-sa, sa, _state);
 | |
|     *info = 1;
 | |
|     
 | |
|     /*
 | |
|      * Fill report
 | |
|      */
 | |
|     rep->rmserror = (double)(0);
 | |
|     rep->avgerror = (double)(0);
 | |
|     rep->avgrelerror = (double)(0);
 | |
|     rep->maxerror = (double)(0);
 | |
|     relcnt = (double)(0);
 | |
|     spline1dconvcubic(&bx, &rightpart, m, 2, 0.0, 2, 0.0, x, n, &fcolumn, _state);
 | |
|     for(i=0; i<=n-1; i++)
 | |
|     {
 | |
|         v = (sb-sa)*fcolumn.ptr.p_double[i]+sa;
 | |
|         rep->rmserror = rep->rmserror+ae_sqr(v-yoriginal.ptr.p_double[i], _state);
 | |
|         rep->avgerror = rep->avgerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state);
 | |
|         if( ae_fp_neq(yoriginal.ptr.p_double[i],(double)(0)) )
 | |
|         {
 | |
|             rep->avgrelerror = rep->avgrelerror+ae_fabs(v-yoriginal.ptr.p_double[i], _state)/ae_fabs(yoriginal.ptr.p_double[i], _state);
 | |
|             relcnt = relcnt+1;
 | |
|         }
 | |
|         rep->maxerror = ae_maxreal(rep->maxerror, ae_fabs(v-yoriginal.ptr.p_double[i], _state), _state);
 | |
|     }
 | |
|     rep->rmserror = ae_sqrt(rep->rmserror/n, _state);
 | |
|     rep->avgerror = rep->avgerror/n;
 | |
|     if( ae_fp_neq(relcnt,(double)(0)) )
 | |
|     {
 | |
|         rep->avgrelerror = rep->avgrelerror/relcnt;
 | |
|     }
 | |
|     ae_frame_leave(_state);
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| 
 | |
| }
 | |
| 
 | 
