1st c++ draft

This commit is contained in:
Jérôme 2019-04-04 00:06:16 +02:00
parent 7b2a9a6d4a
commit d83a997804
15 changed files with 3276 additions and 142 deletions

46
.gitignore vendored
View file

@ -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

File diff suppressed because it is too large Load diff

41
cpp/Makefile Normal file
View 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
View file

@ -0,0 +1,3 @@
CppQuickStart
=============
"Empty" project for a quicker start writing something in c++.

167
cpp/TOMS748.hpp Normal file
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,4 @@
// Let Catch provide main()
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>

BIN
cpp/test/run Normal file

Binary file not shown.

30
cpp/test/utils_test.hpp Normal file
View 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
View 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

View file

@ -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
View 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)

View file

@ -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)