// Copyright (C) 2006  Davis E. King (davis@dlib.net)
#undef DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_
#ifdef DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_

#include "matrix_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                          Exponential Functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

const matrix_exp exp (
const matrix_exp& m
);
/*!
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::exp(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp log10 (
const matrix_exp& m
);
/*!
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::log10(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp log (
const matrix_exp& m
);
/*!
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::log(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp sqrt (
const matrix_exp& m
);
/*!
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == sqrt(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

template <typename T>
const matrix_exp pow (
const matrix_exp& m,
const T& e
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == pow(m(r,c),e)
!*/

// ----------------------------------------------------------------------------------------

template <typename T>
const matrix_exp pow (
const T& b,
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == pow(b, m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp squared (
const matrix_exp& m
);
/*!
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == m(r,c)*m(r,c)
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp cubed (
const matrix_exp& m
);
/*!
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == m(r,c)*m(r,c)*m(r,c)
!*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                               Miscellaneous
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

const matrix_exp sign (
const matrix_exp& m
);
/*!
ensures
- returns a matrix that tells the sign of each element in m. In particular:
returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
- if (m(r,c) >= 0) then
- R(r,c) == +1
- else
- R(r,c) == -1
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp sigmoid (
const matrix_exp& m
);
/*!
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == 1/(1 + exp(-m(r,c)))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp abs (
const matrix_exp& m
);
/*!
ensures
- returns a matrix R such that:
- if (m contains std::complex<T> objects) then
- R::type == T
- else
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::abs(m(r,c))
(note that if m is complex then std::abs(val) performs sqrt(std::norm(val))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp reciprocal (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, long double, std::complex<float>,
std::complex<double>, or std::complex<long double>
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
- if (m(r,c) != 0) then
- R(r,c) == 1.0/m(r,c)
- else
- R(r,c) == 0
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp reciprocal_max (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
- if (m(r,c) != 0) then
- R(r,c) == 1.0/m(r,c)
- else
- R(r,c) == std::numeric_limits<R::type>::max()
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp normalize (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- if (sqrt(sum(squared(m))) != 0) then
- returns m/sqrt(sum(squared(m)))
- else
- returns m
!*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                          Rounding numbers one way or another
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

const matrix_exp round (
const matrix_exp& m
);
/*!
requires
- is_built_in_scalar_type<matrix_exp::type>::value == true
(i.e. m must contain a type like int, float, double, long, etc.)
ensures
- if (m contains integers) then
- returns m unmodified
- else
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == m(r,c) rounded to the nearest integral value
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp ceil (
const matrix_exp& m
);
/*!
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::ceil(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp floor (
const matrix_exp& m
);
/*!
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::floor(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp round_zeros (
const matrix_exp& m
);
/*!
requires
- is_built_in_scalar_type<matrix_exp::type>::value == true
(i.e. m must contain a type like int, float, double, long, etc.)
ensures
- if (m contains integers) then
- returns m unmodified
- else
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- let eps == 10*std::numeric_limits<matrix_exp::type>::epsilon()
- for all valid r and c:
- if (abs(m(r,c)) >= eps) then
- R(r,c) == m(r,c)
- else
- R(r,c) == 0
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp round_zeros (
const matrix_exp& m,
matrix_exp::type eps
);
/*!
requires
- is_built_in_scalar_type<matrix_exp::type>::value == true
(i.e. m must contain a type like int, float, double, long, etc.)
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
- if (abs(m(r,c)) >= eps) then
- R(r,c) == m(r,c)
- else
- R(r,c) == 0
!*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                              Complex number utility functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

const matrix_exp conj (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == std::complex<T>
ensures
- returns a matrix R such that:
- R::type == std::complex<T>
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::conj(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp norm (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == std::complex<T>
ensures
- returns a matrix R such that:
- R::type == T
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::norm(m(r,c))
(note that std::norm(val) == val.real()*val.real() + val.imag()*val.imag())
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp imag (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == std::complex<T>
ensures
- returns a matrix R such that:
- R::type == T
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::imag(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp real (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == std::complex<T>
ensures
- returns a matrix R such that:
- R::type == T
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::real(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp complex_matrix (
const matrix_exp& real_part
);
/*!
ensures
- returns a matrix R such that:
- R::type == std::complex<T> where T is whatever type real_part used.
- R has the same dimensions as real_part.
- for all valid r and c:
R(r,c) == std::complex(real_part(r,c), 0)
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp complex_matrix (
const matrix_exp& real_part,
const matrix_exp& imag_part
);
/*!
requires
- real_part.nr() == imag_part.nr()
- real_part.nc() == imag_part.nc()
- real_part and imag_part both contain the same type of element
ensures
- returns a matrix R such that:
- R::type == std::complex<T> where T is whatever type real_part and imag_part used.
- R has the same dimensions as real_part and imag_part
- for all valid r and c:
R(r,c) == std::complex(real_part(r,c),imag_part(r,c))
!*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
//                              Trigonometric Functions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

const matrix_exp sin (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::sin(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp cos (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::cos(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp tan (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::tan(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp asin (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::asin(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp acos (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::acos(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp atan (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::atan(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp sinh (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::sinh(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp cosh (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::cosh(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp tanh (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::tanh(m(r,c))
!*/

// ----------------------------------------------------------------------------------------

const matrix_exp soft_max (
const matrix_exp& m
);
/*!
requires
- matrix_exp::type == float, double, or long double
ensures
- returns a matrix R such that:
- R::type == the same type that was in m
- R has the same dimensions as m
- for all valid r and c:
R(r,c) == std::exp(m(r,c)) / sum(std::exp(m))
!*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_