TransformationModelLinear::TransformationModelLinear(
    const TransformationModel::DataPoints & data, const Param & params)
  {
    params_ = params;
    data_given_ = !data.empty();
    if (!data_given_ && params.exists("slope") && (params.exists("intercept")))
    {
      // don't estimate parameters, use given values
      slope_ = params.getValue("slope");
      intercept_ = params.getValue("intercept");
    }
    else     // estimate parameters from data
    {
      Param defaults;
      getDefaultParameters(defaults);
      params_.setDefaults(defaults);
      symmetric_ = params_.getValue("symmetric_regression") == "true";

      size_t size = data.size();
      if (size == 0)       // no data
      {
        throw Exception::IllegalArgument(__FILE__, __LINE__, __PRETTY_FUNCTION__,
                                         "no data points for 'linear' model");
      }
      else if (size == 1)       // degenerate case, but we can still do something
      {
        slope_ = 1.0;
        intercept_ = data[0].second - data[0].first;
      }
      else       // compute least-squares fit
      {
        vector<double> x(size), y(size);
        for (size_t i = 0; i < size; ++i)
        {
          if (symmetric_)
          {
            x[i] = data[i].second + data[i].first;
            y[i] = data[i].second - data[i].first;
          }
          else
          {
            x[i] = data[i].first;
            y[i] = data[i].second;
          }
        }
        double cov00, cov01, cov11, sumsq;         // covariance values, sum of squares
        double * x_start = &(x[0]), * y_start = &(y[0]);
        gsl_fit_linear(x_start, 1, y_start, 1, size, &intercept_, &slope_,
                       &cov00, &cov01, &cov11, &sumsq);

        if (symmetric_)         // undo coordinate transformation:
        {
          slope_ = (1.0 + slope_) / (1.0 - slope_);
          intercept_ = intercept_ * 1.41421356237309504880;           // 1.41... = sqrt(2)
        }
      }
    }
  }
  TransformationModelLinear::TransformationModelLinear(const TransformationModel::DataPoints& data, const Param& params) :
    TransformationModel(data, params) // initializes model
  {
    data_given_ = !data.empty();

    if (!data_given_ && params.exists("slope") && params.exists("intercept"))
    {
      // don't estimate parameters, use given values
      slope_ = params.getValue("slope");
      intercept_ = params.getValue("intercept");
    }
    else // estimate parameters from data
    {
      Param defaults;
      getDefaultParameters(defaults);
      params_.setDefaults(defaults);
      symmetric_ = params_.getValue("symmetric_regression") == "true";
      // weight the data (if weighting is specified)
      TransformationModel::DataPoints data_weighted = data;
      if ((params.exists("x_weight") && params.getValue("x_weight") != "") || (params.exists("y_weight") && params.getValue("y_weight") != ""))
      {
        weightData(data_weighted);
      }

      size_t size = data_weighted.size();
      std::vector<Wm5::Vector2d> points;
      if (size == 0) // no data
      {
        throw Exception::IllegalArgument(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION,
                                         "no data points for 'linear' model");
      }
      else if (size == 1) // degenerate case, but we can still do something
      {               
        slope_ = 1.0;
        intercept_ = data_weighted[0].second - data_weighted[0].first;
      }
      else // compute least-squares fit
      {
        for (size_t i = 0; i < size; ++i)
        {
          points.push_back(Wm5::Vector2d(data_weighted[i].first, data_weighted[i].second));
        }
        if (!Wm5::HeightLineFit2<double>(static_cast<int>(size), &points.front(), slope_, intercept_))
        {
          throw Exception::UnableToFit(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "TransformationModelLinear", "Unable to fit linear transformation to data points.");
        }
      }
      // update params
      params_.setValue("slope", slope_);
      params_.setValue("intercept", intercept_);
    }
  }