Go to the documentation of this file.00001 #ifndef OPENTISSUE_CORE_MATH_OPTIMIZATION_PROJECTED_GAUSS_SEIDEL_H
00002 #define OPENTISSUE_CORE_MATH_OPTIMIZATION_PROJECTED_GAUSS_SEIDEL_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/math/big/big_types.h>
00013 #include <OpenTissue/core/math/optimization/optimization_constants.h>
00014 #include <OpenTissue/core/math/optimization/optimization_relative_convergence.h>
00015 #include <OpenTissue/core/math/optimization/optimization_absolute_convergence.h>
00016 #include <OpenTissue/core/math/big/big_prod_row.h>
00017
00018 #include <OpenTissue/core/math/math_value_traits.h>
00019 #include <OpenTissue/core/math/math_is_number.h>
00020 #include <cmath>
00021 #include <stdexcept>
00022 #include <cassert>
00023
00024 namespace OpenTissue
00025 {
00026 namespace math
00027 {
00028 namespace optimization
00029 {
00030
00090 template < typename T, typename bound_function_type>
00091 inline void projected_gauss_seidel(
00092 ublas::compressed_matrix<T> const & A
00093 , ublas::vector<T> const & b
00094 , bound_function_type const & l
00095 , bound_function_type const & u
00096 , boost::numeric::ublas::vector<T> & x
00097 , size_t const & max_iterations
00098 , T const & absolute_tolerance
00099 , T const & relative_tolerance
00100 , T const & stagnation_tolerance
00101 , size_t & status
00102 , size_t & iteration
00103 , T & accuracy
00104 , T & relative_accuracy
00105 , ublas::vector<T> * profiling = 0
00106 )
00107 {
00108 using std::fabs;
00109 using std::min;
00110 using std::max;
00111
00112 typedef ublas::vector<T> vector_type;
00113 typedef typename vector_type::size_type size_type;
00114 typedef T real_type;
00115 typedef OpenTissue::math::ValueTraits<T> value_traits;
00116
00117 static real_type const one_half = value_traits::one()/value_traits::two();
00118
00119 if(max_iterations <= 0)
00120 throw std::invalid_argument("max_iterations must be larger than zero");
00121
00122 if(absolute_tolerance < value_traits::zero() )
00123 throw std::invalid_argument("absolute_tolerance must be non-negative");
00124
00125 if(relative_tolerance < value_traits::zero() )
00126 throw std::invalid_argument("relative_tolerance must be non-negative");
00127
00128 if(stagnation_tolerance < value_traits::zero() )
00129 throw std::invalid_argument("stagnation_tolerance must be non-negative");
00130
00131 if(profiling == &x)
00132 throw std::logic_error("profiling must not point to x-vector");
00133
00134 if(profiling == &b)
00135 throw std::logic_error("profiling must not point to b-vector");
00136
00137 accuracy = value_traits::infinity();
00138 relative_accuracy = value_traits::infinity();
00139 iteration = 0;
00140 status = OK;
00141
00142 size_type m = b.size();
00143
00144 if(m==0)
00145 return;
00146
00147 if(x.size()<=0)
00148 throw std::invalid_argument("size of x-vector were zero");
00149
00150 if(profiling)
00151 {
00152 (*profiling).resize( max_iterations );
00153 (*profiling).clear();
00154 }
00155
00156
00157
00158 bool const compute_merit = profiling || (absolute_tolerance > value_traits::zero()) || (absolute_tolerance > value_traits::zero());
00159
00160 status = ITERATING;
00161
00162 for ( ;iteration < max_iterations; )
00163 {
00164 ++iteration;
00165
00166 real_type max_dx = value_traits::zero();
00167
00168 for (size_type i = 0; i < m; ++ i)
00169 {
00170 real_type l_i = l(x,i);
00171 real_type u_i = u(x,i);
00172
00173 assert(l_i<= value_traits::zero() || !"projected_gauss_seidel: lower limit was positive");
00174 assert(u_i>= value_traits::zero() || !"projected_gauss_seidel: upper limit was negative");
00175
00176 real_type y_i = b(i) + OpenTissue::math::big::prod_row(A,x,i);
00177
00178 real_type const A_ii = A(i,i);
00179
00180 assert(A_ii> value_traits::zero() || A_ii<value_traits::zero() || !"projected_gauss_seidel: diagonal entry is zero?");
00181
00182 real_type const old_x = x(i);
00183 real_type const x_tmp = - (y_i / A_ii) + old_x;
00184
00185 assert(is_number(x_tmp) || !"projected_gauss_seidel: not a number encountered");
00186
00187 real_type const x_i = (x_tmp < l_i) ? l_i : ( (x_tmp > u_i) ? u_i : x_tmp );
00188
00189 assert(is_number(x_i) || !"projected_gauss_seidel: not a number encountered");
00190
00191 x(i) = x_i;
00192
00193 max_dx = max( max_dx, fabs( x_i - old_x ) );
00194 }
00195
00196
00197 if(max_dx < stagnation_tolerance)
00198 {
00199 status = STAGNATION;
00200 return;
00201 }
00202
00203
00204 if( compute_merit )
00205 {
00206 real_type const old_accuracy = accuracy;
00207 accuracy = value_traits::zero();
00208 for (size_type i = 0; i < m; ++ i)
00209 {
00210 real_type const l_i = l(x,i);
00211 real_type const u_i = u(x,i);
00212 real_type const y_i = b(i) + OpenTissue::math::big::prod_row(A,x,i);
00213 real_type const x_i = x(i);
00214 real_type const h_i = max( x_i - u_i, min( x_i - l_i, y_i ) );
00215 accuracy += h_i*h_i;
00216 }
00217 accuracy *= one_half;
00218
00219 if(profiling)
00220 (*profiling)(iteration-1) = accuracy;
00221
00222 if( absolute_convergence( accuracy, absolute_tolerance) )
00223 {
00224 status = ABSOLUTE_CONVERGENCE;
00225 return;
00226 }
00227
00228 if( relative_convergence(old_accuracy, accuracy, relative_tolerance) )
00229 {
00230 status = RELATIVE_CONVERGENCE;
00231 return;
00232 }
00233 }
00234 }
00235 }
00236
00237 }
00238 }
00239 }
00240
00241
00242 #endif