ampsci
High-precision calculations for one- and two-valence atomic 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 =
303 (last - first + b * std::log(last / first)) / (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
424template <typename T>
425T variance(std::vector<T> vec, std::size_t dof = 0) {
426 assert(dof < vec.size());
427 const auto xbar = mean(vec);
428 T sum{0};
429 for (const auto &x : vec) {
430 const auto del = x - xbar;
431 sum += del * del;
432 }
433 return sum / T(vec.size() - dof);
434}
435
437template <typename T>
438T sdev(std::vector<T> vec, std::size_t dof = 0) {
439 return std::sqrt(variance(vec, dof));
440}
441
443template <typename T>
444T sem(std::vector<T> vec, std::size_t dof = 0) {
445 return sdev(vec, dof) / std::sqrt(T(vec.size()));
446}
447
448//==============================================================================
449//==============================================================================
451namespace overloads {
452
454template <typename T>
455std::vector<T> &operator+=(std::vector<T> &a, const std::vector<T> &b) {
456 // The following allows this to work for types that can't be default constructed
457 const auto smaller_size = std::min(a.size(), b.size());
458 if (a.size() < b.size())
459 a.insert(a.end(), b.begin() + long(a.size()), b.end());
460 for (auto i = 0ul; i < smaller_size; ++i) {
461 a[i] += b[i];
462 }
463 return a;
464}
465template <typename T>
466std::vector<T> operator+(std::vector<T> a, const std::vector<T> &b) {
467 return a += b;
468}
469// and subtraction
470template <typename T>
471std::vector<T> &operator-=(std::vector<T> &a, const std::vector<T> &b) {
472 const auto size = std::max(a.size(), b.size());
473 a.resize(size);
474 for (auto i = 0ul; i < b.size(); ++i) {
475 a[i] -= b[i];
476 }
477 return a;
478}
479template <typename T>
480std::vector<T> operator-(std::vector<T> a, const std::vector<T> &b) {
481 return a -= b;
482}
483
484// Provide scalar multiplication
485template <typename T, typename U>
486std::vector<T> &operator*=(std::vector<T> &v, U x) {
487 if (x != U{1}) {
488 for (auto &v_i : v) {
489 v_i *= x;
490 }
491 }
492 return v;
493}
494template <typename T, typename U>
495std::vector<T> operator*(std::vector<T> v, U x) {
496 return v *= x;
497}
498template <typename T, typename U>
499std::vector<T> operator*(U x, std::vector<T> v) {
500 return v *= x;
501}
502
503// Provide scalar devision
504template <typename T, typename U>
505std::vector<T> &operator/=(std::vector<T> &v, U x) {
506 if (x != U{1}) {
507 for (auto &v_i : v) {
508 v_i /= x;
509 }
510 }
511 return v;
512}
513template <typename T, typename U>
514std::vector<T> operator/(std::vector<T> v, U x) {
515 return v /= x;
516}
517
518// Provide scalar addition
519template <typename T, typename U>
520std::vector<T> &operator+=(std::vector<T> &v, U x) {
521 if (x != U{0}) {
522 for (auto &v_i : v) {
523 v_i += x;
524 }
525 }
526 return v;
527}
528template <typename T, typename U>
529std::vector<T> operator+(std::vector<T> v, U x) {
530 return v += x;
531}
532template <typename T, typename U>
533std::vector<T> operator+(U x, std::vector<T> v) {
534 return v += x;
535}
536// Provide scalar subtraction
537template <typename T, typename U>
538std::vector<T> &operator-=(std::vector<T> &v, U x) {
539 if (x != U{0}) {
540 for (auto &v_i : v) {
541 v_i -= x;
542 }
543 }
544 return v;
545}
546template <typename T, typename U>
547std::vector<T> operator-(std::vector<T> v, U x) {
548 return v -= x;
549}
550template <typename T, typename U>
551std::vector<T> operator-(U x, std::vector<T> v) {
552 v *= U{-1};
553 return v += x;
554}
555
556// Provide scalar devision, vector in denominator
557template <typename T, typename U>
558std::vector<T> operator/(U x, std::vector<T> v) {
559 for (auto &v_i : v) {
560 v_i = x / v_i;
561 }
562 return v;
563}
564
566template <typename T>
567std::vector<T> &operator*=(std::vector<T> &a, const std::vector<T> &b) {
568 const auto min_size = std::min(a.size(), b.size());
569 for (std::size_t i = 0; i < min_size; ++i) {
570 a[i] *= b[i];
571 }
572 for (std::size_t i = min_size; i < a.size(); ++i) {
573 a[i] = 0.0;
574 }
575 if (a.size() < b.size())
576 a.resize(b.size());
577 return a;
578}
580template <typename T>
581std::vector<T> operator*(std::vector<T> a, const std::vector<T> &b) {
582 return a *= b;
583}
584
586template <typename T>
587std::vector<T> &operator/=(std::vector<T> &a, const std::vector<T> &b) {
588 assert(a.size() == b.size());
589 for (std::size_t i = 0; i < a.size(); ++i) {
590 a[i] /= b[i];
591 }
592 return a;
593}
595template <typename T>
596std::vector<T> operator/(std::vector<T> a, const std::vector<T> &b) {
597 return a /= b;
598}
599
600} // namespace overloads
601
602} // namespace qip
std::vector< T > & operator+=(std::vector< T > &a, const std::vector< T > &b)
Provide addition of two vectors:
Definition Vector.hpp:455
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:444
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: .
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:438
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 using two-pass method: . dof is degrees of freedom; for sample variance dof = 1.
Definition Vector.hpp:425
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