コード例 #1
0
ファイル: plarre.c プロジェクト: ahmadia/Elemental-1
/* Routine to compute eigenvalues */
int plarre(proc_t *procinfo, char *jobz, char *range, in_t *Dstruct, 
	   val_t *Wstruct, tol_t *tolstruct, int *nzp, int *myfirstp)
{
  /* input variables */
  int              pid    = procinfo->pid;
  int              nproc  = procinfo->nproc;
  bool             wantZ  = (jobz[0]  == 'V' || jobz[0]  == 'v');
  bool             cntval = (jobz[0]  == 'C' || jobz[0]  == 'c');
  int              n      = Dstruct->n;
  double *restrict D      = Dstruct->D;
  double *restrict E      = Dstruct->E;
  int    *restrict isplit = Dstruct->isplit;
  double           *vl    = Wstruct->vl;
  double           *vu    = Wstruct->vu;
  int              *il    = Wstruct->il;
  int              *iu    = Wstruct->iu;
  double *restrict W      = Wstruct->W;
  double *restrict Werr   = Wstruct->Werr;
  double *restrict Wgap   = Wstruct->Wgap;
  int    *restrict Windex = Wstruct->Windex;
  int    *restrict iblock = Wstruct->iblock;
  double *restrict gersch = Wstruct->gersch;

  /* constants */
  int             IZERO = 0,   IONE = 1;
  double          DZERO = 0.0;

  /* work space */
  double          *E2, *work;
  int             *iwork;

  /* compute geschgorin disks and spectral diameter */
  double          gl, gu, bl_gu, eold, emax, eabs;

  /* compute splitting points */
  int             bl_begin, bl_end;

  /* distribute work among processes */
  int             ifirst, ilast, ifirst_tmp, ilast_tmp;
  int             chunk, isize, iil, iiu;

  /* gather results */
  int             *rcount, *rdispl;

  /* others */
  int             info, i, j, im, idummy, ind;
  double          tmp1, dummy;
  enum range_enum {allrng=1, valrng=2, indrng=3} irange;
  double          intervals[2];
  int             negcounts[2];
  double          sigma;

  if (range[0] == 'A' || range[0] == 'a') {
    irange = allrng;
  } else if (range[0] == 'V' || range[0] == 'v') {
    irange = valrng;
  } else if (range[0] == 'I' || range[0] == 'i') {
    irange = indrng;
  } else {
    return(1);
  }

  /* allocate work space */
  E2     = (double *) malloc(     n * sizeof(double) );
  assert(E2 != NULL);
  work   = (double *) malloc(   4*n * sizeof(double) );
  assert(work != NULL);
  iwork  = (int *)    malloc(   3*n * sizeof(int) );
  assert(iwork != NULL);
  rcount = (int *)    malloc( nproc * sizeof(int) );
  assert(rcount != NULL);
  rdispl = (int *)    malloc( nproc * sizeof(int) );
  assert(rdispl != NULL);

  /* Compute square of off-diagonal elements */
  for (i=0; i<n-1; i++) {
    E2[i] = E[i]*E[i];
  }

  /* compute geschgorin disks and spectral diameter */
  gl     = D[0];
  gu     = D[0];
  eold   =  0.0;
  emax   =  0.0;
  E[n-1] =  0.0;

  for (i=0; i<n; i++) {
    eabs = fabs(E[i]);
    if (eabs >= emax) emax = eabs;
    tmp1 = eabs + eold;
    gersch[2*i] = D[i] - tmp1;
    gl = fmin(gl, gersch[2*i]);
    gersch[2*i+1] = D[i] + tmp1;
    gu = fmax(gu, gersch[2*i+1]);
    eold = eabs;
  }
  /* min. pivot allowed in the Sturm sequence of T */
  tolstruct->pivmin = DBL_MIN * fmax(1.0, emax*emax);
  /* estimate of spectral diameter */
  Dstruct->spdiam = gu - gl;

  /* compute splitting points with threshold "split" */
  LAPACK(dlarra)
  (&n, D, E, E2, &tolstruct->split, &Dstruct->spdiam, &Dstruct->nsplit, 
   isplit, &info);
  assert(info == 0);

  if (irange == allrng || irange == indrng) {
    *vl = gl;
    *vu = gu;
  }

  /* set eigenvalue indices in case of all or subset by value has
   * to be computed; thereby convert all problem to subset by index
   * computation */
  if (irange == allrng) {
    *il = 1;
    *iu = n;
  } else if (irange == valrng) {
    intervals[0] = *vl; intervals[1] = *vu;
    
    /* find negcount at boundaries 'vl' and 'vu'; 
     * needs work of dim(n) and iwork of dim(n) */
    LAPACK(dlaebz)
    (&IONE, &IZERO, &n, &IONE, &IONE, &IZERO, &DZERO, &DZERO, 
     &tolstruct->pivmin, D, E, E2, &idummy, intervals, &dummy, &idummy, 
     negcounts, work, iwork, &info);
    assert(info == 0);
    
    /* update negcounts of whole matrix with negcounts found for block */
    *il = negcounts[0] + 1;
    *iu = negcounts[1];
  }

  if (cntval && irange == valrng) {
    /* clean up and return */
    *nzp = iceil(*iu-*il+1, nproc);
    clean_up_plarre(E2, work, iwork, rcount, rdispl);
    return(0);
  }

  /* in case only eigenvalues are desired compute eigenvalues 
   * "il" to "iu"; otherwise compute all */
  if (wantZ) {
    iil = 1;
    iiu = n;
  } else {
    iil = *il;
    iiu = *iu;
  }
  
  /* each process computes a subset of the eigenvalues */
  ifirst_tmp = iil;
  for (i=0; i<nproc; i++) {
    chunk  = (iiu-iil+1)/nproc + (i < (iiu-iil+1)%nproc);
    if (i == nproc-1) {
      ilast_tmp = iiu;
    } else {
      ilast_tmp = ifirst_tmp + chunk - 1;
      ilast_tmp = imin(ilast_tmp, iiu);
    }
    if (i == pid) {
      ifirst    = ifirst_tmp;
      ilast     = ilast_tmp;
      isize     = ilast - ifirst + 1;
      *myfirstp = ifirst - iil;;
      *nzp      = isize;
    }
    rcount[i]  = ilast_tmp - ifirst_tmp + 1;
    rdispl[i]  = ifirst_tmp - iil;
    ifirst_tmp = ilast_tmp + 1;
    ifirst_tmp = imin(ifirst_tmp, iiu + 1);
  }

  /* compute eigenvalues assigned to process */
  if (isize != 0) {
    info = eigval_subset_proc(procinfo, range, Dstruct, E2, ifirst, ilast,
			      tolstruct, Wstruct, work, iwork);
    assert(info == 0);
  }

  if (wantZ) {
    /* communicate results */
    memcpy(work, W, isize * sizeof(double) );
    MPI_Allgatherv(work, isize, MPI_DOUBLE, W, rcount, rdispl, 
		   MPI_DOUBLE, procinfo->comm);

    memcpy(work, Werr, isize * sizeof(double) );
    MPI_Allgatherv(work, isize, MPI_DOUBLE, Werr, rcount, rdispl, 
		   MPI_DOUBLE, procinfo->comm);
    
    memcpy(iwork, Windex, isize * sizeof(int) );
    MPI_Allgatherv(iwork, isize, MPI_INT, Windex, rcount, rdispl, 
		   MPI_INT, procinfo->comm);
    
    memcpy(iwork, iblock, isize * sizeof(int) );
    MPI_Allgatherv(iwork, isize, MPI_INT, iblock, rcount, rdispl, 
		   MPI_INT, procinfo->comm);

    /* sort by block */
    memcpy(&work[0],   W,      n*sizeof(double));
    memcpy(&work[n],   Werr,   n*sizeof(double));
    memcpy(&iwork[0],  Windex, n*sizeof(int));
    memcpy(&iwork[n],  iblock, n*sizeof(int));
    
    im = 0;
    for (i=1; i<=Dstruct->nsplit; i++) {
      for (j=0; j<n; j++) {
	if (iwork[j+n] == i) {    /* iblock == i */
	  W[im]      = work[j];
	  Werr[im]   = work[j+n];
	  Windex[im] = iwork[j];
	  iblock[im] = iwork[j+n];
	  im++;
	}
      }
    }
    
    /* recompute gap of blocks */
    bl_begin = 0;
    for (i=0; i < Dstruct->nsplit; i++) {
      bl_end  = isplit[i] - 1;
      sigma   = E[bl_end];
      
      /* find outer bounds GU for block used for last gap */
      bl_gu = D[bl_begin];
      for (j = bl_begin; j <= bl_end; j++) {
	bl_gu = fmax(bl_gu, gersch[2*j+1]);
      }
      
      /* recompute gaps within the blocks */
      for (j = bl_begin; j < bl_end; j++) {
	Wgap[j] = fmax(0.0, (W[j+1] - Werr[j+1]) - (W[j] + Werr[j]) );
      }
      Wgap[bl_end] = fmax(0.0, (bl_gu - sigma) - (W[bl_end] + Werr[bl_end]) );
      
      bl_begin = bl_end + 1;
    } /* end i */
 
  } else {

    /* compute UNSHIFTED eigenvalues */
    for (i=0; i < isize; i++) {
      ind     = iblock[i]   - 1;
      bl_end  = isplit[ind] - 1;
      sigma   = E[bl_end];
      W[i]   += sigma;
    }

  } /* if wantZ */

  /* free memory */
  clean_up_plarre(E2, work, iwork, rcount, rdispl);

  return(0);
}
コード例 #2
0
ファイル: plarre.c プロジェクト: AmiArnab/Elemental
/* Routine to compute eigenvalues */
int plarre(proc_t *procinfo, char *jobz, char *range, in_t *Dstruct, 
	       val_t *Wstruct, tol_t *tolstruct, int *nzp, int *offsetp)
{
  /* input variables */
  int              nproc  = procinfo->nproc;
  bool             wantZ  = (jobz[0]  == 'V' || jobz[0]  == 'v');
  bool             cntval = (jobz[0]  == 'C' || jobz[0]  == 'c');
  int              n      = Dstruct->n;
  double *restrict D      = Dstruct->D;
  double *restrict E      = Dstruct->E;
  int    *restrict isplit = Dstruct->isplit;
  double           *vl    = Wstruct->vl;
  double           *vu    = Wstruct->vu;
  int              *il    = Wstruct->il;
  int              *iu    = Wstruct->iu;
  double *restrict W      = Wstruct->W;
  double *restrict Werr   = Wstruct->Werr;
  double *restrict Wgap   = Wstruct->Wgap;
  int    *restrict Windex = Wstruct->Windex;
  int    *restrict iblock = Wstruct->iblock;
  double *restrict gersch = Wstruct->gersch;

  /* constants */
  int             IZERO = 0,   IONE = 1;
  double          DZERO = 0.0;

  /* work space */
  double          *E2;
  double         *work;
  int             *iwork;

  /* compute geschgorin disks and spectral diameter */
  double          gl, gu, eold, emax, eabs;

  /* compute splitting points */
  int             bl_begin, bl_end, bl_size;

  /* distribute work among processes */
  int             ifirst, ilast, ifirst_tmp, ilast_tmp;
  int             chunk, isize, iil, iiu;

  /* gather results */
  int             *rcount, *rdispl;

  /* others */
  int             info, i, j, jbl, idummy;
  double          tmp1, dummy;
  bool             sorted;
  enum range_enum {allrng=1, valrng=2, indrng=3} irange;
  double          intervals[2];
  int             negcounts[2];
  double          sigma;

  if (range[0] == 'A' || range[0] == 'a') {
    irange = allrng;
  } else if (range[0] == 'V' || range[0] == 'v') {
    irange = valrng;
  } else if (range[0] == 'I' || range[0] == 'i') {
    irange = indrng;
  } else {
    return 1;
  }

  /* allocate work space */
  E2     = (double *) malloc(     n * sizeof(double) );
  assert(E2 != NULL);
  work   = (double *) malloc(   4*n * sizeof(double) );
  assert(work != NULL);
  iwork  = (int *)    malloc(   3*n * sizeof(int) );
  assert(iwork != NULL);
  rcount = (int *)    malloc( nproc * sizeof(int) );
  assert(rcount != NULL);
  rdispl = (int *)    malloc( nproc * sizeof(int) );
  assert(rdispl != NULL);

  /* Compute square of off-diagonal elements */
  for (i=0; i<n-1; i++) {
    E2[i] = E[i]*E[i];
  }

  /* compute geschgorin disks and spectral diameter */
  gl     = D[0];
  gu     = D[0];
  eold   =  0.0;
  emax   =  0.0;
  E[n-1] =  0.0;

  for (i=0; i<n; i++) {
    eabs = fabs(E[i]);
    if (eabs >= emax) emax = eabs;
    tmp1 = eabs + eold;
    gersch[2*i] = D[i] - tmp1;
    gl = fmin(gl, gersch[2*i]);
    gersch[2*i+1] = D[i] + tmp1;
    gu = fmax(gu, gersch[2*i+1]);
    eold = eabs;
  }
  /* min. pivot allowed in the Sturm sequence of T */
  tolstruct->pivmin = DBL_MIN * fmax(1.0, emax*emax);
  /* estimate of spectral diameter */
  Dstruct->spdiam = gu - gl;

  /* compute splitting points with threshold "split" */
  odrra(&n, D, E, E2, &tolstruct->split, &Dstruct->spdiam,
        &Dstruct->nsplit, isplit, &info);
  assert(info == 0);

  if (irange == allrng || irange == indrng) {
    *vl = gl;
    *vu = gu;
  }

  /* set eigenvalue indices in case of all or subset by value has
   * to be computed; thereby convert all problem to subset by index
   * computation */
  if (irange == allrng) {
    *il = 1;
    *iu = n;
  } else if (irange == valrng) {
    intervals[0] = *vl; intervals[1] = *vu;
    
    /* find negcount at boundaries 'vl' and 'vu';
     * needs work of dim(n) and iwork of dim(n) */
    odebz(&IONE, &IZERO, &n, &IONE, &IONE, &IZERO,
  	  &DZERO, &DZERO, &tolstruct->pivmin, D, E, E2, &idummy,
  	  intervals, &dummy, &idummy, negcounts, work, iwork, &info);
    assert(info == 0);
    
    /* update negcounts of whole matrix with negcounts found for block */
    *il = negcounts[0] + 1;
    *iu = negcounts[1];
  }

  if (cntval && irange == valrng) {
    /* clean up and return */
    *nzp = iceil(*iu-*il+1, nproc);
    clean_up_plarre(E2, work, iwork, rcount, rdispl);
    return 0;
  }


  /* loop over unreduced blocks */  
  bl_begin  = 0;
  
  for (jbl=0; jbl<Dstruct->nsplit; jbl++) {
    
    bl_end  = isplit[jbl] - 1;
    bl_size = bl_end - bl_begin + 1;
    
    /* deal with 1x1 block immediately */
    if (bl_size == 1) {
      E[bl_end] = 0.0;
      W[bl_begin]      = D[bl_begin];
      Werr[bl_begin]   = 0.0;
      Werr[bl_begin]   = 0.0;
      iblock[bl_begin] = jbl + 1;
      Windex[bl_begin] = 1;
      bl_begin  = bl_end + 1;
      continue;
    }

    /* Indix range of block */
    iil = 1;
    iiu = bl_size;

    /* each process computes a subset of the eigenvalues of the block */
    ifirst_tmp = iil;
    for (i=0; i<nproc; i++) {
      chunk  = (iiu-iil+1)/nproc + (i < (iiu-iil+1)%nproc);
      if (i == nproc-1) {
	ilast_tmp = iiu;
      } else {
	ilast_tmp = ifirst_tmp + chunk - 1;
	ilast_tmp = imin(ilast_tmp, iiu);
      }
      if (i == procinfo->pid) {
	ifirst    = ifirst_tmp;
	ilast     = ilast_tmp;
	isize     = ilast - ifirst + 1;
	*offsetp = ifirst - iil;
	*nzp      = isize;
      }
      rcount[i]  = ilast_tmp - ifirst_tmp + 1;
      rdispl[i]  = ifirst_tmp - iil;
      ifirst_tmp = ilast_tmp + 1;
      ifirst_tmp = imin(ifirst_tmp, iiu + 1);
    }
    
    /* approximate eigenvalues of input assigned to process */
    if (isize != 0) {      
      info = eigval_approx_proc(procinfo, ifirst, ilast,
				    bl_size, &D[bl_begin], &E[bl_begin], &E2[bl_begin], 
				    &Windex[bl_begin], &iblock[bl_begin], &gersch[2*bl_begin],
				    tolstruct, &W[bl_begin], &Werr[bl_begin], &Wgap[bl_begin], 
				    work, iwork);
      assert(info == 0);    
    }

    /* compute root representation of block */
    info = eigval_root_proc(procinfo, ifirst, ilast,
				  bl_size, &D[bl_begin], &E[bl_begin], &E2[bl_begin], 
				  &Windex[bl_begin], &iblock[bl_begin], &gersch[2*bl_begin],
				  tolstruct, &W[bl_begin], &Werr[bl_begin], &Wgap[bl_begin], 
				  work, iwork);
    assert(info == 0);    

    /* refine eigenvalues assigned to process w.r.t root */
    if (isize != 0) {
      info = eigval_refine_proc(procinfo, ifirst, ilast,
				    bl_size, &D[bl_begin], &E[bl_begin], &E2[bl_begin], 
				    &Windex[bl_begin], &iblock[bl_begin], &gersch[2*bl_begin],
				    tolstruct, &W[bl_begin], &Werr[bl_begin], &Wgap[bl_begin], 
				    work, iwork);
      assert(info == 0);    
    }
    
    memcpy(work, &W[bl_begin], isize * sizeof(double) );
    MPI_Allgatherv(work, isize, MPI_DOUBLE, &W[bl_begin], rcount, rdispl,
		   MPI_DOUBLE, procinfo->comm);
    
    memcpy(work, &Werr[bl_begin], isize * sizeof(double) );
    MPI_Allgatherv(work, isize, MPI_DOUBLE, &Werr[bl_begin], rcount, rdispl,
		   MPI_DOUBLE, procinfo->comm);
    
    memcpy(iwork, &Windex[bl_begin], isize * sizeof(int) );
    MPI_Allgatherv(iwork, isize, MPI_INT, &Windex[bl_begin], rcount, rdispl,
		   MPI_INT, procinfo->comm);
    
    /* Ensure that within block eigenvalues sorted */
    sorted = false;
    while (sorted == false) {
    	sorted = true;
    	for (j=bl_begin; j < bl_end; j++) {
    	  if (W[j+1] < W[j]) {
    	    sorted = false;
    	    tmp1 = W[j];
    	    W[j] = W[j+1];
    	    W[j+1] = tmp1;
    	    tmp1 = Werr[j];
    	    Werr[j] = Werr[j+1];
    	    Werr[j+1] = tmp1;
    	  }
    	}
    }
    
    /* Set indices index correctly */
    for (j=bl_begin; j <= bl_end; j++)
      iblock[j] = jbl + 1;
    
    /* Recompute gaps within the blocks */
    for (j = bl_begin; j < bl_end; j++) {
      Wgap[j] = fmax(0.0, (W[j+1] - Werr[j+1]) - (W[j] + Werr[j]) );
    }
    sigma = E[bl_end];
    Wgap[bl_end] = fmax(0.0, (gu - sigma) - (W[bl_end] + Werr[bl_end]) );

    /* Compute UNSHIFTED eigenvalues */
    if (!wantZ) {
      sigma = E[bl_end];
      for (i=bl_begin; i<=bl_end; i++) {
	W[i]   += sigma;
      }
    }
    
    /* Proceed with next block */
    bl_begin  = bl_end  + 1;
  }
  /* end of loop over unreduced blocks */    
  
  /* free memory */
  clean_up_plarre(E2, work, iwork, rcount, rdispl);
  
  return 0;
}