/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis 
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA 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.
 *
 * This program 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 MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef __SOLVERCG_HH
#define __SOLVERCG_HH

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <mia/3d.hh>
#include <cstdio>
#include <stdexcept>
#include <string>



NS_MIA_BEGIN

using namespace std;



/*! 
  @ingroup filtering 
  \brief function defining field borders

    \param index  index running from 0 to NoOfPixels
    \param nx     no of pixels in x
    \param ny     no of pixels in y
    \param nz     no of pixels in z

*/
extern bool fborder (long index, long nx, long ny, long nz);

/*! 
  @ingroup filtering 
  \brief a class providing a CG solver
  
  This contains basic solver functions based on CG schemes
  
  \author Stefan Burckhardt and Carsten Wolters, wolters@mis.mpg.de, 2004
  \remark adapted for libmona by Heike Jaenicke and Marc Tittgemeyer, tittge@cbs.mpg.de, 2004
  \remark adapted for mia2 by Gert Wollny, gw.fossdev@gmail.com 2011 
*/


class solve_sCG {

  private:

	double __lambda1;
	double __lambda2;

	// Dimension of images
	long __iter;
	unsigned int  __nx, __ny, __nz;
	unsigned long __count;

	// Pointer to Elements of w
	float *__weight_imagePtr;
	float *__fptr;
	float *__gain_image_ptr;



	// b and x for solution of system
	double *__b;
	double *__v;

	// counts iterations


	// help pointers for one iteration cycle
	double *__r;	   // r^(k)
	double *__rho;     // p^(k)
	double *__g;
	double *__Ag;	   // speichert A * p
	// Field of scaling factors
	double *__scale;
	double *__scale2;

	// field for border voxels
	bool *__border;


	double __r1rho1;   // speichert r1 * rho1
	double __r2rho2;   // speichert r2 * rho2
	double __normr0;
	double __q, __e, __sprod;

	// minimal residuum
	double __min_res, __relres;

	/** function for initialising
         */
        void init();

  public:
	/** constructor
	    \param w1
	    \param f1
	    \param g1
	    \param l1
	    \param l2
	    \param r_res
	    \param m_res
	 */
	solve_sCG (C3DFImage& w1, C3DFImage&  f1, C3DFImage& g1, double l1, double l2, double r_res, double m_res);

	~solve_sCG();

	/** Function to solve ...
	    \param max_iterations Maximum number of iterations
	    \param firstnormr0
	    \returns
	 */
	int solve(long max_iterations, double *firstnormr0);

	/** Function to get preset number of iterations
	    \returns Number of iterations
	 */
	inline long get_iterations() {return __iter;}

	/** Multiplication of vector and matrix

	TODO mit standard classe Austauschen

	    \param x
	    \param result
	    \param start
	    \param ende
	 */
	void multA(double *x, double *result, long start, long ende);

	/** Multiplication

	TODO mit standard classe Austauschen

	    \param x Pointer at
	    \param result Pointer at
	 */
	void multA_float(float *x, float *result);

	/**
	    \param gain Image with gain-field
	 */
	void get_solution(C3DFImage& gain);

	/**
	    \param e
	 */
	void add_to_solution(C3DFImage *e);

	/** function for parallel solver
	    @param max_iteration
	    @param normr
	    @param firstnormr0
	 */
	void solvepar(long *max_iteration, double *normr, double *firstnormr0);

};

NS_MIA_END

#endif
