Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2015-2023 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : #ifndef __PLUMED_tools_LoopUnroller_h 23 : #define __PLUMED_tools_LoopUnroller_h 24 : 25 : namespace PLMD { 26 : 27 : /** 28 : \ingroup TOOLBOX 29 : Utiliy class for loop unrolling. 30 : 31 : Many c++ compilers do not unroll small loops such as those 32 : used in the PLMD::Vector and PLMD::Tensor classes. 33 : This class provides methods to perform basic vector 34 : operations with unrolled loops. The methods work on double* 35 : so that they can be used in principles in other places of the code, 36 : but they are designed to be used in PLMD::Vector and PLMD::Tensor . 37 : 38 : In case in the future we see that some compiler better optimize explicit loops, 39 : it should be easy to replace the methods here with loops. Alternatively, 40 : we could provide two paths using a cpp macro (e.g. __PLUMED_UNROLL_LOOPS or so). 41 : 42 : All the methods for class LoopUnroller<n> act on n elements. 43 : Implementation is made using template metaprogramming, that is: 44 : - LoopUnroller<1>::xxx acts on the element [0] of the array. 45 : - LoopUnroller<n>::xxx calls LoopUnroller<n-1>::xxx then acts on element [n-1] of the array. 46 : 47 : Here xxx is any of the methods of the class. 48 : 49 : */ 50 : template<unsigned n> 51 : class LoopUnroller { 52 : public: 53 : /// Set to zero. 54 : /// Same as `for(unsigned i=0;i<n;i++) d[i]=0.0;` 55 : static void _zero(double*d); 56 : /// Add v to d. 57 : /// Same as `for(unsigned i=0;i<n;i++) d[i]+=v[i];` 58 : static void _add(double*d,const double*v); 59 : /// Subtract v from d. 60 : /// Same as `for(unsigned i=0;i<n;i++) d[i]-=v[i];` 61 : static void _sub(double*d,const double*v); 62 : /// Multiply d by s. 63 : /// Same as `for(unsigned i=0;i<n;i++) d[i]*=s;` 64 : static void _mul(double*d,const double s); 65 : /// Set d to -v. 66 : /// Same as `for(unsigned i=0;i<n;i++) d[i]=-v[i];` 67 : static void _neg(double*d,const double*v); 68 : /// Squared modulo of d; 69 : /// Same as `r=0.0; for(unsigned i=0;i<n;i++) r+=d[i]*d[i]; return r;` 70 : static double _sum2(const double*d); 71 : /// Dot product of d and v 72 : /// Same as `r=0.0; for(unsigned i=0;i<n;i++) r+=d[i]*v[i]; return r;` 73 : static double _dot(const double*d,const double*v); 74 : }; 75 : 76 : template<unsigned n> 77 1857921970 : void LoopUnroller<n>::_zero(double*d) { 78 1133358977 : LoopUnroller<n-1>::_zero(d); 79 1857921970 : d[n-1]=0.0; 80 1857921970 : } 81 : 82 : template<> 83 : inline 84 : void LoopUnroller<1>::_zero(double*d) { 85 725127515 : d[0]=0.0; 86 : } 87 : 88 : template<unsigned n> 89 4385992438 : void LoopUnroller<n>::_add(double*d,const double*a) { 90 2373307643 : LoopUnroller<n-1>::_add(d,a); 91 4385992438 : d[n-1]+=a[n-1]; 92 4385992438 : } 93 : 94 : template<> 95 : inline 96 : void LoopUnroller<1>::_add(double*d,const double*a) { 97 2012684795 : d[0]+=a[0]; 98 : } 99 : 100 : template<unsigned n> 101 4202975496 : void LoopUnroller<n>::_sub(double*d,const double*a) { 102 2249533734 : LoopUnroller<n-1>::_sub(d,a); 103 4202975496 : d[n-1]-=a[n-1]; 104 4202975496 : } 105 : 106 : template<> 107 : inline 108 : void LoopUnroller<1>::_sub(double*d,const double*a) { 109 1953441762 : d[0]-=a[0]; 110 : } 111 : 112 : template<unsigned n> 113 5519797986 : void LoopUnroller<n>::_mul(double*d,const double s) { 114 3004691937 : LoopUnroller<n-1>::_mul(d,s); 115 5519797986 : d[n-1]*=s; 116 5519797986 : } 117 : 118 : template<> 119 : inline 120 : void LoopUnroller<1>::_mul(double*d,const double s) { 121 2515106049 : d[0]*=s; 122 : } 123 : 124 : template<unsigned n> 125 414906482 : void LoopUnroller<n>::_neg(double*d,const double*a ) { 126 208205425 : LoopUnroller<n-1>::_neg(d,a); 127 414906482 : d[n-1]=-a[n-1]; 128 414906482 : } 129 : 130 : template<> 131 : inline 132 : void LoopUnroller<1>::_neg(double*d,const double*a) { 133 206701057 : d[0]=-a[0]; 134 : } 135 : 136 : template<unsigned n> 137 2205960584 : double LoopUnroller<n>::_sum2(const double*d) { 138 2205960584 : return LoopUnroller<n-1>::_sum2(d)+d[n-1]*d[n-1]; 139 : } 140 : 141 : template<> 142 : inline 143 : double LoopUnroller<1>::_sum2(const double*d) { 144 1102420741 : return d[0]*d[0]; 145 : } 146 : 147 : template<unsigned n> 148 540766018 : double LoopUnroller<n>::_dot(const double*d,const double*v) { 149 540766018 : return LoopUnroller<n-1>::_dot(d,v)+d[n-1]*v[n-1]; 150 : } 151 : 152 : template<> 153 : inline 154 : double LoopUnroller<1>::_dot(const double*d,const double*v) { 155 264281153 : return d[0]*v[0]; 156 : } 157 : 158 : } 159 : 160 : #endif