#include	"BSprivate.h"

/*@ BSfree_off_map - Free an offset mapping

    Input Parameters:
.   map - the map to be freed

    Returns:
    void

 @*/
void BSfree_off_map(BSoff_map *map)
{
	MY_FREE(map->proc_id);
	MY_FREE(map->offset);
	MY_FREE(map);
}

/*@ BSmake_off_map - Generate a mapping from global rows to processor id

    Input Parameters:
.   offset - the offset of the local processor in the global numbering
.   procinfo - the usual processor information
.   max - the number of global rows

    Returns:
    the mapping

    Notes:
    For example, processor 0 has 10 rows and an offset of 0, processor
    1 has 3 rows and an offset of 10 and processor 2 has 4 rows and
    an offset of 13 (there are 3 processors and 17 rows).  The offset
    mapping (see BSsparse.h) would have the offsets in sorted order
    with the corresponding processor id.  In this way, given a global
    row number, one could determine the processor on which it lies.

 @*/
BSoff_map *BSmake_off_map(int offset, BSprocinfo *procinfo, int max) 
{
	BSoff_map *map;
	int	i;

	MY_MALLOCN(map,(BSoff_map *),sizeof(BSoff_map),1);
	MPI_Comm_size(procinfo->procset,&(map->length));
	MY_MALLOCN(map->proc_id,(int *),sizeof(int)*map->length,2);
	MY_MALLOCN(map->offset,(int *),sizeof(int)*((map->length)+1),3);
	MPI_Allgather(&offset,1,MPI_INT,map->offset,1,MPI_INT,procinfo->procset);
	map->offset[map->length] = max;

	/* get the numbers of all the nodes in my procset */
	for (i=0;i<map->length;i++) {
		map->proc_id[i] = i;
	}

	/* sort by offset */
	BSheap_sort1(map->length,map->offset,map->proc_id); CHKERRN(0);
	for (i=0;i<map->length;i++) {
		if (map->proc_id[i] == procinfo->my_id) {
			map->my_ind = i;
			break;
		}
	}

	return(map);
}

/*@ BSfreel2g - Free a local to global mapping

    Input Parameters:
.   data - the structure to be freed

    Returns:
    void

 @*/
void BSfreel2g(void *data)
{
	MY_FREE(data);
}

/*@ BSloc2glob - Map local row numbers to global row numbers

    Input Parameters:
.   length - the number of row numbers to map
.   req_array - the row numbers to map
.   procinfo - the usual processor information
.   map - the map to use

    Output Parameters:
.   ans_array - on exit, the corresponding global row numbers

    Returns:
    void

    Notes:
    Only valid for local row numbers that reside on the calling processor

 @*/
void BSloc2glob(int length,int *req_array,int *ans_array,
	            BSprocinfo *procinfo, BSmapping *map)
{
	int	i;
	int	offset;

	offset = *((int *) map->vlocal2global);
	for (i=0;i<length;i++) {
		ans_array[i] = req_array[i]+offset;
	}
}

/*@ BSglob2proc - Map global row numbers to processor id's

    Input Parameters:
.   length - the number of row numbers to map
.   req_array - the row numbers to map
.   procinfo - the usual processor information
.   map - the map to use

    Output Parameters:
.   ans_array - on exit, the corresponding processor id's

    Returns:
    void

 @*/
void BSglob2proc(int length,int *req_array,int *ans_array,
                 BSprocinfo *procinfo,BSmapping *map)
{
	int	i;
	BSoff_map *trans;
	int	left, right, mid, found;

	trans = (BSoff_map *)map->vglobal2proc;
	/* start out mid with the index for my processor */
	/* after that let mid start at the index of the last place */
	mid = trans->my_ind;
	for (i=0;i<length;i++) {
		left = 0;
		right = trans->length-1;
		found = FALSE;
		while (!found) {
			if (req_array[i] < trans->offset[mid]) {
				right = mid-1;
				mid = (left+right) / 2;
			} else if (req_array[i] >= trans->offset[mid+1]) {
				left = mid+1;
				mid = (left+right) / 2;
			} else {
				found = TRUE;
			}
		}
		ans_array[i] = trans->proc_id[mid];
	}
}

/*@ BSfreeg2l - Free a global to local mapping

    Input Parameters:
.   data - the structure to be freed

    Returns:
    void

 @*/
void BSfreeg2l(void *data)
{
	MY_FREE(data);
}

/*@ BSglob2loc - Map global row numbers to local row numbers

    Input Parameters:
.   length - the number of row numbers to map
.   req_array - the row numbers to map
.   procinfo - the usual processor information
.   map - the map to use

    Output Parameters:
.   ans_array - on exit, the corresponding local row numbers or
                a -1 if the row does not reside on the calling processor
               

    Returns:
    void

 @*/
void BSglob2loc(int length,int *req_array,int *ans_array,
				BSprocinfo *procinfo,BSmapping *map)
{
	int	i;
	int	offset;

	offset = *((int *) map->vlocal2global);
	BSglob2proc(length,req_array,ans_array,procinfo,map); CHKERR(0);
	for (i=0;i<length;i++) {
		if (ans_array[i] != procinfo->my_id) {
			ans_array[i] = -1;
		} else {
			ans_array[i] = req_array[i] - offset;
		}
	}
}



syntax highlighted by Code2HTML, v. 0.9.1