|
 |
c245cf4 |
From facb9273c571b6bef430e71b31ff229abd6d1a46 Mon Sep 17 00:00:00 2001
|
|
 |
c245cf4 |
From: Mark Abraham <mark.j.abraham@gmail.com>
|
|
 |
c245cf4 |
Date: Mon, 11 Jun 2018 08:30:19 +0200
|
|
 |
c245cf4 |
Subject: [PATCH] Bump lmfit support to version 7
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
The breaking API change means that distributions will not be able to
|
|
 |
c245cf4 |
build GROMACS reliably with support for lmfit of arbitrary versions.
|
|
 |
c245cf4 |
Nor does lmfit provide any support for querying the version. Tools
|
|
 |
c245cf4 |
that call such fitting will now issue a fatal error.
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
Updated the FindLmfit and other cmake code to make better use of
|
|
 |
c245cf4 |
modern cmake idioms for managing build targets. lmfit support is now
|
|
 |
c245cf4 |
handled by a tri-state GMX_USE_LMFIT cmake variable, which defaults to
|
|
 |
c245cf4 |
using the bundled version.
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
Reorganized aspects of gmx_lmcurve to better encapsulate the
|
|
 |
c245cf4 |
dependency, now that we have to support the absence of lmfit.
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
Updated install guide and COPYING file.
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
Refs #2533
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
Change-Id: I6b14e08be216f803326b0ad9215b8d89bb0962c1
|
|
 |
c245cf4 |
---
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
diff --git a/COPYING b/COPYING
|
|
 |
c245cf4 |
index 4cc52a2..ba2710e 100644
|
|
 |
c245cf4 |
--- a/COPYING
|
|
 |
c245cf4 |
+++ b/COPYING
|
|
 |
c245cf4 |
@@ -1249,7 +1249,7 @@
|
|
 |
c245cf4 |
--
|
|
 |
c245cf4 |
Copyright (c) 1980-1999 University of Chicago,
|
|
 |
c245cf4 |
as operator of Argonne National Laboratory
|
|
 |
c245cf4 |
- Copyright (c) 2004-2013 Joachim Wuttke, Forschungszentrum Juelich GmbH
|
|
 |
c245cf4 |
+ Copyright (c) 2004-2015 Joachim Wuttke, Forschungszentrum Juelich GmbH
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
All rights reserved.
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
diff --git a/cmake/FindLmfit.cmake b/cmake/FindLmfit.cmake
|
|
 |
c245cf4 |
index 5bf489a..9dd23f1 100644
|
|
 |
c245cf4 |
--- a/cmake/FindLmfit.cmake
|
|
 |
c245cf4 |
+++ b/cmake/FindLmfit.cmake
|
|
 |
c245cf4 |
@@ -1,7 +1,7 @@
|
|
 |
c245cf4 |
#
|
|
 |
c245cf4 |
# This file is part of the GROMACS molecular simulation package.
|
|
 |
c245cf4 |
#
|
|
 |
c245cf4 |
-# Copyright (c) 2016, by the GROMACS development team, led by
|
|
 |
c245cf4 |
+# Copyright (c) 2016,2018, by the GROMACS development team, led by
|
|
 |
c245cf4 |
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
|
|
 |
c245cf4 |
# and including many others, as listed in the AUTHORS file in the
|
|
 |
c245cf4 |
# top-level source directory and at http://www.gromacs.org.
|
|
 |
c245cf4 |
@@ -32,19 +32,20 @@
|
|
 |
c245cf4 |
# To help us fund GROMACS development, we humbly ask that you cite
|
|
 |
c245cf4 |
# the research papers on the package. Check out http://www.gromacs.org.
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-# This package tries to find an external lmfit library. It is intended
|
|
 |
c245cf4 |
-# to work with pkg-config, because that is the mechanism supported in
|
|
 |
c245cf4 |
-# lmfit. Upon exit, the following variables may be set:
|
|
 |
c245cf4 |
+# This package tries to find an external lmfit library, version
|
|
 |
c245cf4 |
+# 7. Note that pkg-config support was removed before version 7, so is
|
|
 |
c245cf4 |
+# no longer supported here. Upon exit, the following variables may be
|
|
 |
c245cf4 |
+# set:
|
|
 |
c245cf4 |
#
|
|
 |
c245cf4 |
# LMFIT_FOUND - lmfit was found
|
|
 |
c245cf4 |
# LMFIT_INCLUDE_DIR - lmfit include directory
|
|
 |
c245cf4 |
-# LMFIT_LIBRARIES - lmfit libraries
|
|
 |
c245cf4 |
+# LMFIT_LIBRARY - lmfit library
|
|
 |
c245cf4 |
# LMFIT_LINKS_OK - lmfit libraries link correctly
|
|
 |
c245cf4 |
# LMFIT_VERSION - lmfit version string as "major.minor"
|
|
 |
c245cf4 |
#
|
|
 |
c245cf4 |
-# If you cannot use pkg-config for some reason, then setting
|
|
 |
c245cf4 |
-# LMFIT_INCLUDE_DIRS and LMFIT_LIBRARY_DIRS on the cmake command line
|
|
 |
c245cf4 |
-# to suitable values will work.
|
|
 |
c245cf4 |
+# CMake will search the CMAKE_PREFIX_PATH in the usual way, but if you
|
|
 |
c245cf4 |
+# need more control then setting LMFIT_INCLUDE_DIR and LMFIT_LIBRARY
|
|
 |
c245cf4 |
+# on the cmake command line to suitable values will work.
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
include(CMakePushCheckState)
|
|
 |
c245cf4 |
cmake_push_check_state()
|
|
 |
c245cf4 |
@@ -55,12 +56,12 @@
|
|
 |
c245cf4 |
# lmfit doesn't support CMake-based find_package version
|
|
 |
c245cf4 |
# checking in 6.1, so this code does nothing.
|
|
 |
c245cf4 |
if(LMFIT_FIND_VERSION_EXACT)
|
|
 |
c245cf4 |
- pkg_check_modules(PC_LMFIT lmfit=${LMFIT_FIND_VERSION})
|
|
 |
c245cf4 |
+ pkg_check_modules(PC_LMFIT QUIET lmfit=${LMFIT_FIND_VERSION})
|
|
 |
c245cf4 |
else()
|
|
 |
c245cf4 |
- pkg_check_modules(PC_LMFIT lmfit>=${LMFIT_FIND_VERSION})
|
|
 |
c245cf4 |
+ pkg_check_modules(PC_LMFIT QUIET lmfit>=${LMFIT_FIND_VERSION})
|
|
 |
c245cf4 |
endif()
|
|
 |
c245cf4 |
else()
|
|
 |
c245cf4 |
- pkg_check_modules(PC_LMFIT lmfit)
|
|
 |
c245cf4 |
+ pkg_check_modules(PC_LMFIT QUIET lmfit)
|
|
 |
c245cf4 |
if (PC_LMFIT_VERSION)
|
|
 |
c245cf4 |
string(REGEX REPLACE "^([0-9]+):([0-9]+)" "\\1.\\2" LMFIT_VERSION "${PC_LMFIT_VERSION}")
|
|
 |
c245cf4 |
endif()
|
|
 |
c245cf4 |
@@ -68,20 +69,15 @@
|
|
 |
c245cf4 |
endif()
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
# Try to find lmfit, perhaps with help from pkg-config
|
|
 |
c245cf4 |
-find_path(LMFIT_INCLUDE_DIRS lmcurve.h HINTS "${PC_LMFIT_INCLUDE_DIRS}" PATH_SUFFIXES include)
|
|
 |
c245cf4 |
-find_library(LMFIT_LIBRARY_DIRS NAMES lmfit HINTS "${PC_LMFIT_LIBRARY_DIRS}" PATH_SUFFIXES lib64 lib)
|
|
 |
c245cf4 |
+find_path(LMFIT_INCLUDE_DIR lmcurve.h HINTS "${PC_LMFIT_INCLUDE_DIRS}" PATH_SUFFIXES include)
|
|
 |
c245cf4 |
+find_library(LMFIT_LIBRARY NAMES lmfit HINTS "${PC_LMFIT_LIBRARY_DIRS}" PATH_SUFFIXES lib64 lib)
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
# Make sure we can also link, so that cross-compilation is properly supported
|
|
 |
c245cf4 |
-if (LMFIT_INCLUDE_DIRS AND LMFIT_LIBRARY_DIRS)
|
|
 |
c245cf4 |
+if (LMFIT_INCLUDE_DIR AND LMFIT_LIBRARY)
|
|
 |
c245cf4 |
include(CheckCXXSourceCompiles)
|
|
 |
c245cf4 |
- set(CMAKE_REQUIRED_INCLUDES ${LMFIT_INCLUDE_DIRS})
|
|
 |
c245cf4 |
- set(CMAKE_REQUIRED_LIBRARIES ${LMFIT_LIBRARY_DIRS})
|
|
 |
c245cf4 |
+ set(CMAKE_REQUIRED_INCLUDES ${LMFIT_INCLUDE_DIR})
|
|
 |
c245cf4 |
+ set(CMAKE_REQUIRED_LIBRARIES ${LMFIT_LIBRARY})
|
|
 |
c245cf4 |
check_cxx_source_compiles("#include <lmcurve.h>\nint main(){lmcurve(0,0,0,0,0,0,0,0);}" LMFIT_LINKS_OK)
|
|
 |
c245cf4 |
-endif()
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
-if (LMFIT_LINKS_OK)
|
|
 |
c245cf4 |
- set(LMFIT_INCLUDE_DIR ${LMFIT_INCLUDE_DIRS})
|
|
 |
c245cf4 |
- set(LMFIT_LIBRARIES ${LMFIT_LIBRARY_DIRS})
|
|
 |
c245cf4 |
endif()
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
include(FindPackageHandleStandardArgs)
|
|
 |
c245cf4 |
@@ -90,11 +86,19 @@
|
|
 |
c245cf4 |
LMFIT_FOUND
|
|
 |
c245cf4 |
REQUIRED_VARS
|
|
 |
c245cf4 |
LMFIT_INCLUDE_DIR
|
|
 |
c245cf4 |
- LMFIT_LIBRARIES
|
|
 |
c245cf4 |
+ LMFIT_LIBRARY
|
|
 |
c245cf4 |
LMFIT_LINKS_OK
|
|
 |
c245cf4 |
VERSION_VAR
|
|
 |
c245cf4 |
LMFIT_VERSION)
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-mark_as_advanced(LMFIT_INCLUDE_DIRS LMFIT_LIBRARY_DIRS)
|
|
 |
c245cf4 |
+mark_as_advanced(LMFIT_INCLUDE_DIR LMFIT_LIBRARY)
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+if (LMFIT_FOUND)
|
|
 |
c245cf4 |
+ add_library(lmfit INTERFACE IMPORTED)
|
|
 |
c245cf4 |
+ set_target_properties(lmfit PROPERTIES
|
|
 |
c245cf4 |
+ INTERFACE_INCLUDE_DIRECTORIES "${LMFIT_INCLUDE_DIR}"
|
|
 |
c245cf4 |
+ INTERFACE_LINK_LIBRARIES "${LMFIT_LIBRARY}"
|
|
 |
c245cf4 |
+ )
|
|
 |
c245cf4 |
+endif()
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
cmake_pop_check_state()
|
|
 |
c245cf4 |
diff --git a/cmake/gmxManageLmfit.cmake b/cmake/gmxManageLmfit.cmake
|
|
 |
c245cf4 |
index 182928f..5953a19 100644
|
|
 |
c245cf4 |
--- a/cmake/gmxManageLmfit.cmake
|
|
 |
c245cf4 |
+++ b/cmake/gmxManageLmfit.cmake
|
|
 |
c245cf4 |
@@ -1,7 +1,7 @@
|
|
 |
c245cf4 |
#
|
|
 |
c245cf4 |
# This file is part of the GROMACS molecular simulation package.
|
|
 |
c245cf4 |
#
|
|
 |
c245cf4 |
-# Copyright (c) 2016, by the GROMACS development team, led by
|
|
 |
c245cf4 |
+# Copyright (c) 2016,2018, by the GROMACS development team, led by
|
|
 |
c245cf4 |
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
|
|
 |
c245cf4 |
# and including many others, as listed in the AUTHORS file in the
|
|
 |
c245cf4 |
# top-level source directory and at http://www.gromacs.org.
|
|
 |
c245cf4 |
@@ -32,21 +32,16 @@
|
|
 |
c245cf4 |
# To help us fund GROMACS development, we humbly ask that you cite
|
|
 |
c245cf4 |
# the research papers on the package. Check out http://www.gromacs.org.
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-set(GMX_LMFIT_MINIMUM_REQUIRED_VERSION "6.1")
|
|
 |
c245cf4 |
-set(GMX_BUNDLED_LMFIT_DIR "${CMAKE_SOURCE_DIR}/src/external/lmfit")
|
|
 |
c245cf4 |
+# Note that lmfit does not have a stable API, so GROMACS only supports
|
|
 |
c245cf4 |
+# the same version that it bundles.
|
|
 |
c245cf4 |
+set(GMX_LMFIT_REQUIRED_VERSION "7.0")
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-option(GMX_EXTERNAL_LMFIT "Use external lmfit instead of compiling the version bundled with GROMACS." OFF)
|
|
 |
c245cf4 |
-mark_as_advanced(GMX_EXTERNAL_LMFIT)
|
|
 |
c245cf4 |
+include(gmxOptionUtilities)
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-macro(manage_lmfit)
|
|
 |
c245cf4 |
- if(GMX_EXTERNAL_LMFIT)
|
|
 |
c245cf4 |
- # Find an external lmfit library.
|
|
 |
c245cf4 |
- find_package(Lmfit ${GMX_LMFIT_MINIMUM_REQUIRED_VERSION})
|
|
 |
c245cf4 |
- if(NOT LMFIT_FOUND)
|
|
 |
c245cf4 |
- message(FATAL_ERROR "External lmfit could not be found, please adjust your pkg-config path to include the lmfit.pc file")
|
|
 |
c245cf4 |
- endif()
|
|
 |
c245cf4 |
- endif()
|
|
 |
c245cf4 |
-endmacro()
|
|
 |
c245cf4 |
+gmx_option_multichoice(GMX_USE_LMFIT
|
|
 |
c245cf4 |
+ "Use external lmfit instead of compiling the version bundled with GROMACS."
|
|
 |
c245cf4 |
+ INTERNAL
|
|
 |
c245cf4 |
+ INTERNAL EXTERNAL NONE)
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
macro(get_lmfit_properties LMFIT_SOURCES_VAR LMFIT_LIBRARIES_VAR LMFIT_INCLUDE_DIR_VAR LMFIT_INCLUDE_DIR_ORDER_VAR)
|
|
 |
c245cf4 |
if (GMX_EXTERNAL_LMFIT)
|
|
 |
c245cf4 |
@@ -62,5 +57,29 @@
|
|
 |
c245cf4 |
endif()
|
|
 |
c245cf4 |
endmacro()
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-manage_lmfit()
|
|
 |
c245cf4 |
+function(manage_lmfit)
|
|
 |
c245cf4 |
+ if(GMX_USE_LMFIT STREQUAL "INTERNAL")
|
|
 |
c245cf4 |
+ set(BUNDLED_LMFIT_DIR "${CMAKE_SOURCE_DIR}/src/external/lmfit")
|
|
 |
c245cf4 |
+ file(GLOB LMFIT_SOURCES ${BUNDLED_LMFIT_DIR}/*.cpp)
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
+ # Create a fake library for lmfit for libgromacs to depend on
|
|
 |
c245cf4 |
+ add_library(lmfit INTERFACE)
|
|
 |
c245cf4 |
+ target_sources(lmfit INTERFACE ${LMFIT_SOURCES})
|
|
 |
c245cf4 |
+ target_include_directories(lmfit INTERFACE
|
|
 |
c245cf4 |
+ $<BUILD_INTERFACE:${BUNDLED_LMFIT_DIR}>)
|
|
 |
c245cf4 |
+ target_link_libraries(libgromacs PRIVATE lmfit)
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ set(HAVE_LMFIT_VALUE TRUE)
|
|
 |
c245cf4 |
+ elseif(GMX_USE_LMFIT STREQUAL "EXTERNAL")
|
|
 |
c245cf4 |
+ # Find an external lmfit library.
|
|
 |
c245cf4 |
+ find_package(Lmfit ${GMX_LMFIT_MINIMUM_REQUIRED_VERSION})
|
|
 |
c245cf4 |
+ if(NOT LMFIT_FOUND)
|
|
 |
c245cf4 |
+ message(FATAL_ERROR "External lmfit could not be found, please adjust your pkg-config path to include the lmfit.pc file")
|
|
 |
c245cf4 |
+ endif()
|
|
 |
c245cf4 |
+ target_link_libraries(libgromacs PRIVATE lmfit)
|
|
 |
c245cf4 |
+ set(HAVE_LMFIT_VALUE TRUE)
|
|
 |
c245cf4 |
+ else()
|
|
 |
c245cf4 |
+ set(HAVE_LMFIT_VALUE FALSE)
|
|
 |
c245cf4 |
+ endif()
|
|
 |
c245cf4 |
+ set(HAVE_LMFIT ${HAVE_LMFIT_VALUE} CACHE BOOL "Whether lmfit library support is enabled")
|
|
 |
c245cf4 |
+endfunction()
|
|
 |
c245cf4 |
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
|
|
 |
c245cf4 |
index 9b38d75..3f050b5 100644
|
|
 |
c245cf4 |
--- a/docs/CMakeLists.txt
|
|
 |
c245cf4 |
+++ b/docs/CMakeLists.txt
|
|
 |
c245cf4 |
@@ -366,7 +366,7 @@
|
|
 |
c245cf4 |
REQUIRED_CUDA_COMPUTE_CAPABILITY REGRESSIONTEST_VERSION
|
|
 |
c245cf4 |
SOURCE_MD5SUM REGRESSIONTEST_MD5SUM_STRING
|
|
 |
c245cf4 |
GMX_TNG_MINIMUM_REQUIRED_VERSION
|
|
 |
c245cf4 |
- GMX_LMFIT_MINIMUM_REQUIRED_VERSION
|
|
 |
c245cf4 |
+ GMX_LMFIT_REQUIRED_VERSION
|
|
 |
c245cf4 |
COMMENT "Configuring Sphinx configuration file")
|
|
 |
c245cf4 |
gmx_add_sphinx_input_file(${SPHINX_CONFIG_VARS_FILE})
|
|
 |
c245cf4 |
gmx_add_sphinx_source_files(FILES ${SPHINX_SOURCE_FILES})
|
|
 |
c245cf4 |
diff --git a/docs/conf-vars.py.cmakein b/docs/conf-vars.py.cmakein
|
|
 |
c245cf4 |
index f4c3e02..038014a 100644
|
|
 |
c245cf4 |
--- a/docs/conf-vars.py.cmakein
|
|
 |
c245cf4 |
+++ b/docs/conf-vars.py.cmakein
|
|
 |
c245cf4 |
@@ -1,7 +1,7 @@
|
|
 |
c245cf4 |
#
|
|
 |
c245cf4 |
# This file is part of the GROMACS molecular simulation package.
|
|
 |
c245cf4 |
#
|
|
 |
c245cf4 |
-# Copyright (c) 2015,2016,2017, by the GROMACS development team, led by
|
|
 |
c245cf4 |
+# Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
|
|
 |
c245cf4 |
# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
|
|
 |
c245cf4 |
# and including many others, as listed in the AUTHORS file in the
|
|
 |
c245cf4 |
# top-level source directory and at http://www.gromacs.org.
|
|
 |
c245cf4 |
@@ -48,5 +48,5 @@
|
|
 |
c245cf4 |
('SOURCE_MD5SUM', '@SOURCE_MD5SUM@'),
|
|
 |
c245cf4 |
('REGRESSIONTEST_MD5SUM', '@REGRESSIONTEST_MD5SUM_STRING@'),
|
|
 |
c245cf4 |
('GMX_TNG_MINIMUM_REQUIRED_VERSION', '@GMX_TNG_MINIMUM_REQUIRED_VERSION@'),
|
|
 |
c245cf4 |
- ('GMX_LMFIT_MINIMUM_REQUIRED_VERSION', '@GMX_LMFIT_MINIMUM_REQUIRED_VERSION@')
|
|
 |
c245cf4 |
+ ('GMX_LMFIT_REQUIRED_VERSION', '@GMX_LMFIT_REQUIRED_VERSION@')
|
|
 |
c245cf4 |
]
|
|
 |
c245cf4 |
diff --git a/docs/install-guide/index.rst b/docs/install-guide/index.rst
|
|
 |
c245cf4 |
index 48fe2c3..5324629 100644
|
|
 |
c245cf4 |
--- a/docs/install-guide/index.rst
|
|
 |
c245cf4 |
+++ b/docs/install-guide/index.rst
|
|
 |
c245cf4 |
@@ -340,10 +340,14 @@
|
|
 |
c245cf4 |
by setting ``-DGMX_EXTERNAL_TNG=yes``, but TNG
|
|
 |
c245cf4 |
|GMX_TNG_MINIMUM_REQUIRED_VERSION| is bundled in the |Gromacs|
|
|
 |
c245cf4 |
source already.
|
|
 |
c245cf4 |
-* An external lmfit library for Levenberg-Marquardt curve fitting
|
|
 |
c245cf4 |
- can be used by setting ``-DGMX_EXTERNAL_LMFIT=yes``, but lmfit
|
|
 |
c245cf4 |
- |GMX_LMFIT_MINIMUM_REQUIRED_VERSION| is bundled in the |Gromacs|
|
|
 |
c245cf4 |
- source already.
|
|
 |
c245cf4 |
+* The lmfit library for Levenberg-Marquardt curve fitting is used in
|
|
 |
c245cf4 |
+ |Gromacs|. Only lmfit |GMX_LMFIT_REQUIRED_VERSION| is supported. A
|
|
 |
c245cf4 |
+ reduced version of that library is bundled in the |Gromacs|
|
|
 |
c245cf4 |
+ distribution, and the default build uses it. That default may be
|
|
 |
c245cf4 |
+ explicitly enabled with ``-DGMX_USE_LMFIT=internal``. To use an
|
|
 |
c245cf4 |
+ external lmfit library, set ``-DGMX_USE_LMFIT=external``, and adjust
|
|
 |
c245cf4 |
+ ``CMAKE_PREFIX_PATH`` as needed. lmfit support can be disabled with
|
|
 |
c245cf4 |
+ ``-DGMX_USE_LMFIT=none``.
|
|
 |
c245cf4 |
* zlib is used by TNG for compressing some kinds of trajectory data
|
|
 |
c245cf4 |
* Building the |Gromacs| documentation is optional, and requires
|
|
 |
c245cf4 |
ImageMagick, pdflatex, bibtex, doxygen, python 2.7, sphinx
|
|
 |
c245cf4 |
diff --git a/src/config.h.cmakein b/src/config.h.cmakein
|
|
 |
c245cf4 |
index b7e5964..d0c3c35 100644
|
|
 |
c245cf4 |
--- a/src/config.h.cmakein
|
|
 |
c245cf4 |
+++ b/src/config.h.cmakein
|
|
 |
c245cf4 |
@@ -377,6 +377,9 @@
|
|
 |
c245cf4 |
/* Define if we have feenableexcept */
|
|
 |
c245cf4 |
#cmakedefine01 HAVE_FEENABLEEXCEPT
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
+/* Define if we have lmfit support */
|
|
 |
c245cf4 |
+#cmakedefine01 HAVE_LMFIT
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
/*! \endcond */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
#endif
|
|
 |
c245cf4 |
diff --git a/src/external/lmfit/README b/src/external/lmfit/README
|
|
 |
c245cf4 |
index 3c0557b..4b8d7c6 100644
|
|
 |
c245cf4 |
--- a/src/external/lmfit/README
|
|
 |
c245cf4 |
+++ b/src/external/lmfit/README
|
|
 |
c245cf4 |
@@ -1,5 +1,5 @@
|
|
 |
c245cf4 |
This directory contains only the barebones version of the
|
|
 |
c245cf4 |
-lmfit package, version 6.1. Full version is available from
|
|
 |
c245cf4 |
+lmfit package, version 7.0. Full version is available from
|
|
 |
c245cf4 |
http://apps.jcns.fz-juelich.de/doku/sc/lmfit
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
The license under which lmfit is bundled may be found in the GROMACS
|
|
 |
c245cf4 |
diff --git a/src/external/lmfit/lmmin.cpp b/src/external/lmfit/lmmin.cpp
|
|
 |
c245cf4 |
index eb2d298..813fe5d 100644
|
|
 |
c245cf4 |
--- a/src/external/lmfit/lmmin.cpp
|
|
 |
c245cf4 |
+++ b/src/external/lmfit/lmmin.cpp
|
|
 |
c245cf4 |
@@ -16,40 +16,41 @@
|
|
 |
c245cf4 |
#include <assert.h>
|
|
 |
c245cf4 |
#include <stdlib.h>
|
|
 |
c245cf4 |
#include <stdio.h>
|
|
 |
c245cf4 |
-#include <cmath>
|
|
 |
c245cf4 |
+#include <math.h>
|
|
 |
c245cf4 |
#include <float.h>
|
|
 |
c245cf4 |
#include "lmmin.h"
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-using namespace std;
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
-static double lm_enorm(int n, const double* x);
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
-#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
|
|
 |
c245cf4 |
-#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
|
|
 |
c245cf4 |
-#define SQR(x) (x) * (x)
|
|
 |
c245cf4 |
+#define MIN(a,b) (((a)<=(b)) ? (a) : (b))
|
|
 |
c245cf4 |
+#define MAX(a,b) (((a)>=(b)) ? (a) : (b))
|
|
 |
c245cf4 |
+#define SQR(x) (x)*(x)
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
/* Declare functions that do the heavy numerics.
|
|
 |
c245cf4 |
Implementions are in this source file, below lmmin.
|
|
 |
c245cf4 |
- Dependences: lmmin calls lmpar, which calls qrfac and qrsolv. */
|
|
 |
c245cf4 |
-static void lm_lmpar(const int n, double* r, const int ldr, const int* Pivot,
|
|
 |
c245cf4 |
- const double* diag, const double* qtb, const double delta,
|
|
 |
c245cf4 |
- double* par, double* x, double* Sdiag, double* aux, double* xdi);
|
|
 |
c245cf4 |
-static void lm_qrfac(const int m, const int n, double* A, int* Pivot, double* Rdiag,
|
|
 |
c245cf4 |
- double* Acnorm, double* W);
|
|
 |
c245cf4 |
-static void lm_qrsolv(const int n, double* r, const int ldr, const int* Pivot,
|
|
 |
c245cf4 |
- const double* diag, const double* qtb, double* x,
|
|
 |
c245cf4 |
- double* Sdiag, double* W);
|
|
 |
c245cf4 |
+ Dependences: lmmin calls qrfac and lmpar; lmpar calls qrsolv. */
|
|
 |
c245cf4 |
+void lm_lmpar(
|
|
 |
c245cf4 |
+ const int n, double *const r, const int ldr, int *const ipvt,
|
|
 |
c245cf4 |
+ double *const diag, double *const qtb, double delta, double *const par,
|
|
 |
c245cf4 |
+ double *const x,
|
|
 |
c245cf4 |
+ double *const sdiag, double *const aux, double *const xdi);
|
|
 |
c245cf4 |
+void lm_qrfac(
|
|
 |
c245cf4 |
+ const int m, const int n, double *const a, int *const ipvt,
|
|
 |
c245cf4 |
+ double *const rdiag, double *const acnorm, double *const wa );
|
|
 |
c245cf4 |
+void lm_qrsolv(
|
|
 |
c245cf4 |
+ const int n, double *const r, const int ldr, int *const ipvt,
|
|
 |
c245cf4 |
+ double *const diag, double *const qtb, double *const x,
|
|
 |
c245cf4 |
+ double *const sdiag, double *const wa);
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
-/* Numeric constants */
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/* Set machine-dependent constants to values from float.h. */
|
|
 |
c245cf4 |
-#define LM_MACHEP DBL_EPSILON /* resolution of arithmetic */
|
|
 |
c245cf4 |
-#define LM_DWARF DBL_MIN /* smallest nonzero number */
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+/* Numeric constants */
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+/* machine-dependent constants from float.h */
|
|
 |
c245cf4 |
+#define LM_MACHEP DBL_EPSILON /* resolution of arithmetic */
|
|
 |
c245cf4 |
+#define LM_DWARF DBL_MIN /* smallest nonzero number */
|
|
 |
c245cf4 |
#define LM_SQRT_DWARF sqrt(DBL_MIN) /* square should not underflow */
|
|
 |
c245cf4 |
#define LM_SQRT_GIANT sqrt(DBL_MAX) /* square should not overflow */
|
|
 |
c245cf4 |
-#define LM_USERTOL 30 * LM_MACHEP /* users are recommended to require this */
|
|
 |
c245cf4 |
+#define LM_USERTOL 30*LM_MACHEP /* users are recommended to require this */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
/* If the above values do not work, the following seem good for an x86:
|
|
 |
c245cf4 |
LM_MACHEP .555e-16
|
|
 |
c245cf4 |
@@ -65,19 +66,19 @@
|
|
 |
c245cf4 |
LM_USER_TOL 1.e-14
|
|
 |
c245cf4 |
*/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/* Predefined control parameter sets (msgfile=NULL means stdout). */
|
|
 |
c245cf4 |
const lm_control_struct lm_control_double = {
|
|
 |
c245cf4 |
- LM_USERTOL, LM_USERTOL, LM_USERTOL, LM_USERTOL,
|
|
 |
c245cf4 |
- 100., 100, 1, NULL, 0, -1, -1};
|
|
 |
c245cf4 |
+ LM_USERTOL, LM_USERTOL, LM_USERTOL, LM_USERTOL, 100., 100, 1,
|
|
 |
c245cf4 |
+ NULL, 0, -1, -1 };
|
|
 |
c245cf4 |
const lm_control_struct lm_control_float = {
|
|
 |
c245cf4 |
- 1.e-7, 1.e-7, 1.e-7, 1.e-7,
|
|
 |
c245cf4 |
- 100., 100, 1, NULL, 0, -1, -1};
|
|
 |
c245cf4 |
+ 1.e-7, 1.e-7, 1.e-7, 1.e-7, 100., 100, 1,
|
|
 |
c245cf4 |
+ NULL, 0, -1, -1 };
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
-/* Message texts (indexed by status.info) */
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-const char* lm_infmsg[] = {
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+/* Message texts (indexed by status.info) */
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+const char *lm_infmsg[] = {
|
|
 |
c245cf4 |
"found zero (sum of squares below underflow limit)",
|
|
 |
c245cf4 |
"converged (the relative error in the sum of squares is at most tol)",
|
|
 |
c245cf4 |
"converged (the relative error of the parameter vector is at most tol)",
|
|
 |
c245cf4 |
@@ -90,66 +91,86 @@
|
|
 |
c245cf4 |
"crashed (not enough memory)",
|
|
 |
c245cf4 |
"exploded (fatal coding error: improper input parameters)",
|
|
 |
c245cf4 |
"stopped (break requested within function evaluation)",
|
|
 |
c245cf4 |
- "found nan (function value is not-a-number or infinite)"};
|
|
 |
c245cf4 |
+ "found nan (function value is not-a-number or infinite)",
|
|
 |
c245cf4 |
+ "won't fit (no free parameter)"
|
|
 |
c245cf4 |
+};
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
-/* Monitoring auxiliaries. */
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
+const char *lm_shortmsg[] = {
|
|
 |
c245cf4 |
+ "found zero", // 0
|
|
 |
c245cf4 |
+ "converged (f)", // 1
|
|
 |
c245cf4 |
+ "converged (p)", // 2
|
|
 |
c245cf4 |
+ "converged (2)", // 3
|
|
 |
c245cf4 |
+ "degenerate", // 4
|
|
 |
c245cf4 |
+ "call limit", // 5
|
|
 |
c245cf4 |
+ "failed (f)", // 6
|
|
 |
c245cf4 |
+ "failed (p)", // 7
|
|
 |
c245cf4 |
+ "failed (o)", // 8
|
|
 |
c245cf4 |
+ "no memory", // 9
|
|
 |
c245cf4 |
+ "invalid input", // 10
|
|
 |
c245cf4 |
+ "user break", // 11
|
|
 |
c245cf4 |
+ "found nan", // 12
|
|
 |
c245cf4 |
+ "no free par" // 13
|
|
 |
c245cf4 |
+};
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-static void lm_print_pars(int nout, const double* par, FILE* fout)
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+/* Monitoring auxiliaries. */
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+static void lm_print_pars(const int nout, const double *par, FILE* fout)
|
|
 |
c245cf4 |
{
|
|
 |
c245cf4 |
- int i;
|
|
 |
c245cf4 |
- for (i = 0; i < nout; ++i)
|
|
 |
c245cf4 |
- fprintf(fout, " %16.9g", par[i]);
|
|
 |
c245cf4 |
+ fprintf(fout, " pars:");
|
|
 |
c245cf4 |
+ for (int i = 0; i < nout; ++i)
|
|
 |
c245cf4 |
+ fprintf(fout, " %23.16g", par[i]);
|
|
 |
c245cf4 |
fprintf(fout, "\n");
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
-/* lmmin (main minimization routine) */
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-void lmmin(const int n, double* x, const int m, const void* data,
|
|
 |
c245cf4 |
- void (*evaluate)(const double* par, const int m_dat,
|
|
 |
c245cf4 |
- const void* data, double* fvec, int* userbreak),
|
|
 |
c245cf4 |
- const lm_control_struct* C, lm_status_struct* S)
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+/* lmmin (main minimization routine) */
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+void lmmin(
|
|
 |
c245cf4 |
+ const int n, double *const x, const int m, const double* y,
|
|
 |
c245cf4 |
+ const void *const data,
|
|
 |
c245cf4 |
+ void (*const evaluate)(
|
|
 |
c245cf4 |
+ const double *const par, const int m_dat, const void *const data,
|
|
 |
c245cf4 |
+ double *const fvec, int *const userbreak),
|
|
 |
c245cf4 |
+ const lm_control_struct *const C, lm_status_struct *const S)
|
|
 |
c245cf4 |
{
|
|
 |
c245cf4 |
int j, i;
|
|
 |
c245cf4 |
- double actred, dirder, fnorm, fnorm1, gnorm, pnorm, prered, ratio, step,
|
|
 |
c245cf4 |
- sum, temp, temp1, temp2, temp3;
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
- /*** Initialize internal variables. ***/
|
|
 |
c245cf4 |
+ double actred, dirder, fnorm, fnorm1, gnorm, pnorm,
|
|
 |
c245cf4 |
+ prered, ratio, step, sum, temp, temp1, temp2, temp3;
|
|
 |
c245cf4 |
+ static double p1 = 0.1, p0001 = 1.0e-4;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
int maxfev = C->patience * (n+1);
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- int inner_success; /* flag for loop control */
|
|
 |
c245cf4 |
- double lmpar = 0; /* Levenberg-Marquardt parameter */
|
|
 |
c245cf4 |
+ int inner_success; /* flag for loop control */
|
|
 |
c245cf4 |
+ double lmpar = 0; /* Levenberg-Marquardt parameter */
|
|
 |
c245cf4 |
double delta = 0;
|
|
 |
c245cf4 |
double xnorm = 0;
|
|
 |
c245cf4 |
double eps = sqrt(MAX(C->epsilon, LM_MACHEP)); /* for forward differences */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- int nout = C->n_maxpri == -1 ? n : MIN(C->n_maxpri, n);
|
|
 |
c245cf4 |
+ int nout = C->n_maxpri==-1 ? n : MIN(C->n_maxpri, n);
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /* Reinterpret C->msgfile=NULL as stdout (which is unavailable for
|
|
 |
c245cf4 |
- compile-time initialization of lm_control_double and similar). */
|
|
 |
c245cf4 |
+ /* The workaround msgfile=NULL is needed for default initialization */
|
|
 |
c245cf4 |
FILE* msgfile = C->msgfile ? C->msgfile : stdout;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Default status info; must be set before first return statement. ***/
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
- S->outcome = 0; /* status code */
|
|
 |
c245cf4 |
+ /* Default status info; must be set ahead of first return statements */
|
|
 |
c245cf4 |
+ S->outcome = 0; /* status code */
|
|
 |
c245cf4 |
S->userbreak = 0;
|
|
 |
c245cf4 |
- S->nfev = 0; /* function evaluation counter */
|
|
 |
c245cf4 |
+ S->nfev = 0; /* function evaluation counter */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Check input parameters for errors. ***/
|
|
 |
c245cf4 |
+/*** Check input parameters for errors. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- if (n <= 0) {
|
|
 |
c245cf4 |
+ if ( n < 0 ) {
|
|
 |
c245cf4 |
fprintf(stderr, "lmmin: invalid number of parameters %i\n", n);
|
|
 |
c245cf4 |
- S->outcome = 10;
|
|
 |
c245cf4 |
+ S->outcome = 10; /* invalid parameter */
|
|
 |
c245cf4 |
return;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
if (m < n) {
|
|
 |
c245cf4 |
fprintf(stderr, "lmmin: number of data points (%i) "
|
|
 |
c245cf4 |
- "smaller than number of parameters (%i)\n",
|
|
 |
c245cf4 |
- m, n);
|
|
 |
c245cf4 |
+ "smaller than number of parameters (%i)\n", m, n);
|
|
 |
c245cf4 |
S->outcome = 10;
|
|
 |
c245cf4 |
return;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
@@ -173,93 +194,99 @@
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
if (C->scale_diag != 0 && C->scale_diag != 1) {
|
|
 |
c245cf4 |
fprintf(stderr, "lmmin: logical variable scale_diag=%i, "
|
|
 |
c245cf4 |
- "should be 0 or 1\n",
|
|
 |
c245cf4 |
- C->scale_diag);
|
|
 |
c245cf4 |
+ "should be 0 or 1\n", C->scale_diag);
|
|
 |
c245cf4 |
S->outcome = 10;
|
|
 |
c245cf4 |
return;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Allocate work space. ***/
|
|
 |
c245cf4 |
+/*** Allocate work space. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
/* Allocate total workspace with just one system call */
|
|
 |
c245cf4 |
- char* ws;
|
|
 |
c245cf4 |
- if ((ws = (char *)malloc((2*m + 5*n + m*n) * sizeof(double) +
|
|
 |
c245cf4 |
- n * sizeof(int))) == NULL) {
|
|
 |
c245cf4 |
+ char *ws;
|
|
 |
c245cf4 |
+ if ( ( ws = static_cast<char *>(malloc(
|
|
 |
c245cf4 |
+ (2*m+5*n+m*n)*sizeof(double) + n*sizeof(int)) ) ) == NULL ) {
|
|
 |
c245cf4 |
S->outcome = 9;
|
|
 |
c245cf4 |
return;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
/* Assign workspace segments. */
|
|
 |
c245cf4 |
- char* pws = ws;
|
|
 |
c245cf4 |
- double* fvec = (double*)pws;
|
|
 |
c245cf4 |
- pws += m * sizeof(double) / sizeof(char);
|
|
 |
c245cf4 |
- double* diag = (double*)pws;
|
|
 |
c245cf4 |
- pws += n * sizeof(double) / sizeof(char);
|
|
 |
c245cf4 |
- double* qtf = (double*)pws;
|
|
 |
c245cf4 |
- pws += n * sizeof(double) / sizeof(char);
|
|
 |
c245cf4 |
- double* fjac = (double*)pws;
|
|
 |
c245cf4 |
- pws += n * m * sizeof(double) / sizeof(char);
|
|
 |
c245cf4 |
- double* wa1 = (double*)pws;
|
|
 |
c245cf4 |
- pws += n * sizeof(double) / sizeof(char);
|
|
 |
c245cf4 |
- double* wa2 = (double*)pws;
|
|
 |
c245cf4 |
- pws += n * sizeof(double) / sizeof(char);
|
|
 |
c245cf4 |
- double* wa3 = (double*)pws;
|
|
 |
c245cf4 |
- pws += n * sizeof(double) / sizeof(char);
|
|
 |
c245cf4 |
- double* wf = (double*)pws;
|
|
 |
c245cf4 |
- pws += m * sizeof(double) / sizeof(char);
|
|
 |
c245cf4 |
- int* Pivot = (int*)pws;
|
|
 |
c245cf4 |
- //pws += n * sizeof(int) / sizeof(char);
|
|
 |
c245cf4 |
+ char *pws = ws;
|
|
 |
c245cf4 |
+ double *fvec = (double*) pws; pws += m * sizeof(double)/sizeof(char);
|
|
 |
c245cf4 |
+ double *diag = (double*) pws; pws += n * sizeof(double)/sizeof(char);
|
|
 |
c245cf4 |
+ double *qtf = (double*) pws; pws += n * sizeof(double)/sizeof(char);
|
|
 |
c245cf4 |
+ double *fjac = (double*) pws; pws += n*m*sizeof(double)/sizeof(char);
|
|
 |
c245cf4 |
+ double *wa1 = (double*) pws; pws += n * sizeof(double)/sizeof(char);
|
|
 |
c245cf4 |
+ double *wa2 = (double*) pws; pws += n * sizeof(double)/sizeof(char);
|
|
 |
c245cf4 |
+ double *wa3 = (double*) pws; pws += n * sizeof(double)/sizeof(char);
|
|
 |
c245cf4 |
+ double *wf = (double*) pws; pws += m * sizeof(double)/sizeof(char);
|
|
 |
c245cf4 |
+ int *ipvt = (int*) pws; pws += n * sizeof(int) /sizeof(char);
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /* Initialize diag. */
|
|
 |
c245cf4 |
- if (!C->scale_diag)
|
|
 |
c245cf4 |
+ /* Initialize diag */ // TODO: check whether this is still needed
|
|
 |
c245cf4 |
+ if (!C->scale_diag) {
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
- diag[j] = 1;
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
- /*** Evaluate function at starting point and calculate norm. ***/
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
- if (C->verbosity) {
|
|
 |
c245cf4 |
- fprintf(msgfile, "lmmin start ");
|
|
 |
c245cf4 |
- lm_print_pars(nout, x, msgfile);
|
|
 |
c245cf4 |
+ diag[j] = 1.;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- (*evaluate)(x, m, data, fvec, &(S->userbreak));
|
|
 |
c245cf4 |
- if (C->verbosity > 4)
|
|
 |
c245cf4 |
- for (i = 0; i < m; ++i)
|
|
 |
c245cf4 |
- fprintf(msgfile, " fvec[%4i] = %18.8g\n", i, fvec[i]);
|
|
 |
c245cf4 |
- S->nfev = 1;
|
|
 |
c245cf4 |
- if (S->userbreak)
|
|
 |
c245cf4 |
- goto terminate;
|
|
 |
c245cf4 |
- fnorm = lm_enorm(m, fvec);
|
|
 |
c245cf4 |
- if (C->verbosity)
|
|
 |
c245cf4 |
- fprintf(msgfile, " fnorm = %18.8g\n", fnorm);
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- if (!std::isfinite(fnorm)) {
|
|
 |
c245cf4 |
+/*** Evaluate function at starting point and calculate norm. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ if( C->verbosity&1 )
|
|
 |
c245cf4 |
+ fprintf(msgfile, "lmmin start (ftol=%g gtol=%g xtol=%g)\n",
|
|
 |
c245cf4 |
+ C->ftol, C->gtol, C->xtol);
|
|
 |
c245cf4 |
+ if( C->verbosity&2 )
|
|
 |
c245cf4 |
+ lm_print_pars(nout, x, msgfile);
|
|
 |
c245cf4 |
+ (*evaluate)(x, m, data, fvec, &(S->userbreak));
|
|
 |
c245cf4 |
+ if( C->verbosity&8 )
|
|
 |
c245cf4 |
+ {
|
|
 |
c245cf4 |
+ if (y) {
|
|
 |
c245cf4 |
+ for( i=0; i
|
|
 |
c245cf4 |
+ fprintf(msgfile, " i, f, y-f: %4i %18.8g %18.8g\n",
|
|
 |
c245cf4 |
+ i, fvec[i], y[i]-fvec[i]);
|
|
 |
c245cf4 |
+ } else {
|
|
 |
c245cf4 |
+ for( i=0; i
|
|
 |
c245cf4 |
+ fprintf(msgfile, " i, f: %4i %18.8g\n", i, fvec[i]);
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
+ S->nfev = 1;
|
|
 |
c245cf4 |
+ if ( S->userbreak )
|
|
 |
c245cf4 |
+ goto terminate;
|
|
 |
c245cf4 |
+ if ( n == 0 ) {
|
|
 |
c245cf4 |
+ S->outcome = 13; /* won't fit */
|
|
 |
c245cf4 |
+ goto terminate;
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
+ fnorm = lm_fnorm(m, fvec, y);
|
|
 |
c245cf4 |
+ if( C->verbosity&2 )
|
|
 |
c245cf4 |
+ fprintf(msgfile, " fnorm = %24.16g\n", fnorm);
|
|
 |
c245cf4 |
+ if( !isfinite(fnorm) ){
|
|
 |
c245cf4 |
+ if( C->verbosity )
|
|
 |
c245cf4 |
+ fprintf(msgfile, "nan case 1\n");
|
|
 |
c245cf4 |
S->outcome = 12; /* nan */
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
- } else if (fnorm <= LM_DWARF) {
|
|
 |
c245cf4 |
+ } else if( fnorm <= LM_DWARF ){
|
|
 |
c245cf4 |
S->outcome = 0; /* sum of squares almost zero, nothing to do */
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** The outer loop: compute gradient, then descend. ***/
|
|
 |
c245cf4 |
+/*** The outer loop: compute gradient, then descend. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- for (int outer = 0;; ++outer) {
|
|
 |
c245cf4 |
+ for( int outer=0; ; ++outer ) {
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Calculate the Jacobian. **/
|
|
 |
c245cf4 |
+/*** [outer] Calculate the Jacobian. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
temp = x[j];
|
|
 |
c245cf4 |
- step = MAX(eps * eps, eps * fabs(temp));
|
|
 |
c245cf4 |
+ step = MAX(eps*eps, eps * fabs(temp));
|
|
 |
c245cf4 |
x[j] += step; /* replace temporarily */
|
|
 |
c245cf4 |
(*evaluate)(x, m, data, wf, &(S->userbreak));
|
|
 |
c245cf4 |
++(S->nfev);
|
|
 |
c245cf4 |
- if (S->userbreak)
|
|
 |
c245cf4 |
+ if ( S->userbreak )
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
for (i = 0; i < m; i++)
|
|
 |
c245cf4 |
fjac[j*m+i] = (wf[i] - fvec[i]) / step;
|
|
 |
c245cf4 |
x[j] = temp; /* restore */
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- if (C->verbosity >= 10) {
|
|
 |
c245cf4 |
+ if ( C->verbosity&16 ) {
|
|
 |
c245cf4 |
/* print the entire matrix */
|
|
 |
c245cf4 |
- printf("\nlmmin Jacobian\n");
|
|
 |
c245cf4 |
+ printf("Jacobian\n");
|
|
 |
c245cf4 |
for (i = 0; i < m; i++) {
|
|
 |
c245cf4 |
printf(" ");
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
@@ -268,34 +295,39 @@
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Compute the QR factorization of the Jacobian. **/
|
|
 |
c245cf4 |
+/*** [outer] Compute the QR factorization of the Jacobian. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /* fjac is an m by n array. The upper n by n submatrix of fjac is made
|
|
 |
c245cf4 |
- * to contain an upper triangular matrix R with diagonal elements of
|
|
 |
c245cf4 |
- * nonincreasing magnitude such that
|
|
 |
c245cf4 |
- *
|
|
 |
c245cf4 |
- * P^T*(J^T*J)*P = R^T*R
|
|
 |
c245cf4 |
- *
|
|
 |
c245cf4 |
- * (NOTE: ^T stands for matrix transposition),
|
|
 |
c245cf4 |
- *
|
|
 |
c245cf4 |
- * where P is a permutation matrix and J is the final calculated
|
|
 |
c245cf4 |
- * Jacobian. Column j of P is column Pivot(j) of the identity matrix.
|
|
 |
c245cf4 |
- * The lower trapezoidal part of fjac contains information generated
|
|
 |
c245cf4 |
- * during the computation of R.
|
|
 |
c245cf4 |
- *
|
|
 |
c245cf4 |
- * Pivot is an integer array of length n. It defines a permutation
|
|
 |
c245cf4 |
- * matrix P such that jac*P = Q*R, where jac is the final calculated
|
|
 |
c245cf4 |
- * Jacobian, Q is orthogonal (not stored), and R is upper triangular
|
|
 |
c245cf4 |
- * with diagonal elements of nonincreasing magnitude. Column j of P
|
|
 |
c245cf4 |
- * is column Pivot(j) of the identity matrix.
|
|
 |
c245cf4 |
- */
|
|
 |
c245cf4 |
+/* fjac is an m by n array. The upper n by n submatrix of fjac
|
|
 |
c245cf4 |
+ * is made to contain an upper triangular matrix R with diagonal
|
|
 |
c245cf4 |
+ * elements of nonincreasing magnitude such that
|
|
 |
c245cf4 |
+ *
|
|
 |
c245cf4 |
+ * P^T*(J^T*J)*P = R^T*R
|
|
 |
c245cf4 |
+ *
|
|
 |
c245cf4 |
+ * (NOTE: ^T stands for matrix transposition),
|
|
 |
c245cf4 |
+ *
|
|
 |
c245cf4 |
+ * where P is a permutation matrix and J is the final calculated
|
|
 |
c245cf4 |
+ * Jacobian. Column j of P is column ipvt(j) of the identity matrix.
|
|
 |
c245cf4 |
+ * The lower trapezoidal part of fjac contains information generated
|
|
 |
c245cf4 |
+ * during the computation of R.
|
|
 |
c245cf4 |
+ *
|
|
 |
c245cf4 |
+ * ipvt is an integer array of length n. It defines a permutation
|
|
 |
c245cf4 |
+ * matrix P such that jac*P = Q*R, where jac is the final calculated
|
|
 |
c245cf4 |
+ * Jacobian, Q is orthogonal (not stored), and R is upper triangular
|
|
 |
c245cf4 |
+ * with diagonal elements of nonincreasing magnitude. Column j of P
|
|
 |
c245cf4 |
+ * is column ipvt(j) of the identity matrix.
|
|
 |
c245cf4 |
+ */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- lm_qrfac(m, n, fjac, Pivot, wa1, wa2, wa3);
|
|
 |
c245cf4 |
- /* return values are Pivot, wa1=rdiag, wa2=acnorm */
|
|
 |
c245cf4 |
+ lm_qrfac(m, n, fjac, ipvt, wa1, wa2, wa3);
|
|
 |
c245cf4 |
+ /* return values are ipvt, wa1=rdiag, wa2=acnorm */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Form Q^T * fvec, and store first n components in qtf. **/
|
|
 |
c245cf4 |
- for (i = 0; i < m; i++)
|
|
 |
c245cf4 |
- wf[i] = fvec[i];
|
|
 |
c245cf4 |
+/*** [outer] Form Q^T * fvec, and store first n components in qtf. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ if (y)
|
|
 |
c245cf4 |
+ for (i = 0; i < m; i++)
|
|
 |
c245cf4 |
+ wf[i] = fvec[i] - y[i];
|
|
 |
c245cf4 |
+ else
|
|
 |
c245cf4 |
+ for (i = 0; i < m; i++)
|
|
 |
c245cf4 |
+ wf[i] = fvec[i];
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
temp3 = fjac[j*m+j];
|
|
 |
c245cf4 |
@@ -311,15 +343,16 @@
|
|
 |
c245cf4 |
qtf[j] = wf[j];
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Compute norm of scaled gradient and detect degeneracy. **/
|
|
 |
c245cf4 |
+/*** [outer] Compute norm of scaled gradient and detect degeneracy. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
gnorm = 0;
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
- if (wa2[Pivot[j]] == 0)
|
|
 |
c245cf4 |
+ if (wa2[ipvt[j]] == 0)
|
|
 |
c245cf4 |
continue;
|
|
 |
c245cf4 |
sum = 0;
|
|
 |
c245cf4 |
for (i = 0; i <= j; i++)
|
|
 |
c245cf4 |
sum += fjac[j*m+i] * qtf[i];
|
|
 |
c245cf4 |
- gnorm = MAX(gnorm, fabs(sum / wa2[Pivot[j]] / fnorm));
|
|
 |
c245cf4 |
+ gnorm = MAX(gnorm, fabs( sum / wa2[ipvt[j]] / fnorm ));
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
if (gnorm <= C->gtol) {
|
|
 |
c245cf4 |
@@ -327,8 +360,10 @@
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Initialize or update diag and delta. **/
|
|
 |
c245cf4 |
- if (!outer) { /* first iteration only */
|
|
 |
c245cf4 |
+/*** [outer] Initialize / update diag and delta. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ if ( !outer ) {
|
|
 |
c245cf4 |
+ /* first iteration only */
|
|
 |
c245cf4 |
if (C->scale_diag) {
|
|
 |
c245cf4 |
/* diag := norms of the columns of the initial Jacobian */
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
@@ -337,129 +372,140 @@
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
wa3[j] = diag[j] * x[j];
|
|
 |
c245cf4 |
xnorm = lm_enorm(n, wa3);
|
|
 |
c245cf4 |
- if (C->verbosity >= 2) {
|
|
 |
c245cf4 |
- fprintf(msgfile, "lmmin diag ");
|
|
 |
c245cf4 |
- lm_print_pars(nout, x, msgfile); // xnorm
|
|
 |
c245cf4 |
- fprintf(msgfile, " xnorm = %18.8g\n", xnorm);
|
|
 |
c245cf4 |
- }
|
|
 |
c245cf4 |
- /* Only now print the header for the loop table. */
|
|
 |
c245cf4 |
- if (C->verbosity >= 3) {
|
|
 |
c245cf4 |
- fprintf(msgfile, " o i lmpar prered"
|
|
 |
c245cf4 |
- " ratio dirder delta"
|
|
 |
c245cf4 |
- " pnorm fnorm");
|
|
 |
c245cf4 |
- for (i = 0; i < nout; ++i)
|
|
 |
c245cf4 |
- fprintf(msgfile, " p%i", i);
|
|
 |
c245cf4 |
- fprintf(msgfile, "\n");
|
|
 |
c245cf4 |
- }
|
|
 |
c245cf4 |
} else {
|
|
 |
c245cf4 |
xnorm = lm_enorm(n, x);
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- if (!std::isfinite(xnorm)) {
|
|
 |
c245cf4 |
+ if( !isfinite(xnorm) ){
|
|
 |
c245cf4 |
+ if( C->verbosity )
|
|
 |
c245cf4 |
+ fprintf(msgfile, "nan case 2\n");
|
|
 |
c245cf4 |
S->outcome = 12; /* nan */
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- /* Initialize the step bound delta. */
|
|
 |
c245cf4 |
- if (xnorm)
|
|
 |
c245cf4 |
+ /* initialize the step bound delta. */
|
|
 |
c245cf4 |
+ if ( xnorm )
|
|
 |
c245cf4 |
delta = C->stepbound * xnorm;
|
|
 |
c245cf4 |
else
|
|
 |
c245cf4 |
delta = C->stepbound;
|
|
 |
c245cf4 |
+ /* only now print the header for the loop table */
|
|
 |
c245cf4 |
+ if( C->verbosity&2 ) {
|
|
 |
c245cf4 |
+ fprintf(msgfile, " #o #i lmpar prered actred"
|
|
 |
c245cf4 |
+ " ratio dirder delta"
|
|
 |
c245cf4 |
+ " pnorm fnorm");
|
|
 |
c245cf4 |
+ for (i = 0; i < nout; ++i)
|
|
 |
c245cf4 |
+ fprintf(msgfile, " p%i", i);
|
|
 |
c245cf4 |
+ fprintf(msgfile, "\n");
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
} else {
|
|
 |
c245cf4 |
if (C->scale_diag) {
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
- diag[j] = MAX(diag[j], wa2[j]);
|
|
 |
c245cf4 |
+ diag[j] = MAX( diag[j], wa2[j] );
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** The inner loop. **/
|
|
 |
c245cf4 |
+/*** The inner loop. ***/
|
|
 |
c245cf4 |
int inner = 0;
|
|
 |
c245cf4 |
do {
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Determine the Levenberg-Marquardt parameter. **/
|
|
 |
c245cf4 |
- lm_lmpar(n, fjac, m, Pivot, diag, qtf, delta, &lmpar,
|
|
 |
c245cf4 |
+/*** [inner] Determine the Levenberg-Marquardt parameter. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ lm_lmpar(n, fjac, m, ipvt, diag, qtf, delta, &lmpar,
|
|
 |
c245cf4 |
wa1, wa2, wf, wa3);
|
|
 |
c245cf4 |
/* used return values are fjac (partly), lmpar, wa1=x, wa3=diag*x */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /* Predict scaled reduction. */
|
|
 |
c245cf4 |
+ /* predict scaled reduction */
|
|
 |
c245cf4 |
pnorm = lm_enorm(n, wa3);
|
|
 |
c245cf4 |
- if (!std::isfinite(pnorm)) {
|
|
 |
c245cf4 |
+ if( !isfinite(pnorm) ){
|
|
 |
c245cf4 |
+ if( C->verbosity )
|
|
 |
c245cf4 |
+ fprintf(msgfile, "nan case 3\n");
|
|
 |
c245cf4 |
S->outcome = 12; /* nan */
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- temp2 = lmpar * SQR(pnorm / fnorm);
|
|
 |
c245cf4 |
+ temp2 = lmpar * SQR( pnorm / fnorm );
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
wa3[j] = 0;
|
|
 |
c245cf4 |
for (i = 0; i <= j; i++)
|
|
 |
c245cf4 |
- wa3[i] -= fjac[j*m+i] * wa1[Pivot[j]];
|
|
 |
c245cf4 |
+ wa3[i] -= fjac[j*m+i] * wa1[ipvt[j]];
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- temp1 = SQR(lm_enorm(n, wa3) / fnorm);
|
|
 |
c245cf4 |
- if (!std::isfinite(temp1)) {
|
|
 |
c245cf4 |
+ temp1 = SQR( lm_enorm(n, wa3) / fnorm );
|
|
 |
c245cf4 |
+ if( !isfinite(temp1) ){
|
|
 |
c245cf4 |
+ if( C->verbosity )
|
|
 |
c245cf4 |
+ fprintf(msgfile, "nan case 4\n");
|
|
 |
c245cf4 |
S->outcome = 12; /* nan */
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- prered = temp1 + 2*temp2;
|
|
 |
c245cf4 |
+ prered = temp1 + 2 * temp2;
|
|
 |
c245cf4 |
dirder = -temp1 + temp2; /* scaled directional derivative */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /* At first call, adjust the initial step bound. */
|
|
 |
c245cf4 |
- if (!outer && pnorm < delta)
|
|
 |
c245cf4 |
+ /* at first call, adjust the initial step bound. */
|
|
 |
c245cf4 |
+ if ( !outer && !inner && pnorm < delta )
|
|
 |
c245cf4 |
delta = pnorm;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Evaluate the function at x + p. **/
|
|
 |
c245cf4 |
+/*** [inner] Evaluate the function at x + p. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
wa2[j] = x[j] - wa1[j];
|
|
 |
c245cf4 |
- (*evaluate)(wa2, m, data, wf, &(S->userbreak));
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ (*evaluate)( wa2, m, data, wf, &(S->userbreak) );
|
|
 |
c245cf4 |
++(S->nfev);
|
|
 |
c245cf4 |
- if (S->userbreak)
|
|
 |
c245cf4 |
+ if ( S->userbreak )
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
- fnorm1 = lm_enorm(m, wf);
|
|
 |
c245cf4 |
- if (!std::isfinite(fnorm1)) {
|
|
 |
c245cf4 |
- S->outcome = 12; /* nan */
|
|
 |
c245cf4 |
- goto terminate;
|
|
 |
c245cf4 |
+ fnorm1 = lm_fnorm(m, wf, y);
|
|
 |
c245cf4 |
+ // exceptionally, for this norm we do not test for infinity
|
|
 |
c245cf4 |
+ // because we can deal with it without terminating.
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+/*** [inner] Evaluate the scaled reduction. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ /* actual scaled reduction (supports even the case fnorm1=infty) */
|
|
 |
c245cf4 |
+ if (p1 * fnorm1 < fnorm)
|
|
 |
c245cf4 |
+ actred = 1 - SQR(fnorm1 / fnorm);
|
|
 |
c245cf4 |
+ else
|
|
 |
c245cf4 |
+ actred = -1;
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ /* ratio of actual to predicted reduction */
|
|
 |
c245cf4 |
+ ratio = prered ? actred/prered : 0;
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ if( C->verbosity&32 ) {
|
|
 |
c245cf4 |
+ if (y) {
|
|
 |
c245cf4 |
+ for( i=0; i
|
|
 |
c245cf4 |
+ fprintf(msgfile, " i, f, y-f: %4i %18.8g %18.8g\n",
|
|
 |
c245cf4 |
+ i, fvec[i], y[i]-fvec[i]);
|
|
 |
c245cf4 |
+ } else {
|
|
 |
c245cf4 |
+ for( i=0; i
|
|
 |
c245cf4 |
+ fprintf(msgfile, " i, f, y-f: %4i %18.8g\n",
|
|
 |
c245cf4 |
+ i, fvec[i]);
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
- /** Evaluate the scaled reduction. **/
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
- /* Actual scaled reduction. */
|
|
 |
c245cf4 |
- actred = 1 - SQR(fnorm1 / fnorm);
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
- /* Ratio of actual to predicted reduction. */
|
|
 |
c245cf4 |
- ratio = prered ? actred / prered : 0;
|
|
 |
c245cf4 |
-
|
|
 |
c245cf4 |
- if (C->verbosity == 2) {
|
|
 |
c245cf4 |
- fprintf(msgfile, "lmmin (%i:%i) ", outer, inner);
|
|
 |
c245cf4 |
- lm_print_pars(nout, wa2, msgfile); // fnorm1,
|
|
 |
c245cf4 |
- } else if (C->verbosity >= 3) {
|
|
 |
c245cf4 |
- printf("%3i %2i %9.2g %9.2g %14.6g"
|
|
 |
c245cf4 |
+ if( C->verbosity&2 ) {
|
|
 |
c245cf4 |
+ printf("%3i %2i %9.2g %9.2g %9.2g %14.6g"
|
|
 |
c245cf4 |
" %9.2g %10.3e %10.3e %21.15e",
|
|
 |
c245cf4 |
- outer, inner, lmpar, prered, ratio,
|
|
 |
c245cf4 |
+ outer, inner, lmpar, prered, actred, ratio,
|
|
 |
c245cf4 |
dirder, delta, pnorm, fnorm1);
|
|
 |
c245cf4 |
for (i = 0; i < nout; ++i)
|
|
 |
c245cf4 |
fprintf(msgfile, " %16.9g", wa2[i]);
|
|
 |
c245cf4 |
fprintf(msgfile, "\n");
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /* Update the step bound. */
|
|
 |
c245cf4 |
- if (ratio <= 0.25) {
|
|
 |
c245cf4 |
- if (actred >= 0)
|
|
 |
c245cf4 |
- temp = 0.5;
|
|
 |
c245cf4 |
- else if (actred > -99) /* -99 = 1-1/0.1^2 */
|
|
 |
c245cf4 |
- temp = MAX(dirder / (2*dirder + actred), 0.1);
|
|
 |
c245cf4 |
- else
|
|
 |
c245cf4 |
- temp = 0.1;
|
|
 |
c245cf4 |
- delta = temp * MIN(delta, pnorm / 0.1);
|
|
 |
c245cf4 |
- lmpar /= temp;
|
|
 |
c245cf4 |
- } else if (ratio >= 0.75) {
|
|
 |
c245cf4 |
- delta = 2 * pnorm;
|
|
 |
c245cf4 |
- lmpar *= 0.5;
|
|
 |
c245cf4 |
- } else if (!lmpar) {
|
|
 |
c245cf4 |
- delta = 2 * pnorm;
|
|
 |
c245cf4 |
- }
|
|
 |
c245cf4 |
+ /* update the step bound */
|
|
 |
c245cf4 |
+ if (ratio <= 0.25) {
|
|
 |
c245cf4 |
+ if (actred >= 0)
|
|
 |
c245cf4 |
+ temp = 0.5;
|
|
 |
c245cf4 |
+ else
|
|
 |
c245cf4 |
+ temp = 0.5 * dirder / (dirder + 0.5 * actred);
|
|
 |
c245cf4 |
+ if (p1 * fnorm1 >= fnorm || temp < p1)
|
|
 |
c245cf4 |
+ temp = p1;
|
|
 |
c245cf4 |
+ delta = temp * MIN(delta, pnorm / p1);
|
|
 |
c245cf4 |
+ lmpar /= temp;
|
|
 |
c245cf4 |
+ } else if (lmpar == 0 || ratio >= 0.75) {
|
|
 |
c245cf4 |
+ delta = 2 * pnorm;
|
|
 |
c245cf4 |
+ lmpar *= 0.5;
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** On success, update solution, and test for convergence. **/
|
|
 |
c245cf4 |
+/*** [inner] On success, update solution, and test for convergence. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- inner_success = ratio >= 1e-4;
|
|
 |
c245cf4 |
- if (inner_success) {
|
|
 |
c245cf4 |
+ inner_success = ratio >= p0001;
|
|
 |
c245cf4 |
+ if ( inner_success ) {
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /* Update x, fvec, and their norms. */
|
|
 |
c245cf4 |
+ /* update x, fvec, and their norms */
|
|
 |
c245cf4 |
if (C->scale_diag) {
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
x[j] = wa2[j];
|
|
 |
c245cf4 |
@@ -472,172 +518,193 @@
|
|
 |
c245cf4 |
for (i = 0; i < m; i++)
|
|
 |
c245cf4 |
fvec[i] = wf[i];
|
|
 |
c245cf4 |
xnorm = lm_enorm(n, wa2);
|
|
 |
c245cf4 |
- if (!std::isfinite(xnorm)) {
|
|
 |
c245cf4 |
+ if( !isfinite(xnorm) ){
|
|
 |
c245cf4 |
+ if( C->verbosity )
|
|
 |
c245cf4 |
+ fprintf(msgfile, "nan case 6\n");
|
|
 |
c245cf4 |
S->outcome = 12; /* nan */
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
fnorm = fnorm1;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /* Convergence tests. */
|
|
 |
c245cf4 |
+ /* convergence tests */
|
|
 |
c245cf4 |
S->outcome = 0;
|
|
 |
c245cf4 |
- if (fnorm <= LM_DWARF)
|
|
 |
c245cf4 |
- goto terminate; /* success: sum of squares almost zero */
|
|
 |
c245cf4 |
- /* Test two criteria (both may be fulfilled). */
|
|
 |
c245cf4 |
+ if( fnorm<=LM_DWARF )
|
|
 |
c245cf4 |
+ goto terminate; /* success: sum of squares almost zero */
|
|
 |
c245cf4 |
+ /* test two criteria (both may be fulfilled) */
|
|
 |
c245cf4 |
if (fabs(actred) <= C->ftol && prered <= C->ftol && ratio <= 2)
|
|
 |
c245cf4 |
- S->outcome = 1; /* success: x almost stable */
|
|
 |
c245cf4 |
+ S->outcome = 1; /* success: x almost stable */
|
|
 |
c245cf4 |
if (delta <= C->xtol * xnorm)
|
|
 |
c245cf4 |
S->outcome += 2; /* success: sum of squares almost stable */
|
|
 |
c245cf4 |
if (S->outcome != 0) {
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Tests for termination and stringent tolerances. **/
|
|
 |
c245cf4 |
- if (S->nfev >= maxfev) {
|
|
 |
c245cf4 |
+/*** [inner] Tests for termination and stringent tolerances. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ if ( S->nfev >= maxfev ){
|
|
 |
c245cf4 |
S->outcome = 5;
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- if (fabs(actred) <= LM_MACHEP && prered <= LM_MACHEP &&
|
|
 |
c245cf4 |
- ratio <= 2) {
|
|
 |
c245cf4 |
+ if ( fabs(actred) <= LM_MACHEP &&
|
|
 |
c245cf4 |
+ prered <= LM_MACHEP && ratio <= 2 ){
|
|
 |
c245cf4 |
S->outcome = 6;
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- if (delta <= LM_MACHEP * xnorm) {
|
|
 |
c245cf4 |
+ if ( delta <= LM_MACHEP*xnorm ){
|
|
 |
c245cf4 |
S->outcome = 7;
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- if (gnorm <= LM_MACHEP) {
|
|
 |
c245cf4 |
+ if ( gnorm <= LM_MACHEP ){
|
|
 |
c245cf4 |
S->outcome = 8;
|
|
 |
c245cf4 |
goto terminate;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** End of the inner loop. Repeat if iteration unsuccessful. **/
|
|
 |
c245cf4 |
- ++inner;
|
|
 |
c245cf4 |
- } while (!inner_success);
|
|
 |
c245cf4 |
+/*** [inner] End of the loop. Repeat if iteration unsuccessful. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- }; /*** End of the outer loop. ***/
|
|
 |
c245cf4 |
+ ++inner;
|
|
 |
c245cf4 |
+ } while ( !inner_success );
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+/*** [outer] End of the loop. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ };
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
terminate:
|
|
 |
c245cf4 |
- S->fnorm = lm_enorm(m, fvec);
|
|
 |
c245cf4 |
- if (C->verbosity >= 2)
|
|
 |
c245cf4 |
- printf("lmmin outcome (%i) xnorm %g ftol %g xtol %g\n", S->outcome,
|
|
 |
c245cf4 |
- xnorm, C->ftol, C->xtol);
|
|
 |
c245cf4 |
- if (C->verbosity & 1) {
|
|
 |
c245cf4 |
- fprintf(msgfile, "lmmin final ");
|
|
 |
c245cf4 |
- lm_print_pars(nout, x, msgfile); // S->fnorm,
|
|
 |
c245cf4 |
- fprintf(msgfile, " fnorm = %18.8g\n", S->fnorm);
|
|
 |
c245cf4 |
+ S->fnorm = lm_fnorm(m, fvec, y);
|
|
 |
c245cf4 |
+ if( C->verbosity&1 )
|
|
 |
c245cf4 |
+ fprintf(msgfile, "lmmin terminates with outcome %i\n", S->outcome);
|
|
 |
c245cf4 |
+ if( C->verbosity&2 )
|
|
 |
c245cf4 |
+ lm_print_pars(nout, x, msgfile);
|
|
 |
c245cf4 |
+ if( C->verbosity&8 ) {
|
|
 |
c245cf4 |
+ if (y) {
|
|
 |
c245cf4 |
+ for( i=0; i
|
|
 |
c245cf4 |
+ fprintf(msgfile, " i, f, y-f: %4i %18.8g %18.8g\n",
|
|
 |
c245cf4 |
+ i, fvec[i], y[i]-fvec[i] );
|
|
 |
c245cf4 |
+ } else {
|
|
 |
c245cf4 |
+ for( i=0; i
|
|
 |
c245cf4 |
+ fprintf(msgfile, " i, f, y-f: %4i %18.8g\n", i, fvec[i]);
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- if (S->userbreak) /* user-requested break */
|
|
 |
c245cf4 |
+ if( C->verbosity&2 )
|
|
 |
c245cf4 |
+ fprintf(msgfile, " fnorm=%24.16g xnorm=%24.16g\n", S->fnorm, xnorm);
|
|
 |
c245cf4 |
+ if ( S->userbreak ) /* user-requested break */
|
|
 |
c245cf4 |
S->outcome = 11;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Deallocate the workspace. ***/
|
|
 |
c245cf4 |
+/*** Deallocate the workspace. ***/
|
|
 |
c245cf4 |
free(ws);
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
} /*** lmmin. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
-/* lm_lmpar (determine Levenberg-Marquardt parameter) */
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-static void lm_lmpar(const int n, double* r, const int ldr, const int* Pivot,
|
|
 |
c245cf4 |
- const double* diag, const double* qtb, const double delta,
|
|
 |
c245cf4 |
- double* par, double* x, double* Sdiag, double* aux, double* xdi)
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+/* lm_lmpar (determine Levenberg-Marquardt parameter) */
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+void lm_lmpar(
|
|
 |
c245cf4 |
+ const int n, double *const r, const int ldr, int *const ipvt,
|
|
 |
c245cf4 |
+ double *const diag, double *const qtb, double delta, double *const par,
|
|
 |
c245cf4 |
+ double *const x, double *const sdiag, double *const aux, double *const xdi)
|
|
 |
c245cf4 |
+{
|
|
 |
c245cf4 |
/* Given an m by n matrix A, an n by n nonsingular diagonal matrix D,
|
|
 |
c245cf4 |
* an m-vector b, and a positive number delta, the problem is to
|
|
 |
c245cf4 |
* determine a parameter value par such that if x solves the system
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* A*x = b and sqrt(par)*D*x = 0
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * in the least squares sense, and dxnorm is the Euclidean norm of D*x,
|
|
 |
c245cf4 |
- * then either par=0 and (dxnorm-delta) < 0.1*delta, or par>0 and
|
|
 |
c245cf4 |
- * abs(dxnorm-delta) < 0.1*delta.
|
|
 |
c245cf4 |
+ * in the least squares sense, and dxnorm is the euclidean
|
|
 |
c245cf4 |
+ * norm of D*x, then either par=0 and (dxnorm-delta) < 0.1*delta,
|
|
 |
c245cf4 |
+ * or par>0 and abs(dxnorm-delta) < 0.1*delta.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* Using lm_qrsolv, this subroutine completes the solution of the
|
|
 |
c245cf4 |
- * problem if it is provided with the necessary information from the
|
|
 |
c245cf4 |
- * QR factorization, with column pivoting, of A. That is, if A*P = Q*R,
|
|
 |
c245cf4 |
- * where P is a permutation matrix, Q has orthogonal columns, and R is
|
|
 |
c245cf4 |
- * an upper triangular matrix with diagonal elements of nonincreasing
|
|
 |
c245cf4 |
- * magnitude, then lmpar expects the full upper triangle of R, the
|
|
 |
c245cf4 |
- * permutation matrix P, and the first n components of Q^T*b. On output
|
|
 |
c245cf4 |
- * lmpar also provides an upper triangular matrix S such that
|
|
 |
c245cf4 |
+ * problem if it is provided with the necessary information from
|
|
 |
c245cf4 |
+ * the QR factorization, with column pivoting, of A. That is, if
|
|
 |
c245cf4 |
+ * A*P = Q*R, where P is a permutation matrix, Q has orthogonal
|
|
 |
c245cf4 |
+ * columns, and R is an upper triangular matrix with diagonal
|
|
 |
c245cf4 |
+ * elements of nonincreasing magnitude, then lmpar expects the
|
|
 |
c245cf4 |
+ * full upper triangle of R, the permutation matrix P, and the
|
|
 |
c245cf4 |
+ * first n components of Q^T*b. On output lmpar also provides an
|
|
 |
c245cf4 |
+ * upper triangular matrix S such that
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* P^T*(A^T*A + par*D*D)*P = S^T*S.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* S is employed within lmpar and may be of separate interest.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * Only a few iterations are generally needed for convergence of the
|
|
 |
c245cf4 |
- * algorithm. If, however, the limit of 10 iterations is reached, then
|
|
 |
c245cf4 |
- * the output par will contain the best value obtained so far.
|
|
 |
c245cf4 |
+ * Only a few iterations are generally needed for convergence
|
|
 |
c245cf4 |
+ * of the algorithm. If, however, the limit of 10 iterations
|
|
 |
c245cf4 |
+ * is reached, then the output par will contain the best value
|
|
 |
c245cf4 |
+ * obtained so far.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* Parameters:
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* n is a positive integer INPUT variable set to the order of r.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * r is an n by n array. On INPUT the full upper triangle must contain
|
|
 |
c245cf4 |
- * the full upper triangle of the matrix R. On OUTPUT the full upper
|
|
 |
c245cf4 |
- * triangle is unaltered, and the strict lower triangle contains the
|
|
 |
c245cf4 |
- * strict upper triangle (transposed) of the upper triangular matrix S.
|
|
 |
c245cf4 |
+ * r is an n by n array. On INPUT the full upper triangle
|
|
 |
c245cf4 |
+ * must contain the full upper triangle of the matrix R.
|
|
 |
c245cf4 |
+ * On OUTPUT the full upper triangle is unaltered, and the
|
|
 |
c245cf4 |
+ * strict lower triangle contains the strict upper triangle
|
|
 |
c245cf4 |
+ * (transposed) of the upper triangular matrix S.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * ldr is a positive integer INPUT variable not less than n which
|
|
 |
c245cf4 |
- * specifies the leading dimension of the array R.
|
|
 |
c245cf4 |
+ * ldr is a positive integer INPUT variable not less than n
|
|
 |
c245cf4 |
+ * which specifies the leading dimension of the array R.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * Pivot is an integer INPUT array of length n which defines the
|
|
 |
c245cf4 |
- * permutation matrix P such that A*P = Q*R. Column j of P is column
|
|
 |
c245cf4 |
- * Pivot(j) of the identity matrix.
|
|
 |
c245cf4 |
+ * ipvt is an integer INPUT array of length n which defines the
|
|
 |
c245cf4 |
+ * permutation matrix P such that A*P = Q*R. Column j of P
|
|
 |
c245cf4 |
+ * is column ipvt(j) of the identity matrix.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * diag is an INPUT array of length n which must contain the diagonal
|
|
 |
c245cf4 |
- * elements of the matrix D.
|
|
 |
c245cf4 |
+ * diag is an INPUT array of length n which must contain the
|
|
 |
c245cf4 |
+ * diagonal elements of the matrix D.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* qtb is an INPUT array of length n which must contain the first
|
|
 |
c245cf4 |
* n elements of the vector Q^T*b.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * delta is a positive INPUT variable which specifies an upper bound
|
|
 |
c245cf4 |
- * on the Euclidean norm of D*x.
|
|
 |
c245cf4 |
+ * delta is a positive INPUT variable which specifies an upper
|
|
 |
c245cf4 |
+ * bound on the euclidean norm of D*x.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * par is a nonnegative variable. On INPUT par contains an initial
|
|
 |
c245cf4 |
- * estimate of the Levenberg-Marquardt parameter. On OUTPUT par
|
|
 |
c245cf4 |
- * contains the final estimate.
|
|
 |
c245cf4 |
+ * par is a nonnegative variable. On INPUT par contains an
|
|
 |
c245cf4 |
+ * initial estimate of the Levenberg-Marquardt parameter.
|
|
 |
c245cf4 |
+ * On OUTPUT par contains the final estimate.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * x is an OUTPUT array of length n which contains the least-squares
|
|
 |
c245cf4 |
- * solution of the system A*x = b, sqrt(par)*D*x = 0, for the output par.
|
|
 |
c245cf4 |
+ * x is an OUTPUT array of length n which contains the least
|
|
 |
c245cf4 |
+ * squares solution of the system A*x = b, sqrt(par)*D*x = 0,
|
|
 |
c245cf4 |
+ * for the output par.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * Sdiag is an array of length n needed as workspace; on OUTPUT it
|
|
 |
c245cf4 |
- * contains the diagonal elements of the upper triangular matrix S.
|
|
 |
c245cf4 |
+ * sdiag is an array of length n needed as workspace; on OUTPUT
|
|
 |
c245cf4 |
+ * it contains the diagonal elements of the upper triangular
|
|
 |
c245cf4 |
+ * matrix S.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* aux is a multi-purpose work array of length n.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* xdi is a work array of length n. On OUTPUT: diag[j] * x[j].
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
*/
|
|
 |
c245cf4 |
-{
|
|
 |
c245cf4 |
int i, iter, j, nsing;
|
|
 |
c245cf4 |
double dxnorm, fp, fp_old, gnorm, parc, parl, paru;
|
|
 |
c245cf4 |
double sum, temp;
|
|
 |
c245cf4 |
static double p1 = 0.1;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Compute and store in x the Gauss-Newton direction. If the Jacobian
|
|
 |
c245cf4 |
- is rank-deficient, obtain a least-squares solution. ***/
|
|
 |
c245cf4 |
+/*** lmpar: compute and store in x the gauss-newton direction. if the
|
|
 |
c245cf4 |
+ jacobian is rank-deficient, obtain a least squares solution. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
nsing = n;
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
aux[j] = qtb[j];
|
|
 |
c245cf4 |
- if (r[j*ldr+j] == 0 && nsing == n)
|
|
 |
c245cf4 |
+ if (r[j * ldr + j] == 0 && nsing == n)
|
|
 |
c245cf4 |
nsing = j;
|
|
 |
c245cf4 |
if (nsing < n)
|
|
 |
c245cf4 |
aux[j] = 0;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- for (j = nsing-1; j >= 0; j--) {
|
|
 |
c245cf4 |
- aux[j] = aux[j] / r[j+ldr*j];
|
|
 |
c245cf4 |
+ for (j = nsing - 1; j >= 0; j--) {
|
|
 |
c245cf4 |
+ aux[j] = aux[j] / r[j + ldr * j];
|
|
 |
c245cf4 |
temp = aux[j];
|
|
 |
c245cf4 |
for (i = 0; i < j; i++)
|
|
 |
c245cf4 |
- aux[i] -= r[j*ldr+i] * temp;
|
|
 |
c245cf4 |
+ aux[i] -= r[j * ldr + i] * temp;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
- x[Pivot[j]] = aux[j];
|
|
 |
c245cf4 |
+ x[ipvt[j]] = aux[j];
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Initialize the iteration counter, evaluate the function at the origin,
|
|
 |
c245cf4 |
- and test for acceptance of the Gauss-Newton direction. ***/
|
|
 |
c245cf4 |
+/*** lmpar: initialize the iteration counter, evaluate the function at the
|
|
 |
c245cf4 |
+ origin, and test for acceptance of the gauss-newton direction. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
xdi[j] = diag[j] * x[j];
|
|
 |
c245cf4 |
@@ -645,65 +712,67 @@
|
|
 |
c245cf4 |
fp = dxnorm - delta;
|
|
 |
c245cf4 |
if (fp <= p1 * delta) {
|
|
 |
c245cf4 |
#ifdef LMFIT_DEBUG_MESSAGES
|
|
 |
c245cf4 |
- printf("debug lmpar nsing=%d, n=%d, terminate[fp<=p1*del]\n", nsing, n);
|
|
 |
c245cf4 |
+ printf("debug lmpar nsing %d n %d, terminate (fp
|
|
 |
c245cf4 |
+ nsing, n);
|
|
 |
c245cf4 |
#endif
|
|
 |
c245cf4 |
*par = 0;
|
|
 |
c245cf4 |
return;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** If the Jacobian is not rank deficient, the Newton step provides a
|
|
 |
c245cf4 |
- lower bound, parl, for the zero of the function. Otherwise set this
|
|
 |
c245cf4 |
- bound to zero. ***/
|
|
 |
c245cf4 |
+/*** lmpar: if the jacobian is not rank deficient, the newton
|
|
 |
c245cf4 |
+ step provides a lower bound, parl, for the zero of
|
|
 |
c245cf4 |
+ the function. otherwise set this bound to zero. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
parl = 0;
|
|
 |
c245cf4 |
if (nsing >= n) {
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
- aux[j] = diag[Pivot[j]] * xdi[Pivot[j]] / dxnorm;
|
|
 |
c245cf4 |
+ aux[j] = diag[ipvt[j]] * xdi[ipvt[j]] / dxnorm;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
sum = 0;
|
|
 |
c245cf4 |
for (i = 0; i < j; i++)
|
|
 |
c245cf4 |
- sum += r[j*ldr+i] * aux[i];
|
|
 |
c245cf4 |
- aux[j] = (aux[j] - sum) / r[j+ldr*j];
|
|
 |
c245cf4 |
+ sum += r[j * ldr + i] * aux[i];
|
|
 |
c245cf4 |
+ aux[j] = (aux[j] - sum) / r[j + ldr * j];
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
temp = lm_enorm(n, aux);
|
|
 |
c245cf4 |
parl = fp / delta / temp / temp;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Calculate an upper bound, paru, for the zero of the function. ***/
|
|
 |
c245cf4 |
+/*** lmpar: calculate an upper bound, paru, for the zero of the function. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
sum = 0;
|
|
 |
c245cf4 |
for (i = 0; i <= j; i++)
|
|
 |
c245cf4 |
- sum += r[j*ldr+i] * qtb[i];
|
|
 |
c245cf4 |
- aux[j] = sum / diag[Pivot[j]];
|
|
 |
c245cf4 |
+ sum += r[j * ldr + i] * qtb[i];
|
|
 |
c245cf4 |
+ aux[j] = sum / diag[ipvt[j]];
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
gnorm = lm_enorm(n, aux);
|
|
 |
c245cf4 |
paru = gnorm / delta;
|
|
 |
c245cf4 |
if (paru == 0)
|
|
 |
c245cf4 |
paru = LM_DWARF / MIN(delta, p1);
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** If the input par lies outside of the interval (parl,paru),
|
|
 |
c245cf4 |
- set par to the closer endpoint. ***/
|
|
 |
c245cf4 |
+/*** lmpar: if the input par lies outside of the interval (parl,paru),
|
|
 |
c245cf4 |
+ set par to the closer endpoint. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
*par = MAX(*par, parl);
|
|
 |
c245cf4 |
*par = MIN(*par, paru);
|
|
 |
c245cf4 |
if (*par == 0)
|
|
 |
c245cf4 |
*par = gnorm / dxnorm;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Iterate. ***/
|
|
 |
c245cf4 |
+/*** lmpar: iterate. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- for (iter = 0;; iter++) {
|
|
 |
c245cf4 |
+ for (iter=0; ; iter++) {
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Evaluate the function at the current value of par. **/
|
|
 |
c245cf4 |
+ /** evaluate the function at the current value of par. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
if (*par == 0)
|
|
 |
c245cf4 |
*par = MAX(LM_DWARF, 0.001 * paru);
|
|
 |
c245cf4 |
temp = sqrt(*par);
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
aux[j] = temp * diag[j];
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- lm_qrsolv(n, r, ldr, Pivot, aux, qtb, x, Sdiag, xdi);
|
|
 |
c245cf4 |
- /* return values are r, x, Sdiag */
|
|
 |
c245cf4 |
+ lm_qrsolv(n, r, ldr, ipvt, aux, qtb, x, sdiag, xdi);
|
|
 |
c245cf4 |
+ /* return values are r, x, sdiag */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
xdi[j] = diag[j] * x[j]; /* used as output */
|
|
 |
c245cf4 |
@@ -711,49 +780,58 @@
|
|
 |
c245cf4 |
fp_old = fp;
|
|
 |
c245cf4 |
fp = dxnorm - delta;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** If the function is small enough, accept the current value
|
|
 |
c245cf4 |
+ /** if the function is small enough, accept the current value
|
|
 |
c245cf4 |
of par. Also test for the exceptional cases where parl
|
|
 |
c245cf4 |
is zero or the number of iterations has reached 10. **/
|
|
 |
c245cf4 |
- if (fabs(fp) <= p1 * delta ||
|
|
 |
c245cf4 |
- (parl == 0 && fp <= fp_old && fp_old < 0) || iter == 10) {
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ if (fabs(fp) <= p1 * delta
|
|
 |
c245cf4 |
+ || (parl == 0 && fp <= fp_old && fp_old < 0)
|
|
 |
c245cf4 |
+ || iter == 10) {
|
|
 |
c245cf4 |
#ifdef LMFIT_DEBUG_MESSAGES
|
|
 |
c245cf4 |
- printf("debug lmpar nsing=%d, iter=%d, "
|
|
 |
c245cf4 |
- "par=%.4e [%.4e %.4e], delta=%.4e, fp=%.4e\n",
|
|
 |
c245cf4 |
+ printf("debug lmpar nsing %d iter %d "
|
|
 |
c245cf4 |
+ "par %.4e [%.4e %.4e] delta %.4e fp %.4e\n",
|
|
 |
c245cf4 |
nsing, iter, *par, parl, paru, delta, fp);
|
|
 |
c245cf4 |
#endif
|
|
 |
c245cf4 |
break; /* the only exit from the iteration. */
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Compute the Newton correction. **/
|
|
 |
c245cf4 |
+ /** compute the Newton correction. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
- aux[j] = diag[Pivot[j]] * xdi[Pivot[j]] / dxnorm;
|
|
 |
c245cf4 |
+ aux[j] = diag[ipvt[j]] * xdi[ipvt[j]] / dxnorm;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
- aux[j] = aux[j] / Sdiag[j];
|
|
 |
c245cf4 |
- for (i = j+1; i < n; i++)
|
|
 |
c245cf4 |
- aux[i] -= r[j*ldr+i] * aux[j];
|
|
 |
c245cf4 |
+ aux[j] = aux[j] / sdiag[j];
|
|
 |
c245cf4 |
+ for (i = j + 1; i < n; i++)
|
|
 |
c245cf4 |
+ aux[i] -= r[j * ldr + i] * aux[j];
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
temp = lm_enorm(n, aux);
|
|
 |
c245cf4 |
parc = fp / delta / temp / temp;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Depending on the sign of the function, update parl or paru. **/
|
|
 |
c245cf4 |
+ /** depending on the sign of the function, update parl or paru. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
if (fp > 0)
|
|
 |
c245cf4 |
parl = MAX(parl, *par);
|
|
 |
c245cf4 |
- else /* fp < 0 [the case fp==0 is precluded by the break condition] */
|
|
 |
c245cf4 |
+ else if (fp < 0)
|
|
 |
c245cf4 |
paru = MIN(paru, *par);
|
|
 |
c245cf4 |
+ /* the case fp==0 is precluded by the break condition */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Compute an improved estimate for par. **/
|
|
 |
c245cf4 |
+ /** compute an improved estimate for par. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
*par = MAX(parl, *par + parc);
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
} /*** lm_lmpar. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
-/* lm_qrfac (QR factorization, from lapack) */
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+/* lm_qrfac (QR factorization, from lapack) */
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-static void lm_qrfac(const int m, const int n, double* A, int* Pivot, double* Rdiag,
|
|
 |
c245cf4 |
- double* Acnorm, double* W)
|
|
 |
c245cf4 |
+void lm_qrfac(
|
|
 |
c245cf4 |
+ const int m, const int n, double *const A, int *const Pivot,
|
|
 |
c245cf4 |
+ double *const Rdiag, double *const Acnorm, double *const W)
|
|
 |
c245cf4 |
+{
|
|
 |
c245cf4 |
/*
|
|
 |
c245cf4 |
* This subroutine uses Householder transformations with column pivoting
|
|
 |
c245cf4 |
* to compute a QR factorization of the m by n matrix A. That is, qrfac
|
|
 |
c245cf4 |
@@ -772,27 +850,27 @@
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* n is an INPUT parameter set to the number of columns of A.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * A is an m by n array. On INPUT, A contains the matrix for which the
|
|
 |
c245cf4 |
- * QR factorization is to be computed. On OUTPUT the strict upper
|
|
 |
c245cf4 |
- * trapezoidal part of A contains the strict upper trapezoidal part
|
|
 |
c245cf4 |
- * of R, and the lower trapezoidal part of A contains a factored form
|
|
 |
c245cf4 |
- * of Q (the non-trivial elements of the vectors w described above).
|
|
 |
c245cf4 |
+ * A is an m by n array. On INPUT, A contains the matrix for
|
|
 |
c245cf4 |
+ * which the QR factorization is to be computed. On OUTPUT
|
|
 |
c245cf4 |
+ * the strict upper trapezoidal part of A contains the strict
|
|
 |
c245cf4 |
+ * upper trapezoidal part of R, and the lower trapezoidal
|
|
 |
c245cf4 |
+ * part of A contains a factored form of Q (the non-trivial
|
|
 |
c245cf4 |
+ * elements of the vectors w described above).
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* Pivot is an integer OUTPUT array of length n that describes the
|
|
 |
c245cf4 |
- * permutation matrix P. Column j of P is column Pivot(j) of the
|
|
 |
c245cf4 |
- * identity matrix.
|
|
 |
c245cf4 |
+ * permutation matrix P:
|
|
 |
c245cf4 |
+ * Column j of P is column ipvt(j) of the identity matrix.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * Rdiag is an OUTPUT array of length n which contains the diagonal
|
|
 |
c245cf4 |
- * elements of R.
|
|
 |
c245cf4 |
+ * Rdiag is an OUTPUT array of length n which contains the
|
|
 |
c245cf4 |
+ * diagonal elements of R.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * Acnorm is an OUTPUT array of length n which contains the norms of
|
|
 |
c245cf4 |
- * the corresponding columns of the input matrix A. If this information
|
|
 |
c245cf4 |
- * is not needed, then Acnorm can share storage with Rdiag.
|
|
 |
c245cf4 |
+ * Acnorm is an OUTPUT array of length n which contains the norms
|
|
 |
c245cf4 |
+ * of the corresponding columns of the input matrix A. If this
|
|
 |
c245cf4 |
+ * information is not needed, then Acnorm can share storage with Rdiag.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* W is a work array of length n.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
*/
|
|
 |
c245cf4 |
-{
|
|
 |
c245cf4 |
int i, j, k, kmax;
|
|
 |
c245cf4 |
double ajnorm, sum, temp;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
@@ -802,16 +880,19 @@
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
/** Compute initial column norms;
|
|
 |
c245cf4 |
initialize Pivot with identity permutation. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
W[j] = Rdiag[j] = Acnorm[j] = lm_enorm(m, &A[j*m]);
|
|
 |
c245cf4 |
Pivot[j] = j;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
/** Loop over columns of A. **/
|
|
 |
c245cf4 |
- assert(n <= m);
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ assert( n <= m );
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
/** Bring the column of largest norm into the pivot position. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
kmax = j;
|
|
 |
c245cf4 |
for (k = j+1; k < n; k++)
|
|
 |
c245cf4 |
if (Rdiag[k] > Rdiag[kmax])
|
|
 |
c245cf4 |
@@ -834,6 +915,7 @@
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
/** Compute the Householder reflection vector w_j to reduce the
|
|
 |
c245cf4 |
j-th column of A to a multiple of the j-th unit vector. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
ajnorm = lm_enorm(m-j, &A[j*m+j]);
|
|
 |
c245cf4 |
if (ajnorm == 0) {
|
|
 |
c245cf4 |
Rdiag[j] = 0;
|
|
 |
c245cf4 |
@@ -850,6 +932,7 @@
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
/** Apply the Householder transformation U_w := 1 - 2*w_j.w_j/|w_j|^2
|
|
 |
c245cf4 |
to the remaining columns, and update the norms. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
for (k = j+1; k < n; k++) {
|
|
 |
c245cf4 |
/* Compute scalar product w_j * a_j. */
|
|
 |
c245cf4 |
sum = 0;
|
|
 |
c245cf4 |
@@ -866,12 +949,12 @@
|
|
 |
c245cf4 |
/* No idea what happens here. */
|
|
 |
c245cf4 |
if (Rdiag[k] != 0) {
|
|
 |
c245cf4 |
temp = A[m*k+j] / Rdiag[k];
|
|
 |
c245cf4 |
- if (fabs(temp) < 1) {
|
|
 |
c245cf4 |
- Rdiag[k] *= sqrt(1 - SQR(temp));
|
|
 |
c245cf4 |
+ if ( fabs(temp)<1 ) {
|
|
 |
c245cf4 |
+ Rdiag[k] *= sqrt(1-SQR(temp));
|
|
 |
c245cf4 |
temp = Rdiag[k] / W[k];
|
|
 |
c245cf4 |
} else
|
|
 |
c245cf4 |
temp = 0;
|
|
 |
c245cf4 |
- if (temp == 0 || 0.05 * SQR(temp) <= LM_MACHEP) {
|
|
 |
c245cf4 |
+ if ( temp == 0 || 0.05 * SQR(temp) <= LM_MACHEP ) {
|
|
 |
c245cf4 |
Rdiag[k] = lm_enorm(m-j-1, &A[m*k+j+1]);
|
|
 |
c245cf4 |
W[k] = Rdiag[k];
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
@@ -882,13 +965,16 @@
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
} /*** lm_qrfac. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
-/* lm_qrsolv (linear least-squares) */
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-static void lm_qrsolv(const int n, double* r, const int ldr, const int* Pivot,
|
|
 |
c245cf4 |
- const double* diag, const double* qtb, double* x,
|
|
 |
c245cf4 |
- double* Sdiag, double* W)
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+/* lm_qrsolv (linear least-squares) */
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+void lm_qrsolv(
|
|
 |
c245cf4 |
+ const int n, double *const r, const int ldr, int *const ipvt,
|
|
 |
c245cf4 |
+ double *const diag, double *const qtb, double *const x,
|
|
 |
c245cf4 |
+ double *const sdiag, double *const wa)
|
|
 |
c245cf4 |
+{
|
|
 |
c245cf4 |
/*
|
|
 |
c245cf4 |
* Given an m by n matrix A, an n by n diagonal matrix D, and an
|
|
 |
c245cf4 |
* m-vector b, the problem is to determine an x which solves the
|
|
 |
c245cf4 |
@@ -921,145 +1007,152 @@
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* n is a positive integer INPUT variable set to the order of R.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * r is an n by n array. On INPUT the full upper triangle must contain
|
|
 |
c245cf4 |
- * the full upper triangle of the matrix R. On OUTPUT the full upper
|
|
 |
c245cf4 |
- * triangle is unaltered, and the strict lower triangle contains the
|
|
 |
c245cf4 |
- * strict upper triangle (transposed) of the upper triangular matrix S.
|
|
 |
c245cf4 |
+ * r is an n by n array. On INPUT the full upper triangle must
|
|
 |
c245cf4 |
+ * contain the full upper triangle of the matrix R. On OUTPUT
|
|
 |
c245cf4 |
+ * the full upper triangle is unaltered, and the strict lower
|
|
 |
c245cf4 |
+ * triangle contains the strict upper triangle (transposed) of
|
|
 |
c245cf4 |
+ * the upper triangular matrix S.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * ldr is a positive integer INPUT variable not less than n which
|
|
 |
c245cf4 |
- * specifies the leading dimension of the array R.
|
|
 |
c245cf4 |
+ * ldr is a positive integer INPUT variable not less than n
|
|
 |
c245cf4 |
+ * which specifies the leading dimension of the array R.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * Pivot is an integer INPUT array of length n which defines the
|
|
 |
c245cf4 |
- * permutation matrix P such that A*P = Q*R. Column j of P is column
|
|
 |
c245cf4 |
- * Pivot(j) of the identity matrix.
|
|
 |
c245cf4 |
+ * ipvt is an integer INPUT array of length n which defines the
|
|
 |
c245cf4 |
+ * permutation matrix P such that A*P = Q*R. Column j of P
|
|
 |
c245cf4 |
+ * is column ipvt(j) of the identity matrix.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * diag is an INPUT array of length n which must contain the diagonal
|
|
 |
c245cf4 |
- * elements of the matrix D.
|
|
 |
c245cf4 |
+ * diag is an INPUT array of length n which must contain the
|
|
 |
c245cf4 |
+ * diagonal elements of the matrix D.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* qtb is an INPUT array of length n which must contain the first
|
|
 |
c245cf4 |
* n elements of the vector Q^T*b.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * x is an OUTPUT array of length n which contains the least-squares
|
|
 |
c245cf4 |
- * solution of the system A*x = b, D*x = 0.
|
|
 |
c245cf4 |
+ * x is an OUTPUT array of length n which contains the least
|
|
 |
c245cf4 |
+ * squares solution of the system A*x = b, D*x = 0.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * Sdiag is an OUTPUT array of length n which contains the diagonal
|
|
 |
c245cf4 |
- * elements of the upper triangular matrix S.
|
|
 |
c245cf4 |
+ * sdiag is an OUTPUT array of length n which contains the
|
|
 |
c245cf4 |
+ * diagonal elements of the upper triangular matrix S.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * W is a work array of length n.
|
|
 |
c245cf4 |
+ * wa is a work array of length n.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
*/
|
|
 |
c245cf4 |
-{
|
|
 |
c245cf4 |
int i, kk, j, k, nsing;
|
|
 |
c245cf4 |
double qtbpj, sum, temp;
|
|
 |
c245cf4 |
double _sin, _cos, _tan, _cot; /* local variables, not functions */
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Copy R and Q^T*b to preserve input and initialize S.
|
|
 |
c245cf4 |
- In particular, save the diagonal elements of R in x. ***/
|
|
 |
c245cf4 |
+/*** qrsolv: copy R and Q^T*b to preserve input and initialize S.
|
|
 |
c245cf4 |
+ In particular, save the diagonal elements of R in x. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
for (i = j; i < n; i++)
|
|
 |
c245cf4 |
- r[j*ldr+i] = r[i*ldr+j];
|
|
 |
c245cf4 |
- x[j] = r[j*ldr+j];
|
|
 |
c245cf4 |
- W[j] = qtb[j];
|
|
 |
c245cf4 |
+ r[j * ldr + i] = r[i * ldr + j];
|
|
 |
c245cf4 |
+ x[j] = r[j * ldr + j];
|
|
 |
c245cf4 |
+ wa[j] = qtb[j];
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Eliminate the diagonal matrix D using a Givens rotation. ***/
|
|
 |
c245cf4 |
+/*** qrsolv: eliminate the diagonal matrix D using a Givens rotation. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Prepare the row of D to be eliminated, locating the diagonal
|
|
 |
c245cf4 |
- element using P from the QR factorization. ***/
|
|
 |
c245cf4 |
+/*** qrsolv: prepare the row of D to be eliminated, locating the
|
|
 |
c245cf4 |
+ diagonal element using P from the QR factorization. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- if (diag[Pivot[j]] != 0) {
|
|
 |
c245cf4 |
- for (k = j; k < n; k++)
|
|
 |
c245cf4 |
- Sdiag[k] = 0;
|
|
 |
c245cf4 |
- Sdiag[j] = diag[Pivot[j]];
|
|
 |
c245cf4 |
+ if (diag[ipvt[j]] == 0)
|
|
 |
c245cf4 |
+ goto L90;
|
|
 |
c245cf4 |
+ for (k = j; k < n; k++)
|
|
 |
c245cf4 |
+ sdiag[k] = 0;
|
|
 |
c245cf4 |
+ sdiag[j] = diag[ipvt[j]];
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** The transformations to eliminate the row of D modify only
|
|
 |
c245cf4 |
- a single element of Q^T*b beyond the first n, which is
|
|
 |
c245cf4 |
- initially 0. ***/
|
|
 |
c245cf4 |
+/*** qrsolv: the transformations to eliminate the row of D modify only
|
|
 |
c245cf4 |
+ a single element of Q^T*b beyond the first n, which is initially 0. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- qtbpj = 0;
|
|
 |
c245cf4 |
- for (k = j; k < n; k++) {
|
|
 |
c245cf4 |
+ qtbpj = 0;
|
|
 |
c245cf4 |
+ for (k = j; k < n; k++) {
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Determine a Givens rotation which eliminates the
|
|
 |
c245cf4 |
- appropriate element in the current row of D. **/
|
|
 |
c245cf4 |
- if (Sdiag[k] == 0)
|
|
 |
c245cf4 |
- continue;
|
|
 |
c245cf4 |
- kk = k + ldr * k;
|
|
 |
c245cf4 |
- if (fabs(r[kk]) < fabs(Sdiag[k])) {
|
|
 |
c245cf4 |
- _cot = r[kk] / Sdiag[k];
|
|
 |
c245cf4 |
- _sin = 1 / hypot(1, _cot);
|
|
 |
c245cf4 |
- _cos = _sin * _cot;
|
|
 |
c245cf4 |
- } else {
|
|
 |
c245cf4 |
- _tan = Sdiag[k] / r[kk];
|
|
 |
c245cf4 |
- _cos = 1 / hypot(1, _tan);
|
|
 |
c245cf4 |
- _sin = _cos * _tan;
|
|
 |
c245cf4 |
- }
|
|
 |
c245cf4 |
+ /** determine a Givens rotation which eliminates the
|
|
 |
c245cf4 |
+ appropriate element in the current row of D. **/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Compute the modified diagonal element of R and
|
|
 |
c245cf4 |
- the modified element of (Q^T*b,0). **/
|
|
 |
c245cf4 |
- r[kk] = _cos * r[kk] + _sin * Sdiag[k];
|
|
 |
c245cf4 |
- temp = _cos * W[k] + _sin * qtbpj;
|
|
 |
c245cf4 |
- qtbpj = -_sin * W[k] + _cos * qtbpj;
|
|
 |
c245cf4 |
- W[k] = temp;
|
|
 |
c245cf4 |
+ if (sdiag[k] == 0)
|
|
 |
c245cf4 |
+ continue;
|
|
 |
c245cf4 |
+ kk = k + ldr * k;
|
|
 |
c245cf4 |
+ if (fabs(r[kk]) < fabs(sdiag[k])) {
|
|
 |
c245cf4 |
+ _cot = r[kk] / sdiag[k];
|
|
 |
c245cf4 |
+ _sin = 1 / sqrt(1 + SQR(_cot));
|
|
 |
c245cf4 |
+ _cos = _sin * _cot;
|
|
 |
c245cf4 |
+ } else {
|
|
 |
c245cf4 |
+ _tan = sdiag[k] / r[kk];
|
|
 |
c245cf4 |
+ _cos = 1 / sqrt(1 + SQR(_tan));
|
|
 |
c245cf4 |
+ _sin = _cos * _tan;
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Accumulate the tranformation in the row of S. **/
|
|
 |
c245cf4 |
- for (i = k+1; i < n; i++) {
|
|
 |
c245cf4 |
- temp = _cos * r[k*ldr+i] + _sin * Sdiag[i];
|
|
 |
c245cf4 |
- Sdiag[i] = -_sin * r[k*ldr+i] + _cos * Sdiag[i];
|
|
 |
c245cf4 |
- r[k*ldr+i] = temp;
|
|
 |
c245cf4 |
- }
|
|
 |
c245cf4 |
+ /** compute the modified diagonal element of R and
|
|
 |
c245cf4 |
+ the modified element of (Q^T*b,0). **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ r[kk] = _cos * r[kk] + _sin * sdiag[k];
|
|
 |
c245cf4 |
+ temp = _cos * wa[k] + _sin * qtbpj;
|
|
 |
c245cf4 |
+ qtbpj = -_sin * wa[k] + _cos * qtbpj;
|
|
 |
c245cf4 |
+ wa[k] = temp;
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ /** accumulate the tranformation in the row of S. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ for (i = k + 1; i < n; i++) {
|
|
 |
c245cf4 |
+ temp = _cos * r[k * ldr + i] + _sin * sdiag[i];
|
|
 |
c245cf4 |
+ sdiag[i] = -_sin * r[k * ldr + i] + _cos * sdiag[i];
|
|
 |
c245cf4 |
+ r[k * ldr + i] = temp;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Store the diagonal element of S and restore
|
|
 |
c245cf4 |
+ L90:
|
|
 |
c245cf4 |
+ /** store the diagonal element of S and restore
|
|
 |
c245cf4 |
the corresponding diagonal element of R. **/
|
|
 |
c245cf4 |
- Sdiag[j] = r[j*ldr+j];
|
|
 |
c245cf4 |
- r[j*ldr+j] = x[j];
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ sdiag[j] = r[j * ldr + j];
|
|
 |
c245cf4 |
+ r[j * ldr + j] = x[j];
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Solve the triangular system for z. If the system is singular, then
|
|
 |
c245cf4 |
- obtain a least-squares solution. ***/
|
|
 |
c245cf4 |
+/*** qrsolv: solve the triangular system for z. If the system is
|
|
 |
c245cf4 |
+ singular, then obtain a least squares solution. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
nsing = n;
|
|
 |
c245cf4 |
for (j = 0; j < n; j++) {
|
|
 |
c245cf4 |
- if (Sdiag[j] == 0 && nsing == n)
|
|
 |
c245cf4 |
+ if (sdiag[j] == 0 && nsing == n)
|
|
 |
c245cf4 |
nsing = j;
|
|
 |
c245cf4 |
if (nsing < n)
|
|
 |
c245cf4 |
- W[j] = 0;
|
|
 |
c245cf4 |
+ wa[j] = 0;
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- for (j = nsing-1; j >= 0; j--) {
|
|
 |
c245cf4 |
+ for (j = nsing - 1; j >= 0; j--) {
|
|
 |
c245cf4 |
sum = 0;
|
|
 |
c245cf4 |
- for (i = j+1; i < nsing; i++)
|
|
 |
c245cf4 |
- sum += r[j*ldr+i] * W[i];
|
|
 |
c245cf4 |
- W[j] = (W[j] - sum) / Sdiag[j];
|
|
 |
c245cf4 |
+ for (i = j + 1; i < nsing; i++)
|
|
 |
c245cf4 |
+ sum += r[j * ldr + i] * wa[i];
|
|
 |
c245cf4 |
+ wa[j] = (wa[j] - sum) / sdiag[j];
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /*** Permute the components of z back to components of x. ***/
|
|
 |
c245cf4 |
+/*** qrsolv: permute the components of z back to components of x. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
for (j = 0; j < n; j++)
|
|
 |
c245cf4 |
- x[Pivot[j]] = W[j];
|
|
 |
c245cf4 |
+ x[ipvt[j]] = wa[j];
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
} /*** lm_qrsolv. ***/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
-/* lm_enorm (Euclidean norm) */
|
|
 |
c245cf4 |
-/******************************************************************************/
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-static double lm_enorm(int n, const double* x)
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+/* lm_enorm (Euclidean norm) */
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+double lm_enorm(const int n, const double *const x)
|
|
 |
c245cf4 |
+{
|
|
 |
c245cf4 |
/* This function calculates the Euclidean norm of an n-vector x.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * The Euclidean norm is computed by accumulating the sum of squares
|
|
 |
c245cf4 |
- * in three different sums. The sums of squares for the small and large
|
|
 |
c245cf4 |
- * components are scaled so that no overflows occur. Non-destructive
|
|
 |
c245cf4 |
- * underflows are permitted. Underflows and overflows do not occur in
|
|
 |
c245cf4 |
- * the computation of the unscaled sum of squares for the intermediate
|
|
 |
c245cf4 |
- * components. The definitions of small, intermediate and large components
|
|
 |
c245cf4 |
+ * The Euclidean norm is computed by accumulating the sum of
|
|
 |
c245cf4 |
+ * squares in three different sums. The sums of squares for the
|
|
 |
c245cf4 |
+ * small and large components are scaled so that no overflows
|
|
 |
c245cf4 |
+ * occur. Non-destructive underflows are permitted. Underflows
|
|
 |
c245cf4 |
+ * and overflows do not occur in the computation of the unscaled
|
|
 |
c245cf4 |
+ * sum of squares for the intermediate components.
|
|
 |
c245cf4 |
+ * The definitions of small, intermediate and large components
|
|
 |
c245cf4 |
* depend on two constants, LM_SQRT_DWARF and LM_SQRT_GIANT. The main
|
|
 |
c245cf4 |
- * restrictions on these constants are that LM_SQRT_DWARF**2 not underflow
|
|
 |
c245cf4 |
- * and LM_SQRT_GIANT**2 not overflow.
|
|
 |
c245cf4 |
+ * restrictions on these constants are that LM_SQRT_DWARF**2 not
|
|
 |
c245cf4 |
+ * underflow and LM_SQRT_GIANT**2 not overflow.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* Parameters:
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
@@ -1067,9 +1160,8 @@
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* x is an INPUT array of length n.
|
|
 |
c245cf4 |
*/
|
|
 |
c245cf4 |
-{
|
|
 |
c245cf4 |
int i;
|
|
 |
c245cf4 |
- double agiant, s1, s2, s3, xabs, x1max, x3max;
|
|
 |
c245cf4 |
+ double agiant, s1, s2, s3, xabs, x1max, x3max, temp;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
s1 = 0;
|
|
 |
c245cf4 |
s2 = 0;
|
|
 |
c245cf4 |
@@ -1078,27 +1170,33 @@
|
|
 |
c245cf4 |
x3max = 0;
|
|
 |
c245cf4 |
agiant = LM_SQRT_GIANT / n;
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Sum squares. **/
|
|
 |
c245cf4 |
+ /** sum squares. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
for (i = 0; i < n; i++) {
|
|
 |
c245cf4 |
xabs = fabs(x[i]);
|
|
 |
c245cf4 |
if (xabs > LM_SQRT_DWARF) {
|
|
 |
c245cf4 |
- if (xabs < agiant) {
|
|
 |
c245cf4 |
- s2 += SQR(xabs);
|
|
 |
c245cf4 |
- } else if (xabs > x1max) {
|
|
 |
c245cf4 |
- s1 = 1 + s1 * SQR(x1max / xabs);
|
|
 |
c245cf4 |
+ if ( xabs < agiant ) {
|
|
 |
c245cf4 |
+ s2 += xabs * xabs;
|
|
 |
c245cf4 |
+ } else if ( xabs > x1max ) {
|
|
 |
c245cf4 |
+ temp = x1max / xabs;
|
|
 |
c245cf4 |
+ s1 = 1 + s1 * SQR(temp);
|
|
 |
c245cf4 |
x1max = xabs;
|
|
 |
c245cf4 |
} else {
|
|
 |
c245cf4 |
- s1 += SQR(xabs / x1max);
|
|
 |
c245cf4 |
+ temp = xabs / x1max;
|
|
 |
c245cf4 |
+ s1 += SQR(temp);
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
- } else if (xabs > x3max) {
|
|
 |
c245cf4 |
- s3 = 1 + s3 * SQR(x3max / xabs);
|
|
 |
c245cf4 |
+ } else if ( xabs > x3max ) {
|
|
 |
c245cf4 |
+ temp = x3max / xabs;
|
|
 |
c245cf4 |
+ s3 = 1 + s3 * SQR(temp);
|
|
 |
c245cf4 |
x3max = xabs;
|
|
 |
c245cf4 |
} else if (xabs != 0) {
|
|
 |
c245cf4 |
- s3 += SQR(xabs / x3max);
|
|
 |
c245cf4 |
+ temp = xabs / x3max;
|
|
 |
c245cf4 |
+ s3 += SQR(temp);
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
}
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
- /** Calculate the norm. **/
|
|
 |
c245cf4 |
+ /** calculation of norm. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
if (s1 != 0)
|
|
 |
c245cf4 |
return x1max * sqrt(s1 + (s2 / x1max) / x1max);
|
|
 |
c245cf4 |
else if (s2 != 0)
|
|
 |
c245cf4 |
@@ -1110,3 +1208,80 @@
|
|
 |
c245cf4 |
return x3max * sqrt(s3);
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
} /*** lm_enorm. ***/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+/* lm_fnorm (Euclidean norm of difference) */
|
|
 |
c245cf4 |
+/*****************************************************************************/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+double lm_fnorm(const int n, const double *const x, const double *const y)
|
|
 |
c245cf4 |
+{
|
|
 |
c245cf4 |
+/* This function calculates the Euclidean norm of an n-vector x-y.
|
|
 |
c245cf4 |
+ *
|
|
 |
c245cf4 |
+ * The Euclidean norm is computed by accumulating the sum of
|
|
 |
c245cf4 |
+ * squares in three different sums. The sums of squares for the
|
|
 |
c245cf4 |
+ * small and large components are scaled so that no overflows
|
|
 |
c245cf4 |
+ * occur. Non-destructive underflows are permitted. Underflows
|
|
 |
c245cf4 |
+ * and overflows do not occur in the computation of the unscaled
|
|
 |
c245cf4 |
+ * sum of squares for the intermediate components.
|
|
 |
c245cf4 |
+ * The definitions of small, intermediate and large components
|
|
 |
c245cf4 |
+ * depend on two constants, LM_SQRT_DWARF and LM_SQRT_GIANT. The main
|
|
 |
c245cf4 |
+ * restrictions on these constants are that LM_SQRT_DWARF**2 not
|
|
 |
c245cf4 |
+ * underflow and LM_SQRT_GIANT**2 not overflow.
|
|
 |
c245cf4 |
+ *
|
|
 |
c245cf4 |
+ * Parameters:
|
|
 |
c245cf4 |
+ *
|
|
 |
c245cf4 |
+ * n is a positive integer INPUT variable.
|
|
 |
c245cf4 |
+ *
|
|
 |
c245cf4 |
+ * x, y are INPUT arrays of length n.
|
|
 |
c245cf4 |
+ */
|
|
 |
c245cf4 |
+ if (!y)
|
|
 |
c245cf4 |
+ return lm_enorm(n, x);
|
|
 |
c245cf4 |
+ int i;
|
|
 |
c245cf4 |
+ double agiant, s1, s2, s3, xabs, x1max, x3max, temp;
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ s1 = 0;
|
|
 |
c245cf4 |
+ s2 = 0;
|
|
 |
c245cf4 |
+ s3 = 0;
|
|
 |
c245cf4 |
+ x1max = 0;
|
|
 |
c245cf4 |
+ x3max = 0;
|
|
 |
c245cf4 |
+ agiant = LM_SQRT_GIANT / n;
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ /** sum squares. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ for (i = 0; i < n; i++) {
|
|
 |
c245cf4 |
+ xabs = fabs(x[i]-y[i]);
|
|
 |
c245cf4 |
+ if (xabs > LM_SQRT_DWARF) {
|
|
 |
c245cf4 |
+ if ( xabs < agiant ) {
|
|
 |
c245cf4 |
+ s2 += xabs * xabs;
|
|
 |
c245cf4 |
+ } else if ( xabs > x1max ) {
|
|
 |
c245cf4 |
+ temp = x1max / xabs;
|
|
 |
c245cf4 |
+ s1 = 1 + s1 * SQR(temp);
|
|
 |
c245cf4 |
+ x1max = xabs;
|
|
 |
c245cf4 |
+ } else {
|
|
 |
c245cf4 |
+ temp = xabs / x1max;
|
|
 |
c245cf4 |
+ s1 += SQR(temp);
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
+ } else if ( xabs > x3max ) {
|
|
 |
c245cf4 |
+ temp = x3max / xabs;
|
|
 |
c245cf4 |
+ s3 = 1 + s3 * SQR(temp);
|
|
 |
c245cf4 |
+ x3max = xabs;
|
|
 |
c245cf4 |
+ } else if (xabs != 0) {
|
|
 |
c245cf4 |
+ temp = xabs / x3max;
|
|
 |
c245cf4 |
+ s3 += SQR(temp);
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
+ }
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ /** calculation of norm. **/
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+ if (s1 != 0)
|
|
 |
c245cf4 |
+ return x1max * sqrt(s1 + (s2 / x1max) / x1max);
|
|
 |
c245cf4 |
+ else if (s2 != 0)
|
|
 |
c245cf4 |
+ if (s2 >= x3max)
|
|
 |
c245cf4 |
+ return sqrt(s2 * (1 + (x3max / s2) * (x3max * s3)));
|
|
 |
c245cf4 |
+ else
|
|
 |
c245cf4 |
+ return sqrt(x3max * ((s2 / x3max) + (x3max * s3)));
|
|
 |
c245cf4 |
+ else
|
|
 |
c245cf4 |
+ return x3max * sqrt(s3);
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+} /*** lm_fnorm. ***/
|
|
 |
c245cf4 |
diff --git a/src/external/lmfit/lmmin.h b/src/external/lmfit/lmmin.h
|
|
 |
c245cf4 |
index 17b4880..d2ccfae 100644
|
|
 |
c245cf4 |
--- a/src/external/lmfit/lmmin.h
|
|
 |
c245cf4 |
+++ b/src/external/lmfit/lmmin.h
|
|
 |
c245cf4 |
@@ -17,9 +17,15 @@
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
#include "lmstruct.h"
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
-/*! \brief
|
|
 |
c245cf4 |
- * Levenberg-Marquardt minimization.
|
|
 |
c245cf4 |
- *
|
|
 |
c245cf4 |
+/* Levenberg-Marquardt minimization. */
|
|
 |
c245cf4 |
+void lmmin(
|
|
 |
c245cf4 |
+ const int n_par, double* par, const int m_dat, const double* y,
|
|
 |
c245cf4 |
+ const void* data,
|
|
 |
c245cf4 |
+ void (*evaluate)(
|
|
 |
c245cf4 |
+ const double* par, const int m_dat, const void* data,
|
|
 |
c245cf4 |
+ double* fvec, int* userbreak),
|
|
 |
c245cf4 |
+ const lm_control_struct* control, lm_status_struct* status);
|
|
 |
c245cf4 |
+/*
|
|
 |
c245cf4 |
* This routine contains the core algorithm of our library.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* It minimizes the sum of the squares of m nonlinear functions
|
|
 |
c245cf4 |
@@ -29,14 +35,16 @@
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* Parameters:
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * \param[in] n_par The number of variables (INPUT, positive integer).
|
|
 |
c245cf4 |
- * \param par The parameters to be fitted
|
|
 |
c245cf4 |
- * x is the solution vector (INPUT/OUTPUT, array of length n).
|
|
 |
c245cf4 |
+ * n_par is the number of variables (INPUT, positive integer).
|
|
 |
c245cf4 |
+ *
|
|
 |
c245cf4 |
+ * par is the solution vector (INPUT/OUTPUT, array of length n).
|
|
 |
c245cf4 |
* On input it must be set to an estimated solution.
|
|
 |
c245cf4 |
* On output it yields the final estimate of the solution.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
- * m is the number of functions to be minimized (INPUT, positive integer).
|
|
 |
c245cf4 |
+ * m_dat is the number of functions to be minimized (INPUT, positive integer).
|
|
 |
c245cf4 |
* It must fulfill m>=n.
|
|
 |
c245cf4 |
+ *
|
|
 |
c245cf4 |
+ * y contains data to be fitted. Use a null pointer if there are no data.
|
|
 |
c245cf4 |
*
|
|
 |
c245cf4 |
* data is a pointer that is ignored by lmmin; it is however forwarded
|
|
 |
c245cf4 |
* to the user-supplied functions evaluate and printout.
|
|
 |
c245cf4 |
@@ -56,9 +64,9 @@
|
|
 |
c245cf4 |
* status contains OUTPUT variables that inform about the fit result,
|
|
 |
c245cf4 |
* as declared and explained in lmstruct.h
|
|
 |
c245cf4 |
*/
|
|
 |
c245cf4 |
-void lmmin( const int n_par, double *par, const int m_dat, const void *data,
|
|
 |
c245cf4 |
- void (*evaluate) (const double *par, const int m_dat, const void *data,
|
|
 |
c245cf4 |
- double *fvec, int *userbreak),
|
|
 |
c245cf4 |
- const lm_control_struct *control, lm_status_struct *status );
|
|
 |
c245cf4 |
+
|
|
 |
c245cf4 |
+/* Refined calculation of Eucledian norm. */
|
|
 |
c245cf4 |
+double lm_enorm(const int, const double*);
|
|
 |
c245cf4 |
+double lm_fnorm(const int, const double*, const double*);
|
|
 |
c245cf4 |
|
|
 |
c245cf4 |
#endif /* LMMIN_H */
|
|
 |
c245cf4 |
diff --git a/src/external/lmfit/lmstruct.h b/src/external/lmfit/lmstruct.h
|
|
 |
c245cf4 |
index d545ff1..1f513b3 100644
|
|
 |
c245cf4 |
--- a/src/external/lmfit/lmstruct.h
|
|
 |
c245cf4 |
+++ b/src/external/lmfit/lmstruct.h
|
|
 |
c245cf4 |
@@ -39,23 +39,23 @@
|
|
 |
c245cf4 |
stepbound itself. In most cases stepbound should lie
|
|
 |
c245cf4 |
in the interval (0.1,100.0). Generally, the value
|
|
 |
c245cf4 |
100.0 is recommended. */
|
|
 |
c245cf4 |
- int patience; /* Used to set the maximum number of function evaluations
|
|
 |
c245cf4 |
+ int patience; /* Used to set the maximum number of function evaluations
|
|
 |
c245cf4 |
to patience*(number_of_parameters+1). */
|
|
 |
c245cf4 |
- int scale_diag; /* If 1, the variables will be rescaled internally.
|
|
 |
c245cf4 |
+ int scale_diag; /* If 1, the vari
|