/**
 * \file trace/linearregression.cpp
 * \date 17/9/2016
 * \author Olivier Langella
 * \brief compute linear regression
 */

/*******************************************************************************
 * Copyright (c) 2016 Olivier Langella <Olivier.Langella@u-psud.fr>.
 *
 * This file is part of peptider.
 *
 *     peptider is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     peptider is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with peptider.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/
#include "linearregression.h"
#include <numeric>
#include <cmath>

using namespace pappso;

pappso::LinearRegression::LinearRegression(const pappso::LinearRegression &other)
  : m_slope(other.m_slope), m_intercept(other.m_intercept), m_data(other.m_data)
{
}


LinearRegression::LinearRegression(const Trace &data)
{

  m_data           = data;
  std::size_t size = data.size();
  if(size > 2)
    {
      pappso::pappso_double x_vec_mean =

        (std::accumulate(
           data.begin(), data.end(), 0, [](double a, const DataPoint &b) { return a + b.x; }) /
         size);
      pappso::pappso_double y_vec_mean = (sumYTrace(data.begin(), data.end(), 0) / size);

      pappso::pappso_double sx  = 0;
      pappso::pappso_double sxy = 0;
      for(size_t i = 0; i < size; i++)
        {
          sx += std::pow((data[i].x - x_vec_mean), 2);
          sxy += (data[i].x - x_vec_mean) * (data[i].y - y_vec_mean);
        }
      m_slope = sxy / sx;

      m_intercept = y_vec_mean - (m_slope * x_vec_mean);
    }
}

std::size_t
pappso::LinearRegression::getSize() const
{
  return m_data.size();
}


pappso::pappso_double
LinearRegression::getIntercept() const
{
  return m_intercept;
}
pappso::pappso_double
LinearRegression::getSlope() const
{
  return m_slope;
}
pappso::pappso_double
LinearRegression::getYfromX(pappso::pappso_double x) const
{
  return (m_slope * x + m_intercept);
}

double
LinearRegression::getRmsd() const
{

  std::size_t size = m_data.size();
  if(size > 2)
    {

      pappso::pappso_double sum_square_deviation = 0;
      for(size_t i = 0; i < size; i++)
        {
          sum_square_deviation += std::pow((m_data[i].y - getYfromX(m_data[i].x)), 2);
        }
      return sqrt(sum_square_deviation / (double)size);
    }
  return 0;
}

double
LinearRegression::getNrmsd() const
{
  return (getRmsd() / (maxYDataPoint(m_data.begin(), m_data.end())->y -
                       minYDataPoint(m_data.begin(), m_data.end())->y));
}

double
LinearRegression::getCoefficientOfDetermination() const
{
  std::size_t size = m_data.size();
  if(size > 2)
    {
      double meanY                               = meanYTrace(m_data.begin(), m_data.end());
      pappso::pappso_double sum_square_deviation = 0;
      for(size_t i = 0; i < size; i++)
        {
          sum_square_deviation += std::pow((m_data[i].y - getYfromX(m_data[i].x)), 2);
        }
      pappso::pappso_double sum_square_total = 0;
      for(size_t i = 0; i < size; i++)
        {
          sum_square_total += std::pow((m_data[i].y - meanY), 2);
        }
      return ((double)1.0 - (sum_square_deviation / sum_square_total));
    }
  return 0;
}
