int sci_umf_luget(char* fname, void* pvApiCtx)
{
    /*
    *  LU_ptr is (a pointer to) a factorization of A, we have:
    *             -1
    *          P R  A Q = L U
    *
    *      A is n_row x n_col
    *      L is n_row x n
    *      U is n     x n_col     n = min(n_row, n_col)
    */

    SciErr sciErr;
    void* Numeric = NULL;
    int lnz = 0, unz = 0, n_row = 0, n_col = 0, n = 0, nz_udiag = 0, i = 0, stat = 0, do_recip = 0, it_flag = 0;
    int *L_mnel = NULL, *L_icol = NULL, *L_ptrow = NULL, *U_mnel = NULL, *U_icol = NULL, *U_ptrow = NULL, *V_irow = NULL, *V_ptcol = NULL;
    double *L_R = NULL, *L_I = NULL, *U_R = NULL, *U_I = NULL, *V_R = NULL, *V_I = NULL, *Rs = NULL;
    int *p = NULL, *q = NULL, pl_miss = 0, error_flag = 0 ;

    int* piAddr1 = NULL;
    int iType1   = 0;

    /* Check numbers of input/output arguments */
    CheckInputArgument(pvApiCtx, 1, 1);
    CheckOutputArgument(pvApiCtx, 1, 5);

    /* get the pointer to the LU factors */
    sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr1);
    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        return 1;
    }

    /* Check if the first argument is a pointer */
    sciErr = getVarType(pvApiCtx, piAddr1, &iType1);
    if (sciErr.iErr || iType1 != sci_pointer)
    {
        printError(&sciErr, 0);
        Scierror(999, _("%s: Wrong type for input argument #%d: A pointer expected.\n"), fname, 1);
        return 1;
    }

    sciErr = getPointer(pvApiCtx, piAddr1, &Numeric);
    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        return 1;
    }

    /* Check if the pointer is a valid ref to ... */
    if ( IsAdrInList(Numeric, ListNumeric, &it_flag) )
    {
        if (it_flag == 0 )
        {
            umfpack_di_get_lunz(&lnz, &unz, &n_row, &n_col, &nz_udiag, Numeric);
        }
        else
        {
            umfpack_zi_get_lunz(&lnz, &unz, &n_row, &n_col, &nz_udiag, Numeric);
        }
    }
    else
    {
        Scierror(999, _("%s: Wrong value for input argument #%d: Must be a valid reference to (umf) LU factors.\n"), fname, 1);
        return 1;
    }

    if (n_row <= n_col)
    {
        n = n_row;
    }
    else
    {
        n = n_col;
    }
    L_mnel  = (int*)MALLOC(n_row * sizeof(int));
    L_icol  = (int*)MALLOC(lnz * sizeof(int));
    L_ptrow = (int*)MALLOC((n_row + 1) * sizeof(int));
    L_R     = (double*)MALLOC( lnz * sizeof(double));
    U_mnel  = (int*)MALLOC(n * sizeof(int));
    U_icol  = (int*)MALLOC(unz * sizeof(int));
    U_ptrow = (int*)MALLOC((n + 1) * sizeof(int));
    U_R     = (double*)MALLOC( unz * sizeof(double));
    V_irow  = (int*)MALLOC(unz * sizeof(int));
    V_ptcol = (int*)MALLOC((n_col + 1) * sizeof(int));
    V_R     = (double*)MALLOC( unz * sizeof(double));
    p       = (int*)MALLOC(n_row * sizeof(int));
    q       = (int*)MALLOC(n_col * sizeof(int));
    Rs      = (double*)MALLOC(n_row * sizeof(double));

    if ( it_flag == 1 )
    {
        L_I = (double*)MALLOC(lnz * sizeof(double));
        U_I = (double*)MALLOC(unz * sizeof(double));
        V_I = (double*)MALLOC(unz * sizeof(double));
    }
    else
    {
        L_I = U_I = V_I = NULL;
    }

    if (    !(L_mnel && L_icol && L_R && L_ptrow  && p &&
              U_mnel && U_icol && U_R && U_ptrow  && q &&
              V_irow && V_R && V_ptcol  && Rs)
            || (it_flag && !(L_I && U_I && V_I))   )
    {
        error_flag = 1;
        goto the_end;
    }

    if ( it_flag == 0 )
    {
        stat = umfpack_di_get_numeric(L_ptrow, L_icol, L_R, V_ptcol, V_irow, V_R,
                                      p, q, (double *)NULL, &do_recip, Rs, Numeric);
    }
    else
    {
        stat = umfpack_zi_get_numeric(L_ptrow, L_icol, L_R, L_I, V_ptcol, V_irow, V_R, V_I,
                                      p, q, (double *)NULL, (double *)NULL, &do_recip, Rs, Numeric);
    }

    if ( stat != UMFPACK_OK )
    {
        error_flag = 2;
        goto the_end;
    };

    if ( do_recip )
    {
        for ( i = 0 ; i < n_row ; i++ )
        {
            Rs[i] = 1.0 / Rs[i];
        }
    }

    if ( it_flag == 0 )
    {
        stat = umfpack_di_transpose(n, n_col, V_ptcol, V_irow, V_R, (int *) NULL,
                                    (int*) NULL, U_ptrow, U_icol, U_R);
    }
    else
    {
        stat = umfpack_zi_transpose(n, n_col, V_ptcol, V_irow, V_R, V_I, (int *) NULL,
                                    (int*) NULL, U_ptrow, U_icol, U_R, U_I, 0);
    }

    if ( stat != UMFPACK_OK )
    {
        error_flag = 2;
        goto the_end;
    };

    for ( i = 0 ; i < n_row ; i++ )
    {
        L_mnel[i] = L_ptrow[i + 1] - L_ptrow[i];
    }
    for ( i = 0 ; i < n ; i++ )
    {
        U_mnel[i] = U_ptrow[i + 1] - U_ptrow[i];
    }

    for ( i = 0 ; i < lnz ; i++ )
    {
        L_icol[i]++;
    }
    for ( i = 0 ; i < unz ; i++ )
    {
        U_icol[i]++;
    }

    for ( i = 0 ; i < n_row ; i++ )
    {
        p[i]++;
    }
    for ( i = 0 ; i < n_col ; i++ )
    {
        q[i]++;
    }

    /* output L */
    if (it_flag) // complex
    {
        sciErr = createComplexSparseMatrix(pvApiCtx, 2, n_row, n, lnz, L_mnel, L_icol, L_R, L_I);
    }
    else
    {
        sciErr = createSparseMatrix(pvApiCtx, 2, n_row, n, lnz, L_mnel, L_icol, L_R);
    }

    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        FREE(L_mnel);
        FREE(U_mnel);
        return 1;
    }

    /* output U */
    if (it_flag) // complex
    {
        sciErr = createComplexSparseMatrix(pvApiCtx, 3, n, n_col, unz, U_mnel, U_icol, U_R, U_I);
    }
    else
    {
        sciErr = createSparseMatrix(pvApiCtx, 3, n, n_col, unz, U_mnel, U_icol, U_R);
    }

    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        FREE(L_mnel);
        FREE(U_mnel);
        return 1;
    }

    /* output p */
    sciErr = createMatrixOfDoubleAsInteger(pvApiCtx, 4, n_row, 1, p);
    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        FREE(L_mnel);
        FREE(U_mnel);
        return 1;
    }

    /* output q */
    sciErr = createMatrixOfDoubleAsInteger(pvApiCtx, 5, n_col, 1, q);
    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        FREE(L_mnel);
        FREE(U_mnel);
        return 1;
    }

    /* output res */
    sciErr = createMatrixOfDouble(pvApiCtx, 6, n_row, 1, Rs);
    if (sciErr.iErr)
    {
        printError(&sciErr, 0);
        FREE(L_mnel);
        FREE(U_mnel);
        return 1;
    }

the_end:
    FREE(L_mnel);
    FREE(L_icol);
    FREE(L_R);
    FREE(L_ptrow);
    FREE(p);
    FREE(U_mnel);
    FREE(U_icol);
    FREE(U_R);
    FREE(U_ptrow);
    FREE(q);
    FREE(V_irow);
    FREE(V_R);
    FREE(V_ptcol);
    FREE(Rs);

    if ( it_flag == 1 )
    {
        FREE(L_I);
        FREE(V_I);
        FREE(U_I);
    }

    switch (error_flag)
    {
        case 0:   /* no error */
            AssignOutputVariable(pvApiCtx, 1) = 2;
            AssignOutputVariable(pvApiCtx, 2) = 3;
            AssignOutputVariable(pvApiCtx, 3) = 4;
            AssignOutputVariable(pvApiCtx, 4) = 5;
            AssignOutputVariable(pvApiCtx, 5) = 6;
            ReturnArguments(pvApiCtx);
            return 0;

        case 1:   /* enough memory (with malloc) */
            Scierror(999, _("%s: No more memory.\n"), fname);
            break;

        case 2:   /* a problem with one umfpack routine */
            Scierror(999, "%s: %s\n", fname, UmfErrorMes(stat));
            break;
    }

    return 1;
}
Beispiel #2
0
/* This returns an integer identifier that should be unique to your
 * system.  There were problems with UMF mixing up systems becuase it
 * would identify unique systems just by its size.
 *
 * This unique identifier is passed in as system_id.  If you're
 * creating the matrix for the first time, then you should pass in a
 * -1, otherwise you should pass in the returned value from SL_UMF
 * when you created your system.
 *
 * Note that we don't do this very intelligently.  We simply use
 * indices sequentially.  There is no mechanism to allow re-use.
 */
int
SL_UMF ( int system_id,
	 int *first,
	 int *fact_optn,
	 int *matr_form,
	 int *nj,
	 int *nnz_j,
	 int *row,
	 int *col,
	 double *a,
	 double *b,
	 double *x  )
{
  /* Static struct holds all linear systems also keep track of number
   * of systems we have set up */
  static struct UMF_Linear_Solver_System ums_a[UMF_MAX_SYSTEMS];
  static int number_systems = 0;
  
  double Control[UMFPACK_CONTROL], Info[UMFPACK_INFO];
        
  struct UMF_Linear_Solver_System *ums = 0;  /* pointer to current system */

  int i, j, k, umf_option = 0;
  int hit_diag, err;

  for (i = 0; i < UMFPACK_CONTROL; i++) {
    Control[i] = 0;
  }

  for (i = 0; i < UMFPACK_INFO; i++) {
    Info[i] = 0;
  }
          
#ifdef DEBUG_SL_UMF
  fprintf(stderr, "SL_UMF: system_id = %d, *first = %d, *fact_optn = %d\n",
	  system_id, *first, *fact_optn);
#endif

  /* MEMORY */
  switch (*first) {
  case 1:
    /* If *first == 1, then we're creating a new matrix. */

    /* If system_id isn't -1, then we're probably making some sort of mistake... */
    if(system_id != -1)
      EH(-1, "Entered SL_UMF with *first == 1, but system_id != -1");
    /* If we've already gone through all of our slots, get out. */
    if(number_systems == UMF_MAX_SYSTEMS)
      EH(-1, "Already created UMF_MAX_SYSTEMS systems");

    system_id = number_systems;
    ums = &ums_a[number_systems++];
    ums->n = *nj;
    ums->nnz = *nnz_j;

    /* MATRIX VECTORS */
    ums->ap = Ivector_birth(ums->n + 1);
    ums->ai = Ivector_birth(ums->nnz);
    ums->ax = Dvector_birth(ums->nnz);

    /* MSR needs extra allocation for A-transpose */
    ums->atp = NULL;
    ums->ati = NULL;
    ums->atx = NULL;
    if ( *matr_form == 1 ) {
      ums->atp = Ivector_birth(ums->n + 1);
      ums->ati = Ivector_birth(ums->nnz);
      ums->atx = Dvector_birth(ums->nnz);
    } 
    
    break;
                         
  case 0:
    /* If *first == 0, then we want to just reuse a previously created 
     * system. */

    /* system_id should have the appropriate identifier. */
    if(system_id == -1)
      EH(-1, "Conflicting orders: system_id == -1 and *first != 1");
    if(system_id < 0 || system_id >= UMF_MAX_SYSTEMS)
      EH(-1, "Index out of range: system_id");

    /* Grab the hopeful system. */
    ums = &ums_a[system_id];

    /* Run through some sanity checks to help ensure we're dealing
     * with the correct system. */
    if(ums->n != *nj || ums->nnz != *nnz_j)
      EH(-1, "Tried to access a bad system");
    break;

  case -1:
    /* If *first == -1, then we want to free space. */

    /* system_id should have the appropriate identifier. */
    if(system_id == -1)
      EH(-1, "Conflicting orders: system_id == -1 and *first != 1");
    if(system_id < 0 || system_id >= UMF_MAX_SYSTEMS)
      EH(-1, "Index out of range: system_id");

    ums = &ums_a[system_id];
    /* Run through some sanity checks to help ensure we're dealing
     * with the correct system. */
    if(ums->n != *nj || ums->nnz != *nnz_j)
      EH(-1, "Tried to free a bad system");

    umfpack_di_free_symbolic(&ums->symbolic);
    ums->symbolic = NULL;  
    umfpack_di_free_numeric(&ums->numeric);
    ums->numeric = NULL;                
    Ivector_death(ums->ap, ums->n + 1);
    Ivector_death(ums->ai, ums->nnz);
    Dvector_death(ums->ax, ums->nnz);

    if ( ums->atp != NULL ) {
      Ivector_death(ums->atp, ums->n + 1);
      Ivector_death(ums->ati, ums->nnz);
      Dvector_death(ums->atx, ums->nnz);
    } 

    /* MMH: The fix that changed the world... */
    ums->n = 0;
    ums->nnz = 0;

    /* So things break later in case we actually use the return value
     * after deallocating space. */
    system_id = -1;

    break;
  }

  /* CONVERT MSR FORMAT TO MATLAB FORMAT IF NEEDED */
  if (abs(*fact_optn) < 3) { 
    switch (*matr_form) {
    case 0: /* COORDINATE FORMAT */
      umfpack_di_triplet_to_col( ums->n, ums->n, ums->nnz,
                                 row, col, a,
                                 ums->ap, ums->ai, ums->ax,
                                 NULL );
      break;
    case 1: /* MSR FORMAT */
      /* Note: MSR is row-oriented and UMF wants column-oriented data.
         So, assemble A-transpose in UMF format, and use umf utility
         to get back A in UMF format.
         Note also that UMF can operate directly on A-transpose.  This
         can save having to make another copy of the matrix, but it limited
         experiments, I found it to be slower. -DRN

         To form A-transpose in UMF format, merge the diagonal entries
         back into the rows.
      */
      k = 0;
      for (i=0;i<ums->n;i++) {  /* loop over rows */
        ums->atp[i] = k;
        hit_diag = FALSE;
	for (j=col[i];j<col[i+1];j++) {  /* loop over colums within row */
          /* if we get to the spot where the diagonal term belongs, merge it in */
          if (!hit_diag && col[j] > i ) {
            ums->ati[k] = i;
            ums->atx[k] = a[i];
            k++;
            hit_diag = TRUE;
          }
          ums->ati[k] = col[j];
          ums->atx[k] = a[j];
          k++;
        }
        /* if we never got to the diagonal, merge it in now */
        if (!hit_diag) {
          ums->ati[k] = i;
          ums->atx[k] = a[i];
          k++;
          hit_diag = TRUE;
        }
      }
      ums->atp[ums->n] = ums->nnz;
      
      if (ums->nnz != k) {
	DPRINTF(stderr, "E: NNZ=%12d CT=%12d\n", ums->nnz, k);
	exit(0);
      }
      
      /* transpose matrix */
      err = umfpack_di_transpose (ums->n, ums->n, ums->atp, ums->ati, ums->atx,
	(int *) NULL, (int *) NULL, ums->ap, ums->ai, ums->ax);
      if ( err != UMFPACK_OK )
        {
	  fprintf(stderr,"UMFPACK error = %d\n",err);
	  EH(-1,"Error computing matrix transpose using umfpack_di_transpose\n");
	}

      break;
    case 2: /* CSR FORMAT - NOT DONE YET */
      EH(-1, "Sorry, cannot convert CSR systems");
      break;
    }

    /* SET OPTIONS */
    switch (*fact_optn) {
    case -2: /* FULL ANALYSIS AND FACTORIZATION */
      umf_option = 1;
      break;
    case -1: /* FACTORIZATION WITH PAST ANALYSIS */
      umf_option = 0;
      break;
    case  0: /* FULL ANALYSIS AND FACTORIZATION */
      umf_option = 1;
      break;
    case  1: /* FACTORIZATION WITH PAST ANALYSIS */
      umf_option = 0;
      break;
    case 3:
      umf_option = 0;
      break;
    default:
      EH(-1, "Bad *fact_optn");
    }

    /* load default control parameters for UMF */
    umfpack_di_defaults( Control );
    /* optionally can ask for feedback from routines by uncommenting below */
    /*Control[UMFPACK_PRL] = 2.;*/
    /* optionally force solution strategy */
    Control[UMFPACK_STRATEGY] = UMFPACK_STRATEGY_UNSYMMETRIC;
    
    if ( umf_option == 1 ) {
      /* analysis */
      if ( ums->symbolic != NULL ) {
        umfpack_di_free_symbolic(&ums->symbolic);
        ums->symbolic = NULL;
      }
      err = umfpack_di_symbolic( ums->n, ums->n,
                                 ums->ap, ums->ai, ums->ax,
                                 &ums->symbolic, Control, Info );
      umfpack_di_report_status(Control, err);
      umfpack_di_report_info(Control, Info);
    }

    /* factorization */
    if ( ums->numeric != NULL ) {
      umfpack_di_free_numeric(&ums->numeric);
      ums->numeric = NULL;
    }
    err = umfpack_di_numeric( ums->ap, ums->ai, ums->ax,
                              ums->symbolic, &ums->numeric, Control, Info );
    umfpack_di_report_status(Control, err);
    umfpack_di_report_info(Control, Info);

  }

  /* solve */
  if ( *fact_optn >= 0 ) {
    err = umfpack_di_solve( UMFPACK_A, ums->ap, ums->ai, ums->ax,
                            x, b,
                            ums->numeric, Control, Info );
    umfpack_di_report_status(Control, err);
    umfpack_di_report_info(Control, Info);
  }

  return system_id;

} /* END of routine SL_UMF */