Update Eigen to commit:b396a6fbb2e173f52edb3360485dedf3389ef830

CHANGELOG
=========
b396a6fbb - Add free-function swap.
820e8a45f - add compile time info to reverse in place
b55dab7f2 - Fix DenseBase::tail for Dynamic template argument
e0cbc55d9 - Update README.md

PiperOrigin-RevId: 686151157
Change-Id: Ib5c5a685c6277a21aa6fd75f5468de4c42461ddd
diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h
index 8c8ca73..e1fbb0b 100644
--- a/Eigen/src/Core/DenseBase.h
+++ b/Eigen/src/Core/DenseBase.h
@@ -642,6 +642,18 @@
   EIGEN_DEVICE_FUNC explicit DenseBase(const DenseBase<OtherDerived>&);
 };
 
+/** Free-function swap.
+ */
+template <typename DerivedA, typename DerivedB>
+EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
+    // Use forwarding references to capture all combinations of cv-qualified l+r-value cases.
+    std::enable_if_t<std::is_base_of<DenseBase<std::decay_t<DerivedA>>, std::decay_t<DerivedA>>::value &&
+                         std::is_base_of<DenseBase<std::decay_t<DerivedB>>, std::decay_t<DerivedB>>::value,
+                     void>
+    swap(DerivedA&& a, DerivedB&& b) {
+  a.swap(b);
+}
+
 }  // end namespace Eigen
 
 #endif  // EIGEN_DENSEBASE_H
diff --git a/Eigen/src/Core/Reverse.h b/Eigen/src/Core/Reverse.h
index 66116aa..eb06fff 100644
--- a/Eigen/src/Core/Reverse.h
+++ b/Eigen/src/Core/Reverse.h
@@ -127,19 +127,25 @@
  * \sa VectorwiseOp::reverseInPlace(), reverse() */
 template <typename Derived>
 EIGEN_DEVICE_FUNC inline void DenseBase<Derived>::reverseInPlace() {
+  constexpr int HalfRowsAtCompileTime = RowsAtCompileTime == Dynamic ? Dynamic : RowsAtCompileTime / 2;
+  constexpr int HalfColsAtCompileTime = ColsAtCompileTime == Dynamic ? Dynamic : ColsAtCompileTime / 2;
   if (cols() > rows()) {
     Index half = cols() / 2;
-    leftCols(half).swap(rightCols(half).reverse());
+    this->template leftCols<HalfColsAtCompileTime>(half).swap(
+        this->template rightCols<HalfColsAtCompileTime>(half).reverse());
     if ((cols() % 2) == 1) {
       Index half2 = rows() / 2;
-      col(half).head(half2).swap(col(half).tail(half2).reverse());
+      col(half).template head<HalfRowsAtCompileTime>(half2).swap(
+          col(half).template tail<HalfRowsAtCompileTime>(half2).reverse());
     }
   } else {
     Index half = rows() / 2;
-    topRows(half).swap(bottomRows(half).reverse());
+    this->template topRows<HalfRowsAtCompileTime>(half).swap(
+        this->template bottomRows<HalfRowsAtCompileTime>(half).reverse());
     if ((rows() % 2) == 1) {
       Index half2 = cols() / 2;
-      row(half).head(half2).swap(row(half).tail(half2).reverse());
+      row(half).template head<HalfColsAtCompileTime>(half2).swap(
+          row(half).template tail<HalfColsAtCompileTime>(half2).reverse());
     }
   }
 }
diff --git a/Eigen/src/SparseCore/SparseMatrix.h b/Eigen/src/SparseCore/SparseMatrix.h
index 16ee8da..caa8ffa 100644
--- a/Eigen/src/SparseCore/SparseMatrix.h
+++ b/Eigen/src/SparseCore/SparseMatrix.h
@@ -829,6 +829,8 @@
     std::swap(m_innerNonZeros, other.m_innerNonZeros);
     m_data.swap(other.m_data);
   }
+  /** Free-function swap. */
+  friend EIGEN_DEVICE_FUNC void swap(SparseMatrix& a, SparseMatrix& b) { a.swap(b); }
 
   /** Sets *this to the identity matrix.
    * This function also turns the matrix into compressed mode, and drop any reserved memory. */
diff --git a/Eigen/src/SparseCore/SparseVector.h b/Eigen/src/SparseCore/SparseVector.h
index 58ebb1b..3f72a34 100644
--- a/Eigen/src/SparseCore/SparseVector.h
+++ b/Eigen/src/SparseCore/SparseVector.h
@@ -278,6 +278,7 @@
     std::swap(m_size, other.m_size);
     m_data.swap(other.m_data);
   }
+  friend EIGEN_DEVICE_FUNC void swap(SparseVector& a, SparseVector& b) { a.swap(b); }
 
   template <int OtherOptions>
   inline void swap(SparseMatrix<Scalar, OtherOptions, StorageIndex>& other) {
@@ -285,6 +286,14 @@
     std::swap(m_size, other.m_innerSize);
     m_data.swap(other.m_data);
   }
+  template <int OtherOptions>
+  friend EIGEN_DEVICE_FUNC void swap(SparseVector& a, SparseMatrix<Scalar, OtherOptions, StorageIndex>& b) {
+    a.swap(b);
+  }
+  template <int OtherOptions>
+  friend EIGEN_DEVICE_FUNC void swap(SparseMatrix<Scalar, OtherOptions, StorageIndex>& a, SparseVector& b) {
+    b.swap(a);
+  }
 
   inline SparseVector& operator=(const SparseVector& other) {
     if (other.isRValue()) {
diff --git a/Eigen/src/plugins/BlockMethods.inc b/Eigen/src/plugins/BlockMethods.inc
index 122a2f4..46dc9dd 100644
--- a/Eigen/src/plugins/BlockMethods.inc
+++ b/Eigen/src/plugins/BlockMethods.inc
@@ -1304,14 +1304,14 @@
 template <int N>
 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename FixedSegmentReturnType<N>::Type tail(Index n = N) {
   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
-  return typename FixedSegmentReturnType<N>::Type(derived(), size() - n);
+  return typename FixedSegmentReturnType<N>::Type(derived(), size() - n, n);
 }
 
 /// This is the const version of tail<int>.
 template <int N>
 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename ConstFixedSegmentReturnType<N>::Type tail(Index n = N) const {
   EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
-  return typename ConstFixedSegmentReturnType<N>::Type(derived(), size() - n);
+  return typename ConstFixedSegmentReturnType<N>::Type(derived(), size() - n, n);
 }
 
 /// \returns the \a outer -th column (resp. row) of the matrix \c *this if \c *this
diff --git a/test/swap.cpp b/test/swap.cpp
index bc29704..7bfabc3 100644
--- a/test/swap.cpp
+++ b/test/swap.cpp
@@ -63,6 +63,16 @@
   }
   m1 = m1_copy;
   m2 = m2_copy;
+  d1 = m1.data(), d2 = m2.data();
+  swap(m1, m2);
+  VERIFY_IS_APPROX(m1, m2_copy);
+  VERIFY_IS_APPROX(m2, m1_copy);
+  if (MatrixType::SizeAtCompileTime == Dynamic) {
+    VERIFY(m1.data() == d2);
+    VERIFY(m2.data() == d1);
+  }
+  m1 = m1_copy;
+  m2 = m2_copy;
 
   // test swapping 2 matrices of different types
   m1.swap(m3);
@@ -70,6 +80,11 @@
   VERIFY_IS_APPROX(m3, m1_copy);
   m1 = m1_copy;
   m3 = m3_copy;
+  swap(m1, m3);
+  VERIFY_IS_APPROX(m1, m3_copy);
+  VERIFY_IS_APPROX(m3, m1_copy);
+  m1 = m1_copy;
+  m3 = m3_copy;
 
   // test swapping matrix with expression
   m1.swap(m2.block(0, 0, rows, cols));
@@ -77,6 +92,11 @@
   VERIFY_IS_APPROX(m2, m1_copy);
   m1 = m1_copy;
   m2 = m2_copy;
+  swap(m1, m2.block(0, 0, rows, cols));
+  VERIFY_IS_APPROX(m1, m2_copy);
+  VERIFY_IS_APPROX(m2, m1_copy);
+  m1 = m1_copy;
+  m2 = m2_copy;
 
   // test swapping two expressions of different types
   m1.transpose().swap(m3.transpose());
@@ -84,6 +104,11 @@
   VERIFY_IS_APPROX(m3, m1_copy);
   m1 = m1_copy;
   m3 = m3_copy;
+  swap(m1.transpose(), m3.transpose());
+  VERIFY_IS_APPROX(m1, m3_copy);
+  VERIFY_IS_APPROX(m3, m1_copy);
+  m1 = m1_copy;
+  m3 = m3_copy;
 
   check_row_swap(m1);
 }