#include "BSprivate.h"

/*+ BStrans_perm_in - Get the complete mapping from i-node to rows

    Input Parameters:
.   A - a sparse matrix
.   gnum - the global permuted numbering
.   onum - the original global numbering
.   inode_distr - the distribution of the inode numbering
.   procinfo - the usual processor stuff

    Returns:
    the mapping from i-nodes to rows

 +*/

#define __TREE_RETURN
#include "BStree.h"

typedef struct __this_data {
	int	data1;
	int	data2;
} this_data;

BSinode_list *BStrans_perm_in(BSspmat *A, BSnumbering *gnum,
	BSnumbering *onum, BSdistribution *inode_distr, BSprocinfo *procinfo)
{
	BStree	tree;
	BStree_ptr	node_ptr;
	this_data	*data_ptr;
	BSbb *row_bb;
	int	i, j;
	int	count;
	BSsprow *row;
	int	*colptr;
	int	*addrs, *answs, *answs2, *answs3;
	void    (*map)(int,int *,int *,BSprocinfo *,BSmapping *);
	void    (*glmap)(int,int *,int *,BSprocinfo *,BSmapping *);
	int	num_cols;
	int	num_nz;
	int	cval, oval, lval, row_gval, ival;
	int	found;
	BSinode_list *trans;
	int	max_row_len;
	int	*map_work;

	/* set up requests */
	num_nz = BSnonlocalnz(A,&max_row_len,procinfo); CHKERRN(0);
	MY_MALLOCN(addrs,(int *),sizeof(int)*num_nz,1);
	MY_MALLOCN(map_work,(int *),sizeof(int)*max_row_len,2);
	count = 0;
	map = A->map->fglobal2proc;
	for (i=0;i<A->num_rows;i++) {
		row = A->rows[i];
		colptr = row->col;
     	(*map)(row->length,colptr,map_work,procinfo,A->map); CHKERRN(0);
		for (j=0;j<row->length;j++) {
			if (map_work[j] != procinfo->my_id) {
				addrs[count] = colptr[j];
				count++;
			}
		}
	}

	/* initialize BB */
	row_bb = BSinit_bb(A->num_rows,A->map); CHKERRN(0);

	/* query BB for inode numbers */
	BSpost_noaddr_bb(row_bb,A->num_rows,gnum->numbers); CHKERRN(0);
	MY_MALLOCN(answs,(int *),sizeof(int)*num_nz,2);
	BSquery_match_bb(row_bb,count,addrs,answs,procinfo); CHKERRN(0);

	/* query BB for inode lengths */
	BSpost_noaddr_bb(row_bb,A->num_rows,inode_distr->distribution);
	CHKERRN(0);
	MY_MALLOCN(answs2,(int *),sizeof(int)*num_nz,2);
	BSquery_match_bb(row_bb,count,addrs,answs2,procinfo); CHKERRN(0);

	/* query BB for original inode numbers */
	BSpost_noaddr_bb(row_bb,A->num_rows,onum->numbers); CHKERRN(0);
	MY_MALLOCN(answs3,(int *),sizeof(int)*num_nz,3);
	BSquery_match_bb(row_bb,count,addrs,answs3,procinfo); CHKERRN(0);

	/* free up BB */
	MY_FREEN(addrs);
	BSfree_bb(row_bb); CHKERRN(0);

	/* set up a dummy head pointer */
	MY_INIT_TREE(tree,(2*sizeof(int)));
	count = 0;
	map = A->map->fglobal2proc;
	glmap = A->map->fglobal2local;
	num_cols = 0;
	for (i=0;i<A->num_rows;i++) {
		row = A->rows[i];
		colptr = row->col;
		row_gval = gnum->numbers[i];
     	(*map)(row->length,colptr,map_work,procinfo,A->map); CHKERRN(0);
		for (j=0;j<row->length;j++) {
			if (map_work[j] != procinfo->my_id) {
				cval = answs[count];
				ival = answs2[count];
				oval = answs3[count];
				count++;
			} else {
				(*glmap)(1,&(colptr[j]),&lval,procinfo,A->map); CHKERRN(0);
				cval = gnum->numbers[lval];
				ival = inode_distr->distribution[lval];
				oval = onum->numbers[lval];
			}
			if(A->icc_storage) {
				if (row_gval >= cval) {
					/* check to see if the column is already there */
					MY_INSERT_TREE_NODE(tree,cval,found,node_ptr,num_cols);
					if (!found) {
						data_ptr = (this_data *) MY_GET_TREE_DATA(node_ptr);
						data_ptr->data1 = oval;
						data_ptr->data2 = ival;
					}
				}
			} else {
				/* Do not need row_gval >= cval check for nonsymmetric case */
				/* check to see if the column is already there */
				MY_INSERT_TREE_NODE(tree,cval,found,node_ptr,num_cols);
				if (!found) {
					data_ptr = (this_data *) MY_GET_TREE_DATA(node_ptr);
					data_ptr->data1 = oval;
					data_ptr->data2 = ival;
				}
			}
		}
	}
	MY_FREEN(map_work);
	MY_FREEN(answs);
	MY_FREEN(answs2);
	MY_FREEN(answs3);

	/* copy the linked list into the array structure */
	MY_MALLOCN(trans,(BSinode_list *),sizeof(BSinode_list),5);
	trans->length = num_cols;
	MY_MALLOCN(trans->list,(BSinode *),sizeof(BSinode)*(num_cols+1),5);
	trans->list[num_cols].gcol_num = INT_MAX;
	MY_MALLOCN(trans->list[num_cols].o_gcol_num,(int *),sizeof(int),6);
	trans->list[num_cols].o_gcol_num[0] = INT_MAX;
	count = 0;
	MY_FIRST_IN_TREE(tree,node_ptr);
	while (! IS_TREE_PTR_NULL(node_ptr)) {
		trans->list[count].gcol_num = MY_GET_TREE_KEY(node_ptr);
		data_ptr = (this_data *) MY_GET_TREE_DATA(node_ptr);
		trans->list[count].num_cols = data_ptr->data2;
		MY_MALLOCN(trans->list[count].o_gcol_num,(int *),sizeof(int)*
			data_ptr->data2,1);
		trans->list[count].o_gcol_num[0] = data_ptr->data1;
		count++;
		MY_NEXT_IN_TREE(node_ptr);
	}
	MY_FREE_TREE(tree);
	return(trans);
}


syntax highlighted by Code2HTML, v. 0.9.1