// ---------------------------------------------------------------------
//
// Copyright (C) 1999 - 2018 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE.md at
// the top level directory of deal.II.
//
// ---------------------------------------------------------------------



for (S : REAL_AND_COMPLEX_SCALARS)
  {
    template class FullMatrix<S>;

    template void FullMatrix<S>::print(LogStream &,
                                       const unsigned int,
                                       const unsigned int) const;
    template void FullMatrix<S>::print(std::ostream &,
                                       const unsigned int,
                                       const unsigned int) const;

    template void FullMatrix<S>::copy_from<1>(const Tensor<2, 1> &,
                                              const unsigned int,
                                              const unsigned int,
                                              unsigned int,
                                              const unsigned int,
                                              const size_type,
                                              const size_type);

    template void FullMatrix<S>::copy_from<2>(const Tensor<2, 2> &,
                                              const unsigned int,
                                              const unsigned int,
                                              unsigned int,
                                              const unsigned int,
                                              const size_type,
                                              const size_type);

    template void FullMatrix<S>::copy_from<3>(const Tensor<2, 3> &,
                                              const unsigned int,
                                              const unsigned int,
                                              unsigned int,
                                              const unsigned int,
                                              const size_type,
                                              const size_type);
  }


for (S : REAL_SCALARS)
  {
    template void FullMatrix<S>::copy_to<1>(Tensor<2, 1> &,
                                            const size_type,
                                            const size_type,
                                            const size_type,
                                            const size_type,
                                            const unsigned int,
                                            const unsigned int) const;

    template void FullMatrix<S>::copy_to<2>(Tensor<2, 2> &,
                                            const size_type,
                                            const size_type,
                                            const size_type,
                                            const size_type,
                                            const unsigned int,
                                            const unsigned int) const;

    template void FullMatrix<S>::copy_to<3>(Tensor<2, 3> &,
                                            const size_type,
                                            const size_type,
                                            const size_type,
                                            const size_type,
                                            const unsigned int,
                                            const unsigned int) const;
  }


for (S1, S2 : REAL_SCALARS)
  {
    template FullMatrix<S1> &FullMatrix<S1>::operator=(
      const LAPACKFullMatrix<S2> &);

    template void FullMatrix<S1>::fill<S2>(
      const FullMatrix<S2> &, size_type, size_type, size_type, size_type);
    template void FullMatrix<S1>::add<S2>(const S1, const FullMatrix<S2> &);
    template void FullMatrix<S1>::add<S2>(const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &);
    template void FullMatrix<S1>::add<S2>(const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &);
    template void FullMatrix<S1>::add<S2>(
      const FullMatrix<S2> &, S1, size_type, size_type, size_type, size_type);
    template void FullMatrix<S1>::Tadd<S2>(const S1, const FullMatrix<S2> &);
    template void FullMatrix<S1>::Tadd<S2>(
      const FullMatrix<S2> &, S1, size_type, size_type, size_type, size_type);
    template void FullMatrix<S1>::equ<S2>(const S1, const FullMatrix<S2> &);
    template void FullMatrix<S1>::equ<S2>(const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &);
    template void FullMatrix<S1>::equ<S2>(const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &);
    template void FullMatrix<S1>::mmult<S2>(FullMatrix<S2> &,
                                            const FullMatrix<S2> &,
                                            const bool) const;
    template void FullMatrix<S1>::Tmmult<S2>(FullMatrix<S2> &,
                                             const FullMatrix<S2> &,
                                             const bool) const;
    template void FullMatrix<S1>::mTmult<S2>(FullMatrix<S2> &,
                                             const FullMatrix<S2> &,
                                             const bool) const;
    template void FullMatrix<S1>::TmTmult<S2>(FullMatrix<S2> &,
                                              const FullMatrix<S2> &,
                                              const bool) const;
    template void FullMatrix<S1>::invert<S2>(const FullMatrix<S2> &);

    template void FullMatrix<S1>::left_invert<S2>(const FullMatrix<S2> &);
    template void FullMatrix<S1>::right_invert<S2>(const FullMatrix<S2> &);

    template void FullMatrix<S1>::fill_permutation<S2>(
      const FullMatrix<S2> &,
      const std::vector<size_type> &,
      const std::vector<size_type> &);

    template void FullMatrix<S1>::cholesky<S2>(const FullMatrix<S2> &);

    template void FullMatrix<S1>::outer_product<S2>(const Vector<S2> &,
                                                    const Vector<S2> &);
  }


// real matrices can be multiplied by real or complex vectors
for (S1 : REAL_SCALARS; S2 : REAL_AND_COMPLEX_SCALARS)
  {
    template void FullMatrix<S1>::vmult<S2>(Vector<S2> &,
                                            const Vector<S2> &,
                                            bool) const;
    template void FullMatrix<S1>::Tvmult<S2>(Vector<S2> &,
                                             const Vector<S2> &,
                                             bool) const;
    template S2   FullMatrix<S1>::matrix_norm_square<S2>(const Vector<S2> &)
      const;
    template S2 FullMatrix<S1>::matrix_scalar_product<S2>(const Vector<S2> &,
                                                          const Vector<S2> &)
      const;
    template void FullMatrix<S1>::forward<S2>(Vector<S2> &, const Vector<S2> &)
      const;
    template void FullMatrix<S1>::backward<S2>(Vector<S2> &, const Vector<S2> &)
      const;

    template void FullMatrix<S1>::precondition_Jacobi<S2>(Vector<S2> &,
                                                          const Vector<S2> &,
                                                          const S1) const;
  }


// complex matrices can be multiplied only by complex vectors
for (S1 : COMPLEX_SCALARS; S2 : COMPLEX_SCALARS)
  {
    template void FullMatrix<S1>::vmult<S2>(Vector<S2> &,
                                            const Vector<S2> &,
                                            bool) const;
    template void FullMatrix<S1>::Tvmult<S2>(Vector<S2> &,
                                             const Vector<S2> &,
                                             bool) const;
    template S2   FullMatrix<S1>::matrix_norm_square<S2>(const Vector<S2> &)
      const;
    template S2 FullMatrix<S1>::matrix_scalar_product<S2>(const Vector<S2> &,
                                                          const Vector<S2> &)
      const;
    template void FullMatrix<S1>::forward<S2>(Vector<S2> &, const Vector<S2> &)
      const;
    template void FullMatrix<S1>::backward<S2>(Vector<S2> &, const Vector<S2> &)
      const;

    template void FullMatrix<S1>::precondition_Jacobi<S2>(Vector<S2> &,
                                                          const Vector<S2> &,
                                                          const S1) const;
  }



for (S1, S2, S3 : REAL_SCALARS)
  {
    template S1 FullMatrix<S1>::residual<S2, S3>(Vector<S2> &,
                                                 const Vector<S2> &,
                                                 const Vector<S3> &) const;
  }



for (S1, S2 : COMPLEX_SCALARS)
  {
    template void FullMatrix<S1>::fill<S2>(
      const FullMatrix<S2> &, size_type, size_type, size_type, size_type);
    template void FullMatrix<S1>::add<S2>(const S1, const FullMatrix<S2> &);
    template void FullMatrix<S1>::add<S2>(const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &);
    template void FullMatrix<S1>::add<S2>(const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &);
    template void FullMatrix<S1>::add<S2>(
      const FullMatrix<S2> &, S1, size_type, size_type, size_type, size_type);
    template void FullMatrix<S1>::Tadd<S2>(const S1, const FullMatrix<S2> &);
    template void FullMatrix<S1>::Tadd<S2>(
      const FullMatrix<S2> &, S1, size_type, size_type, size_type, size_type);
    template void FullMatrix<S1>::equ<S2>(const S1, const FullMatrix<S2> &);
    template void FullMatrix<S1>::equ<S2>(const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &);
    template void FullMatrix<S1>::equ<S2>(const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &,
                                          const S1,
                                          const FullMatrix<S2> &);
    template void FullMatrix<S1>::mmult<S2>(FullMatrix<S2> &,
                                            const FullMatrix<S2> &,
                                            const bool) const;
    template void FullMatrix<S1>::Tmmult<S2>(FullMatrix<S2> &,
                                             const FullMatrix<S2> &,
                                             const bool) const;
    template void FullMatrix<S1>::invert<S2>(const FullMatrix<S2> &);

    template void FullMatrix<S1>::left_invert<S2>(const FullMatrix<S2> &);
    template void FullMatrix<S1>::right_invert<S2>(const FullMatrix<S2> &);

    template void FullMatrix<S1>::fill_permutation<S2>(
      const FullMatrix<S2> &,
      const std::vector<size_type> &,
      const std::vector<size_type> &);
  }

for (S1, S2, S3 : COMPLEX_SCALARS)
  {
    template S1 FullMatrix<S1>::residual<S2, S3>(Vector<S2> &,
                                                 const Vector<S2> &,
                                                 const Vector<S3> &) const;
  }
