/*
    Module: cubestr.c -- routines for managing the global cube structure
*/

#include "espresso.h"

/*
    cube_setup -- assume that the fields "num_vars", "num_binary_vars", and
    part_size[num_binary_vars .. num_vars-1] are setup, and initialize the
    rest of cube and cdata->

    If a part_size is < 0, then the field size is abs(part_size) and the
    field read from the input is symbolic.
*/
/** MM: vrati -1 pri chybe alokacie a aj pri zlych poctoch premennych */
/** MM: setdown_cube musi vykonat volajuci */
int cube_setup(void)
{
    register int i, var;
    register pcube p;

    if (cube->num_binary_vars < 0 || cube->num_vars < cube->num_binary_vars){ /** MM: ak chyba */
    	fatal2("cube size is silly, error in .i/.o or .mv");
    	cube->num_binary_vars = -1; /** MM: nastavenie premennych, aby bola vzdy zachytena chyba */
    	cube->num_vars = -2;
    	return -1;
    }

    cube->num_mv_vars = cube->num_vars - cube->num_binary_vars;
    cube->output = cube->num_mv_vars > 0 ? cube->num_vars - 1 : -1;

    cube->size = 0;
    cube->first_part = ALLOC(int, cube->num_vars);
    cube->last_part = ALLOC(int, cube->num_vars);
    cube->first_word = ALLOC(int, cube->num_vars);
    cube->last_word = ALLOC(int, cube->num_vars);
    if ( (cube->first_part == NULL) || (cube->last_part == NULL) || (cube->first_word == NULL) || (cube->last_word == NULL) ) return -1; /** MM: ak chyba alokacie */
    for(var = 0; var < cube->num_vars; var++) {
    	if (var < cube->num_binary_vars)
    	    cube->part_size[var] = 2;
    	cube->first_part[var] = cube->size;
    	cube->first_word[var] = WHICH_WORD(cube->size);
    	cube->size += ABS(cube->part_size[var]);
    	cube->last_part[var] = cube->size - 1;
    	cube->last_word[var] = WHICH_WORD(cube->size - 1);
    }

    cube->var_mask = ALLOC(pset, cube->num_vars);
    cube->sparse = ALLOC(int, cube->num_vars);
    cube->binary_mask = new_cube();
    cube->mv_mask = new_cube();
    if ( (cube->var_mask == NULL) || (cube->sparse == NULL) || (cube->binary_mask == NULL) || (cube->mv_mask == NULL) ) return -1; /** MM: ak chyba alokacie */    
    for(var = 0; var < cube->num_vars; var++) {
    	p = cube->var_mask[var] = new_cube();
    	for(i = cube->first_part[var]; i <= cube->last_part[var]; i++)
    	    set_insert(p, i);
    	if (var < cube->num_binary_vars) {
    	    INLINEset_or(cube->binary_mask, cube->binary_mask, p);
    	    cube->sparse[var] = 0;
    	} else {
    	    INLINEset_or(cube->mv_mask, cube->mv_mask, p);
    	    cube->sparse[var] = 1;
    	}
    }
    if (cube->num_binary_vars == 0)
    	cube->inword = -1;
    else {
    	cube->inword = cube->last_word[cube->num_binary_vars - 1];
    	cube->inmask = cube->binary_mask[cube->inword] & DISJOINT;
    }

    cube->temp = ALLOC(pset, CUBE_TEMP);
    if (cube->temp == NULL) return -1; /** MM: ak chyba alokacie */
    for(i = 0; i < CUBE_TEMP; i++){
    	cube->temp[i] = new_cube();
    	if (cube->temp[i] == NULL) return -1; /** MM: ak chyba alokacie */
    }
    cube->fullset = set_fill(new_cube(), cube->size);
    cube->emptyset = new_cube();
    if ( (cube->fullset == NULL) || (cube->emptyset == NULL) ) return -1; /** MM: ak chyba alokacie */    

    cdata->part_zeros = ALLOC(int, cube->size);
    cdata->var_zeros = ALLOC(int, cube->num_vars);
    cdata->parts_active = ALLOC(int, cube->num_vars);
    cdata->is_unate = ALLOC(int, cube->num_vars);
    if ( (cdata->part_zeros == NULL) || (cdata->var_zeros == NULL) || (cdata->parts_active == NULL) || (cdata->is_unate == NULL) ) return -1; /** MM: ak chyba alokacie */    
    return 0;
}

/*
    setdown_cube -- free memory allocated for the cube/cdata structs
    (free's all but the part_size array)

    (I wanted to call this cube_setdown, but that violates the 8-character
    external routine limit on the IBM !)
*/
void setdown_cube(void)
{
    register int i, var;

    FREE(cube->first_part);
    FREE(cube->last_part);
    FREE(cube->first_word);
    FREE(cube->last_word);
    FREE(cube->sparse);

    free_cube(cube->binary_mask);
    free_cube(cube->mv_mask);
    free_cube(cube->fullset);
    free_cube(cube->emptyset);
    if (cube->var_mask!=NULL) /* pridane kvoli setdownu na neuplne inicializovanu kocku */
        for(var = 0; var < cube->num_vars; var++)
        	free_cube(cube->var_mask[var]);
    FREE(cube->var_mask);

    /** MM: pridane pre pripad pouzitia setdown_cube na neinicializovanu kocku */
    if (cube->temp != NULL){
        for(i = 0; i < CUBE_TEMP; i++)
        	free_cube(cube->temp[i]);
        FREE(cube->temp);
    }

    FREE(cdata->part_zeros);
    FREE(cdata->var_zeros);
    FREE(cdata->parts_active);
    FREE(cdata->is_unate);

    cube->first_part = cube->last_part = (int *) NULL;
    cube->first_word = cube->last_word = (int *) NULL;
    cube->sparse = (int *) NULL;
    cube->binary_mask = cube->mv_mask = (pcube) NULL;
    cube->fullset = cube->emptyset = (pcube) NULL;
    cube->var_mask = cube->temp = (pcube *) NULL;

    cdata->part_zeros = cdata->var_zeros = cdata->parts_active = (int *) NULL;
    cdata->is_unate = (bool3 *) NULL;
}

/** MM: nove setdown_cube() pre ukazatel na kocku */
/* uvolni komplet vsetky data kocky ->  aj cube->part_size! */
int setdown_cube(cube_struct *cub, struct cdata_struct *cdta)
{
    register int i, var;

    if (cub && cdta){
        FREE(cub->first_part);
        FREE(cub->last_part);
        FREE(cub->first_word);
        FREE(cub->last_word);
        FREE(cub->sparse);
    
        free_cube(cub->binary_mask);
        free_cube(cub->mv_mask);
        free_cube(cub->fullset);
        free_cube(cub->emptyset);
        if (cub->var_mask!=NULL) 
            for(var = 0; var < cub->num_vars; var++)
            	free_cube(cub->var_mask[var]);
        FREE(cub->var_mask);
    
        /** MM: pridane pre pripad pouzitia setdown_cube na neinicializovanu kocku */
        if (cub->temp != NULL){
            for(i = 0; i < CUBE_TEMP; i++)
            	free_cube(cub->temp[i]);
            FREE(cub->temp);
        }
    
        FREE(cdta->part_zeros);
        FREE(cdta->var_zeros);
        FREE(cdta->parts_active);
        FREE(cdta->is_unate);
    
        cub->first_part = cub->last_part = NULL;
        cub->first_word = cub->last_word = NULL;
        cub->sparse = NULL;
        cub->binary_mask = cub->mv_mask = NULL;
        cub->fullset = cub->emptyset = NULL;
        cub->var_mask = cub->temp = NULL;
    
        cdta->part_zeros = cdta->var_zeros = cdta->parts_active = NULL;
        cdta->is_unate = NULL;
        /** MM: a na zaver sa uvolni aj part_size */
        FREE(cub->part_size);
        cub->part_size = NULL;
        
        /** MM: na zaver nastavenie celociselnych premennych na neplatne hodnoty */
        cub->size = 0;
        cub->num_vars = -1;
        cub->num_binary_vars = -2;
        cub->inmask = 0;
        cub->inword = 0;
        cub->num_mv_vars = 0;
        cub->output = -1;
        
        cdta->vars_active = 0;
        cdta->vars_unate = 0;
        cdta->best = 0;
        
        return 0;
    }
    return -1;
}
