text: // --------------------------------------------------------------------------
  //                   OpenMS -- Open-Source Mass Spectrometry
  // --------------------------------------------------------------------------
  // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
  // ETH Zurich, and Freie Universitaet Berlin 2002-2020.
  //
  // This software is released under a three-clause BSD license:
  //  * Redistributions of source code must retain the above copyright
  //    notice, this list of conditions and the following disclaimer.
  //  * Redistributions in binary form must reproduce the above copyright
  //    notice, this list of conditions and the following disclaimer in the
  //    documentation and/or other materials provided with the distribution.
  //  * Neither the name of any author or any participating institution
  //    may be used to endorse or promote products derived from this software
  //    without specific prior written permission.
  // For a full list of authors, refer to the file AUTHORS.
  // --------------------------------------------------------------------------
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
  // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  //
  // --------------------------------------------------------------------------
  // $Maintainer: Timo Sachsenberg $
  // $Authors: Clemens Groepl, Hendrik Weisser $
  // --------------------------------------------------------------------------
  
  #pragma once
  
  #include <OpenMS/DATASTRUCTURES/Param.h>
  #include <OpenMS/ANALYSIS/MAPMATCHING/TransformationModel.h>
  #include <iostream>
  #include <map>
  
  namespace OpenMS
  {
    /**
      @brief Generic description of a coordinate transformation.
  
      This description primarily stores data points (coordinate pairs) from which a @ref TransformationModel "transformation model" can be estimated. Applying the transformation to a coordinate (via @p apply) then means evaluating the model at that coordinate.
  
      The following models are available:
      - @p none (TransformationModel): \f$ f(x) = x \f$ (identity)
      - @p identity: Same as @p none, but intended for reference files (used to indicate that no other model should be fit, because the identity is already optimal).
      - @p linear (TransformationModelLinear): \f$ f(x) = slope * x + intercept \f$
      - @p interpolated (TransformationModelInterpolated): Interpolation between pairs, extrapolation using first and last pair. Supports different interpolation types.
      - @p b-spline (TransformationModelBSpline): Non-linear smoothing spline, with different options for extrapolation.
      - @b lowess (TransformationModelLowess): Non-linear smoothing via local regression, with different options for extrapolation.
  
      @remark TransformationDescription stores data points, TransformationModel stores parameters. That way, data can be modeled using different models/parameters, and models can still keep a representation of the data in the format they need (if at all).
  
      @ingroup MapAlignment
    */
    class OPENMS_DLLAPI TransformationDescription
    {
      // friend class MapAlignmentAlgorithm;
  
  public:
  
      /** @brief Summary statistics before/after applying the transformation.
                For deviations before/after transformation, the percentiles 
                100, 99, 95, 90, 75, 50, 25 are returned.
       */ 
      struct TransformationStatistics
      {
        TransformationStatistics& operator=(const TransformationStatistics& rhs)
        {
          if (this == &rhs)
            return *this;
  
          // percents = rhs.percents; // const, cannot be assigned
          xmin = rhs.xmin;
          xmax = rhs.xmax;
          ymin = rhs.ymin;
          ymax = rhs.ymax;
          percentiles_before = rhs.percentiles_before;
          percentiles_after = rhs.percentiles_after;
  
          return *this;
        }
  
        const std::vector<Size> percents = {100, 99, 95, 90, 75, 50, 25};
        double xmin = 0; ///< smallest x value before transformation
        double xmax = 0; ///< largest x value before transformation
        double ymin = 0; ///< smallest y value before transformation
        double ymax = 0; ///< largest y value before transformation
        
        std::map<Size, double> percentiles_before; ///< percentiles of x/y deviations before transformation
        std::map<Size, double> percentiles_after; ///< percentiles of x/y deviations after transformation
      };
      
  
      /// Coordinate pair
      typedef TransformationModel::DataPoint DataPoint;
      /// Vector of coordinate pairs
      typedef TransformationModel::DataPoints DataPoints;
  
      /// Default constructor
      TransformationDescription();
      /// Constructor from data
      explicit TransformationDescription(const DataPoints& data);
      /// Destructor
      ~TransformationDescription();
  
      /// Copy constructor
      TransformationDescription(const TransformationDescription& rhs);
      /// Assignment operator
      TransformationDescription& operator=(const TransformationDescription& rhs);
  
      /// Fits a model to the data
      void fitModel(const String& model_type, const Param& params = Param());
  
      /**
        @brief Applies the transformation to @p value.
  
        Returns the result of evaluating the fitted model at @p value.
        Returns @p value unchanged if no model was fitted.
      */
      double apply(double value) const;
  
      /// Gets the type of the fitted model
      const String& getModelType() const;
  
      /// Gets the possible types of models
      static void getModelTypes(StringList& result);
  
      /**
        @brief Sets the data points
  
        Removes the model that was previously fitted to the data (if any).
      */
      void setDataPoints(const DataPoints& data);
  
      /**
        @brief Sets the data points (backwards-compatible overload)
  
        Removes the model that was previously fitted to the data (if any).
      */
      void setDataPoints(const std::vector<std::pair<double, double> >& data);
  
      /// Returns the data points
      const DataPoints& getDataPoints() const;
  
      /// Non-mutable access to the model parameters
      const Param& getModelParameters() const;
  
      /// Computes an (approximate) inverse of the transformation
      void invert();
  
      /**
         @brief Get the deviations between the data pairs
  
         @param diffs Output
         @param do_apply Get deviations after applying the model?
         @param do_sort Sort @p diffs before returning?
      */
      void getDeviations(std::vector<double>& diffs, bool do_apply = false,
                         bool do_sort = true) const;
  
      /// Get summary statistics (ranges and errors before/after)
      TransformationStatistics getStatistics() const;
  
      /// Print summary statistics for the transformation
      void printSummary(std::ostream& os = std::cout) const;
  
  protected:
      /// Data points
      DataPoints data_;
      /// Type of model
      String model_type_;
      /// Pointer to model
      TransformationModel* model_;
    };
  
  } // end of namespace OpenMS
  
  