ampsci
c++ program for high-precision atomic structure calculations of single-valence systems
Loading...
Searching...
No Matches
Vector.hpp
1#pragma once
2#include "qip/Methods.hpp"
3#include <algorithm>
4#include <array>
5#include <cassert>
6#include <cmath>
7#include <type_traits>
8#include <utility>
9#include <vector>
10
11namespace qip {
12
13// Uses "no non-const ref" rule. Pass by pointer means modify value
14
15//==============================================================================
17template <typename T, typename... Args>
18std::vector<T> merge(std::vector<T> first, const std::vector<T> &second,
19 const Args &...rest) {
20 first.insert(first.end(), second.cbegin(), second.cend());
21 if constexpr (sizeof...(rest) == 0) {
22 return first;
23 } else {
24 return merge(std::move(first), rest...);
25 }
26}
27//==============================================================================
32template <typename T>
33auto compare(const std::vector<T> &first, const std::vector<T> &second) {
34 static_assert(
35 std::is_arithmetic_v<T>,
36 "In compare(std::vector<T>, std::vector<T>), T must be arithmetic");
37 assert(first.size() == second.size()); //?
38
39 auto it1 = first.cbegin();
40 auto it2 = second.cbegin();
41 auto largest_delta = static_cast<T>(0);
42 auto largest_at = first.cend();
43 for (; it1 != first.cend(); ++it1, ++it2) {
44 const auto delta = *it1 - *it2;
45 if (std::abs(delta) > std::abs(largest_delta)) {
46 largest_delta = delta;
47 largest_at = it1;
48 }
49 }
50 return std::make_pair(largest_delta, largest_at);
51}
52
57template <typename T, typename U, typename Func>
58auto compare(const std::vector<T> &first, const std::vector<U> &second,
59 Func &func) {
60 assert(first.size() == second.size()); //?
61
62 auto it1 = first.cbegin();
63 auto it2 = second.cbegin();
64 auto largest_eps = 0.0; // double always?
65 auto largest_at = first.cend();
66 for (; it1 != first.cend(); ++it1, ++it2) {
67 const auto eps = func(*it1, *it2);
68 if (std::abs(eps) > std::abs(largest_eps)) {
69 largest_eps = eps;
70 largest_at = it1;
71 }
72 }
73 return std::make_pair(largest_eps, largest_at);
74}
75
81template <typename T>
82auto compare_eps(const std::vector<T> &first, const std::vector<T> &second) {
83 static_assert(
84 std::is_floating_point_v<T>,
85 "In compare_eps(std::vector<T>, std::vector<T>), T must be floating pt");
86 assert(first.size() == second.size()); //?
87
88 auto it1 = first.cbegin();
89 auto it2 = second.cbegin();
90 auto largest_eps = static_cast<T>(0);
91 auto largest_at = first.cend();
92 for (; it1 != first.cend(); ++it1, ++it2) {
93 const auto eps = (*it1 - *it2) / (*it2); // may be +/-inf, fine
94 if (std::abs(eps) > std::abs(largest_eps)) {
95 largest_eps = eps;
96 largest_at = it1;
97 }
98 }
99 return std::make_pair(largest_eps, largest_at);
100}
101
102//==============================================================================
105template <typename T, typename... Args>
106void add(std::vector<T> *first, const std::vector<T> &second,
107 const Args &...rest) {
108 // re-sizes vector:
109 if (first->size() < second.size())
110 first->resize(second.size());
111
112 for (std::size_t i = 0; i < second.size(); ++i) {
113 (*first)[i] += second[i];
114 }
115 if constexpr (sizeof...(rest) != 0)
116 add(first, rest...);
117}
118
122template <typename T, typename... Args>
123[[nodiscard]] std::vector<T>
124add(std::vector<T> first, const std::vector<T> &second, const Args &...rest) {
125 add(&first, second, rest...);
126 return first;
127}
128
129// template <typename T, typename... Args>
130// [[nodiscard]] std::vector<T> add(std::vector<T> first, const Args &... rest)
131// {
132// add(&first, rest...);
133// return first;
134// }
135
136//==============================================================================
140template <typename T, typename... Args>
141void multiply(std::vector<T> *first, const std::vector<T> &second,
142 const Args &...rest) {
143
144 static_assert(std::is_arithmetic_v<T>,
145 "In multiply(std::vector<T>...) : T must be arithmetic");
146
147 // {1,1,1,1}*{1,1} -> {1,1,0,0}; re-sizes vector
148 const auto size = std::min(first->size(), second.size());
149 if (first->size() < second.size())
150 first->resize(second.size());
151
152 for (std::size_t i = 0; i < size; ++i) {
153 (*first)[i] *= second[i];
154 }
155 for (std::size_t i = size; i < first->size(); ++i) {
156 (*first)[i] = static_cast<T>(0);
157 }
158 if constexpr (sizeof...(rest) != 0)
159 multiply(first, rest...);
160}
161
165template <typename T, typename... Args>
166[[nodiscard]] std::vector<T> multiply(std::vector<T> first,
167 const std::vector<T> &second,
168 const Args &...rest) {
169 multiply(&first, second, rest...);
170 return first;
171}
172
173//==============================================================================
178template <typename F, typename T, typename... Args>
179void compose(const F &func, std::vector<T> *first, const std::vector<T> &second,
180 const Args &...rest) {
181 // XXX Comiple=-time constraints on f! Must be T(T,T)!
182
183 if (first->size() < second.size())
184 first->resize(second.size());
185
186 for (std::size_t i = 0; i < second.size(); ++i) {
187 (*first)[i] = func((*first)[i], second[i]);
188 }
189 for (std::size_t i = second.size(); i < first->size(); ++i) {
190 (*first)[i] = func((*first)[i], static_cast<T>(0));
191 }
192 if constexpr (sizeof...(rest) != 0)
193 compose(func, first, rest...);
194}
195
199template <typename F, typename T, typename... Args>
200[[nodiscard]] std::vector<T> compose(const F &func, std::vector<T> first,
201 const std::vector<T> &second,
202 const Args &...rest) {
203 compose(func, &first, second, rest...);
204 return first;
205}
206
207//==============================================================================
209template <typename T>
210void scale(std::vector<T> *vec, T x) {
211 static_assert(std::is_arithmetic_v<T>,
212 "In scale(std::vector<T>, T) : T must be arithmetic");
213 for (auto &v : *vec)
214 v *= x;
215}
216
218template <typename T>
219[[nodiscard]] std::vector<T> scale(std::vector<T> vec, T x) {
220 scale(&vec, x);
221 return vec;
222}
223
224//==============================================================================
231template <typename T = double, typename N = std::size_t>
232std::vector<T> uniform_range(T first, T last, N number) {
233 static_assert(std::is_arithmetic_v<T>,
234 "In uniform_range(T, T, N), T must be arithmetic");
235 static_assert(std::is_integral_v<N>,
236 "In uniform_range(T, T, N), N must be integral");
237 std::vector<T> range;
238 if (number == 0)
239 return range;
240 range.reserve(static_cast<std::size_t>(number));
241 range.push_back(first); // guarentee first is first
242 if (number <= 1)
243 return range;
244 const auto interval = static_cast<double>(last - first);
245 for (N i = 1; i < number - 1; ++i) {
246 const auto eps = static_cast<double>(i) / static_cast<double>(number - 1);
247 const auto value = static_cast<double>(first) + (eps * interval);
248 range.push_back(static_cast<T>(value));
249 }
250 range.push_back(last); // guarentee last is last
251 return range;
252}
253
260template <typename T = double, typename N = std::size_t>
261std::vector<T> logarithmic_range(T first, T last, N number) {
262 static_assert(std::is_arithmetic_v<T>,
263 "In logarithmic_range(T, T, N), T must be arithmetic");
264 static_assert(std::is_integral_v<N>,
265 "In logarithmic_range(T, T, N), N must be integral");
266
267 std::vector<T> range;
268 if (number == 0)
269 return range;
270 range.reserve(static_cast<std::size_t>(number));
271 range.push_back(first);
272 if (number <= 1)
273 return range;
274 const auto log_ratio =
275 std::log(static_cast<double>(last) / static_cast<double>(first));
276 for (N i = 1; i < number - 1; ++i) {
277 const auto eps = static_cast<double>(i) / static_cast<double>(number - 1);
278 const auto value = static_cast<double>(first) * std::exp(log_ratio * eps);
279 range.push_back(static_cast<T>(value));
280 }
281 range.push_back(last);
282 return range;
283}
284
290template <typename T = double, typename N = std::size_t>
291std::vector<T> loglinear_range(T first, T last, T b, N number) {
292 static_assert(std::is_floating_point_v<T>,
293 "In loglinear_range(T, T, T, N), T must be floating point");
294 static_assert(std::is_integral_v<N>,
295 "In loglinear_range(T, T, T, N), N must be integral");
296 assert(number >= 3);
297 assert(first > 0.0 && last > 0.0 && b > 0.0);
298
299 std::vector<T> range;
300 range.reserve(static_cast<std::size_t>(number));
301
302 const auto du = (last - first + b * std::log(last / first)) /
303 (static_cast<T>(number - 1));
304
305 auto next_r = [b](auto u1, auto r_guess) {
306 // Solve eq. u = r + b ln(r) to find r
307 // Use Newtons method
308 // => f(r) = r + b ln(r) - u = 0
309 // dfdr = b(1/r + 1/(b+r))
310 const auto f_u = [b, u1](double tr) { return tr + b * std::log(tr) - u1; };
311 const auto dr = 0.1 * r_guess;
312 const auto delta_targ = r_guess * 1.0e-18;
313 const auto [ri, delta_r] = qip::Newtons(f_u, r_guess, delta_targ, dr, 30);
314 return ri;
315 };
316
317 auto u = first + b * std::log(first);
318 range.push_back(first);
319 for (N i = 1; i < number - 1; ++i) {
320 u += du;
321 range.push_back(next_r(u, range.back()));
322 }
323 range.push_back(last);
324
325 return range;
326}
327
328//==============================================================================
330template <typename T, typename... Args>
331constexpr auto multiply_at(std::size_t i, const T &first, const Args &...rest) {
332 // assert(first.size() < i);
333 if constexpr (sizeof...(rest) == 0) {
334 return first[i];
335 } else {
336 return first[i] * multiply_at(i, rest...);
337 }
338}
339
341template <typename T, typename... Args>
342constexpr auto inner_product(const T &first, const Args &...rest) {
343 auto res = multiply_at(0, first, rest...);
344 for (std::size_t i = 1; i < first.size(); ++i) {
345 res += multiply_at(i, first, rest...);
346 }
347 return res;
348}
349
350template <typename T, typename... Args>
351auto inner_product_sub(std::size_t p0, std::size_t pinf, const T &first,
352 const Args &...rest) {
353 auto res = decltype(first[0])(0);
354 for (std::size_t i = p0; i < pinf; ++i) {
355 res += multiply_at(i, first, rest...);
356 }
357 return res;
358}
359
360//==============================================================================
361template <typename F, typename T>
362T apply_to(const F &func, T list) {
363 for (auto &l : list) {
364 l = func(l);
365 }
366 return list;
367}
368
369//==============================================================================
372template <typename T, typename Func>
373std::vector<T> select_if(const std::vector<T> &in, Func condition) {
374 std::vector<T> out;
375 for (const auto &el : in) {
376 if (condition(el)) {
377 out.push_back(el);
378 }
379 }
380 return out;
381}
382
384template <typename T, typename Func>
385void insert_into_if(const std::vector<T> &in, std::vector<T> *inout,
386 Func condition) {
387 for (const auto &el : in) {
388 if (condition(el)) {
389 inout->push_back(el);
390 }
391 }
392}
393
394//==============================================================================
396template <typename T>
397std::vector<T> reverse(std::vector<T> in) {
398
399 std::size_t i = 0ul;
400 std::size_t f = in.size();
401
402 while (f > i + 1) {
403 std::swap(in[i], in[f - 1]);
404 ++i;
405 --f;
406 }
407
408 return in;
409}
410
411//==============================================================================
413template <typename T>
414T mean(std::vector<T> vec) {
415 T sum{0};
416 for (const auto &x : vec) {
417 sum += x;
418 }
419 return sum / T(vec.size());
420}
421
423template <typename T>
424T variance(std::vector<T> vec, std::size_t dof = 0) {
425 assert(dof < vec.size());
426 const auto xbar = mean(vec);
427 T sum{0};
428 for (const auto &x : vec) {
429 const auto del = x - xbar;
430 sum += del * del;
431 }
432 return sum / T(vec.size() - dof);
433}
434
436template <typename T>
437T sdev(std::vector<T> vec, std::size_t dof = 0) {
438 return std::sqrt(variance(vec, dof));
439}
440
442template <typename T>
443T sem(std::vector<T> vec, std::size_t dof = 0) {
444 return sdev(vec, dof) / std::sqrt(T(vec.size()));
445}
446
447//==============================================================================
448//==============================================================================
450namespace overloads {
451
453template <typename T>
454std::vector<T> &operator+=(std::vector<T> &a, const std::vector<T> &b) {
455 // The following allows this to work for types that can't be default constructed
456 const auto smaller_size = std::min(a.size(), b.size());
457 if (a.size() < b.size())
458 a.insert(a.end(), b.begin() + long(a.size()), b.end());
459 for (auto i = 0ul; i < smaller_size; ++i) {
460 a[i] += b[i];
461 }
462 return a;
463}
464template <typename T>
465std::vector<T> operator+(std::vector<T> a, const std::vector<T> &b) {
466 return a += b;
467}
468// and subtraction
469template <typename T>
470std::vector<T> &operator-=(std::vector<T> &a, const std::vector<T> &b) {
471 const auto size = std::max(a.size(), b.size());
472 a.resize(size);
473 for (auto i = 0ul; i < b.size(); ++i) {
474 a[i] -= b[i];
475 }
476 return a;
477}
478template <typename T>
479std::vector<T> operator-(std::vector<T> a, const std::vector<T> &b) {
480 return a -= b;
481}
482
483// Provide scalar multiplication
484template <typename T, typename U>
485std::vector<T> &operator*=(std::vector<T> &v, U x) {
486 if (x != U{1}) {
487 for (auto &v_i : v) {
488 v_i *= x;
489 }
490 }
491 return v;
492}
493template <typename T, typename U>
494std::vector<T> operator*(std::vector<T> v, U x) {
495 return v *= x;
496}
497template <typename T, typename U>
498std::vector<T> operator*(U x, std::vector<T> v) {
499 return v *= x;
500}
501
502// Provide scalar devision
503template <typename T, typename U>
504std::vector<T> &operator/=(std::vector<T> &v, U x) {
505 if (x != U{1}) {
506 for (auto &v_i : v) {
507 v_i /= x;
508 }
509 }
510 return v;
511}
512template <typename T, typename U>
513std::vector<T> operator/(std::vector<T> v, U x) {
514 return v /= x;
515}
516
517// Provide scalar addition
518template <typename T, typename U>
519std::vector<T> &operator+=(std::vector<T> &v, U x) {
520 if (x != U{0}) {
521 for (auto &v_i : v) {
522 v_i += x;
523 }
524 }
525 return v;
526}
527template <typename T, typename U>
528std::vector<T> operator+(std::vector<T> v, U x) {
529 return v += x;
530}
531template <typename T, typename U>
532std::vector<T> operator+(U x, std::vector<T> v) {
533 return v += x;
534}
535// Provide scalar subtraction
536template <typename T, typename U>
537std::vector<T> &operator-=(std::vector<T> &v, U x) {
538 if (x != U{0}) {
539 for (auto &v_i : v) {
540 v_i -= x;
541 }
542 }
543 return v;
544}
545template <typename T, typename U>
546std::vector<T> operator-(std::vector<T> v, U x) {
547 return v -= x;
548}
549template <typename T, typename U>
550std::vector<T> operator-(U x, std::vector<T> v) {
551 v *= U{-1};
552 return v += x;
553}
554
555// Provide scalar devision, vector in denominator
556template <typename T, typename U>
557std::vector<T> operator/(U x, std::vector<T> v) {
558 for (auto &v_i : v) {
559 v_i = x / v_i;
560 }
561 return v;
562}
563
565template <typename T>
566std::vector<T> &operator*=(std::vector<T> &a, const std::vector<T> &b) {
567 const auto min_size = std::min(a.size(), b.size());
568 for (std::size_t i = 0; i < min_size; ++i) {
569 a[i] *= b[i];
570 }
571 for (std::size_t i = min_size; i < a.size(); ++i) {
572 a[i] = 0.0;
573 }
574 if (a.size() < b.size())
575 a.resize(b.size());
576 return a;
577}
579template <typename T>
580std::vector<T> operator*(std::vector<T> a, const std::vector<T> &b) {
581 return a *= b;
582}
583
585template <typename T>
586std::vector<T> &operator/=(std::vector<T> &a, const std::vector<T> &b) {
587 assert(a.size() == b.size());
588 for (std::size_t i = 0; i < a.size(); ++i) {
589 a[i] /= b[i];
590 }
591 return a;
592}
594template <typename T>
595std::vector<T> operator/(std::vector<T> a, const std::vector<T> &b) {
596 return a /= b;
597}
598
599} // namespace overloads
600
601} // namespace qip
std::vector< T > & operator+=(std::vector< T > &a, const std::vector< T > &b)
Provide addition of two vectors:
Definition Vector.hpp:454
qip library: A collection of useful functions
Definition Array.hpp:9
void add(std::vector< T > *first, const std::vector< T > &second, const Args &...rest)
Adds any number of vectors, in place (modifies first vector). Must be of same type....
Definition Vector.hpp:106
std::vector< T > logarithmic_range(T first, T last, N number)
Produces a logarithmicly*(see below) distributed range of values between [first,last] with number ste...
Definition Vector.hpp:261
auto compare_eps(const std::vector< T > &first, const std::vector< T > &second)
Compares values of two arithmetic vectors of the same type and length, relative to second value....
Definition Vector.hpp:82
void compose(const F &func, std::vector< T > *first, const std::vector< T > &second, const Args &...rest)
Composes any number of vectors, in place (modifies first vector), using the provided function....
Definition Vector.hpp:179
void scale(std::vector< T > *vec, T x)
In-place scalar multiplication of std::vector - types must match.
Definition Vector.hpp:210
T sem(std::vector< T > vec, std::size_t dof=0)
Standard deviation: sqrt(variance)
Definition Vector.hpp:443
std::vector< T > select_if(const std::vector< T > &in, Func condition)
Creates a subset of a vector, whose element match condition. By copy. condition must have function si...
Definition Vector.hpp:373
T mean(std::vector< T > vec)
Mean: xbar = \sum_i x_i / N.
Definition Vector.hpp:414
std::pair< Real, Real > Newtons(Function f, Real x, Real delta_target=Real{1.0e-6}, Real dx=Real{0.01}, unsigned it_limit=250)
Solve f(x) = 0 for x using Newtons method. Returns root + error estimate/.
Definition Methods.hpp:41
std::vector< T > merge(std::vector< T > first, const std::vector< T > &second, const Args &...rest)
Merges a number of vectors: {a,b,c},{d,e},{f} -> {a,b,c,d,e,f}.
Definition Vector.hpp:18
std::vector< T > uniform_range(T first, T last, N number)
Produces a uniformly*(see below) distributed range of values between [first,last] with number steps....
Definition Vector.hpp:232
std::vector< T > reverse(std::vector< T > in)
Reverses a list.
Definition Vector.hpp:397
constexpr auto inner_product(const T &first, const Args &...rest)
Variadic inner product (v1,v2,...vn) : sum_i v1[i]*v2[i]*...vn[i].
Definition Vector.hpp:342
T sdev(std::vector< T > vec, std::size_t dof=0)
Standard deviation: sqrt(variance)
Definition Vector.hpp:437
void insert_into_if(const std::vector< T > &in, std::vector< T > *inout, Func condition)
Inserts elements from in into inout, if condition is met.
Definition Vector.hpp:385
void multiply(std::vector< T > *first, const std::vector< T > &second, const Args &...rest)
Multiplies any number of (arithmetic) vectors, in place (modifies first vector). Must be of same type...
Definition Vector.hpp:141
auto compare(const std::vector< T > &first, const std::vector< T > &second)
Directly compare two arithmetic vectors of the same type and length. Returns pair {delta,...
Definition Vector.hpp:33
T variance(std::vector< T > vec, std::size_t dof=0)
Variance: \sum_i (x_i-xbar)^2 / (N-dof)
Definition Vector.hpp:424
std::vector< T > loglinear_range(T first, T last, T b, N number)
Produces a Log-Linear distributed range of values between [first,last] with number steps....
Definition Vector.hpp:291
constexpr auto multiply_at(std::size_t i, const T &first, const Args &...rest)
first[i]*...rest[i] – used to allow inner_product
Definition Vector.hpp:331