//#####################################################################
// Copyright 2013.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class ZERO_MATRIX
//##################################################################### 
#ifndef __ZERO_MATRIX__
#define __ZERO_MATRIX__

#include <Core/Math_Tools/cube.h>
#include <Core/Matrices/GENERAL_MATRIX_BASE.h>
#include <Core/Matrices/MATRIX.h>
#include <Core/Matrices/MATRIX_FORWARD.h>
#include <Core/Matrices/SYMMETRIC_MATRIX.h>
#include <Core/Vectors/VECTOR.h>
#include <Core/Vectors/ZERO_VECTOR.h>
#include <cmath>
namespace PhysBAM{
template<class T,int mm,int nn>
class ZERO_MATRIX:public GENERAL_MATRIX_BASE<T,ZERO_MATRIX<T,mm,nn>>
{
    // Invalid; hide it.
    using GENERAL_MATRIX_BASE<T,ZERO_MATRIX<T,mm,nn>>::Identity_Matrix;
public:
    typedef T SCALAR;
    static constexpr int m=mm,n=nn;
    static constexpr int fixed_m=m,fixed_n=n;
    static constexpr bool is_sym=(m==n),is_diag=(m==n);
    static constexpr int type=mat_zero;

    ZERO_MATRIX()=default;

    explicit ZERO_MATRIX(INITIAL_SIZE mm_,INITIAL_SIZE nn_=INITIAL_SIZE(n)){}
    ZERO_MATRIX(const ZERO_MATRIX&)=default;

    int Rows() const
    {return m;}

    int Columns() const
    {return n;}

    T operator()(const int i,const int j) const
    {return T{};}

    ZERO_MATRIX operator-() const
    {return *this;}

    ZERO_MATRIX operator+(const ZERO_MATRIX&) const
    {return *this;}

    ZERO_MATRIX operator-(const ZERO_MATRIX&) const
    {return *this;}

    ZERO_MATRIX operator*(const T&) const
    {return *this;}

    ZERO_MATRIX operator/(const T&) const
    {return *this;}

    ZERO_MATRIX<T,nn,mm> Transposed() const
    {return ZERO_MATRIX<T,nn,mm>();}

    template<class A>
    auto Transpose_Times(const A& a) const
    {return ::PhysBAM::Transpose_Times(*this,a);}

    template<class A>
    auto Times_Transpose(const A& a) const
    {return ::PhysBAM::Times_Transpose(*this,a);}

    ZERO_MATRIX Twice_Symmetric_Part() const
    {return *this;}

    ZERO_MATRIX Symmetric_Part() const
    {return *this;}

    ZERO_MATRIX Diagonal_Part() const
    {return *this;}

    ZERO_MATRIX<T,nn,nn> Normal_Equations_Matrix() const
    {return ZERO_MATRIX<T,nn,nn>();}

    ZERO_MATRIX<T,mm,mm> Outer_Product_Matrix() const
    {return ZERO_MATRIX<T,mm,mm>();}

    FIXED_NUMBER<T,0> Trace() const
    {return FIXED_NUMBER<T,0>();}

    FIXED_NUMBER<T,0> Determinant() const
    {return {};}

    FIXED_NUMBER<T,0> Max_Abs() const
    {return {};}

    template<class A>
    auto Double_Contract(const A& a)
    {return ::PhysBAM::Double_Contract(*this,a);}

    FIXED_NUMBER<T,0> Frobenius_Norm_Squared() const
    {return FIXED_NUMBER<T,0>();}

    FIXED_NUMBER<T,0> Frobenius_Norm() const
    {return FIXED_NUMBER<T,0>();}
    
};
template<int i,int j,class T,int m,int n> auto get(const ZERO_MATRIX<T,m,n>& a){return T{};}
template<class T,int m,int n> auto get(const ZERO_MATRIX<T,m,n>& a,int i,int j){return T{};}
template<class T,int m,int n> auto diag(const ZERO_MATRIX<T,m,n>& a,int i){return T{};}
template<class T,int m,int n> auto lower(const ZERO_MATRIX<T,m,n>& a,int i,int j){return T{};}
template<class T,int m,int n> auto lower_(const ZERO_MATRIX<T,m,n>& a,int i,int j){return T{};}
template<class T,int m,int n> auto upper(const ZERO_MATRIX<T,m,n>& a,int i,int j){return T{};}
template<class T,int m,int n> auto upper_(const ZERO_MATRIX<T,m,n>& a,int i,int j){return T{};}

template<class T,int m,int n>
inline std::ostream& operator<< (std::ostream& output_stream,const ZERO_MATRIX<T,m,n>& A)
{return output_stream<<MATRIX<T,m,n>();}
}
#endif
