#include "greedy.h"


#ifndef _SIMAN_SOLVER_H
#define	_SIMAN_SOLVER_H

#include "scproblem.h"
#include "scpview.h"
#include "qsorter.h"
#include "lagrange.h"
#include <math.h>


#ifdef	__cplusplus
extern "C" {
#endif

 /** \defgroup SA Simulated annealing metaheuristic for SCP
 *   Simulated annealing is well known metaheuristic used for many
  *  NP problems.
  *
 * @{
 */

typedef struct _SimanSolver SimanSolver;

/** \brief State of Simulated annealing*/
struct _SimanSolver {
    
    /**\brief View to the underlying problem*/
    SCPView* problemView;
    /**\brief Temperature*/
    float temp;
    /**\brief Cooling constant*/
    float constant;
    /**\brief Cost of best solution*/
    int bestSolutionCost;
    /**\brief Best solution found*/
    unsigned char* bestSolutionFound;
    /**\brief Current solution*/
    unsigned char* currentSolution;
    /**\brief Neighbor solution*/
    unsigned char* neighborSolution;
    /**\brief Perturb call counter*/
    int perturbCounter;
    /**\brief Construct call counter*/
    int constructCounter;
    /**\brief Sorted view to the columns*/
    SCPView* sortedView;
    /**\brief Collection of morphs*/
    int** morphCollection;
    /** Whether morphing is used*/
    int morphFlag;
    /** Number of total SA iterations*/
    int stIterationCounter;
    
};

/** \brief Create new Simulated annealing
 *  \param pv View to the problem that will be solved
 *  \param spv Sorted view to the problem. If NULL is passed, that
 *   sorted view is automatically created
 *  \return New Simulated annealing
 */
SimanSolver* siman_solver_new(SCPView* pv,SCPView* spv);

/** \brief Solve the problem using Simulated annealing
 *  \param temp Initial temperature
 *  \param frozenTemp Final temperature
 *  \param iterations Number of iterations at single temperature
 *  \param morphFlag Indicates whether to use morphs
 *  \param constant Cooling constant
 *  \param baseSolution Initial solution, must be feasible
 *  \param lowerBound Lower bound for the solution. When this lower bound is
 *   reached, algorithm is finished
 */
void siman_solver_solve(SimanSolver* s, float temp, float frozenTemp, int iterations, int morphFlag,float constant,unsigned char* baseSolution,int lowerBound);

/** \brief Perform DEFLECT phase of SEARCH operation*/
void siman_solver_deflect(SimanSolver* s);

/** \brief Perform CONSTRUCT phase of SEARCH operation*/
void siman_solver_construct(SimanSolver* s);

/** \brief Perform REDUND phase of SEARCH operation*/
void siman_solver_redund(SimanSolver* s);

/** \brief Perform SEARCH operation. Find neighbor of current solution*/
void siman_solver_search(SimanSolver* s);

/** \brief Perform MORPH operation
 *  \param solution What solution is to be morphed
 */
void siman_solver_morph(SimanSolver* s,unsigned char* solution);

/** \brief Get random index from binary vector
 *  \param mask Binary vector
 *  \return Index or -1 when nothing found
 */
int siman_solver_get_random_index(unsigned char* mask,int range);

/** \brief Copy best solution found to the retMask parameter
 *  \param retMask pointer to allocated memory where the solution is
 *   copied
 */
void siman_solver_get_solution(SimanSolver* s,unsigned char* retMask);

/** \brief Delete Simulated annealing*/
void siman_solver_delete(SimanSolver* s);

/** \brief Print state of Simulated annealing*/
void siman_solver_print(SimanSolver* s);

/** \brief Supplementary comparation function*/
int siman_solver_compare(SCPView* v,int c1,int c2,void* miscData);

/** \brief Return index of least unique column*/
int siman_solver_get_least_unique(SimanSolver* s);

 /**@}*/

#ifdef	__cplusplus
}
#endif

#endif	/* _SIMAN_SOLVER_H */

