1 #pragma once
2 // blas_l1.hpp: BLAS Level 1 functions
3 //
4 // Copyright (C) 2017-2021 Stillwater Supercomputing, Inc.
5 //
6 // This file is part of the universal numbers project, which is released under an MIT Open Source license.
7 #include <cmath>
8 #include <universal/math/math> // injection of native IEEE-754 math library functions into sw::universal namespace
9 #include <universal/number/posit/posit.hpp>
10 #include <universal/blas/vector.hpp>
11
12 namespace sw::universal::blas {
13
14 // 1-norm of a vector: sum of magnitudes of the vector elements, default increment stride is 1
15 template<typename Vector>
asum(size_t n,const Vector & x,size_t incx=1)16 typename Vector::value_type asum(size_t n, const Vector& x, size_t incx = 1) {
17 typename Vector::value_type sum = 0;
18 size_t ix;
19 for (ix = 0; ix < n; ix += incx) {
20 sum += (x[ix] < 0 ? -x[ix] : x[ix]);
21 }
22 return sum;
23 }
24
25 // sum of the vector elements, default increment stride is 1
26 template<typename Vector>
sum(const Vector & x)27 typename Vector::value_type sum(const Vector& x) {
28 typename Vector::value_type sum = 0;
29 size_t ix;
30 for (ix = 0; ix < size(x); ++ix) {
31 sum += x[ix];
32 }
33 return sum;
34 }
35
36 // a times x plus y
37 template<typename Scalar, typename Vector>
axpy(size_t n,Scalar a,const Vector & x,size_t incx,Vector & y,size_t incy)38 void axpy(size_t n, Scalar a, const Vector& x, size_t incx, Vector& y, size_t incy) {
39 size_t cnt, ix, iy;
40 for (cnt = 0, ix = 0, iy = 0; cnt < n && ix < size(x) && iy < size(y); ++cnt, ix += incx, iy += incy) {
41 y[iy] += a * x[ix];
42 }
43 }
44
45 // vector copy
46 template<typename Vector>
copy(size_t n,const Vector & x,size_t incx,Vector & y,size_t incy)47 void copy(size_t n, const Vector& x, size_t incx, Vector& y, size_t incy) {
48 size_t cnt, ix, iy;
49 for (cnt = 0, ix = 0, iy = 0; cnt < n && ix < size(x) && iy < size(y); ++cnt, ix += incx, iy += incy) {
50 y[iy] = x[ix];
51 }
52 }
53
54 // adapter for STL vectors
size(const std::vector<Scalar> & v)55 template<typename Scalar> auto size(const std::vector<Scalar>& v) { return v.size(); }
56
57 // dot product: the operator vector::x[index] is limited to uint32_t, so the arguments are limited to uint32_t as well
58 // The library does support arbitrary posit configuration conversions, but to simplify the
59 // behavior of the dot product, the element type of the vectors x and y are declared to be the same.
60 // TODO: investigate if the vector<> index is always a 32bit entity?
61 template<typename Vector>
dot(size_t n,const Vector & x,size_t incx,const Vector & y,size_t incy)62 typename Vector::value_type dot(size_t n, const Vector& x, size_t incx, const Vector& y, size_t incy) {
63 using value_type = typename Vector::value_type;
64 value_type sum_of_products = value_type(0);
65 size_t cnt, ix, iy;
66 for (cnt = 0, ix = 0, iy = 0; cnt < n && ix < size(x) && iy < size(y); ++cnt, ix += incx, iy += incy) {
67 sum_of_products += x[ix] * y[iy];
68 }
69 return sum_of_products;
70 }
71 // specialized dot product assuming constant stride
72 template<typename Vector>
dot(const Vector & x,const Vector & y)73 typename Vector::value_type dot(const Vector& x, const Vector& y) {
74 using value_type = typename Vector::value_type;
75 value_type sum_of_products = value_type(0);
76 size_t nx = size(x);
77 if (nx <= size(y)) {
78 for (size_t i = 0; i < nx; ++i) {
79 sum_of_products += x[i] * y[i];
80 }
81 }
82 return sum_of_products;
83 }
84
85 // rotation of points in the plane
86 template<typename Rotation, typename Vector>
rot(size_t n,Vector & x,size_t incx,Vector & y,size_t incy,Rotation c,Rotation s)87 void rot(size_t n, Vector& x, size_t incx, Vector& y, size_t incy, Rotation c, Rotation s) {
88 // x_i = c*x_i + s*y_i
89 // y_i = c*y_i - s*x_i
90 size_t cnt, ix, iy;
91 for (cnt = 0, ix = 0, iy = 0; cnt < n && ix < size(x) && iy < size(y); ++cnt, ix += incx, iy += incy) {
92 Rotation x_i = c * x[ix] + s * y[iy];
93 Rotation y_i = c * y[iy] - s * x[ix];
94 y[iy] = y_i;
95 x[ix] = x_i;
96 }
97 }
98
99 // compute parameters for a Givens rotation
100 template<typename T>
rotg(T & a,T & b,T & c,T & s)101 void rotg(T& a, T& b, T& c, T&s) {
102 // Given Cartesian coordinates (a,b) of a point, return parameters c,s,r, and z associated with the Givens rotation.
103 }
104
105 // scale a vector
106 template<typename Scalar, typename Vector>
scale(size_t n,Scalar alpha,Vector & x,size_t incx)107 void scale(size_t n, Scalar alpha, Vector& x, size_t incx) {
108 size_t cnt, ix;
109 for (cnt = 0, ix = 0; cnt < n && ix < size(x); ix += incx) {
110 x[ix] *= alpha;
111 }
112 }
113
114 // swap two vectors
115 template<typename Vector>
swap(size_t n,Vector & x,size_t incx,Vector & y,size_t incy)116 void swap(size_t n, Vector& x, size_t incx, Vector& y, size_t incy) {
117 size_t cnt, ix, iy;
118 for (cnt = 0, ix = 0, iy = 0; cnt < n && ix < size(x) && iy < size(y); ++cnt, ix += incx, iy += incy) {
119 typename Vector::value_type tmp = x[ix];
120 x[ix] = y[iy];
121 y[iy] = tmp;
122 }
123 }
124
125 // find the index of the element with maximum absolute value
126 template<typename Vector>
amax(size_t n,const Vector & x,size_t incx)127 size_t amax(size_t n, const Vector& x, size_t incx) {
128 typename Vector::value_type running_max = -INFINITY;
129 size_t ix, index;
130 for (ix = 0; ix < size(x); ix += incx) {
131 if (x[ix] > running_max) {
132 index = ix;
133 running_max = x[ix];
134 }
135 }
136 return index;
137 }
138
139 // find the index of the element with minimum absolute value
140 template<typename Vector>
amin(size_t n,const Vector & x,size_t incx)141 size_t amin(size_t n, const Vector& x, size_t incx) {
142 typename Vector::value_type running_min = INFINITY;
143 size_t ix, index;
144 for (ix = 0; ix < size(x); ix += incx) {
145 if (x[ix] < running_min) {
146 index = ix;
147 running_min = x[ix];
148 }
149 }
150 return index;
151 }
152
153 // absolute value of a complex number
154 template<typename T>
cabs(T z)155 T cabs(T z) {
156 }
157
158 // print a vector
159 template<typename Vector>
strided_print(std::ostream & ostr,size_t n,Vector & x,size_t incx=1)160 void strided_print(std::ostream& ostr, size_t n, Vector& x, size_t incx = 1) {
161 size_t cnt, ix;
162 for (cnt = 0, ix = 0; cnt < n && ix < size(x); ++cnt, ix += incx) {
163 cnt == 0 ? ostr << "[" << x[ix] : ostr << ", " << x[ix];
164 }
165 ostr << "]";
166 }
167
168 // norms
169
170 // L1-norm of a vector
171 template<typename Scalar>
normL1(const sw::universal::blas::vector<Scalar> & v)172 Scalar normL1(const sw::universal::blas::vector<Scalar>& v) {
173 using namespace sw::universal; // to specialize abs()
174 Scalar L1Norm{ 0 };
175 for (auto e : v) {
176 L1Norm += abs(e);
177 }
178 return L1Norm;
179 }
180
181 // L2-norm of a vector
182 template<typename Scalar>
normL2(const sw::universal::blas::vector<Scalar> & v)183 Scalar normL2(const sw::universal::blas::vector<Scalar>& v) {
184 Scalar L2Norm{ 0 };
185 for (auto e : v) {
186 L2Norm += e * e;
187 }
188 return sqrt(L2Norm);
189 }
190
191 // L3-norm of a vector
192 template<typename Scalar>
normL3(const sw::universal::blas::vector<Scalar> & v)193 Scalar normL3(const sw::universal::blas::vector<Scalar>& v) {
194 using namespace std;
195 using namespace sw::universal; // to specialize abs()
196 Scalar L3Norm{ 0 };
197 for (auto e : v) {
198 Scalar abse = abs(e);
199 L3Norm += abse * abse * abse;
200 }
201 return pow(L3Norm, Scalar(1) / Scalar(3));
202 }
203
204 // L4-norm of a vector
205 template<typename Scalar>
normL4(const sw::universal::blas::vector<Scalar> & v)206 Scalar normL4(const sw::universal::blas::vector<Scalar>& v) {
207 Scalar L4Norm{ 0 };
208 for (auto e : v) {
209 Scalar esqr = e * e;
210 L4Norm += esqr * esqr;
211 }
212 return pow(L4Norm, Scalar(1) / Scalar(4));
213 }
214
215 // Linf-norm of a vector
216 template<typename Scalar>
normLinf(const sw::universal::blas::vector<Scalar> & v)217 Scalar normLinf(const sw::universal::blas::vector<Scalar>& v) {
218 using namespace std;
219 using namespace sw::universal; // to specialize abs()
220 Scalar LinfNorm{ 0 };
221 for (auto e : v) {
222 LinfNorm = (abs(e) > LinfNorm) ? abs(e) : LinfNorm;
223 }
224 return LinfNorm;
225 }
226
227 template<typename Scalar>
norm(const sw::universal::blas::vector<Scalar> & v,int p)228 Scalar norm(const sw::universal::blas::vector<Scalar>& v, int p) {
229 using namespace std;
230 using namespace sw::universal; // to specialize pow() and abs()
231 Scalar norm{ 0 };
232 switch (p) {
233 case 0:
234 break; //should be the geometric mean
235 case 1:
236 norm = normL1(v);
237 break;
238 case 2:
239 norm = normL2(v);
240 break;
241 case 3:
242 norm = normL3(v);
243 break;
244 case 4:
245 norm = normL4(v);
246 break;
247 case std::numeric_limits<int>::max():
248 norm = normLinf(v);
249 break;
250 default:
251 {
252 for (auto e : v) {
253 norm += pow(abs(e), Scalar( p ));
254 }
255 norm = pow(norm, Scalar( 1 ) / Scalar( p ));
256 }
257 break;
258 }
259 return norm;
260 }
261
262 } // namespace sw::universal::blas
263
264 // specializations for STL vectors
265
266 template<typename Ty>
minValue(const std::vector<Ty> & samples)267 Ty minValue(const std::vector<Ty>& samples) {
268 typename std::vector<Ty>::const_iterator it = min_element(samples.begin(), samples.end());
269 return *it;
270 }
271
272 template<typename Ty>
maxValue(const std::vector<Ty> & samples)273 Ty maxValue(const std::vector<Ty>& samples) {
274 typename std::vector<Ty>::const_iterator it = max_element(samples.begin(), samples.end());
275 return *it;
276 }
277