BASKER_INLINE
  void BaskerMatrix<Int,Entry,Exe_Space>::Finalize()
  {
    if(v_fill == BASKER_TRUE)
      {
        FREE_INT_1DARRAY(col_ptr);
        FREE_INT_1DARRAY(row_idx);
        FREE_ENTRY_1DARRAY(val);
        v_fill = BASKER_FALSE;
      }
    
    if(w_fill == BASKER_TRUE)
      {
        FREE_INT_1DARRAY(iws);
        FREE_ENTRY_1DARRAY(ews);
        w_fill = BASKER_FALSE;
      }

    if(inc_lvl_flg == BASKER_TRUE)
      {
	FREE_INT_1DARRAY(inc_lvl);
	inc_lvl_flg = BASKER_FALSE;
      }
    

  }//end finalize()
  BASKER_INLINE
  int Basker<Int, Entry, Exe_Space>::permute
  (
   ENTRY_1DARRAY vec,
   INT_1DARRAY   p, 
   Int n
   )
  {
    ENTRY_1DARRAY temp;
    MALLOC_ENTRY_1DARRAY(temp, n);
    init_value(temp, n, (Entry) 0.0);

    //Permute
    for(Int i = 0; i < n; i++)
      {
	temp(i) = vec(p(i));
	//temp(p(i)) = vec(i);
      }
    //Copy back
    for(Int i = 0; i < n; i++)
      {
	vec(i) = temp(i);
      }
   
    
    FREE_ENTRY_1DARRAY(temp);

    return 0;
  }
  BASKER_INLINE
  int Basker<Int, Entry, Exe_Space>::permute
  (
   ENTRY_1DARRAY vec,
   INT_1DARRAY   p, 
   Int n, //n = size(vec) //n > m 
   Int m,  //m = size(p) 
   Int start
   )
  {

    if(m > n)
      {
        printf("ERROR permtue \n");
        return BASKER_ERROR;
      }

    ENTRY_1DARRAY temp;
    MALLOC_ENTRY_1DARRAY(temp, n);
    init_value(temp, n, (Entry) 0.0);

    //Permute
    for(Int i = 0; i < n; i++)
      {
	temp(i) = vec(p(i));
	//temp(p(i)) = vec(i);
      }
    //Copy back
    for(Int i = 0; i < n; i++)
      {
	vec(i) = temp(i);
      }
   
    FREE_ENTRY_1DARRAY(temp);

    return 0;
  }
  BASKER_INLINE
  int Basker<Int,Entry,Exe_Space>::solve_interface
  (
   Entry *_x, //Solution (len = gn)
   Entry *_y
   )
  {
  
    //===== Move to view===========
    ENTRY_1DARRAY  x;
    ENTRY_1DARRAY  y;

    MALLOC_ENTRY_1DARRAY(x, gn);
    MALLOC_ENTRY_1DARRAY(y, gm);
    
    for(Int i =0; i < gn; i++)
      {
	x(i) = (Entry) 0;
        y(i) = (Entry) _y[i];
      }
    
    //printf("RHS: \n");
    //printVec(y, gn);
    //printf("\n");


    //===== Permute
    //printf("Permute RHS\n");
    //==== Need to make this into one global perm
    if(match_flag == BASKER_TRUE)
      {
	//printf("match order\n");
	//printVec("match.txt", order_match_array, gn);
	permute_inv(y,order_match_array, gn);
      }
    if(btf_flag == BASKER_TRUE)
      {
	//printf("btf order\n");
	//printVec("btf.txt", order_btf_array, gn);
	permute_inv(y,order_btf_array, gn);
        //printVec("btf_amd.txt", order_c_csym_array, gn);
        permute_inv(y,order_blk_amd_array, gn);

      }
    if(nd_flag == BASKER_TRUE)
      {
	//printf("ND order \n");
	//printVec("nd.txt", part_tree.permtab, gn);
	permute_inv(y,part_tree.permtab, gn);
      }
    if(amd_flag == BASKER_TRUE)
      {
	//printf("AMD order \n");
	//printVec("amd.txt",order_csym_array, gn);
	permute_inv(y,order_csym_array, gn);
      }


    //printVec("perm.txt" , gperm, gn);
    permute_inv(y,gperm, gn);


    solve_interface(x,y);

    //Inverse perm
    //Note: don't need to inverse a row only perm
    if(btf_flag == BASKER_TRUE)
      {
	//printf("btf order\n");
	//printVec(order_btf_array, gn);
	permute(x,order_btf_array, gn);
      }
    if(nd_flag == BASKER_TRUE)
      {
	//printf("ND order \n");
	//printVec(part_tree.permtab, gn);
	permute(x,part_tree.permtab, gn);
      }
    if(amd_flag == BASKER_TRUE)
      {
	//printf("AMD order \n");
	//printVec(order_csym_array, gn);
	//FILE *fpamd;
	//fpamd = fopen("amd.csv", "w");
	//for(Int i = 0; i < gn; i++)
	// {
	//   fprintf(fpamd, "%d \n", 
	//	    order_csym_array(i));
	//  }
	//fclose(fpamd);
	    
	permute(x,order_csym_array, gn);
      }
   


    #ifdef BASKER_DEBUG_SOLVE_RHS
    printf("\n\n");
    printf("X: \n");
    for(Int i = 0; i < gn; i++)
      {
	printf("%f, " , x(i));
      }
    printf("\n\n");
    printf("RHS: \n");
    for(Int i =0; i < gm; i++)
      {
	printf("%f, ", y(i)); 
      }
    printf("\n\n");
    #endif

    for(Int i = 0; i < gn; i++)
      {
        _x[i] = x(i);
      } 

    #ifndef BASKER_KOKKOS
    FREE_ENTRY_1DARRAY(x);
    FREE_ENTRY_1DARRAY(y);
    #endif

    return 0;
  }
  BASKER_INLINE
  int Basker<Int, Entry, Exe_Space>::permute_col
  (
   BASKER_MATRIX &M,
   INT_1DARRAY col
   )
  {
    if((M.ncol == 0)||(M.nnz == 0))
      return 0;

    Int n = M.ncol;
    Int nnz = M.nnz;
    //printf("Using n: %d nnz: %d \n", n, nnz);
    INT_1DARRAY temp_p;
    MALLOC_INT_1DARRAY(temp_p, n+1);
    init_value(temp_p, n+1, (Int)0);
    INT_1DARRAY temp_i;
    MALLOC_INT_1DARRAY(temp_i, nnz);
    init_value(temp_i, nnz, (Int)0);
    ENTRY_1DARRAY temp_v;
    MALLOC_ENTRY_1DARRAY(temp_v, nnz);
    init_value(temp_v, nnz, (Entry)0.0);
    //printf("done with init \n");
   
    //Determine column ptr of output matrix
    for(Int j = 0; j < n; j++)
      {
        Int i = col (j);
        temp_p (i+1) = M.col_ptr (j+1) - M.col_ptr (j);
      }
    //Get ptrs from lengths
    temp_p (0) = 0;
  
    for(Int j = 0; j < n; j++)
      {
        temp_p (j+1) = temp_p (j+1) + temp_p (j);
      }
    //copy idxs
    
    for(Int ii = 0; ii < n; ii++)
      {
        Int ko = temp_p (col (ii) );
        for(Int k = M.col_ptr (ii); k < M.col_ptr (ii+1); k++)
          {
            temp_i (ko) = M.row_idx (k);
            temp_v (ko) = M.val (k);
            ko++;
          }
      }
    
    //copy back int A
    for(Int ii=0; ii < n+1; ii++)
      {
        M.col_ptr (ii) = temp_p (ii);
      }
    for(Int ii=0; ii < nnz; ii++)
      {
        M.row_idx (ii) = temp_i (ii);
        M.val (ii) = temp_v (ii);
      }
    FREE_INT_1DARRAY(temp_p);
    FREE_INT_1DARRAY(temp_i);
    FREE_ENTRY_1DARRAY(temp_v);

    return 0;
  }//end permute_col(int) 
  BASKER_INLINE
  void Basker<Int,Entry,Exe_Space>::Finalize()
  {
    
    //finalize all matrices
    A.Finalize();
    At.Finalize(); //??? is At even used
    BTF_A.Finalize();
    BTF_C.Finalize();
    BTF_B.Finalize();
    BTF_D.Finalize();
    BTF_E.Finalize();
   
    //finalize array of 2d matrics
    FREE_MATRIX_VIEW_2DARRAY(AV, tree.nblks);
    FREE_MATRIX_VIEW_2DARRAY(AL, tree.nblks);
    FREE_MATRIX_2DARRAY(AVM, tree.nblks);
    FREE_MATRIX_2DARRAY(ALM, tree.nblks);
    
    FREE_MATRIX_2DARRAY(LL, tree.nblks);
    FREE_MATRIX_2DARRAY(LU, tree.nblks);
   
    FREE_INT_1DARRAY(LL_size);
    FREE_INT_1DARRAY(LU_size);
    
    //BTF structure
    FREE_INT_1DARRAY(btf_tabs);
    FREE_INT_1DARRAY(btf_blk_work);
    FREE_INT_1DARRAY(btf_blk_nnz);
    FREE_MATRIX_1DARRAY(LBTF);
    FREE_MATRIX_1DARRAY(UBTF);
       
    //Thread Array
    FREE_THREAD_1DARRAY(thread_array);
    basker_barrier.Finalize();
       
    //S (Check on this)
    FREE_INT_2DARRAY(S, tree.nblks);
    
    //Permuations
    FREE_INT_1DARRAY(gperm);
    FREE_INT_1DARRAY(gpermi);
    if(match_flag == BASKER_TRUE)
      {
        FREE_INT_1DARRAY(order_match_array);
        match_flag = BASKER_FALSE;
      }
    if(btf_flag == BASKER_TRUE)
      {
        FREE_INT_1DARRAY(order_btf_array);
        btf_flag = BASKER_FALSE;
      }
    if(nd_flag == BASKER_TRUE)
      {
        FREE_INT_1DARRAY(order_scotch_array);
        nd_flag = BASKER_FALSE;
      }
    if(amd_flag == BASKER_TRUE)
      {
        FREE_INT_1DARRAY(order_csym_array);
        amd_flag = BASKER_FALSE;
      }

    //NDE: Free workspace and permutation arrays
    FREE_INT_1DARRAY(perm_comp_array);
    FREE_INT_1DARRAY(perm_inv_comp_array);
    FREE_INT_1DARRAY(perm_comp_iworkspace_array);
    FREE_ENTRY_1DARRAY(perm_comp_fworkspace_array);
    FREE_ENTRY_1DARRAY(x_view_ptr_copy);
    FREE_ENTRY_1DARRAY(y_view_ptr_copy);


    //Structures
    part_tree.Finalize();
    tree.Finalize();
    stree.Finalize();
    stats.Finalize();

  }//end Finalize()
  BASKER_INLINE
  int Basker<Int,Entry,Exe_Space>::solve_interface
  (
   Entry *_x, //Solution (len = gn)
   Entry *_y
   )
  {

    //Need to modify to use global perm 
    INT_1DARRAY temp_array;
    MALLOC_INT_1DARRAY(temp_array, gn);
  
    //===== Move to view===========
    ENTRY_1DARRAY  x;
    ENTRY_1DARRAY  y;

    MALLOC_ENTRY_1DARRAY(x, gn);
    MALLOC_ENTRY_1DARRAY(y, gm);
    
    for(Int i =0; i < gn; i++)
      {
	x(i) = (Entry) 0;
        y(i) = (Entry) _y[i];
      }
    
    //printf("RHS: \n");
    //printVec(y, gn);
    //printf("\n");


    //===== Permute
    //printf("Permute RHS\n");
    //==== Need to make this into one global perm
    if(match_flag == BASKER_TRUE)
      {
	//printf("match order\n");
	//printVec("match.txt", order_match_array, gn);
	permute_inv(y,order_match_array, gn);
      }
    if(btf_flag == BASKER_TRUE)
      {
	//printf("btf order\n");
	//printVec("btf.txt", order_btf_array, gn);
	permute_inv(y,order_btf_array, gn);
        //printVec("btf_amd.txt", order_c_csym_array, gn);
        permute_inv(y,order_blk_amd_array, gn);

      }
    if(nd_flag == BASKER_TRUE)
      {
	//printf("ND order \n");
	//printVec("nd.txt", part_tree.permtab, gn);
	for(Int i = 0; i < BTF_A.ncol; ++i)
	  {
	    temp_array(i) = part_tree.permtab(i);
	  }
	for(Int i = BTF_A.ncol; i < gn; ++i)
	  {
	    temp_array(i) = i;
	  }
	//permute_inv(y,part_tree.permtab, gn);
	permute_inv(y, temp_array,gn);
      }
    if(amd_flag == BASKER_TRUE)
      {
	//printf("AMD order \n");
	//printVec("amd.txt",order_csym_array, gn);
	for(Int i = 0; i < BTF_A.ncol; ++i)
	  {
	    temp_array(i) = order_csym_array(i);
	  }
	for(Int i = BTF_A.ncol; i < gn; ++i)
	  {
	    temp_array(i) = i;
	  }
	//permute_inv(y,order_csym_array, gn);
	permute_inv(y,temp_array, gn);
      }


    //printVec("perm.txt" , gperm, gn);
    permute_inv(y,gperm, gn);


    solve_interface(x,y);

    //Inverse perm
    //Note: don't need to inverse a row only perm
    if(btf_flag == BASKER_TRUE)
      {
	//printf("btf order\n");
	//printVec(order_btf_array, gn);
	permute(x,order_btf_array, gn);
      }
    if(nd_flag == BASKER_TRUE)
      {
	//printf("ND order \n");
	//printVec(part_tree.permtab, gn);
	for(Int i = 0; i < BTF_A.ncol; ++i)
	  {
	    temp_array(i) = part_tree.permtab(i);
	  }
	for(Int i = BTF_A.ncol; i < gn; i++)
	  {
	    temp_array(i) = i;
	  }
	//permute(x,part_tree.permtab, gn);
	permute(x,temp_array, gn);
      }
    if(amd_flag == BASKER_TRUE)
      {
	//printf("AMD order \n");
	//printVec(order_csym_array, gn);
	for(Int i = 0; i < BTF_A.ncol; ++i)
	  {
	    temp_array(i) = order_csym_array(i);
	  }
	for(Int i = BTF_A.ncol; i < gn; ++i)
	  {
	    temp_array(i) = order_csym_array(i);
	  }
	//permute(x,order_csym_array, gn);
	permute(x,temp_array,gn);
      }
   


    #ifdef BASKER_DEBUG_SOLVE_RHS
    printf("\n\n");
    printf("X: \n");
    for(Int i = 0; i < gn; i++)
      {
	printf("%f, " , x(i));
      }
    printf("\n\n");
    printf("RHS: \n");
    for(Int i =0; i < gm; i++)
      {
	printf("%f, ", y(i)); 
      }
    printf("\n\n");
    #endif

    for(Int i = 0; i < gn; i++)
      {
        _x[i] = x(i);
      } 

   
    FREE_ENTRY_1DARRAY(x);
    FREE_ENTRY_1DARRAY(y);
    FREE_INT_1DARRAY(temp_array);
   

    return 0;
  }