MiniTensor Version of the Day
Loading...
Searching...
No Matches
MiniTensor_Scalar.h
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MiniTensor Package
4//
5// Copyright 2016 NTESS and the MiniTensor contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#if !defined(MiniTensor_Scalar_h)
11#define MiniTensor_Scalar_h
12
13#include <type_traits>
14
15#include "MiniTensor_config.h"
16#include "MiniTensor_Traits.h"
17#include "Sacado.hpp"
18
19namespace minitensor {
20
23
24//
25// abs function
26//
27template<typename T>
29T
30abs(T const & a);
31
32//
33//swap function
34//
35template<typename T>
37void
38swap(T & a, T & b);
39
40//
41// max function
42//
43template<typename T>
45T
46max(T const & a, T const & b);
47
48//
49// max function
50//
51template<typename T>
53T
54min(T const & a,T const & b);
55
59template<typename T>
61int
62sgn(T const & s);
63
67template<typename T>
69T
70copysign(T const & a, T const & b);
71
78template<typename T>
80typename Sacado::ScalarType<T>::type
82
89template<typename T>
91typename Sacado::ScalarType<T>::type
93
97template<typename T>
100num_digits();
101
105template<>
107Index
109
113template<>
115Index
117
121template<typename T>
123typename Sacado::ScalarType<T>::type
124tau();
125
129template <typename T> typename Sacado::ScalarType<T>::type random();
130
134template <typename T> typename Sacado::ScalarType<T>::type random_uniform();
135
139template <typename T> typename Sacado::ScalarType<T>::type random_normal();
140
144using std::enable_if;
145using std::is_same;
146using Sacado::ScalarType;
147
148template<typename T>
150void
151fill_AD(
152 typename enable_if<is_same<T, typename ScalarType<T>::type>::value, T>::type & x,
153 typename ScalarType<T>::type const c);
154
155template<typename T>
157void
158fill_AD(
159 typename enable_if<!is_same<T, typename ScalarType<T>::type>::value, T>::type & x,
160 typename ScalarType<T>::type const c);
161
165template<typename T>
167T
168integer_power(T const & X, Index const exponent);
169
173template<typename T>
175T
176integer_root(T const & x, Index const root);
177
181template<typename T>
183T
184kronecker_delta(Index const i, Index const j);
185
189template<typename T>
191T
192kronecker_delta(Index const i, Index const j, Index const k);
193
197template<typename T>
199T
200kronecker_delta(Index const i, Index const j, Index const k, Index const l);
201
205template<typename T>
207T
208levi_civita(Index const i, Index const j);
209
213template<typename T>
215T
216levi_civita(Index const i, Index const j, Index const k);
217
221template<typename T>
223T
224levi_civita(Index const i, Index const j, Index const k, Index const l);
225
226} // namespace minitensor
227
228#include <cfloat>
229#include <cmath>
230#include <cstdlib>
231#include <limits>
232
233namespace minitensor {
234
235//
236//
237//
241template<typename T>
243T
244abs(T const & a)
245{
246 return a < T(0) ? -a : a;
247}
248
249//
250//
251//
255template<typename T>
257void
258swap(T & a, T & b)
259{
260 // Guard against the same memory location.
261 if (&a == &b) return;
262
263 auto const c = a;
264 a = b;
265 b = c;
266}
267
268//
269//
270//
274template<typename T>
276T
277max(T const & a, T const & b)
278{
279 return a > b ? a : b;
280}
281
282//
283//
284//
288template<typename T>
290T
291min(T const & a, T const & b)
292{
293 return a < b ? a : b;
294}
295
296//
297// Sign function
298//
299template <typename T>
301int
302sgn(T const & s)
303{
304 return (T(0) < s) - (s < T(0));
305}
306
307//
308// Copysign function
309//
310template<typename T>
312T
313copysign(T const & a, T const & b)
314{
315 return b >= 0 ? T(std::abs(a)) : T(-std::abs(a));
316}
317
318//
319// NaN function. Necessary to choose the proper underlying NaN
320// for non-floating-point types.
321// Assumption: non-floating-point types have a typedef that
322// determines the underlying floating-point type.
323//
324template<typename T>
326typename Sacado::ScalarType<T>::type
328{
329 using S = typename Sacado::ScalarType<T>::type;
330 return std::numeric_limits<S>::quiet_NaN();
331}
332
333//
334// Machine epsilon function. Necessary to choose the proper underlying
335// machine epsilon for non-floating-point types.
336// Assumption: non-floating-point types have a typedef that
337// determines the underlying floating-point type.
338//
339template<typename T>
341typename Sacado::ScalarType<T>::type
343{
344 using S = typename Sacado::ScalarType<T>::type;
345 return std::numeric_limits<S>::epsilon();
346}
347
348//
349// Number of digits for integer types.
350//
351template<typename T>
353Index
355{
356 return 0;
357}
358
359template<>
363{
364 return INDEX_SIZE;
365}
366
367template<>
371{
372 return LONG_INDEX_SIZE;
373}
374
375//
376// The circle constant
377//
378template<typename T>
380typename Sacado::ScalarType<T>::type
382{
383 using S = typename Sacado::ScalarType<T>::type;
384 return static_cast<S>(
385 6.283185307179586476925286766559005768394338798750211641949889185
386 );
387}
388
389//
390// Uniform random number generation on [-1,1].
391//
392template <typename T> typename Sacado::ScalarType<T>::type random() {
393 using S = typename Sacado::ScalarType<T>::type;
394 S const rnd = static_cast<S>(std::rand()) / static_cast<S>(RAND_MAX);
395 return S(-1.0) + S(2.0) * rnd;
396}
397
398//
399// Uniform [0,1] random number generation.
400//
401template <typename T> typename Sacado::ScalarType<T>::type random_uniform() {
402 using S = typename Sacado::ScalarType<T>::type;
403 return static_cast<S>(0.5 * random<S>() + 0.5);
404}
405
406//
407// Normal N(0,1) random number generation.
408//
409template <typename T> typename Sacado::ScalarType<T>::type random_normal() {
410 using S = typename Sacado::ScalarType<T>::type;
411
412 S const
413 R = random_uniform<S>();
414
415 S const
416 Theta = tau<S>() * random_uniform<S>();
417 return static_cast<S>(std::sqrt(-2.0 * std::log(R)) * cos(Theta));
418}
419
420//
421// Fill in all levels of AD with specified constant.
422//
426template<typename T>
428void
430 typename enable_if<is_same<T, typename ScalarType<T>::type>::value, T>::type & x,
431 typename ScalarType<T>::type const c)
432{
433 x = c;
434 return;
435}
436
440template<typename T>
442void
444 typename enable_if<!is_same<T, typename ScalarType<T>::type>::value, T>::type & x,
445 typename ScalarType<T>::type const c)
446{
447 auto const
448 order = x.size();
449
450 // No AD info. Nothing to do.
451 if (order == 0) return;
452
453 using S = typename Sacado::ValueType<T>::type;
454
455 for (auto i = 0; i < order; ++i) {
456 fill_AD<S>(x.fastAccessDx(i), c);
457 }
458
459 return;
460}
461
462//
463// Compute a non-negative integer power by binary manipulation.
464//
465template<typename T>
467T
468integer_power(T const & X, Index const exponent)
469{
470 if (X == 0 || X == 1) return X;
471
472 switch (exponent) {
473 default:
474 break;
475 case 0:
476 return 1;
477 case 1:
478 return X;
479 case 2:
480 return X * X;
481 case 3:
482 return X * X * X;
483 case 4:
484 {
485 T const Y = X * X;
486 return Y * Y;
487 }
488 }
489
490 Index const
491 rightmost_bit = 1;
492
493 Index const
494 number_digits = num_digits<Index>();
495
496 Index const
497 leftmost_bit = rightmost_bit << (number_digits - 1);
498
499 Index
500 t = 0;
501
502 for (Index j = 0; j < number_digits; ++j) {
503
504 if (((exponent << j) & leftmost_bit) != 0) {
505
506 t = number_digits - j - 1;
507 break;
508
509 }
510
511 }
512
513 T
514 P = X;
515
516 Index
517 i = 0;
518
519 Index
520 m = exponent;
521
522 while ((m & rightmost_bit) == 0) {
523 P = P * P;
524 ++i;
525 m = m >> 1;
526 }
527
528 T
529 Y = P;
530
531 for (Index j = i + 1; j <= t; ++j) {
532 P = P * P;
533
534 if (((exponent >> j) & rightmost_bit) != 0) {
535 Y = Y * P;
536 }
537 }
538
539 return Y;
540}
541
542//
543// Integer nth root
544//
545template<typename T>
547T
548integer_root(T const & x, Index const root)
549{
550 assert(root > 0);
551 assert(x >= 0);
552
553 if (root == 1 || x == 0 || x == 1) return x;
554
555 T hi = 1;
556
557 while (integer_power(hi, root) < x) hi *= 2;
558
559 T lo = hi / 2;
560
561 while (hi - lo > 1) {
562 T mid = (lo + hi) / 2;
563 T t = integer_power(mid, root);
564 if (t < x) lo = mid;
565 else if (x < t) hi = mid;
566 else return mid;
567 }
568
569 if (integer_power(hi, root) == x) return hi;
570
571 return lo;
572}
573
574//
575// Utility for Kronecker delta in 2D
576//
577template<typename T>
579T
580kronecker_delta(Index const i, Index const j)
581{
582 assert(0 <= i && i < 2);
583 assert(0 <= j && j < 2);
584
585 if (i == j) return T(1);
586
587 return T(0);
588}
589
590//
591// Utility for Kronecker delta in 3D
592//
593template<typename T>
595T
596kronecker_delta(Index const i, Index const j, Index const k)
597{
598 assert(0 <= i && i < 3);
599 assert(0 <= j && j < 3);
600 assert(0 <= k && k < 3);
601
602 if (i == j && j == k) return T(1);
603
604 return T(0);
605}
606
607//
608// Utility for Kronecker delta in 4D
609//
610template<typename T>
612T
613kronecker_delta(Index const i, Index const j, Index const k, Index const l)
614{
615 assert(0 <= i && i < 4);
616 assert(0 <= j && j < 4);
617 assert(0 <= k && k < 4);
618 assert(0 <= l && l < 4);
619
620 if (i == j && j == k && k == l) return T(1);
621
622 return T(0);
623}
624
625//
626// Utility for Levi-Civita/permutation/alternating symbol in 2D
627//
628template<typename T>
630T
631levi_civita(Index const i, Index const j)
632{
633 assert(0 <= i && i < 2);
634 assert(0 <= j && j < 2);
635
636 if (i == 0 && j == 1) return T(1);
637
638 if (i == 1 && j == 0) return T(-1);
639
640 return T(0);
641}
642
643//
644// Utility for Levi-Civita/permutation/alternating symbol in 3D
645//
646template<typename T>
648T
649levi_civita(Index const i, Index const j, Index const k)
650{
651 assert(0 <= i && i < 3);
652 assert(0 <= j && j < 3);
653 assert(0 <= k && k < 3);
654
655 if (i == 0 && j == 1 && k == 2) return T(1);
656 if (i == 1 && j == 2 && k == 0) return T(1);
657 if (i == 2 && j == 0 && k == 1) return T(1);
658
659 if (i == 2 && j == 1 && k == 0) return T(-1);
660 if (i == 0 && j == 2 && k == 1) return T(-1);
661 if (i == 1 && j == 0 && k == 2) return T(-1);
662
663 return T(0);
664}
665
666//
667// Utility for Levi-Civita/permutation/alternating symbol in 4D
668//
669template<typename T>
671T
672levi_civita(Index const i, Index const j, Index const k, Index const l)
673{
674 assert(0 <= i && i < 4);
675 assert(0 <= j && j < 4);
676 assert(0 <= k && k < 4);
677 assert(0 <= l && l < 4);
678
679 if (i == 0 && j == 1 && k == 2 && l == 3) return T(1);
680 if (i == 1 && j == 2 && k == 3 && l == 0) return T(1);
681 if (i == 2 && j == 3 && k == 0 && l == 1) return T(1);
682 if (i == 3 && j == 0 && k == 1 && l == 2) return T(1);
683
684 if (i == 3 && j == 2 && k == 1 && l == 0) return T(-1);
685 if (i == 0 && j == 3 && k == 2 && l == 1) return T(-1);
686 if (i == 1 && j == 0 && k == 3 && l == 2) return T(-1);
687 if (i == 2 && j == 1 && k == 0 && l == 3) return T(-1);
688
689 return T(0);
690}
691
693} // namespace minitensor
694
695#endif // MiniTensor_Scalar_h
#define KOKKOS_INLINE_FUNCTION
KOKKOS_INLINE_FUNCTION Index num_digits< Index >()
uint32_t Index
Indexing type.
KOKKOS_INLINE_FUNCTION Sacado::ScalarType< T >::type machine_epsilon()
KOKKOS_INLINE_FUNCTION Index num_digits< LongIndex >()
KOKKOS_INLINE_FUNCTION Sacado::ScalarType< T >::type not_a_number()
KOKKOS_INLINE_FUNCTION T kronecker_delta(Index const i, Index const j)
constexpr Index INDEX_SIZE
constexpr Index LONG_INDEX_SIZE
Sacado::ScalarType< T >::type random()
KOKKOS_INLINE_FUNCTION Sacado::ScalarType< T >::type tau()
KOKKOS_INLINE_FUNCTION int sgn(T const &s)
KOKKOS_INLINE_FUNCTION T abs(T const &a)
KOKKOS_INLINE_FUNCTION void swap(T &a, T &b)
KOKKOS_INLINE_FUNCTION void fill_AD(typename enable_if< is_same< T, typename ScalarType< T >::type >::value, T >::type &x, typename ScalarType< T >::type const c)
Sacado::ScalarType< T >::type random_uniform()
KOKKOS_INLINE_FUNCTION Index num_digits()
Sacado::ScalarType< T >::type random_normal()
KOKKOS_INLINE_FUNCTION T min(T const &a, T const &b)
KOKKOS_INLINE_FUNCTION T integer_power(T const &X, Index const exponent)
KOKKOS_INLINE_FUNCTION T integer_root(T const &x, Index const root)
KOKKOS_INLINE_FUNCTION T max(T const &a, T const &b)
KOKKOS_INLINE_FUNCTION T copysign(T const &a, T const &b)
KOKKOS_INLINE_FUNCTION T levi_civita(Index const i, Index const j)