aboutsummaryrefslogtreecommitdiffstats
path: root/astro/cosmo_calc/adapt_trapezoid.h
blob: 35d22b4ae923c19d8414dfe3ed15548ea043869b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#ifndef ADAPT_TRAPEZOID_H
#define ADAPT_TRAPEZOID_H
#include <list>
#include <utility>
#include <cassert>
//#include <iostream>

//using namespace std;

template<typename T1,typename T2,typename T3>
class triple
{
 public:
  T1 first;
  T2 second;
  T3 third;
  triple(T1 x1,T2 x2,T3 x3)
    :first(x1),second(x2),third(x3)
    {
    }
};


template<typename T1,typename T2,typename T3>
triple<T1,T2,T3> make_triple(T1 x1,T2 x2,T3 x3)
{
  return triple<T1,T2,T3>(x1,x2,x3);
}

template <typename T>
T trapezoid(T (*fun)(T),T x1,T x2,T err_limit)
{
  int n=256;
  T result;
  const int max_division=24;
  T old_value=0;
  for(int i=1;i<max_division;i++)
    {
      result=0.;
      n*=2;
      T step=(x2-x1)/n;
      for(int j=0;j<n;j++)
	{
	  result+=(fun(x1+(j+1)*step)+fun(x1+j*step))*step/T(2.);
	}
      old_value-=result;
      old_value=old_value<0?-old_value:old_value;
      if(old_value<err_limit)
	{
	  return result;
	}
      old_value=result;
    }
}


template <typename T>
T adapt_trapezoid(T (*fun)(T),T x1,T x2,T err_limit)
{
  //  const err_limit=.001;
  typedef triple<T,T,bool> interval;
  /*T for interval type,
    bool for state trur for still to be updated,
    false for do not need to be updated
   */
  std::list<interval> interval_list;
  T current_sum=((fun(x1)+fun(x2))/2.*(x2-x1));
  interval_list.push_back(make_triple(x1,current_sum,true));
  interval_list.push_back(make_triple(x2,(T)0.,true));
  bool int_state=1;
  int n_intervals=1;
  while(int_state)
    {
      //std::cout<<n_intervals<<std::endl;
      int_state=0;
      typename std::list<interval>::iterator i1=interval_list.begin();
      typename std::list<interval>::iterator i2=interval_list.begin();
      i2++;
      for(;i2!=interval_list.end();i1++,i2=i1,i2++)
	{
	  //cout<<i1->first<<"\t"<<i2->first<<endl;
	  //assert(i2->first>i1->first);
	  if(i1->third)
	    {
	      interval new_interval((i1->first+i2->first)/2,0,true);
	      
	      T sum1,sum2;
	      sum1=(fun(new_interval.first)+fun(i1->first))/2*(new_interval.first-i1->first);
	      sum2=(fun(new_interval.first)+fun(i2->first))/2*(i2->first-new_interval.first);
	      new_interval.second=sum2;
	      T err;
	      err=i1->second-sum1-sum2;
	      err=err<0?-err:err;

	      if(err>err_limit/n_intervals)
		{
		  i1->second=sum1;
		  interval_list.insert(i2,new_interval);
		  n_intervals++;
		  if(n_intervals>10e6)
		    {
		      
		      break;
		    }
		}
	      else
		{
		  i1->third=false;
		}
	      int_state=1;
	    }
	}
      
    }
  T result=0;
  for(typename std::list<interval>::iterator i=interval_list.begin();i!=interval_list.end();i++)
    {
      result+=i->second;
    }
  return result;
}

#endif
//end of the file