Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2015-2019 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 1705483522 : void LoopUnroller<n>::_zero(double*d) {
78 984668479 : LoopUnroller<n-1>::_zero(d);
79 1705483522 : d[n-1]=0.0;
80 1705483522 : }
81 :
82 : template<>
83 : inline
84 : void LoopUnroller<1>::_zero(double*d) {
85 720815043 : d[0]=0.0;
86 : }
87 :
88 : template<unsigned n>
89 3054376334 : void LoopUnroller<n>::_add(double*d,const double*a) {
90 1641637147 : LoopUnroller<n-1>::_add(d,a);
91 3054376334 : d[n-1]+=a[n-1];
92 3054376334 : }
93 :
94 : template<>
95 : inline
96 : void LoopUnroller<1>::_add(double*d,const double*a) {
97 1412739187 : d[0]+=a[0];
98 : }
99 :
100 : template<unsigned n>
101 2542667716 : void LoopUnroller<n>::_sub(double*d,const double*a) {
102 1345711169 : LoopUnroller<n-1>::_sub(d,a);
103 2542667716 : d[n-1]-=a[n-1];
104 2542667716 : }
105 :
106 : template<>
107 : inline
108 : void LoopUnroller<1>::_sub(double*d,const double*a) {
109 1196956547 : d[0]-=a[0];
110 : }
111 :
112 : template<unsigned n>
113 3956775554 : void LoopUnroller<n>::_mul(double*d,const double s) {
114 2346161602 : LoopUnroller<n-1>::_mul(d,s);
115 3956775554 : d[n-1]*=s;
116 3956775554 : }
117 :
118 : template<>
119 : inline
120 : void LoopUnroller<1>::_mul(double*d,const double s) {
121 1610613952 : d[0]*=s;
122 : }
123 :
124 : template<unsigned n>
125 221541776 : void LoopUnroller<n>::_neg(double*d,const double*a ) {
126 110956582 : LoopUnroller<n-1>::_neg(d,a);
127 221541776 : d[n-1]=-a[n-1];
128 221541776 : }
129 :
130 : template<>
131 : inline
132 : void LoopUnroller<1>::_neg(double*d,const double*a) {
133 110585194 : d[0]=-a[0];
134 : }
135 :
136 : template<unsigned n>
137 1034155680 : double LoopUnroller<n>::_sum2(const double*d) {
138 1034155680 : 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 516518289 : return d[0]*d[0];
145 : }
146 :
147 : template<unsigned n>
148 330001000 : double LoopUnroller<n>::_dot(const double*d,const double*v) {
149 330001000 : 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 165000500 : return d[0]*v[0];
156 : }
157 :
158 : }
159 :
160 : #endif
|