#ifndef _SCPVIEW_H
#define	_SCPVIEW_H

#include "scproblem.h"
#include "ilist.h"

#ifdef	__cplusplus
extern "C" {
#endif

/** \defgroup SCPView View to underlying SCP
 *  @{
 *
 *  This module provides view to underlying set covering problem. Matrices
 *  of set covering problems are very large, so copying them, sorting them
 *  and creating subproblems are memory consuming operations.
 *
 *  Views can provide row and column mappings that allow to construct subproblems,
 *  to sort the columns quickly etc. The cost is little CPU time needed to
 *  perform more dereferencing.
 *
 *  Additionaly there is also mapping between rows and columns of copy and
 *  its parent. so creating a simple hierarchy of derifed views is possible
 *
 *  To provide stability and safety, view does not provide any standard functionality
 *  for modification of underlying set covering problem. One exception is
 *  a modification for group testing heuristic
 *
 */


/** \brief Provides view to the SCProblem*/
typedef struct _SCPView SCPView;

struct _SCPView {
    /** Pointer to the underlying problem*/
    SCProblem* problem;
    /** Column mapping to the original problem columns*/
    int* columnMap;
    /** Row mapping to the original problem rows*/
    int* rowMap;
    /** Number of rows*/
    int rows;
    /** Number of columns*/
    int columns;
    /** Row mapping to parent's rows*/
    int* parentRowMap;
    /** Column mapping to parent's columns*/
    int* parentColumnMap;
};

/** \brief Create new SCPView*/
SCPView* scp_view_new(SCProblem* problem);

/** \brief Delete SCPView*/
void scp_view_delete(SCPView* v);

/** \brief Get value from SCP's matrix
 *  \param row Row
 *  \param column Column
 *  \return 0 or 1
 */
unsigned char scp_view_get(SCPView* v,int row,int column);

/** \brief Get cost of column
 *  \param column Column
 */
int scp_view_get_cost(SCPView* v,int column);

/** \brief Get dumb copy of SCPView. For internal use
 *  \param rows Number of rows of the copy
 *  \param cols Number of columns of the copy
 *  \return Copy of SCPView
 */
SCPView* scp_view_get_dumb_copy(SCPView* v,int rows,int cols);

/** \brief Get exact copy of SCPView
 *  \return Copy of SCPView
 */
SCPView* scp_view_get_copy(SCPView* v);

/** \brief Create derived SCPView that contains columns specified by mask
 *  \param mask Mask of columns
 *  \param trueVal What value of mask[i] indicates that i-th column is to be added to the
 *         derived SCPView
 *  \return Derived SCPView
 */
SCPView* scp_view_get_column_mask_subview(SCPView* v,unsigned char* mask,int trueVal);


SCPView* scp_view_get_column_mask_subclone(SCPView* v,unsigned char* mask,int trueVal);
/** \brief Create derived SCPView that contains rows and columns specified by masks
 *  \param rowMask Mask of rows
 *  \param columnMask Mask of columns
 *  \param trueVal What value of mask[i] indicates that i-th row or column is to be
 *         added to the derived SCPView
 *  \return Derived SCPView
 */
SCPView* scp_view_get_row_and_column_mask_subview(SCPView* v,unsigned char* rowMask,unsigned char* columnMask,int trueVal);


SCPView* scp_view_get_row_and_column_mask_subclone(SCPView* v,unsigned char* rowMask,unsigned char* columnMask,int trueVal);
/** \brief Swap two rows
 *   This is useful for n*logn sorting methods. Mapping is of course updated
 *   \param r1 Row to be swapped
 *   \param r2 Row to be swapped
 */
void scp_view_swap_rows(SCPView* v,int r1,int r2);

/** \brief Swap two columns
 *   This is useful for n*logn sorting methods. Mapping is of course updated
 *   \param r1 Column to be swapped
 *   \param r2 Column to be swapped
 */
void scp_view_swap_columns(SCPView* v,int c1,int c2);

/** \brief Get number of rows covered by specified column
 *  \param c Column
 *  \return Number of rows
 */
int scp_view_get_covered_by_column(SCPView* v,int c);

/** \brief Get number of unique rows that are covered by two columns
 *  \param c1 First column
 *  \param c2 Second column
 *  \return Number of unique rows covered
 */
int scp_view_get_2c_union_size(SCPView* v,int c1,int c2);

/** \brief Get number of unique rows that are:\n
 *   -# Covered by specified column
 *   -# Covered by mask of rows
 *  \param mask Mask of rows
 *  \param c1 Column
 *  \return Number of rows
 */
int scp_view_get_1c_mask_union_size(SCPView* v,unsigned char* mask,int c1);

/** \brief Get number of rows that are covered by intersection of column and
 *   mask of rows
 *  \param mask Mask of rows
 *  \param c1 Column
 *  \return Number of rows
 */
int scp_view_get_1c_mask_intersect_size(SCPView* v,unsigned char* mask,int c1);

/** \brief Get number of columns that are covering specified row
 *  \param r Row
 *  \return Number of columns
 */
int scp_view_get_columns_covering(SCPView* v,int r);

/** \brief Test whether provided mask of columns is a solution to SCP
 *  \param x Mask of columns
 *  \return 0 or 1
 */
int scp_view_is_solution(SCPView* v,unsigned char* x);
int scp_view_is_solution_d(SCPView* v,double* x);

/** \brief Calculate cost of columns specified by mask of columns
 *  \param mask Mask of columns
 *  \param count Length of the mask
 *  \return Cost
 */
int scp_view_get_cost_mask(SCPView* v,unsigned char* mask,int count) ;


/** \brief Get number of rows covered by columns specified in the mask
 *  \param mask Mask of columns
 *  \return Number of rows covered
 */
int scp_view_get_mask_coverage(SCPView* v,unsigned char* mask);

/** \brief Check whether the view has any solutions
 *  \return Returns 1 when there exist a solution or 0 when not
 */
int scp_view_check_solvable(SCPView* v);

/** \brief Modify SCPView for group testing heuristic (part of LCE).
 *   Warning: It is absolutely necessary not to use parentRowMap, because
 *   it is invalid after this modification. Column mapping is safe.
 *  \param startColumn Index of first column from the tested group
 *  \param endColumn Index of last column from the tested group
 */
void scp_view_modify_for_gth(SCPView* v,int startColumn,int endColumn);

/** \brief This should be called after work with gth modified view is finished*/
void scp_view_demodify_for_gth(SCPView* v);

/** \brief Remove columns that are to be fixed (There exist rows that are
 *  covered by only these rows
 *  \return List of columns mapped to the columns of parent
 */
IList* scp_view_remove_fixed_columns(SCPView** v);

/** \brief Remove dominance from the view*/
void scp_view_remove_dominance(SCPView** v);

unsigned char* scp_view_remove_row_dominance(SCPView* v,int* suc);
unsigned char* scp_view_remove_column_dominance(SCPView* v,int* suc);

/** \brief Get subview based on the row mask
 *  \param mask Row mask
 *  \param trueVal. What value in the mask will lead to keeping the row in
 *   the subview
 */
SCPView* scp_view_get_row_mask_subview(SCPView* v,unsigned char* mask,int trueVal);

/** \brief Return how many rows are covered by specified column, taking into
 *   account only rows that are not listed
 *  \param rowList Rows that are not listed
 *  \param c1 Index of column
 */
int scp_view_get_negative_list_diference_size(SCPView* v,IList* rowList,int c1);

/** \brief Return a clone of View that contain only listed columns*/
SCPView* scp_view_get_column_list_subclone(SCPView* v,IList* list);
/** \brief Return subview ot View that contains only listed columns*/
SCPView* scp_view_get_column_list_subview(SCPView* v,IList* list);
/** \brief Return a clone of View that contain only listed rows*/
SCPView* scp_view_get_row_list_subclone(SCPView* v,IList* list);
/** \brief Return a subview of View that contain only listed rows*/
SCPView* scp_view_get_row_list_subview(SCPView* v,IList* list);
/** \brief Return a clone of view that contain only listed rows and columns*/
SCPView* scp_view_get_row_and_column_list_subclone(SCPView* v,IList* rowList,IList* columnList);
/** \brief Return a subview of view that contain only listed rows and columns*/
SCPView* scp_view_get_row_and_column_list_subview(SCPView* v,IList* rowList,IList* columnList);

/** \brief Print debugging info to standard output*/
void scp_view_print(SCPView* v,int showMaps);

#ifdef	__cplusplus
}
#endif

#endif	/* _SCPVIEW_H */

/**@}*/

