From ad71175b991263ed8e12c3046f73b278dfc3aa14 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Sat, 21 Jul 2018 23:31:24 +0200
Subject: [PATCH] Improve slightly TinyVector and TinyMatrix implementations

- variadic input are cleaner
- use more constexpr and noexcept qualifiers

May improve slightly performances
---
 src/algebra/TinyMatrix.hpp | 100 ++++++++++++++++++-------------------
 src/algebra/TinyVector.hpp |  66 ++++++++++++------------
 2 files changed, 81 insertions(+), 85 deletions(-)

diff --git a/src/algebra/TinyMatrix.hpp b/src/algebra/TinyMatrix.hpp
index fb0f94ad0..29a5d6611 100644
--- a/src/algebra/TinyMatrix.hpp
+++ b/src/algebra/TinyMatrix.hpp
@@ -16,27 +16,25 @@ private:
   T m_values[N*N];
   static_assert((N>0),"TinyMatrix size must be strictly positive");
 
-  KOKKOS_INLINE_FUNCTION
-  size_t _index(const size_t& i, const size_t& j) const
+  KOKKOS_FORCEINLINE_FUNCTION
+  constexpr size_t _index(const size_t& i, const size_t& j) const noexcept
   {
     return std::move(i*N+j);
   }
 
-  void _unpackVariadicInput(const T& t)
-  {
-    m_values[N*N-1] = t;
-  }
-
   template <typename... Args>
-  void _unpackVariadicInput(const T& t, Args&&... args)
+  KOKKOS_FORCEINLINE_FUNCTION
+  constexpr void _unpackVariadicInput(const T& t, Args&&... args) noexcept
   {
     m_values[N*N-1-sizeof...(args)] = t;
-    this->_unpackVariadicInput(args...);
+    if constexpr (sizeof...(args) >0) {
+        this->_unpackVariadicInput(args...);
+      }
   }
 
 public:
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix operator-() const
+  constexpr TinyMatrix operator-() const
   {
     TinyMatrix opposed;
     for (size_t i=0; i<N*N; ++i) {
@@ -46,7 +44,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  friend TinyMatrix operator*(const T& t, const TinyMatrix& A)
+  constexpr friend TinyMatrix operator*(const T& t, const TinyMatrix& A)
   {
     TinyMatrix tA;
     for (size_t i=0; i<N*N; ++i) {
@@ -56,7 +54,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix& operator*=(const T& t)
+  constexpr TinyMatrix& operator*=(const T& t)
   {
     for (size_t i=0; i<N*N; ++i) {
       m_values[i] *= t;
@@ -65,7 +63,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix operator*(const TinyMatrix& B) const
+  constexpr TinyMatrix operator*(const TinyMatrix& B) const
   {
     const TinyMatrix& A = *this;
     TinyMatrix AB;
@@ -82,7 +80,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector<N,T> operator*(const TinyVector<N,T>& x) const
+  constexpr TinyVector<N,T> operator*(const TinyVector<N,T>& x) const
   {
     const TinyMatrix& A = *this;
     TinyVector<N,T> Ax;
@@ -97,7 +95,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  friend std::ostream& operator<<(std::ostream& os, const TinyMatrix& A)
+  constexpr friend std::ostream& operator<<(std::ostream& os, const TinyMatrix& A)
   {
     if constexpr(N==1) {
       os << A(0,0);
@@ -117,7 +115,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  bool operator==(const TinyMatrix& A) const
+  constexpr bool operator==(const TinyMatrix& A) const
   {
     for (size_t i=0; i<N*N; ++i) {
       if (m_values[i] != A.m_values[i]) return false;
@@ -126,13 +124,13 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  bool operator!=(const TinyMatrix& A) const
+  constexpr bool operator!=(const TinyMatrix& A) const
   {
     return not this->operator==(A);
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix operator+(const TinyMatrix& A) const
+  constexpr TinyMatrix operator+(const TinyMatrix& A) const
   {
     TinyMatrix sum;
     for (size_t i=0; i<N*N; ++i) {
@@ -142,7 +140,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix operator+(TinyMatrix&& A) const
+  constexpr TinyMatrix operator+(TinyMatrix&& A) const
   {
     for (size_t i=0; i<N*N; ++i) {
       A.m_values[i] += m_values[i];
@@ -151,7 +149,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix operator-(const TinyMatrix& A) const
+  constexpr TinyMatrix operator-(const TinyMatrix& A) const
   {
     TinyMatrix difference;
     for (size_t i=0; i<N*N; ++i) {
@@ -161,7 +159,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix operator-(TinyMatrix&& A) const
+  constexpr TinyMatrix operator-(TinyMatrix&& A) const
   {
     for (size_t i=0; i<N*N; ++i) {
       A.m_values[i] = m_values[i]-A.m_values[i];
@@ -170,7 +168,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix& operator+=(const TinyMatrix& A)
+  constexpr TinyMatrix& operator+=(const TinyMatrix& A)
   {
     for (size_t i=0; i<N*N; ++i) {
       m_values[i] += A.m_values[i];
@@ -179,7 +177,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix& operator-=(const TinyMatrix& A)
+  constexpr TinyMatrix& operator-=(const TinyMatrix& A)
   {
     for (size_t i=0; i<N*N; ++i) {
       m_values[i] -= A.m_values[i];
@@ -188,21 +186,21 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  T& operator()(const size_t& i, const size_t& j)
+  constexpr T& operator()(const size_t& i, const size_t& j) noexcept
   {
     Assert((i<N) and (j<N));
     return m_values[_index(i,j)];
   }
 
   KOKKOS_INLINE_FUNCTION
-  const T& operator()(const size_t& i, const size_t& j) const
+  constexpr const T& operator()(const size_t& i, const size_t& j) const noexcept
   {
     Assert((i<N) and (j<N));
     return m_values[_index(i,j)];
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix& operator=(const ZeroType& z)
+  constexpr TinyMatrix& operator=(const ZeroType& z) noexcept
   {
     static_assert(std::is_arithmetic<T>(),"Cannot assign 'zero' value for non-arithmetic types");
     for (size_t i=0; i<N*N; ++i) {
@@ -212,7 +210,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix& operator=(const IdentityType& I)
+  constexpr TinyMatrix& operator=(const IdentityType& I) noexcept
   {
     static_assert(std::is_arithmetic<T>(),"Cannot assign 'identity' value for non-arithmetic types");
     for (size_t i=0; i<N; ++i) {
@@ -224,7 +222,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix& operator=(const TinyMatrix& A)
+  constexpr TinyMatrix& operator=(const TinyMatrix& A) noexcept
   {
     for (size_t i=0; i<N*N; ++i) {
       m_values[i] = A.m_values[i];
@@ -233,21 +231,21 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix& operator=(TinyMatrix&& A) = default;
+  constexpr TinyMatrix& operator=(TinyMatrix&& A) noexcept = default;
 
   template <typename... Args>
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix(const T& t, Args&&... args)
+  constexpr TinyMatrix(const T& t, Args&&... args) noexcept
   {
     static_assert(sizeof...(args)==N*N-1, "wrong number of parameters");
     this->_unpackVariadicInput(t, args...);
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix()=default;
+  constexpr TinyMatrix() noexcept = default;
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix(const ZeroType& z)
+  constexpr TinyMatrix(const ZeroType& z) noexcept
   {
     static_assert(std::is_arithmetic<T>(),"Cannot construct from 'zero' value for non-arithmetic types");
     for (size_t i=0; i<N*N; ++i) {
@@ -256,7 +254,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix(const IdentityType& I)
+  constexpr TinyMatrix(const IdentityType& I) noexcept
   {
     static_assert(std::is_arithmetic<T>(),"Cannot construct from 'identity' value for non-arithmetic types");
     for (size_t i=0; i<N; ++i) {
@@ -267,7 +265,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix(const TinyMatrix& A)
+  constexpr TinyMatrix(const TinyMatrix& A) noexcept
   {
     for (size_t i=0; i<N*N; ++i) {
       m_values[i] = A.m_values[i];
@@ -275,7 +273,7 @@ public:
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyMatrix(TinyMatrix&& A) = default;
+  constexpr TinyMatrix(TinyMatrix&& A) noexcept = default;
 
   KOKKOS_INLINE_FUNCTION
   ~TinyMatrix()=default;
@@ -283,8 +281,8 @@ public:
 
 template <size_t N, typename T>
 KOKKOS_INLINE_FUNCTION
-TinyMatrix<N,T> tensorProduct(const TinyVector<N,T>& x,
-                              const TinyVector<N,T>& y)
+constexpr TinyMatrix<N,T> tensorProduct(const TinyVector<N,T>& x,
+                                        const TinyVector<N,T>& y)
 {
   TinyMatrix<N,T> A;
   for (size_t i=0; i<N; ++i) {
@@ -297,7 +295,7 @@ TinyMatrix<N,T> tensorProduct(const TinyVector<N,T>& x,
 
 template <size_t N, typename T>
 KOKKOS_INLINE_FUNCTION
-T det(const TinyMatrix<N,T>& A)
+constexpr T det(const TinyMatrix<N,T>& A)
 {
   static_assert(std::is_arithmetic<T>::value, "determinent is not defined for non arithmetic types");
   static_assert(std::is_floating_point<T>::value, "determinent for arbitrary dimension N is defined for floating point types only");
@@ -341,7 +339,7 @@ T det(const TinyMatrix<N,T>& A)
 
 template <typename T>
 KOKKOS_INLINE_FUNCTION
-T det(const TinyMatrix<1,T>& A)
+constexpr T det(const TinyMatrix<1,T>& A)
 {
   static_assert(std::is_arithmetic<T>::value, "determinent is not defined for non arithmetic types");
   return A(0,0);
@@ -349,7 +347,7 @@ T det(const TinyMatrix<1,T>& A)
 
 template <typename T>
 KOKKOS_INLINE_FUNCTION
-T det(const TinyMatrix<2,T>& A)
+constexpr T det(const TinyMatrix<2,T>& A)
 {
   static_assert(std::is_arithmetic<T>::value, "determinent is not defined for non arithmetic types");
   return A(0,0)*A(1,1)-A(1,0)*A(0,1);
@@ -357,7 +355,7 @@ T det(const TinyMatrix<2,T>& A)
 
 template <typename T>
 KOKKOS_INLINE_FUNCTION
-T det(const TinyMatrix<3,T>& A)
+constexpr T det(const TinyMatrix<3,T>& A)
 {
   static_assert(std::is_arithmetic<T>::value, "determinent is not defined for non arithmetic types");
   return
@@ -368,9 +366,9 @@ T det(const TinyMatrix<3,T>& A)
 
 template <size_t N, typename T>
 KOKKOS_INLINE_FUNCTION
-TinyMatrix<N-1,T> getMinor(const TinyMatrix<N,T>& A,
-                        const size_t& I,
-                        const size_t& J)
+constexpr TinyMatrix<N-1,T> getMinor(const TinyMatrix<N,T>& A,
+                                     const size_t& I,
+                                     const size_t& J) noexcept
 {
   static_assert(N>=2, "minor calculation requires at least 2x2 matrices");
   Assert((I<N) and (J<N));
@@ -396,11 +394,11 @@ TinyMatrix<N-1,T> getMinor(const TinyMatrix<N,T>& A,
 
 template <size_t N, typename T>
 KOKKOS_INLINE_FUNCTION
-TinyMatrix<N,T> inverse(const TinyMatrix<N,T>& A);
+constexpr TinyMatrix<N,T> inverse(const TinyMatrix<N,T>& A);
 
 template <typename T>
 KOKKOS_INLINE_FUNCTION
-TinyMatrix<1,T> inverse(const TinyMatrix<1,T>& A)
+constexpr TinyMatrix<1,T> inverse(const TinyMatrix<1,T>& A)
 {
   static_assert(std::is_arithmetic<T>::value, "inverse is not defined for non arithmetic types");
   static_assert(std::is_floating_point<T>::value, "inverse is defined for floating point types only");
@@ -411,9 +409,9 @@ TinyMatrix<1,T> inverse(const TinyMatrix<1,T>& A)
 
 template <size_t N, typename T>
 KOKKOS_INLINE_FUNCTION
-T cofactor(const TinyMatrix<N,T>& A,
-           const size_t& i,
-           const size_t& j)
+constexpr T cofactor(const TinyMatrix<N,T>& A,
+                     const size_t& i,
+                     const size_t& j)
 {
   static_assert(std::is_arithmetic<T>::value, "cofactor is not defined for non arithmetic types");
   const T sign = ((i+j)%2) ? -1 : 1;
@@ -423,7 +421,7 @@ T cofactor(const TinyMatrix<N,T>& A,
 
 template <typename T>
 KOKKOS_INLINE_FUNCTION
-TinyMatrix<2,T> inverse(const TinyMatrix<2,T>& A)
+constexpr TinyMatrix<2,T> inverse(const TinyMatrix<2,T>& A)
 {
   static_assert(std::is_arithmetic<T>::value, "inverse is not defined for non arithmetic types");
   static_assert(std::is_floating_point<T>::value, "inverse is defined for floating point types only");
@@ -439,7 +437,7 @@ TinyMatrix<2,T> inverse(const TinyMatrix<2,T>& A)
 
 template <typename T>
 KOKKOS_INLINE_FUNCTION
-TinyMatrix<3,T> inverse(const TinyMatrix<3,T>& A)
+constexpr TinyMatrix<3,T> inverse(const TinyMatrix<3,T>& A)
 {
   static_assert(std::is_arithmetic<T>::value, "inverse is not defined for non arithmetic types");
   static_assert(std::is_floating_point<T>::value, "inverse is defined for floating point types only");
diff --git a/src/algebra/TinyVector.hpp b/src/algebra/TinyVector.hpp
index 35cdb5d35..8e16d4127 100644
--- a/src/algebra/TinyVector.hpp
+++ b/src/algebra/TinyVector.hpp
@@ -14,21 +14,19 @@ class TinyVector
   T m_values[N];
   static_assert((N>0),"TinyVector size must be strictly positive");
 
-  void _unpackVariadicInput(const T& t)
-  {
-    m_values[N-1] = t;
-  }
-
   template <typename... Args>
-  void _unpackVariadicInput(const T& t, Args&&... args)
+  KOKKOS_FORCEINLINE_FUNCTION
+  constexpr void _unpackVariadicInput(const T& t, Args&&... args) noexcept
   {
     m_values[N-1-sizeof...(args)] = t;
-    this->_unpackVariadicInput(args...);
+    if constexpr (sizeof...(args) > 0) {
+        this->_unpackVariadicInput(args...);
+      }
   }
 
  public:
   KOKKOS_INLINE_FUNCTION
-  TinyVector operator-() const
+  constexpr TinyVector operator-() const
   {
     TinyVector opposed;
     for (size_t i=0; i<N; ++i) {
@@ -44,7 +42,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  bool operator==(const TinyVector& v) const
+  constexpr bool operator==(const TinyVector& v) const
   {
     for (size_t i=0; i<N; ++i) {
       if (m_values[i] != v.m_values[i]) return false;
@@ -53,13 +51,13 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  bool operator!=(const TinyVector& v) const
+  constexpr bool operator!=(const TinyVector& v) const
   {
     return not this->operator==(v);
   }
 
   KOKKOS_INLINE_FUNCTION
-  T operator,(const TinyVector& v) const
+  constexpr T operator,(const TinyVector& v) const
   {
     T t = m_values[0]*v.m_values[0];
     for (size_t i=1; i<N; ++i) {
@@ -69,7 +67,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector& operator*=(const T& t)
+  constexpr TinyVector& operator*=(const T& t)
   {
     for (size_t i=0; i<N; ++i) {
       m_values[i] *= t;
@@ -78,7 +76,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  friend TinyVector operator*(const T& t, const TinyVector& v)
+  constexpr friend TinyVector operator*(const T& t, const TinyVector& v)
   {
     TinyVector tv;
     for (size_t i=0; i<N; ++i) {
@@ -88,14 +86,14 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  friend TinyVector operator*(const T& t, TinyVector&& v)
+  constexpr friend TinyVector operator*(const T& t, TinyVector&& v)
   {
     v *= t;
     return std::move(v);
   }
 
   KOKKOS_INLINE_FUNCTION
-  friend std::ostream& operator<<(std::ostream& os, const TinyVector& v)
+  constexpr friend std::ostream& operator<<(std::ostream& os, const TinyVector& v)
   {
     os << '(' << v.m_values[0];
     for (size_t i=1; i<N; ++i) {
@@ -106,7 +104,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector operator+(const TinyVector& v) const
+  constexpr TinyVector operator+(const TinyVector& v) const
   {
     TinyVector sum;
     for (size_t i=0; i<N; ++i) {
@@ -116,7 +114,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector operator+(TinyVector&& v) const
+  constexpr TinyVector operator+(TinyVector&& v) const
   {
     for (size_t i=0; i<N; ++i) {
       v.m_values[i] += m_values[i];
@@ -125,7 +123,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector operator-(const TinyVector& v) const
+  constexpr TinyVector operator-(const TinyVector& v) const
   {
     TinyVector difference;
     for (size_t i=0; i<N; ++i) {
@@ -135,7 +133,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector operator-(TinyVector&& v) const
+  constexpr TinyVector operator-(TinyVector&& v) const
   {
     for (size_t i=0; i<N; ++i) {
       v.m_values[i] = m_values[i]-v.m_values[i];
@@ -144,7 +142,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector& operator+=(const TinyVector& v)
+  constexpr TinyVector& operator+=(const TinyVector& v)
   {
     for (size_t i=0; i<N; ++i) {
       m_values[i] += v.m_values[i];
@@ -153,7 +151,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector& operator-=(const TinyVector& v)
+  constexpr TinyVector& operator-=(const TinyVector& v)
   {
     for (size_t i=0; i<N; ++i) {
       m_values[i] -= v.m_values[i];
@@ -162,21 +160,21 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  T& operator[](const size_t& i)
+  constexpr T& operator[](const size_t& i)
   {
     Assert(i<N);
     return m_values[i];
   }
 
   KOKKOS_INLINE_FUNCTION
-  const T& operator[](const size_t& i) const
+  constexpr const T& operator[](const size_t& i) const
   {
     Assert(i<N);
     return m_values[i];
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector& operator=(const ZeroType& z)
+  constexpr TinyVector& operator=(const ZeroType& z) noexcept
   {
     static_assert(std::is_arithmetic<T>(),"Cannot assign 'zero' value for non-arithmetic types");
     for (size_t i=0; i<N; ++i) {
@@ -186,7 +184,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  const TinyVector& operator=(const TinyVector& v)
+  const TinyVector& operator=(const TinyVector& v) noexcept
   {
     for (size_t i=0; i<N; ++i) {
       m_values[i] = v.m_values[i];
@@ -195,24 +193,24 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector& operator=(TinyVector&& v) = default;
+  constexpr TinyVector& operator=(TinyVector&& v) noexcept = default;
 
   template <typename... Args>
   KOKKOS_INLINE_FUNCTION
-  TinyVector(const T& t, Args&&... args)
+  constexpr TinyVector(const T& t, Args&&... args) noexcept
   {
     static_assert(sizeof...(args)==N-1, "wrong number of parameters");
     this->_unpackVariadicInput(t, args...);
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector()
+  constexpr TinyVector() noexcept
   {
     ;
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector(const ZeroType& z)
+  constexpr TinyVector(const ZeroType& z) noexcept
   {
     static_assert(std::is_arithmetic<T>(),"Cannot construct from 'zero' value for non-arithmetic types");
     for (size_t i=0; i<N; ++i) {
@@ -221,7 +219,7 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector(const TinyVector& v)
+  constexpr TinyVector(const TinyVector& v) noexcept
   {
     for (size_t i=0; i<N; ++i) {
       m_values[i] = v.m_values[i];
@@ -229,10 +227,10 @@ class TinyVector
   }
 
   KOKKOS_INLINE_FUNCTION
-  TinyVector(TinyVector&& v) = default;
+  constexpr TinyVector(TinyVector&& v) noexcept = default;
 
   KOKKOS_INLINE_FUNCTION
-  ~TinyVector()
+  ~TinyVector() noexcept
   {
     ;
   }
@@ -240,7 +238,7 @@ class TinyVector
 
 template <size_t N, typename T>
 KOKKOS_INLINE_FUNCTION
-T l2Norm(const TinyVector<N,T>& x)
+constexpr T l2Norm(const TinyVector<N,T>& x)
 {
   static_assert(std::is_arithmetic<T>(),"Cannot compute L2 norm for non-arithmetic types");
   static_assert(std::is_floating_point<T>::value, "L2 norm is defined for floating point types only");
@@ -250,7 +248,7 @@ T l2Norm(const TinyVector<N,T>& x)
 // Cross product is only defined for K^3 vectors
 template <typename T>
 KOKKOS_INLINE_FUNCTION
-TinyVector<3,T> crossProduct(const TinyVector<3,T>& u, const TinyVector<3,T>& v)
+constexpr TinyVector<3,T> crossProduct(const TinyVector<3,T>& u, const TinyVector<3,T>& v)
 {
   TinyVector<3,T> cross_product(u[1]*v[2]-u[2]*v[1],
                                 u[2]*v[0]-u[0]*v[2],
-- 
GitLab