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