// MAUS WARNING: THIS IS LEGACY CODE. /* This file is part of MAUS: http://micewww.pp.rl.ac.uk/projects/maus * * MAUS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MAUS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MAUS. If not, see . * */ #include #include #include #include #include "gsl/gsl_sf_gamma.h" #include "gsl/gsl_sf_pow_int.h" #include "gsl/gsl_odeiv.h" #include "gsl/gsl_errno.h" #include "Interface/MathUtils.hh" #include "Utils/Exception.hh" #include "Interface/STLUtils.hh" // Use // d^n E/dx^n = a_n1m1 F(n1) g(m1) + a_n2m1m2 F(n2) g(m1)g(m2)+... // where double Enge::GetEnge(double x, int n) const { std::vector< std::vector > qt = GetQIndex(n); std::vector g; double e(0.); for (size_t i = 0; i < qt.size(); ++i) { double ei(qt[i][0]); for (size_t j = 1; j < qt[i].size(); ++j) { if (j > g.size()) g.push_back(GN(x, j-1)); ei *= gsl_sf_pow_int(g[j-1], qt[i][j]); } if (ei != ei) ei = 0; // div 0, usually g == 0 and index < 0 e += ei; } return e; } // h = a_0+a_1 (x/w)+a_2 (x/w)^2+a_3 (x/w)^3+...+a_m (x/w)^m // h^(n) = d^nh/dx^n = sum^m_{i=n} a_i x^{i-n}/w^i i!/n! double Enge::HN(double x, int n) const { double hn = 0; // optimise by precalculating factor for (unsigned int i = n; i <_a.size(); i++) hn += _a[i]/gsl_sf_pow_int(_lambda, i)*gsl_sf_pow_int(x, i-n)* static_cast(gsl_sf_fact(i)) /static_cast(gsl_sf_fact(i-n)); return hn; } // g = 1+exp(h) // g^(n) = d^ng/dx^n double Enge::GN(double x, int n) const { if (n == 0) return 1+exp(HN(x, 0)); // special case std::vector hn(n+1); for (int i = 0; i <= n; i++) hn[i] = HN(x, i); double exp_h0 = exp(hn[0]); double gn = 0; for (size_t i = 0; i < _h[n].size(); ++i) { double gnj = _h[n][i][0]*exp_h0; for (size_t j = 1; j < _h[n][i].size(); ++j) gnj *= gsl_sf_pow_int(hn[j], _h[n][i][j]); gn += gnj; } return gn; } // _q[i][j][k]; urk, 3d vector // i indexes the derivative of f; // j indexes the element in f derivative // k indexes the derivative of g // this will quickly become grotesque std::vector< std::vector< std::vector > > Enge::_q; std::vector< std::vector< std::vector > > Enge::_h; void Enge::SetEngeDiffIndices(size_t n) { if (_q.size() == 0) { _q.push_back(std::vector< std::vector >(1, std::vector(3)) ); _q[0][0][0] = +1; // f_0 = 1*g^(-1) _q[0][0][1] = -1; _q[0][0][2] = 0; } for (size_t i = _q.size(); i < n+1; ++i) { _q.push_back(std::vector< std::vector >() ); for (size_t j = 0; j < _q[i-1].size(); ++j) { size_t k_max = _q[i-1][j].size(); std::vector new_vec(_q[i-1][j]); // derivative of g^-n0 = -n0*g^(-n0-1)*g(1) new_vec[0] *= new_vec[1]; // alpha *= g(0) power new_vec[1] -= 1; // g(0) power -= 1 new_vec[2] += 1; // g(1) power += 1 _q[i].push_back(new_vec); for (size_t k = 2; k < k_max; ++k) { // 0 is alpha; 1 is g(0) // derivative of g(k)^nk = nk g(k+1) g(k)^(nk-1) if (_q[i-1][j][k] > 0) { std::vector new_vec(_q[i-1][j]); if ( k == k_max-1 ) new_vec.push_back(0); // need enough coefficients new_vec[0] *= new_vec[k]; new_vec[k] -= 1; new_vec[k+1] += 1; _q[i].push_back(new_vec); } } } } if (_h.size() == 0) { // first one is special case (1+e^h dealt with explicitly) _h.push_back(std::vector< std::vector >()); // second is (1*e^h h'^1) _h.push_back(std::vector< std::vector >()); _h[1].push_back(std::vector(2, 1)); } for (size_t i = _h.size(); i < n+1; ++i) { _h.push_back(std::vector< std::vector >()); for (size_t j = 0; j < _h[i-1].size(); ++j) { // d/dx k0 e^g g(1)^k1 ... g(n)^kn ... = k0 e^g g(1)^(k1+1) ... g(n)^kn // + SUM_n k0 kn e^g ... g(n)^(kn-1) g(n-1) std::vector new_vec(_h[i-1][j]); new_vec[1] += 1; _h[i].push_back(new_vec); for (size_t k = 1; k <_h[i-1][j].size(); ++k) { if (_h[i-1][j][k] > 0) { std::vector new_vec(_h[i-1][j]); if (k == _h[i-1][j].size()-1) new_vec.push_back(0); new_vec[0] *= new_vec[k]; new_vec[k] -= 1; new_vec[k+1] += 1; _h[i].push_back(new_vec); } } } _h[i] = MathUtils::CompactVector(_h[i]); } } std::vector< std::vector< std::vector > > Tanh::_tdi; Tanh::Tanh(double x0, double lambda, int max_index) : _x0(x0), _lambda(lambda) { SetTanhDiffIndices(max_index); } double Tanh::GetTanh(double x, int n) const { if (n == 0) return tanh((x+_x0)/_lambda); double t = 0; double lam_n = gsl_sf_pow_int(_lambda, n); double tanh_x = tanh((x+_x0)/_lambda); for (size_t i = 0; i < _tdi[n].size(); i++) t += 1./lam_n*static_cast(_tdi[n][i][0]) *gsl_sf_pow_int(tanh_x, _tdi[n][i][1]); return t; } double Tanh::GetNegTanh(double x, int n) const { if (n == 0) return tanh((x-_x0)/_lambda); double t = 0; double lam_n = gsl_sf_pow_int(_lambda, n); double tanh_x = tanh((x-_x0)/_lambda); for (size_t i = 0; i < _tdi[n].size(); i++) t += 1./lam_n*static_cast(_tdi[n][i][0]) *gsl_sf_pow_int(tanh_x, _tdi[n][i][1]); return t; } double Tanh::GetDoubleTanh(double x, int n) const { return (GetTanh(x, n)-GetNegTanh(x, n))/2.; } void Tanh::SetTanhDiffIndices(size_t n) { if (_tdi.size() == 0) { _tdi.push_back(std::vector< std::vector >(1, std::vector(2))); _tdi[0][0][0] = 1; // 1*tanh(x) - third index is redundant _tdi[0][0][1] = 1; } for (size_t i = _tdi.size(); i < n+1; ++i) { _tdi.push_back(std::vector< std::vector >()); for (size_t j = 0; j < _tdi[i-1].size(); ++j) { if (_tdi[i-1][j][1] != 0) { std::vector new_vec(_tdi[i-1][j]); new_vec[0] *= _tdi[i-1][j][1]; new_vec[1] -= 1; _tdi[i].push_back(new_vec); } if (_tdi[i-1][j][1] != 0) { std::vector new_vec(_tdi[i-1][j]); new_vec[0] *= -_tdi[i-1][j][1]; new_vec[1] += 1; _tdi[i].push_back(new_vec); } } _tdi[i] = MathUtils::CompactVector(_tdi[i]); } } std::vector< std::vector > Tanh::GetTanhDiffIndices(size_t n) { SetTanhDiffIndices(n); return _tdi[n]; } bool MathUtils::GreaterThan(std::vector v1, std::vector v2) { size_t n1(v1.size()), n2(v2.size()); for (size_t i = 0; i < n1 && i < n2; ++i) { if (v1[n1-1-i] > v2[n2-1-i]) return true; if (v1[n1-1-i] < v2[n2-1-i]) return false; } return false; } std::vector< std::vector > MathUtils::CompactVector( std::vector< std::vector > vec) { // first sort the list std::sort(vec.begin(), vec.end(), GreaterThan); // now look for n = n+1 for (size_t j = 0; j < vec.size()-1; ++j) { while (j < vec.size()-1 && STLUtils::IterableEquality( vec[j].begin()+1, vec[j].end(), vec[j+1].begin()+1, vec[j+1].end()) ) { vec[j][0] += vec[j+1][0]; vec.erase(vec.begin()+j+1); } } return vec; }