1st c++ draft
This commit is contained in:
parent
7b2a9a6d4a
commit
d83a997804
15 changed files with 3276 additions and 142 deletions
46
.gitignore
vendored
46
.gitignore
vendored
|
|
@ -1,2 +1,48 @@
|
|||
# executable
|
||||
run
|
||||
|
||||
*.pdf
|
||||
|
||||
# gcov files
|
||||
*.gcov
|
||||
*.gcda
|
||||
*.gcno
|
||||
|
||||
# python cache
|
||||
__pycache__
|
||||
|
||||
# generated documentation
|
||||
html/
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
|
|
|||
2482
cpp/Doxyfile
Normal file
2482
cpp/Doxyfile
Normal file
File diff suppressed because it is too large
Load diff
41
cpp/Makefile
Normal file
41
cpp/Makefile
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Declaration of variables
|
||||
C = clang
|
||||
COMMON_FLAGS = -Wall -MMD
|
||||
C_FLAGS = $(COMMON_FLAGS)
|
||||
CC = clang++
|
||||
CC_FLAGS = $(COMMON_FLAGS) -std=c++17
|
||||
LD_FLAGS =
|
||||
INCLUDES =
|
||||
|
||||
# File names
|
||||
EXEC = run
|
||||
CSOURCES = $(wildcard *.c)
|
||||
COBJECTS = $(CSOURCES:.c=.o)
|
||||
SOURCES = $(wildcard *.cpp)
|
||||
OBJECTS = $(SOURCES:.cpp=.o)
|
||||
|
||||
# Main target
|
||||
$(EXEC): $(COBJECTS) $(OBJECTS)
|
||||
$(CC) $(COBJECTS) $(OBJECTS) -o $(EXEC) $(LD_FLAGS)
|
||||
|
||||
# To obtain object files
|
||||
%.o: %.cpp
|
||||
$(CC) $(INCLUDES) $(CC_FLAGS) -o $@ -c $<
|
||||
|
||||
# To obtain object files
|
||||
%.o: %.c
|
||||
$(C) $(INCLUDES) $(C_FLAGS) -o $@ -c $<
|
||||
|
||||
-include $(SOURCES:%.cpp=%.d)
|
||||
-include $(CSOURCES:%.c=%.d)
|
||||
|
||||
# To generate the documentation
|
||||
doc:
|
||||
doxygen Doxyfile
|
||||
|
||||
# To remove generated files
|
||||
clean:
|
||||
rm -f $(COBJECTS) $(OBJECTS) $(SOURCES:%.cpp=%.d) $(CSOURCES:%.c=%.d)
|
||||
|
||||
cleaner: clean
|
||||
rm -f $(EXEC)
|
||||
3
cpp/README.md
Normal file
3
cpp/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
CppQuickStart
|
||||
=============
|
||||
"Empty" project for a quicker start writing something in c++.
|
||||
167
cpp/TOMS748.hpp
Normal file
167
cpp/TOMS748.hpp
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
#ifndef DEF_TOMS748
|
||||
#define DEF_TOMS748
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace TOMS748
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
// checks that none of the values are the same
|
||||
// returns true if at least two values are identical
|
||||
template<typename T> bool checkTwoValuesIdentical(T fa, T fb, T fc, T fd)
|
||||
{
|
||||
bool same = false;
|
||||
same |= fa == fb;
|
||||
same |= fa == fc;
|
||||
same |= fa == fd;
|
||||
|
||||
same |= fb == fc;
|
||||
same |= fb == fd;
|
||||
|
||||
same |= fc == fd;
|
||||
return same;
|
||||
}
|
||||
|
||||
// finite differences 1st derivative given a, b, fa, fb
|
||||
template<typename T> T fbracket1(T a, T b, T fa, T fb) { return (fb-fa)/(b-a); }
|
||||
|
||||
// finite differences 2nd derivative given a, b, d, fa, fb, fd
|
||||
template<typename T> T fbracket2(T a, T b, T d, T fa, T fb, T fd) { return (fbracket1(b, d, fb, fd) - fbracket1(a, b, fa, fb))/(d-a); }
|
||||
|
||||
// standard bracketing routine
|
||||
// returns ahat, bhat, d
|
||||
// d is a point outside the new interval
|
||||
template<typename T> std::tuple<T,T,T,T,T,T> bracket(T a, T b, T c, T fa, T fb, T fc)
|
||||
{
|
||||
if(fa*fc < T(0))
|
||||
return std::make_tuple(a, c, b, fa, fc, fb);
|
||||
else
|
||||
return std::make_tuple(c, b, a, fc, fb, fa);
|
||||
}
|
||||
|
||||
// standard bracketing routine
|
||||
// checks if f(c) is close enough to 0 and returns ok = true if it is the case
|
||||
// returns ahat, bhat, d
|
||||
// d is a point outside the new interval
|
||||
template<typename T> std::tuple<T,T,T,T,T,T,bool> bracketAndCheckConvergence(T a, T b, T c, T fa, T fb, T fc, T tol)
|
||||
{
|
||||
bool ok = false;
|
||||
if(sureAbs(fc) < tol)
|
||||
ok = true;
|
||||
if(fa*fc < T(0))
|
||||
return std::make_tuple(a, c, b, fa, fc, fb, ok);
|
||||
else
|
||||
return std::make_tuple(c, b, a, fc, fb, fa, ok);
|
||||
}
|
||||
|
||||
// finds an approximate solution to the quadratic P(x) = fa + f[a,b]*(x-a) + f[a,b,d]*(x-a)(x-b)
|
||||
// with f[a,b] = fbracket1(a,b) and f[a,b,d] = fbracket2(a,b,d)
|
||||
template<typename T, int k> T NewtonQuadratic(T a, T b, T d, T fa, T fb, T fd)
|
||||
{
|
||||
T r;
|
||||
T A = fbracket2(a,b,d,fa,fb,fd);
|
||||
T B = fbracket1(a,b,fa,fb);
|
||||
if(A == T(0))
|
||||
return a - fa/B;
|
||||
if(A*fa > T(0))
|
||||
r = a;
|
||||
else
|
||||
r = b;
|
||||
|
||||
for(int i = 0 ; i < k ; i++)
|
||||
r = r - B*r/(B + A*(T(2)*r - a - b));
|
||||
return r;
|
||||
}
|
||||
|
||||
// Inverse cubic interpolation evaluated at 0 (modified Aitken-Neville interpolation)
|
||||
template<typename T> T ipzero(T a, T b, T c, T d, T fa, T fb, T fc, T fd)
|
||||
{
|
||||
T Q11 = (c-d)*fc/(fd-fc);
|
||||
T Q21 = (b-c)*fb/(fc-fb);
|
||||
T Q31 = (a-b)*fa/(fb-fa);
|
||||
T D21 = (b-c)*fc/(fc-fb);
|
||||
T D31 = (a-b)*fb/(fb-fa);
|
||||
T Q22 = (D21-Q11)*fb/(fd-fb);
|
||||
T Q32 = (D31-Q21)*fa/(fc-fa);
|
||||
T D32 = (D31-Q21)*fc/(fc-fa);
|
||||
T Q33 = (D32-Q22)*fa/(fd-fa);
|
||||
return a + Q31 + Q32 + Q33;
|
||||
}
|
||||
}// namespace internal
|
||||
|
||||
/// Algorithm 4.1 from TOMS748 of robust root-solving.
|
||||
/// Use this version if f(a) and f(b) have already been computed.
|
||||
template<typename Func, typename T> std::tuple<T,T,bool> TOMS748_solve1(Func f, T a, T b, T fa, T fb, T tol, int Nmax = 1000)
|
||||
{
|
||||
using namespace internal;
|
||||
T c, d, e, u, dbar, dhat, fc, fd, fe, fu, fdbar, fdhat;
|
||||
T mu = 0.5;
|
||||
bool ok;
|
||||
c = a - fa/fbracket1(a, b, fa, fb); // 4.1.1 secant method
|
||||
fc = f(c);
|
||||
std::tie(a, b, d, fa, fb, fd, ok) = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol); // 4.1.2
|
||||
if(ok) { return std::make_tuple(c, fc, true); }
|
||||
e = d;
|
||||
fe = fd;
|
||||
// ---
|
||||
for(int n = 2 ; n < Nmax ; n++) // 4.1.3
|
||||
{
|
||||
if(n == 2 || checkTwoValuesIdentical(fa, fb, fd, fe))
|
||||
c = NewtonQuadratic<T,2>(a, b, d, fa, fb, fd);
|
||||
else
|
||||
c = ipzero(a, b, d, e, fa, fb, fd, fe);
|
||||
if((c-a)*(c-b) >= T(0))
|
||||
c = NewtonQuadratic<T,2>(a, b, d, fa, fb, fd);
|
||||
// ---
|
||||
fc = f(c);
|
||||
std::tie(a, b, dbar, fa, fb, fdbar, ok) = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol); // 4.1.4
|
||||
if(ok) { return std::make_tuple(c, fc, true); }
|
||||
// ---
|
||||
if(fabs(fa) < fabs(fb)) // 4.1.5
|
||||
{
|
||||
u = a;
|
||||
fu = fa;
|
||||
}
|
||||
else
|
||||
{
|
||||
u = b;
|
||||
fu = fb;
|
||||
}
|
||||
// ---
|
||||
c = u - 2*fu/fbracket1(a, b, fa, fb); // 4.1.6
|
||||
// ---
|
||||
if(fabs(c - u) > 0.5*(b - a)) // 4.1.7
|
||||
c = 0.5*(b + a);
|
||||
// ---
|
||||
fc = f(c);
|
||||
std::tie(a, b, dhat, fa, fb, fdhat, ok) = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol); // 4.1.8
|
||||
if(ok) { return std::make_tuple(c, fc, true); }
|
||||
// ---
|
||||
if(b - a < mu*(b - a)) // 4.1.9
|
||||
{
|
||||
d = dhat;
|
||||
e = dbar;
|
||||
fd = fdhat;
|
||||
fe = fdbar;
|
||||
}
|
||||
else
|
||||
{
|
||||
e = dhat;
|
||||
fe = fdhat;
|
||||
}
|
||||
c = 0.5*(a+b);
|
||||
fc = f(c);
|
||||
std::tie(a, b, d, fa, fb, fd, ok) = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol);
|
||||
if(ok) { return std::make_tuple(c, fc, true); }
|
||||
}
|
||||
return std::make_tuple(c, fc, false);// no solution found, return last estimate
|
||||
}
|
||||
|
||||
template<typename Func, typename T> std::tuple<T,T,bool> TOMS748_solve1(Func f, T a, T b, T tol, int Nmax = 1000)
|
||||
{
|
||||
return TOMS748_solve1(f, a, b, f(a), f(b), tol, Nmax);
|
||||
}
|
||||
}// namespace TOMS748
|
||||
|
||||
#endif
|
||||
49
cpp/main.cpp
Normal file
49
cpp/main.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "TOMS748.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
using namespace TOMS748;
|
||||
using namespace TOMS748::internal;
|
||||
|
||||
template<typename T> T f(T E) { PRINT_VAR(E); return E - 0.5*sin(E) - 0.3; }
|
||||
|
||||
int main()
|
||||
{
|
||||
cout.precision(16);
|
||||
{
|
||||
double a = 0, b = 1, c = 0.3, d = 1.2;
|
||||
double fa = f(a), fb = f(b), fc = f(c), fd = f(d);
|
||||
double tol = 1e-12;
|
||||
|
||||
PRINT_VAR(fbracket1(a, b, fa, fb));
|
||||
PRINT_VAR(fbracket2(a, b, d, fa, fb, fd));
|
||||
std::tie(a, b, d, fa, fb, fd) = bracket(a, b, c, fa, fb, fc);
|
||||
PRINT_VAR(a);
|
||||
PRINT_VAR(b);
|
||||
PRINT_VAR(d);
|
||||
PRINT_VAR(fa);
|
||||
PRINT_VAR(fb);
|
||||
PRINT_VAR(fd);
|
||||
|
||||
PRINT_VAR(checkTwoValuesIdentical(1,2,3,4));
|
||||
PRINT_VAR(checkTwoValuesIdentical(1,2,3,1));
|
||||
PRINT_VAR(checkTwoValuesIdentical(1,1,3,4));
|
||||
PRINT_VAR(checkTwoValuesIdentical(1,2,2,4));
|
||||
PRINT_VAR(checkTwoValuesIdentical(1,2,3,3));
|
||||
PRINT_VAR(checkTwoValuesIdentical(1,2,1,4));
|
||||
PRINT_VAR(checkTwoValuesIdentical(1,2,3,2));
|
||||
|
||||
a = 0; b = 1;
|
||||
auto res = TOMS748_solve1(f<double>, a, b, tol);
|
||||
PRINT_VAR(std::get<0>(res));
|
||||
PRINT_VAR(std::get<1>(res));
|
||||
PRINT_VAR(std::get<2>(res));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
34
cpp/test/1_test.cpp
Normal file
34
cpp/test/1_test.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include <catch2/catch.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include "../utils.hpp"
|
||||
#include "utils_test.hpp"
|
||||
|
||||
#define print(x) PRINT_VAR(x);
|
||||
#define printvec(x) PRINT_VEC(x);
|
||||
#define printstr(x) PRINT_STR(x);
|
||||
|
||||
TEST_CASE( "Test case 1", "[test1]" )
|
||||
{
|
||||
std::cout.precision(16);
|
||||
|
||||
SECTION( "Check almost equal" ) {
|
||||
CHECK(check_almost_equal(1.00, 1.01, 0.1));
|
||||
CHECK(check_almost_equal(1.00, 3.01, 0.01));
|
||||
CHECK(check_almost_equal(1.00, 1.01, 0.001));
|
||||
REQUIRE(true);
|
||||
}
|
||||
|
||||
SECTION( "Check almost equal on vectors" ) {
|
||||
unsigned int N = 5;
|
||||
std::vector<double> v1(N), v2(N);
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
v1[i] = double(i);
|
||||
v2[i] = v1[i] + 0.0001;
|
||||
}
|
||||
|
||||
CHECK(check_almost_equalV(v1, v2, 0.001));
|
||||
CHECK(check_almost_equalV(v1, v2, 0.0001));
|
||||
CHECK(check_almost_equalV(v1, v2, 0.00001));
|
||||
}
|
||||
}
|
||||
49
cpp/test/Makefile
Normal file
49
cpp/test/Makefile
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Declaration of variables
|
||||
C = gcc
|
||||
COMMON_FLAGS = -Wall -MMD -fprofile-arcs -ftest-coverage
|
||||
C_FLAGS = $(COMMON_FLAGS)
|
||||
CC = g++
|
||||
CC_FLAGS = $(COMMON_FLAGS) -std=c++17 -O0
|
||||
LD_FLAGS = -lgcov
|
||||
INCLUDES =
|
||||
|
||||
# File names
|
||||
EXEC = run
|
||||
CSOURCES = $(wildcard *.c)
|
||||
COBJECTS = $(CSOURCES:.c=.o)
|
||||
SOURCES = $(wildcard *.cpp)
|
||||
OBJECTS = $(SOURCES:.cpp=.o)
|
||||
|
||||
# Main target
|
||||
$(EXEC): $(COBJECTS) $(OBJECTS)
|
||||
$(CC) $(COBJECTS) $(OBJECTS) -o $(EXEC) $(LD_FLAGS)
|
||||
|
||||
# To obtain object files
|
||||
%.o: %.cpp
|
||||
$(CC) $(INCLUDES) $(CC_FLAGS) -o $@ -c $<
|
||||
|
||||
# To obtain object files
|
||||
%.o: %.c
|
||||
$(C) $(INCLUDES) $(C_FLAGS) -o $@ -c $<
|
||||
|
||||
-include $(SOURCES:%.cpp=%.d)
|
||||
-include $(CSOURCES:%.c=%.d)
|
||||
|
||||
# To generate the documentation
|
||||
doc:
|
||||
doxygen Doxyfile
|
||||
|
||||
# To generate human-readable coverage data
|
||||
cov:
|
||||
gcov *.gcda
|
||||
|
||||
# To remove all the files generated by gcov
|
||||
cleancov:
|
||||
rm -f *.gcov *.gcda
|
||||
|
||||
# To remove generated files
|
||||
clean: cleancov
|
||||
rm -f $(COBJECTS) $(OBJECTS) $(SOURCES:%.cpp=%.d) $(CSOURCES:%.c=%.d) *.gcno
|
||||
|
||||
cleaner: clean
|
||||
rm -f $(EXEC)
|
||||
4
cpp/test/main_test.cpp
Normal file
4
cpp/test/main_test.cpp
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// Let Catch provide main()
|
||||
#define CATCH_CONFIG_MAIN
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
BIN
cpp/test/run
Normal file
BIN
cpp/test/run
Normal file
Binary file not shown.
30
cpp/test/utils_test.hpp
Normal file
30
cpp/test/utils_test.hpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef DEF_utils_test
|
||||
#define DEF_utils_test
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template<typename T, typename T2>
|
||||
bool check_almost_equal(const T & a, const T & b, const T2 & tol)
|
||||
{
|
||||
T a_b = a - b;
|
||||
return ((a_b < T(0)) ? -a_b : a_b) <= tol;
|
||||
}
|
||||
|
||||
template<typename Vector, typename T>
|
||||
bool check_almost_equalV(const Vector & v1, const Vector & v2, T tol)
|
||||
{
|
||||
assert(v1.size() == v2.size());
|
||||
bool ok = true;
|
||||
for(size_t i = 0 ; i < v1.size() ; i++)
|
||||
{
|
||||
auto v1_v2_i = v1[i] - v2[i];
|
||||
if(((v1_v2_i < 0) ? -v1_v2_i : v1_v2_i) > tol)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
#endif
|
||||
39
cpp/utils.hpp
Normal file
39
cpp/utils.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef DEF_utils
|
||||
#define DEF_utils
|
||||
|
||||
#include <ostream>
|
||||
#include <utility>
|
||||
|
||||
#define PRINT_VAR(x) std::cout << #x << "\t= " << (x) << "\n"
|
||||
#define PRINT_VEC(x); {std::cout << #x << "\t= "; \
|
||||
for(unsigned int i_print_vec = 0 ; i_print_vec < (x).size() ; i_print_vec++) \
|
||||
std::cout << (x)[i_print_vec] << "\t"; \
|
||||
std::cout << "\n";}
|
||||
#define PRINT_STR(x) std::cout << (x) << "\n"
|
||||
|
||||
template<typename T, typename T2> auto min(const T & a, const T2 & b) -> decltype(a | b) { return (a < b) ? T(a) : T(b); }
|
||||
template<typename T, typename T2> auto max(const T & a, const T2 & b) -> decltype(a | b) { return (a < b) ? T(b) : T(a); }
|
||||
|
||||
/// To be sure that floating point numbers won't be casted to integers in ::abs()...
|
||||
template<typename T> T sureAbs(const T & x) { return (x < T(0)) ? -x : x; }
|
||||
|
||||
template<typename T, template<class,class...> class C, class... Args>
|
||||
std::ostream& operator<<(std::ostream& os, const C<T,Args...>& objs)
|
||||
{
|
||||
for (auto const& obj : objs)
|
||||
os << obj << ' ';
|
||||
return os;
|
||||
}
|
||||
|
||||
/// Convenience template class to do StdPairValueCatcher(a, b) = someFunctionThatReturnsAnStdPair<A,B>()
|
||||
/// Instead of doing a = std::get<0>(result_from_function), b = std::get<1>(result_from_function)
|
||||
template<typename A, typename B>
|
||||
struct StdPairValueCatcher
|
||||
{
|
||||
A & a;
|
||||
B & b;
|
||||
StdPairValueCatcher(A & a_, B & b_) : a(a_), b(b_) {}
|
||||
std::pair<A, B> const& operator=(std::pair<A, B> const& p) {a = std::get<0>(p); b = std::get<1>(p); return p; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -9,10 +9,19 @@ def findEnclosingBracket(f, x, factor):
|
|||
If the bracket returned by the function is too wide, try reducing the factor (while always keeping it > 1).
|
||||
"""
|
||||
a = x
|
||||
b = x*factor # try higher
|
||||
b = x*factor # try searching in the positive direction
|
||||
fa = f(a)
|
||||
fb = f(b)
|
||||
|
||||
if fa*fb < 0: # if the original bracket is already enclosing the solution
|
||||
return (a, b, fa, fb)
|
||||
|
||||
if fabs(fa) < fabs(fb): # if fa is closer, search in the other direction
|
||||
a = x/factor
|
||||
b = x
|
||||
fb = fa # f(b) = f(x)
|
||||
fa = f(a)
|
||||
|
||||
i = 0
|
||||
while i in range(100) and fa*fb > 0:
|
||||
if fabs(fa) < fabs(fb): # fa is closer to 0 than fb, extend the interval in the a direction (reducing it)
|
||||
|
|
@ -43,6 +52,16 @@ f = lambda x : x**(1/3)-1000
|
|||
a, b, fa, fb = findEnclosingBracket(f, 1e-10, 2)
|
||||
print((a,b)); print((fa, fb))
|
||||
|
||||
print('exp(x)-2')
|
||||
|
||||
def f(x):
|
||||
fx = exp(x)-2
|
||||
print((x, fx))
|
||||
return fx
|
||||
|
||||
a, b, fa, fb = findEnclosingBracket(f, .1, 2); print((a,b)); print((fa, fb))
|
||||
a, b, fa, fb = findEnclosingBracket(f, 4, 2); print((a,b)); print((fa, fb))
|
||||
|
||||
# from toms748 import TOMS748_solve1
|
||||
# def f(x):
|
||||
# print(x)
|
||||
312
python/toms748.py
Normal file
312
python/toms748.py
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
# Implementation of TOMS748
|
||||
# https://na.math.kit.edu/alefeld/download/1995_Algorithm_748_Enclosing_Zeros_of_Continuous_Functions.pdf
|
||||
|
||||
# from math import sin, fabs, cos
|
||||
from math import *
|
||||
|
||||
# checks that none of the values are the same
|
||||
# returns true if at least two values are identical
|
||||
def checkTwoValuesIdentical(fa, fb, fc, fd):
|
||||
same = False
|
||||
same |= fa == fb
|
||||
same |= fa == fc
|
||||
same |= fa == fd
|
||||
|
||||
same |= fb == fc
|
||||
same |= fb == fd
|
||||
|
||||
same |= fc == fd
|
||||
return same
|
||||
|
||||
# finite differences 1st derivative given a, b, fa, fb
|
||||
def fbracket1(a, b, fa, fb):
|
||||
return (fb-fa)/(b-a)
|
||||
|
||||
# finite differences 2nd derivative given a, b, d, fa, fb, fd
|
||||
def fbracket2(a, b, d, fa, fb, fd):
|
||||
return (fbracket1(b, d, fb, fd) - fbracket1(a, b, fa, fb))/(d-a)
|
||||
|
||||
# standard bracketing routine
|
||||
# returns ahat, bhat, d
|
||||
# d is a point outside the new interval
|
||||
def bracket(a, b, c, fa, fb, fc):
|
||||
if fa*fc < 0:
|
||||
return (a, c, b, fa, fc, fb)
|
||||
else:
|
||||
return (c, b, a, fc, fb, fa)
|
||||
|
||||
# standard bracketing routine
|
||||
# returns ahat, bhat, d
|
||||
# d is a point outside the new interval
|
||||
def bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol):
|
||||
ok = False
|
||||
if fabs(fc) < tol:
|
||||
ok = True
|
||||
if fa*fc < 0:
|
||||
return (a, c, b, fa, fc, fb, ok)
|
||||
else:
|
||||
return (c, b, a, fc, fb, fa, ok)
|
||||
|
||||
# finds an approximate solution to the quadratic P(x) = fa + f[a,b]*(x-a) + f[a,b,d]*(x-a)(x-b)
|
||||
# with f[a,b] = fbracket1(a,b) and f[a,b,d] = fbracket2(a,b,d)
|
||||
def NewtonQuadratic(a, b, d, fa, fb, fd, k):
|
||||
A = fbracket2(a,b,d,fa,fb,fd)
|
||||
B = fbracket1(a,b,fa,fb)
|
||||
if A == 0:
|
||||
return a - fa/B
|
||||
if A*fa > 0:
|
||||
r = a
|
||||
else:
|
||||
r = b
|
||||
|
||||
for i in range(k):
|
||||
r = r - B*r/(B + A*(2*r - a - b))
|
||||
return r
|
||||
|
||||
# Inverse cubic interpolation evaluated at 0 (modified Aitken-Neville interpolation)
|
||||
def ipzero(a, b, c, d, fa, fb, fc, fd):
|
||||
Q11 = (c-d)*fc/(fd-fc)
|
||||
Q21 = (b-c)*fb/(fc-fb)
|
||||
Q31 = (a-b)*fa/(fb-fa)
|
||||
D21 = (b-c)*fc/(fc-fb)
|
||||
D31 = (a-b)*fb/(fb-fa)
|
||||
Q22 = (D21-Q11)*fb/(fd-fb)
|
||||
Q32 = (D31-Q21)*fa/(fc-fa)
|
||||
D32 = (D31-Q21)*fc/(fc-fa)
|
||||
Q33 = (D32-Q22)*fa/(fd-fa)
|
||||
return a + Q31 + Q32 + Q33
|
||||
|
||||
def TOMS748_solve1(f, a, b, tol, Nmax = 1000):
|
||||
mu = 0.5
|
||||
fa, fb = f(a), f(b)
|
||||
c = a - fa/fbracket1(a, b, fa, fb) # 4.1.1 secant method
|
||||
fc = f(c)
|
||||
a, b, d, fa, fb, fd, ok = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol) # 4.1.2
|
||||
if(ok): return (c, fc)
|
||||
e = d
|
||||
fe = fd
|
||||
# ---
|
||||
for n in range(2,Nmax): # 4.1.3
|
||||
if n == 2 or checkTwoValuesIdentical(fa, fb, fd, fe):
|
||||
c = NewtonQuadratic(a, b, d, fa, fb, fd, 2)
|
||||
else:
|
||||
c = ipzero(a, b, d, e, fa, fb, fd, fe)
|
||||
if (c-a)*(c-b) >= 0:
|
||||
c = NewtonQuadratic(a, b, d, fa, fb, fd, 2)
|
||||
# ---
|
||||
fc = f(c)
|
||||
a, b, dbar, fa, fb, fdbar, ok = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol) # 4.1.4
|
||||
if(ok): return (c, fc)
|
||||
# ---
|
||||
if fabs(fa) < fabs(fb): # 4.1.5
|
||||
u = a
|
||||
fu = fa
|
||||
else:
|
||||
u = b
|
||||
fu = fb
|
||||
# ---
|
||||
c = u - 2*fu/fbracket1(a, b, fa, fb) # 4.1.6
|
||||
# ---
|
||||
if fabs(c - u) > 0.5*(b - a): # 4.1.7
|
||||
c = 0.5*(b + a)
|
||||
# ---
|
||||
fc = f(c)
|
||||
a, b, dhat, fa, fb, fdhat, ok = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol) # 4.1.8
|
||||
if(ok): return (c, fc)
|
||||
# ---
|
||||
if b - a < mu*(b - a): # 4.1.9
|
||||
d = dhat
|
||||
e = dbar
|
||||
fd = fdhat
|
||||
fe = fdbar
|
||||
else:
|
||||
e = dhat
|
||||
fe = fdhat
|
||||
c = 0.5*(a+b)
|
||||
fc = f(c)
|
||||
a, b, d, fa, fb, fd, ok = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol)
|
||||
if(ok): return (c, fc)
|
||||
return (c, fc)# no solution found, return last estimate
|
||||
|
||||
def TOMS748_solve2(f, a, b, tol, Nmax = 1000):
|
||||
mu = 0.5
|
||||
fa, fb = f(a), f(b)
|
||||
c = a - fa/fbracket1(a, b, fa, fb) # 4.2.1 secant method
|
||||
fc = f(c)
|
||||
a, b, d, fa, fb, fd, ok = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol) # 4.2.2
|
||||
if(ok): return (c, fc)
|
||||
e = d
|
||||
fe = fd
|
||||
# ---
|
||||
for n in range(2,Nmax): # 4.2.3
|
||||
if n == 2 or checkTwoValuesIdentical(fa, fb, fd, fe):
|
||||
c = NewtonQuadratic(a, b, d, fa, fb, fd, 2)
|
||||
else:
|
||||
c = ipzero(a, b, d, e, fa, fb, fd, fe)
|
||||
if (c-a)*(c-b) >= 0:
|
||||
c = NewtonQuadratic(a, b, d, fa, fb, fd, 2)
|
||||
# ---
|
||||
e = d
|
||||
fe = fd
|
||||
fc = f(c)
|
||||
a, b, d, fa, fb, fd, ok = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol) # 4.2.4
|
||||
if(ok): return (c, fc)
|
||||
# ---
|
||||
if checkTwoValuesIdentical(fa, fb, fd, fe): # 4.2.5
|
||||
c = NewtonQuadratic(a, b, d, fa, fb, fd, 3)
|
||||
else:
|
||||
c = ipzero(a, b, d, e, fa, fb, fd, fe)
|
||||
if (c-a)*(c-b) >= 0:
|
||||
c = NewtonQuadratic(a, b, d, fa, fb, fd, 3)
|
||||
# ---
|
||||
fc = f(c)
|
||||
a, b, dbar, fa, fb, fdbar, ok = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol) # 4.2.6
|
||||
if(ok): return (c, fc)
|
||||
# ---
|
||||
if fabs(fa) < fabs(fb): # 4.2.7
|
||||
u = a
|
||||
fu = fa
|
||||
else:
|
||||
u = b
|
||||
fu = fb
|
||||
# ---
|
||||
c = u - 2*fu/fbracket1(a, b, fa, fb) # 4.2.8
|
||||
# ---
|
||||
if fabs(c - u) > 0.5*(b - a): # 4.2.9
|
||||
c = 0.5*(b + a)
|
||||
# ---
|
||||
fc = f(c)
|
||||
a, b, dhat, fa, fb, fdhat, ok = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol) # 4.2.10
|
||||
if(ok): return (c, fc)
|
||||
# ---
|
||||
if b - a < mu*(b - a): # 4.2.11
|
||||
d = dhat
|
||||
e = dbar
|
||||
fd = fdhat
|
||||
fe = fdbar
|
||||
else:
|
||||
e = dhat
|
||||
fe = fdhat
|
||||
c = 0.5*(a+b)
|
||||
fc = f(c)
|
||||
a, b, d, fa, fb, fd, ok = bracketAndCheckConvergence(a, b, c, fa, fb, fc, tol)
|
||||
if(ok): return (c, fc)
|
||||
return (c, fc)# no solution found, return last estimate
|
||||
|
||||
# TEST
|
||||
f = lambda E : E - 0.5*sin(E) - 0.3
|
||||
a, b, c, d = 0, 1, 0.3, 1.2
|
||||
fa, fb, fc, fd = f(a), f(b), f(c), f(d)
|
||||
tol = 1e-12
|
||||
|
||||
print(fbracket1(a, b, fa, fb))
|
||||
print(fbracket2(a, b, d, fa, fb, fd))
|
||||
print(bracket(a, b, c, fa, fb, fc))
|
||||
print(NewtonQuadratic(a, b, d, fa, fb, fd, 2))
|
||||
print(ipzero(a, b, c, d, fa, fb, fc, fd))
|
||||
|
||||
# TTTEST
|
||||
print(checkTwoValuesIdentical(1,2,3,4))
|
||||
print(checkTwoValuesIdentical(1,2,3,1))
|
||||
print(checkTwoValuesIdentical(1,1,3,4))
|
||||
print(checkTwoValuesIdentical(1,2,2,4))
|
||||
print(checkTwoValuesIdentical(1,2,3,3))
|
||||
print(checkTwoValuesIdentical(1,2,1,4))
|
||||
print(checkTwoValuesIdentical(1,2,3,2))
|
||||
# TTTEST
|
||||
|
||||
# solution using bracket only :
|
||||
print('bracket only')
|
||||
for i in range(50):
|
||||
c = (a+b)/2
|
||||
fc = f(c)
|
||||
a, b, d, fa, fb, fd = bracket(a, b, c, fa, fb, fc)
|
||||
if fabs(b-a) < tol:
|
||||
break
|
||||
print(i)
|
||||
|
||||
print((a,b), (a+b)/2, b-a)
|
||||
|
||||
print('Newton with derivative')
|
||||
df = lambda E : 1 - 0.5*cos(E)
|
||||
x = 0.5
|
||||
for i in range(50):
|
||||
delta = f(x)/df(x)
|
||||
x = x - delta
|
||||
if fabs(delta) < tol:
|
||||
break
|
||||
print(i)
|
||||
print(x)
|
||||
|
||||
print('TOMS748_solve1 only')
|
||||
def fct1(E):
|
||||
print("x = %20.15f" % E)
|
||||
return E - 0.5*sin(E) - 0.3
|
||||
|
||||
c, fc = TOMS748_solve1(fct1, 0, 1, tol)
|
||||
print("Root found :")
|
||||
print((c, fc))
|
||||
|
||||
print('TOMS748_solve2 only')
|
||||
c, fc = TOMS748_solve2(fct1, 0, 1, tol)
|
||||
print("Root found :")
|
||||
print((c, fc))
|
||||
|
||||
# ---
|
||||
|
||||
print('TOMS748_solve1 only')
|
||||
def fct2(x):
|
||||
print("x = %20.15f" % x)
|
||||
n = 20
|
||||
return x**2 - (1-x)**n
|
||||
|
||||
c, fc = TOMS748_solve1(fct2, 0, 1, tol)
|
||||
print("Root found :")
|
||||
print((c, fc))
|
||||
|
||||
print('TOMS748_solve2 only')
|
||||
c, fc = TOMS748_solve2(fct2, 1e-100, 1, tol)# if a is 0 the algorithm does not work (division by zero, because newton step a = 0 finds d = 0). It seems to be just this one case...
|
||||
print("Root found :")
|
||||
print((c, fc))
|
||||
|
||||
print('Newton with derivative')
|
||||
dfct2 = lambda x : 2*x + 20*(-x + 1)**19
|
||||
x = 0.5
|
||||
for i in range(50):
|
||||
delta = fct2(x)/dfct2(x)
|
||||
x = x - delta
|
||||
if fabs(delta) < tol:
|
||||
break
|
||||
print(i)
|
||||
print(x)
|
||||
|
||||
# ---
|
||||
|
||||
print('--------------------------')
|
||||
print('fct3')
|
||||
print('TOMS748_solve1 only')
|
||||
def fct3(x):
|
||||
print("x = %20.15f" % x)
|
||||
return x*exp(-x**2)
|
||||
# a, b = -.5, 1.5
|
||||
a, b = -1/sqrt(2), 2/sqrt(2)
|
||||
|
||||
c, fc = TOMS748_solve1(fct3, a, b, tol)
|
||||
print("Root found :")
|
||||
print((c, fc))
|
||||
|
||||
print('TOMS748_solve2 only')
|
||||
c, fc = TOMS748_solve2(fct3, a, b, tol)# if a is 0 the algorithm does not work (division by zero, because newton step a = 0 finds d = 0). It seems to be just this one case...
|
||||
print("Root found :")
|
||||
print((c, fc))
|
||||
|
||||
print('Newton with derivative')
|
||||
dfct3 = lambda x : (-2*x**2 + 1)*exp(-x**2)
|
||||
x = (a+b)/2
|
||||
for i in range(50):
|
||||
delta = fct3(x)/dfct3(x)
|
||||
x = x - delta
|
||||
if fabs(delta) < tol:
|
||||
break
|
||||
print(i)
|
||||
print(x)
|
||||
141
toms748.py
141
toms748.py
|
|
@ -1,141 +0,0 @@
|
|||
# Implementation of TOMS748
|
||||
# https://na.math.kit.edu/alefeld/download/1995_Algorithm_748_Enclosing_Zeros_of_Continuous_Functions.pdf
|
||||
|
||||
from math import sin, fabs, cos
|
||||
|
||||
# finite differences 1st derivative given a, b, fa, fb
|
||||
def fbracket1(a, b, fa, fb):
|
||||
return (fb-fa)/(b-a)
|
||||
|
||||
# finite differences 2nd derivative given a, b, d, fa, fb, fd
|
||||
def fbracket2(a, b, d, fa, fb, fd):
|
||||
return (fbracket1(b, d, fb, fd) - fbracket1(a, b, fa, fb))/(d-a)
|
||||
|
||||
# standard bracketing routine
|
||||
# returns ahat, bhat, d
|
||||
# d is a point outside the new interval
|
||||
def bracket(a, b, c, fa, fb, fc):
|
||||
# print('bracket')
|
||||
if fabs(fc) < 1e-12:
|
||||
print("root found : %f ; f(root) = %f" % (c, fc))
|
||||
if fa*fc < 0:
|
||||
return (a, c, b, fa, fc, fb)
|
||||
else:
|
||||
return (c, b, a, fc, fb, fa)
|
||||
|
||||
# finds an approximate solution to the quadratic P(x) = fa + f[a,b]*(x-a) + f[a,b,d]*(x-a)(x-b)
|
||||
# with f[a,b] = fbracket1(a,b) and f[a,b,d] = fbracket2(a,b,d)
|
||||
def NewtonQuadratic(a, b, d, fa, fb, fd, k):
|
||||
A = fbracket2(a,b,d,fa,fb,fd)
|
||||
B = fbracket1(a,b,fa,fb)
|
||||
if A == 0:
|
||||
return a - fa/B
|
||||
if A*fa > 0:
|
||||
r = a
|
||||
else:
|
||||
r = b
|
||||
|
||||
for i in range(k):
|
||||
r = r - B*r/(B + A*(2*r - a - b))
|
||||
return r
|
||||
|
||||
# Inverse cubic interpolation evaluated at 0 (modified Aitken-Neville interpolation)
|
||||
def ipzero(a, b, c, d, fa, fb, fc, fd):
|
||||
Q11 = (c-d)*fc/(fd-fc)
|
||||
Q21 = (b-c)*fb/(fc-fb)
|
||||
Q31 = (a-b)*fa/(fb-fa)
|
||||
D21 = (b-c)*fc/(fc-fb)
|
||||
D31 = (a-b)*fb/(fb-fa)
|
||||
Q22 = (D21-Q11)*fb/(fd-fb)
|
||||
Q32 = (D31-Q21)*fa/(fc-fa)
|
||||
D32 = (D31-Q21)*fc/(fc-fa)
|
||||
Q33 = (D32-Q22)*fa/(fd-fa)
|
||||
return a + Q31 + Q32 + Q33
|
||||
|
||||
def TOMS748_solve1(f, a, b):
|
||||
mu = 0.5
|
||||
fa, fb = f(a), f(b)
|
||||
c = a - fa/fbracket1(a, b, fa, fb) # 4.1.1 secant method
|
||||
fc = f(c)
|
||||
a, b, d, fa, fb, fd = bracket(a, b, c, fa, fb, fc) # 4.1.2
|
||||
e = d
|
||||
fe = fd
|
||||
# ---
|
||||
for n in range(2,10): # 4.1.3
|
||||
if n == 2 or (fa == fb or fb == fd or fd == fe):
|
||||
c = NewtonQuadratic(a, b, d, fa, fb, fd, 2)
|
||||
else:
|
||||
c = ipzero(a, b, d, e, fa, fb, fd, fe)
|
||||
if (c-a)*(c-b) >= 0:
|
||||
c = NewtonQuadratic(a, b, d, fa, fb, fd, 2)
|
||||
# ---
|
||||
fc = f(c)
|
||||
a, b, dbar, fa, fb, fdbar = bracket(a, b, c, fa, fb, fc) # 4.1.4
|
||||
# ---
|
||||
if fabs(fa) < fabs(fb): # 4.1.5
|
||||
u = a
|
||||
fu = fa
|
||||
else:
|
||||
u = b
|
||||
fu = fb
|
||||
# ---
|
||||
c = u - 2*fu/fbracket1(a, b, fa, fb) # 4.1.6
|
||||
# ---
|
||||
if fabs(c - u) > 0.5*(b - a): # 4.1.7
|
||||
c = 0.5*(b + a)
|
||||
# ---
|
||||
fc = f(c)
|
||||
a, b, dhat, fa, fb, fdhat = bracket(a, b, c, fa, fb, fc) # 4.1.8
|
||||
# ---
|
||||
if b - a < mu*(b - a): # 4.1.9
|
||||
d = dhat
|
||||
e = dbar
|
||||
fd = fdhat
|
||||
fe = fdbar
|
||||
else:
|
||||
e = dhat
|
||||
fe = fdhat
|
||||
c = 0.5*(a+b)
|
||||
fc = f(c)
|
||||
a, b, d, fa, fb, fd = bracket(a, b, c, fa, fb, fc)
|
||||
|
||||
# TEST
|
||||
f = lambda E : E - 0.5*sin(E) - 0.3
|
||||
a, b, c, d = 0, 1, 0.3, 1.2
|
||||
fa, fb, fc, fd = f(a), f(b), f(c), f(d)
|
||||
|
||||
print(fbracket1(a, b, fa, fb))
|
||||
print(fbracket2(a, b, d, fa, fb, fd))
|
||||
print(bracket(a, b, c, fa, fb, fc))
|
||||
print(NewtonQuadratic(a, b, d, fa, fb, fd, 2))
|
||||
print(ipzero(a, b, c, d, fa, fb, fc, fd))
|
||||
|
||||
# solution using bracket only :
|
||||
print('bracket only')
|
||||
for i in range(50):
|
||||
c = (a+b)/2
|
||||
fc = f(c)
|
||||
a, b, d, fa, fb, fd = bracket(a, b, c, fa, fb, fc)
|
||||
if fabs(b-a) < 1e-12:
|
||||
break
|
||||
print(i)
|
||||
|
||||
print((a,b), (a+b)/2, b-a)
|
||||
|
||||
print('Newton with derivative')
|
||||
df = lambda E : 1 - 0.5*cos(E)
|
||||
x = 0.5
|
||||
for i in range(50):
|
||||
delta = f(x)/df(x)
|
||||
x = x - delta
|
||||
if fabs(delta) < 1e-12:
|
||||
break
|
||||
print(i)
|
||||
print(x)
|
||||
|
||||
print('TOMS748_solve1 only')
|
||||
def fct1(E):
|
||||
print("x = %20.15f" % E)
|
||||
return E - 0.5*sin(E) - 0.3
|
||||
|
||||
TOMS748_solve1(fct1, 0, 1)
|
||||
Loading…
Add table
Reference in a new issue