text: //=============================================================================================================
  /**
   * @file     mne_inverse_operator.h
   * @author   Gabriel B Motta <gabrielbenmotta@gmail.com>;
   *           Lorenz Esch <lesch@mgh.harvard.edu>;
   *           Matti Hamalainen <msh@nmr.mgh.harvard.edu>;
   *           Christoph Dinh <chdinh@nmr.mgh.harvard.edu>
   * @since    0.1.0
   * @date     July, 2012
   *
   * @section  LICENSE
   *
   * Copyright (C) 2012, Gabriel B Motta, Lorenz Esch, Matti Hamalainen, Christoph Dinh. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
   * the following conditions are met:
   *     * 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 MNE-CPP authors nor the names of its contributors may be used
   *       to endorse or promote products derived from this software without specific prior written permission.
   *
   * 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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.
   *
   *
   * @brief     MNEInverseOperator class declaration.
   *
   */
  
  #ifndef MNE_INVERSE_OPERATOR_H
  #define MNE_INVERSE_OPERATOR_H
  
  //=============================================================================================================
  // INCLUDES
  //=============================================================================================================
  
  #include "mne_global.h"
  #include "mne_sourcespace.h"
  #include "mne_forwardsolution.h"
  
  #include <fiff/fiff_types.h>
  #include <fiff/fiff_named_matrix.h>
  #include <fiff/fiff_proj.h>
  #include <fiff/fiff_cov.h>
  #include <fiff/fiff_info.h>
  
  #include <utils/mnemath.h>
  
  //=============================================================================================================
  // EIGEN INCLUDES
  //=============================================================================================================
  
  #include <Eigen/Core>
  
  //=============================================================================================================
  // QT INCLUDES
  //=============================================================================================================
  
  #include <QList>
  
  //=============================================================================================================
  // FORWARD DECLARATIONS
  //=============================================================================================================
  
  namespace FSLIB
  {
      class Label;
  }
  
  //=============================================================================================================
  // DEFINE NAMESPACE MNELIB
  //=============================================================================================================
  
  namespace MNELIB
  {
  
  //=========================================================================================================
  /**
   * Gain matrix output data for one region, used for clustering
   */
  struct RegionMTOut
  {
      Eigen::VectorXi    roiIdx;     /**< Region cluster indices */
      Eigen::MatrixXd    ctrs;       /**< Cluster centers */
      Eigen::VectorXd    sumd;       /**< Sums of the distances to the centroid */
      Eigen::MatrixXd    D;          /**< Distances to the centroid */
  
      qint32      iLabelIdxOut;   /**< Label ID */
  };
  
  //=========================================================================================================
  /**
   * Gain matrix input data for one region, used for clustering
   */
  struct RegionMT
  {
      Eigen::MatrixXd    matRoiMT;           /**< Reshaped region gain matrix sources x sensors(x,y,z)*/
      Eigen::MatrixXd    matRoiMTOrig;       /**< Region gain matrix sensors x sources(x,y,z)*/
  
      qint32      nClusters;      /**< Number of clusters within this region */
      Eigen::VectorXi    idcs;           /**< Get source space indeces */
      qint32      iLabelIdxIn;    /**< Label ID */
  
      QString     sDistMeasure;   /**< "cityblock" or "sqeuclidean" */
  
      RegionMTOut cluster() const
      {
          QString t_sDistMeasure;
           if(sDistMeasure.isEmpty())
               t_sDistMeasure = QString("cityblock");
           else
               t_sDistMeasure = sDistMeasure;
  
          // Kmeans Reduction
          RegionMTOut p_RegionMTOut;
  
          UTILSLIB::KMeans t_kMeans(t_sDistMeasure, QString("sample"), 5);
  
          t_kMeans.calculate(this->matRoiMT, this->nClusters, p_RegionMTOut.roiIdx, p_RegionMTOut.ctrs, p_RegionMTOut.sumd, p_RegionMTOut.D);
  
          p_RegionMTOut.iLabelIdxOut = this->iLabelIdxIn;
  
          return p_RegionMTOut;
      }
  };
  
  //=============================================================================================================
  /**
   * Inverse operator
   *
   * @brief Inverse operator
   */
  class MNESHARED_EXPORT MNEInverseOperator
  {
  public:
      typedef QSharedPointer<MNEInverseOperator> SPtr;            /**< Shared pointer type for MNEInverseOperator. */
      typedef QSharedPointer<const MNEInverseOperator> ConstSPtr; /**< Const shared pointer type for MNEInverseOperator. */
  
      //=========================================================================================================
      /**
       * Default constructor
       */
      MNEInverseOperator();
  
      //=========================================================================================================
      /**
       * Constructs an inverse operator, by reading from a IO device.
       *
       * @param[in] p_IODevice     IO device to read from the evoked data set.
       */
      MNEInverseOperator(QIODevice& p_IODevice);
  
      //=========================================================================================================
      /**
       * Constructs an inverse operator by making one.
       *
       * @param[in] info               The measurement info to specify the channels to include. Bad channels in info['bads'] are not used.
       * @param[in] forward            Forward operator.
       * @param[in] p_noise_cov        The noise covariance matrix.
       * @param[in] loose              float in [0, 1]. Value that weights the source variances of the dipole components defining the tangent space of the cortical surfaces.
       * @param[in] depth              float in [0, 1]. Depth weighting coefficients. If None, no depth weighting is performed.
       * @param[in] fixed              Use fixed source orientations normal to the cortical mantle. If True, the loose parameter is ignored.
       * @param[in] limit_depth_chs    If True, use only grad channels in depth weighting (equivalent to MNE C code). If grad chanels aren't present, only mag channels will be used (if no mag, then eeg). If False, use all channels.
       */
      MNEInverseOperator(const FIFFLIB::FiffInfo &info,
                         const MNEForwardSolution& forward,
                         const FIFFLIB::FiffCov& p_noise_cov,
                         float loose = 0.2f,
                         float depth = 0.8f,
                         bool fixed = false,
                         bool limit_depth_chs = true);
  
      //=========================================================================================================
      /**
       * Copy constructor.
       *
       * @param[in] p_MNEInverseOperator   MNE forward solution
       */
      MNEInverseOperator(const MNEInverseOperator &p_MNEInverseOperator);
  
      //=========================================================================================================
      /**
       * Destroys the MNEInverseOperator.
       */
      ~MNEInverseOperator();
  
      //=========================================================================================================
      /**
       * Simple matrix multiplication followed by combination of the
       * current components
       *
       * This does all the data transformations to compute the weights for the
       * eigenleads
       *
       * @param[in] label          labels.
       * @param[in] method         The applied normals. ("MNE" | "dSPM" | "sLORETA")
       * @param[in] pick_normal    Pick normals.
       * @param[out] K             Kernel.
       * @param[out] noise_norm    Noise normals.
       * @param[out] vertno        Vertices of the hemispheres.
       *
       * @return the assembled kernel
       */
      bool assemble_kernel(const FSLIB::Label &label,
                           QString method,
                           bool pick_normal,
                           Eigen::MatrixXd &K,
                           Eigen::SparseMatrix<double> &noise_norm,
                           QList<Eigen::VectorXi> &vertno);
  
      //=========================================================================================================
      /**
       * Check that channels in inverse operator are measurements.
       *
       * @param[in] info   The measurement info
       *
       * @return true when successful, false otherwise
       */
      bool check_ch_names(const FIFFLIB::FiffInfo &info) const;
  
      //=========================================================================================================
      /**
       * Clusters the current kernel
       *
       * @param[in]    p_AnnotationSet     Annotation set containing the annotation of left & right hemisphere
       * @param[in]    p_iClusterSize      Maximal cluster size per roi
       * @param[out]   p_D                 The cluster operator
       * @param[in]    p_sMethod           "cityblock" or "sqeuclidean"
       *
       * @return the clustered kernel
       */
      Eigen::MatrixXd cluster_kernel(const FSLIB::AnnotationSet &p_AnnotationSet,
                                     qint32 p_iClusterSize,
                                     Eigen::MatrixXd& p_D,
                                     QString p_sMethod = "cityblock") const;
  
      //=========================================================================================================
      /**
       * Returns the current kernel
       *
       * @return the current kernel
       */
      inline Eigen::MatrixXd& getKernel();
  
      //=========================================================================================================
      /**
       * Returns the current kernel
       *
       * @return the current kernel
       */
      inline Eigen::MatrixXd getKernel() const;
  
      //=========================================================================================================
      /**
       * Has inverse operator fixed orientation?
       *
       * @return true if inverse operator has fixed orientation, false otherwise
       */
      inline bool isFixedOrient() const;
  
      //=========================================================================================================
      /**
       * Assembles the inverse operator.
       *
       * @param[in] info               The measurement info to specify the channels to include. Bad channels in info['bads'] are not used.
       * @param[in] forward            Forward operator.
       * @param[in] p_noise_cov        The noise covariance matrix.
       * @param[in] loose              float in [0, 1]. Value that weights the source variances of the dipole components defining the tangent space of the cortical surfaces.
       * @param[in] depth              float in [0, 1]. Depth weighting coefficients. If None, no depth weighting is performed.
       * @param[in] fixed              Use fixed source orientations normal to the cortical mantle. If True, the loose parameter is ignored.
       * @param[in] limit_depth_chs    If True, use only grad channels in depth weighting (equivalent to MNE C code). If grad chanels aren't present, only mag channels will be used (if no mag, then eeg). If False, use all channels.
       *
       * @return the assembled inverse operator
       */
      static MNEInverseOperator make_inverse_operator(const FIFFLIB::FiffInfo &info,
                                                      MNEForwardSolution forward,
                                                      const FIFFLIB::FiffCov& p_noise_cov,
                                                      float loose = 0.2f,
                                                      float depth = 0.8f,
                                                      bool fixed = false,
                                                      bool limit_depth_chs = true);
  
      //=========================================================================================================
      /**
       * mne_prepare_inverse_operator
       *
       * ### MNE toolbox root function ###
       *
       * Prepare for actually computing the inverse
       *
       * @param[in] nave      Number of averages (scales the noise covariance)
       * @param[in] lambda2   The regularization factor
       * @param[in] dSPM      Compute the noise-normalization factors for dSPM?
       * @param[in] sLORETA   Compute the noise-normalization factors for sLORETA?
       *
       * @return the prepared inverse operator
       */
      MNEInverseOperator prepare_inverse_operator(qint32 nave,
                                                  float lambda2,
                                                  bool dSPM,
                                                  bool sLORETA = false) const;
  
      //=========================================================================================================
      /**
       * mne_read_inverse_operator
       *
       * ### MNE toolbox root function ###
       *
       * Reads the inverse operator decomposition from a fif file
       *
       * @param [in] p_IODevice   A fiff IO device like a fiff QFile or QTCPSocket
       * @param [out] inv          The read inverse operator
       *
       * @return true if succeeded, false otherwise
       */
      static bool read_inverse_operator(QIODevice &p_IODevice, MNEInverseOperator& inv);
  
      //=========================================================================================================
      /**
       * write_inverse_operator
       *
       * Writes an inverse operator to a fif file
       *
       * @param [in] p_IODevice   IO device to write the inverse operator to.
       */
      void write(QIODevice &p_IODevice);
  
      //=========================================================================================================
      /**
       * Writes the inverse operator to a FIFF stream
       *
       * @param[in] p_pStream  The stream to write to.
       */
      void writeToStream(FIFFLIB::FiffStream* p_pStream);
  
      //=========================================================================================================
      /**
       * overloading the stream out operator<<
       *
       * @param[in] out                    The stream to which the fiff covariance should be assigned to.
       * @param[in] p_MNEInverseOperator   MNEInverseOperator which should be assigned to the stream.
       *
       * @return the stream with the attached fiff covariance matrix
       */
      friend std::ostream& operator<<(std::ostream& out, const MNELIB::MNEInverseOperator &p_MNEInverseOperator);
  
  public:
      FIFFLIB::FiffInfoBase info;                     /**< light weighted measurement info */
      FIFFLIB::fiff_int_t methods;                    /**< MEG, EEG or both */
      FIFFLIB::fiff_int_t source_ori;                 /**< Source orientation: f */
      FIFFLIB::fiff_int_t nsource;                    /**< Number of source points. */
      FIFFLIB::fiff_int_t nchan;                      /**< Number of channels. */
      FIFFLIB::fiff_int_t coord_frame;                /**< Coordinate system definition */
      Eigen::MatrixXf  source_nn;                     /**< Source normals. */
      Eigen::VectorXd  sing;                          /**< Singular values */
      bool    eigen_leads_weighted;                   /**< If eigen lead are weighted. */
      FIFFLIB::FiffNamedMatrix::SDPtr eigen_leads;    /**< Eigen leads */
      FIFFLIB::FiffNamedMatrix::SDPtr eigen_fields;   /**< Eigen fields */
      FIFFLIB::FiffCov::SDPtr noise_cov;              /**< Noise covariance matrix. */
      FIFFLIB::FiffCov::SDPtr source_cov;             /**< Source covariance matrix. */
      FIFFLIB::FiffCov::SDPtr orient_prior;           /**< Orientation priors */
      FIFFLIB::FiffCov::SDPtr depth_prior;            /**< Depth priors */
      FIFFLIB::FiffCov::SDPtr fmri_prior;             /**< fMRI priors */
      MNESourceSpace src;                             /**< Source Space */
      FIFFLIB::FiffCoordTrans mri_head_t;             /**< MRI head coordinate transformation */
      FIFFLIB::fiff_int_t nave;                       /**< Number of averages used to regularize the solution. Set to 1 on single Epoch by default.*/
      QList<FIFFLIB::FiffProj> projs;                 /**< SSP operator */
      Eigen::MatrixXd proj;                           /**< The projector to apply to the data. */
      Eigen::MatrixXd whitener;                       /**< Whitens the data */
      Eigen::VectorXd reginv;                         /**< The diagonal matrix implementing. regularization and the inverse */
      Eigen::SparseMatrix<double> noisenorm;          /**< These are the noise-normalization factors */
  
  private:
      Eigen::MatrixXd m_K;                            /**< Everytime a new kernel is assamebled a copy is stored here */
  };
  
  //=============================================================================================================
  // INLINE DEFINITIONS
  //=============================================================================================================
  
  inline Eigen::MatrixXd& MNEInverseOperator::getKernel()
  {
      return m_K;
  }
  
  //=============================================================================================================
  
  inline Eigen::MatrixXd MNEInverseOperator::getKernel() const
  {
      return m_K;
  }
  
  //=============================================================================================================
  
  inline bool MNEInverseOperator::isFixedOrient() const
  {
      return this->source_ori == FIFFV_MNE_FIXED_ORI;
  }
  
  //=============================================================================================================
  
  inline std::ostream& operator<<(std::ostream& out, const MNELIB::MNEInverseOperator &p_MNEInverseOperator)
  {
      out << "#### MNE Inverse Operator ####\n";
  
      out << "\n methods: " << p_MNEInverseOperator.methods << std::endl;
      out << "\n source_ori: " << p_MNEInverseOperator.source_ori << std::endl;
      out << "\n nsource: " << p_MNEInverseOperator.nsource << std::endl;
      out << "\n nchan: " << p_MNEInverseOperator.nchan << std::endl;
      out << "\n coord_frame:\n\t" << p_MNEInverseOperator.coord_frame << std::endl;
  
      out << "\n eigen_leads: " << p_MNEInverseOperator.eigen_leads << std::endl;
      out << "\n eigen_fields:\n\t" << p_MNEInverseOperator.eigen_fields << std::endl;
  
      return out;
  }
  } // NAMESPACE
  
  #ifndef metatype_mneinverseoperatorsptr
  #define metatype_mneinverseoperatorsptr
  Q_DECLARE_METATYPE(QSharedPointer<MNELIB::MNEInverseOperator>); /**< Provides QT META type declaration of the QSharedPointer<MNELIB::MNEInverseOperator> type. For signal/slot usage.*/
  #endif
  
  #ifndef metatype_mneinverseoperators
  #define metatype_mneinverseoperators
  Q_DECLARE_METATYPE(MNELIB::MNEInverseOperator); /**< Provides QT META type declaration of the MNELIB::MNEInverseOperator type. For signal/slot usage.*/
  #endif
  
  #endif // MNE_INVERSE_OPERATOR_H
  