#include <complex>
#include <cmath>

#include "pnorms.h"

using namespace std;

template<class T, unsigned int p>
  T pNorm(const complex<T>& z) {
    return pow(pow(abs(z.real()), p) + pow(abs(z.imag()), p), static_cast<T>(1) / p);
}

template<class T, T _norm(const complex<T>&)>
  complex_norm<T, _norm>::complex_norm(T real_, T imag_): complex<T>(real_, imag_) {}

template<class T, T _norm(const complex<T>&)>
  T complex_norm<T, _norm>::norm() const {
    return _norm(*this);
}

template<class T, unsigned int p1, unsigned int p2>
  T pnorm_bound(complex<T> z) {
    complex_pnorm<T, p1> z1{z.real(), z.imag()};
    complex_pnorm<T, p2> z2{z.real(), z.imag()};
    return z1.norm() / z2.norm();
}

template double pNorm<double, 2>(const complex<double>&);
template double pNorm<double, 3>(const complex<double>&);
template class complex_norm<double, pNorm<double, 2>>;
template class complex_norm<double, pNorm<double, 3>>;
template double pnorm_bound<double, 2, 3>(complex<double>);
