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 : //the typename is the second parameter argument so that it can be deduced 51 : template<unsigned n> 52 : class LoopUnroller { 53 : public: 54 : /// Set to zero. 55 : /// Same as `for(unsigned i=0;i<n;i++) d[i]=0.0;` 56 : template<typename T> 57 : static constexpr void _zero(T*d) noexcept; 58 : /// copy the content o v into v 59 : /// Same as `for(unsigned i=0;i<n;i++) d[i]=v[i];` 60 : template<typename T,typename TT> 61 : static constexpr void _copy(T*d,TT const*v) noexcept; 62 : /// Add v to d. 63 : /// Same as `for(unsigned i=0;i<n;i++) d[i]+=v[i];` 64 : template<typename T,typename TT> 65 : static constexpr void _add(T*d,TT const*v) noexcept; 66 : /// Subtract v from d. 67 : /// Same as `for(unsigned i=0;i<n;i++) d[i]-=v[i];` 68 : template<typename T,typename TT> 69 : static constexpr void _sub(T*d,TT const*v) noexcept; 70 : /// Multiply d by s. 71 : /// Same as `for(unsigned i=0;i<n;i++) d[i]*=s;` 72 : template<typename T,typename TT> 73 : static constexpr void _mul(T*d,TT const s) noexcept; 74 : /// Set d to -v. 75 : /// Same as `for(unsigned i=0;i<n;i++) d[i]=-v[i];` 76 : template<typename T,typename TT> 77 : static constexpr void _neg(T*d,TT const*v) noexcept; 78 : /// Squared modulo of d; 79 : /// Same as `r=0.0; for(unsigned i=0;i<n;i++) r+=d[i]*d[i]; return r;` 80 : template<typename T> 81 : static constexpr T _sum2(T const*d) noexcept; 82 : /// Dot product of d and v 83 : /// Same as `r=0.0; for(unsigned i=0;i<n;i++) r+=d[i]*v[i]; return r;` 84 : template<typename T,typename TT> 85 : static constexpr T _dot(T const*d,TT const*v) noexcept; 86 : }; 87 : 88 : template<unsigned n> 89 : template<typename T> 90 : constexpr void LoopUnroller<n>::_zero(T*d) noexcept { 91 : if constexpr (n>1) { 92 : LoopUnroller<n-1>::_zero(d); 93 : } 94 91811603 : d[n-1]=T(0); 95 : } 96 : 97 : template<unsigned n> 98 : template<typename T,typename TT> 99 : constexpr void LoopUnroller<n>::_copy(T*d,TT const*v) noexcept { 100 : if constexpr (n==1) { 101 10243480 : d[0]=v[0]; 102 : } else { 103 : LoopUnroller<n-1>::_copy(d,v); 104 12999027 : d[n-1]=v[n-1]; 105 : } 106 : } 107 : 108 : template<unsigned n> 109 : template<typename T, typename TT> 110 194884753 : constexpr void LoopUnroller<n>::_add(T*d,TT const*a) noexcept { 111 : if constexpr (n>1) { 112 191280783 : LoopUnroller<n-1>::_add(d,a); 113 : } 114 855927476 : d[n-1]+=a[n-1]; 115 194884753 : } 116 : 117 : template<unsigned n> 118 : template<typename T, typename TT> 119 222652113 : constexpr void LoopUnroller<n>::_sub(T*d,TT const*a) noexcept { 120 : if constexpr (n>1) { 121 205512363 : LoopUnroller<n-1>::_sub(d,a); 122 : } 123 1234230135 : d[n-1]-=a[n-1]; 124 222652113 : } 125 : 126 : template<unsigned n> 127 : template<typename T, typename TT> 128 346824563 : constexpr void LoopUnroller<n>::_mul(T*d,TT const s) noexcept { 129 : if constexpr (n>1) { 130 268489730 : LoopUnroller<n-1>::_mul(d,s); 131 : } 132 1317425574 : d[n-1]*=s; 133 346824563 : } 134 : 135 : template<unsigned n> 136 : template<typename T, typename TT> 137 9516933 : constexpr void LoopUnroller<n>::_neg(T*d,TT const*a ) noexcept { 138 : if constexpr (n>1) { 139 7897682 : LoopUnroller<n-1>::_neg(d,a); 140 : } 141 26449899 : d[n-1]=-a[n-1]; 142 9516933 : } 143 : 144 : template<unsigned n> 145 : template<typename T> 146 : constexpr T LoopUnroller<n>::_sum2(T const*d) noexcept { 147 : if constexpr (n>1) { 148 1120135149 : return LoopUnroller<n-1>::_sum2(d)+d[n-1]*d[n-1]; 149 : } else { 150 785234731 : return d[0]*d[0]; 151 : } 152 : } 153 : template<unsigned n> 154 : template<typename T, typename TT> 155 141913330 : constexpr T LoopUnroller<n>::_dot(T const*d,TT const*v) noexcept { 156 : if constexpr (n>1) { 157 377211732 : return LoopUnroller<n-1>::_dot(d,v)+d[n-1]*v[n-1]; 158 : } else { 159 264277052 : return d[0]*v[0]; 160 : } 161 : } 162 : } //PLMD 163 : #endif //__PLUMED_tools_LoopUnroller_h