// ---------------------------------------------------------------------
//
// 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 at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------



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;
}
