Changeset 9f6ab11 in tol


Ignore:
Timestamp:
Nov 21, 2011, 11:22:05 AM (15 years ago)
Author:
Víctor de Buen <vdebuen@…>
Branches:
1941-docker-image-to-test, devel, master
Children:
11d9bec
Parents:
9e93790
Message:

Refs #1342
Forcing interior points in TruncStdGaussian and related methods

git-svn-id: ​https://www.tol-project.org/svn/tolp/trunk@3857 be4846ae-f051-483a-831f-b64e7d08527f

Location:
tol/btol/vmatrix_type
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • tol/btol/vmatrix_type/tol_bvmat.h

    r9e93790 r9f6ab11  
    544544                                       double& upper);
    545545  void TruncStdGaussian(const BVMat& D, const BVMat& d_,
    546                         const BVMat& z0_, int ncol, int burnin);
     546    const BVMat& z0_, int ncol, int burnin, double borderDistance);
    547547  void Histogram(const BVMat& M, int parts);
    548548  void Histogram(const BVMat& M, int parts, double min, double max);
    … …  
    555555                                const BVMat& d,
    556556                                      BVMat& b,
    557                                       BVMat& z);
     557                                      BVMat& z,
     558                                double borderDistance);
    558559  void Histogram_bRd(const BVMat& M, int parts);
    559560  void Histogram_bRd(const BVMat& M, int parts, double min, double max);
  • tol/btol/vmatrix_type/vmat_stats.cpp

    r9e93790 r9f6ab11  
    573573  }
    574574//Std(BText("\nlower=")<<lower<<"\tupper="<<upper);
    575   double length = lower-upper;
     575  double length = upper-lower;
    576576  int length_sign = gsl_fcmp(length+1.0,1.0,vmat_trunc_eps);
    577   if(length_sign>=0)
     577  if(length_sign<=0)
    578578  {
    579579    if(length_sign==0)
    … …  
    597597                                const BVMat& d,
    598598                                      BVMat& b,
    599                                       BVMat& z)
     599                                      BVMat& z,
     600                                double borderDistance)
    600601// Generates a set of standarized multinormal z constrained to
    601602//   D*z <= d 
    … …  
    646647      {
    647648        bx[i] += Dij*zj;
     649        aux = bx[i]/Dij;
    648650      //Std(BText("\n  D[")+i+","+j+"]="+BDat(Dij)+"\tz["+j+"]="+BDat(zj)+"\tb["+i+"]="+BDat(bx[i])+"\td["+i+"]="+BDat(dx[i]));
    649651        if(Dij_sign<0)
    650652        {
    651           aux = bx[i]/Dij;
    652653          if(lower<aux) { lower = aux; }
    653         //Std(BText("\n  aux=")+BDat(aux)+"\tlower="<<BDat(lower));
    654654        }
    655655        else //if(Dij_sign>0)
    656656        {
    657           aux = bx[i]/Dij;
    658657          if(upper>aux) { upper = aux; }
    659         //Std(BText("\n  aux=")+BDat(aux)+"\tupper="<<BDat(upper));
    660658        }
    661659      }
    662660    }
    663661  //Std(BText("\nlower=")<<BDat(lower)<<"\tupper="<<BDat(upper));
    664     double length = lower-upper;
    665     int length_sign = gsl_fcmp(length+1.0,1.0, vmat_trunc_eps);
    666     if(length_sign>=0)
    667     {
    668       if(length_sign==0)
     662    double length = upper-lower;
     663    if(fabs(length)<=1.E-8)
     664    {
     665      //Si el intervalo es cuasi-vacío estamos rondando la frontera pero
     666      //el punto es prácticamente factible. 
     667      Std(BText("(I) TruncStdGaussian [Case A] ")<<
     668        I2("(cuasi-empty interval",
     669        "(intervalo cuasi-vacio")+" ["+BDat(lower).Format("%.16lg")+","+
     670                                       BDat(upper).Format("%.16lg")+"])");
     671      zj = (lower+upper)*0.5;
     672    }
     673    else if(length<0)
     674    {
     675      //Si el intervalo es vacío estamos fuera de la región factible
     676      warn_cannot_apply("(I) TruncStdGaussian [Case B] ",
     677        I2("(empty interval",
     678        "(intervalo vacio")+" ["+BDat(lower).Format("%.16lg")+","+
     679                                 BDat(upper).Format("%.16lg")+"])",z);
     680      return(-1);
     681    }
     682# ifdef USE_BTruncatedNormalDist
     683    else if((lower>negInf)||(upper<posInf))
     684    {
     685      //A continuación se generará una N(0,1) truncada estrictamente en el
     686      //interior del intevalo de dominio abierto (lower, upper) para evitar
     687      //problemas numéricos de frontera.
     688
     689      //Máximo valor absoluto para el que se usará la distribución N(0,1)
     690      double K = 6;
     691      //La probabilidad de estar una N(0,1) fuera del intervalo [-K,K] es
     692      //con K=6 es p=1.973175400848959e-009 ~ 1 entre 500 mil millones, por lo que
     693      //es despreciable cualquier valor fuera del mismo y nos evitamos problemas
     694      //numéricos, pues tanto la cumulativa como su inversa funcionan bien
     695      //en este intervalo pero empiezan a fallar a partir de K=8.
     696      //Quizás podría ponerse K=7 pero se toma K=6 por dar un margen y porque
     697      //la pérdida de precisión es irrelevante tan lejos de la moda.
     698      //Fuera de ahí la distribución se aproximará por la raíz cuadrada de una
     699      //uniforme en el dominio reducido interior al original de tal forma que
     700      //el que el cociente de verosimilitudes entre los extremos sea menor o
     701      //igual a 100, pues en ese rango resulta una buena aproximación de la
     702      //normal truncada y es al mismo tiempo tratable numéricamente.
     703      //
     704      //El cociente de densidades entre dos puntos x,y ~ N(0,1) es
     705      //
     706      //  f(x)/f(y) = Exp(-0.5*(x^2-y^2))
     707      //
     708      //Si queremos un punto y que sea h veces menos probable que x entonces
     709      //
     710      //  Log(h) = -0.5*(x^2-y^2)
     711      //  y^2 = x^2 + 2*Log(h)
     712      //
     713      //Estas operaciones no comportan riesgos numéricos incluso para valores
     714      //muy grandes.
     715      double lowMrg = lower;
     716      double uppMrg = upper;
     717      if(lower>=K)
     718      {
     719        //Si todo el dominio está por encima de K tomamos como nuevos límites
     720        //tentativos los puntos con densidad 1.1 y 110 veces las del límite inferior.
     721        //De esta forma el nuevo límite inferior es por construcción 100 veces más
     722        //probable que el superior
     723        double lowMrg_ = sqrt(pow(lower,2) + 2.0 * log(  1.1) );
     724        double uppMrg_ = sqrt(pow(upper,2) + 2.0 * log(110.0) );
     725        //Si los límites tentativos se salen del dominio hay que meterlos dentro
     726        if(lowMrg_>=upper)
     727        {
     728          lowMrg = 0.99*lower+0.01*upper;
     729          uppMrg = 0.99*upper+0.01*lower;
     730        }
     731        else
     732        {
     733          lowMrg = lowMrg_;
     734          if(uppMrg_>=upper)
     735          {
     736            uppMrg = 0.99*upper+0.01*lowMrg;
     737          }
     738          else
     739          {
     740            uppMrg = uppMrg_;
     741          }
     742        }
     743        //Tomamos un r uniforme
     744        double r = BUniformDist::Random01().Value();
     745        //y calculamos su raíz cuadrada como valor de ponderación de los límites
     746        //para forzar puntos más cercanos al nuevo límite inferior.
     747        double u = sqrt(r);
     748        zj = u*lowMrg + (1.0-u)*uppMrg;
     749        if((zj<=lower) ||(zj>=upper))
     750        {
     751          warn_cannot_apply("(I) TruncStdGaussian [Case C.1] ",
     752            BText(" j=")<<j<<
     753            " domain:["<<lower<<","<<upper<<"] -> "<<
     754            " interior domain: ["<<lowMrg<<","<<uppMrg<<"] -> "<<zj,z);
     755          return(-1);
     756        }
     757      }
     758      else if(upper<=-K)
    669759      {
    670         lower = upper;
     760        //Si todo el dominio está por debajo de -K tomamos como nuevos límites
     761        //tentativos los puntos con densidad 1.1 y 110 veces las del límite superior.
     762        //De esta forma el nuevo límite superior es por construcción 100 veces más
     763        //probable que el inferior
     764        double uppMrg_ = -sqrt(pow(upper,2) + 2.0 * log(  1.1) );
     765        double lowMrg_ = -sqrt(pow(lower,2) + 2.0 * log(110.0) );
     766        //Si los límites tentativos se salen del dominio hay que meterlos dentro
     767        if(uppMrg_<=lower)
     768        {
     769          lowMrg = 0.99*lower+0.01*upper;
     770          uppMrg = 0.99*upper+0.01*lower;
     771        }
     772        else
     773        {
     774          uppMrg = uppMrg_;
     775          if(lowMrg_<=lower)
     776          {
     777            lowMrg = 0.99*lower+0.01*uppMrg;
     778          }
     779          else
     780          {
     781            lowMrg = lowMrg_;
     782          }
     783        }
     784        //Tomamos un r uniforme
     785        double r = BUniformDist::Random01().Value();
     786        //y calculamos su raíz cuadrada como valor de ponderación de los límites
     787        //para forzar puntos más cercanos al nuevo límite inferior.
     788        double u = sqrt(r);
     789        zj = u*uppMrg + (1.0-u)*lowMrg;
     790        if((zj<=lower) ||(zj>=upper))
     791        {
     792          warn_cannot_apply("(I) TruncStdGaussian [Case C.2] ",
     793            BText(" j=")<<j<<
     794            " domain:["<<lower<<","<<upper<<"] -> "<<
     795            " interior domain: ["<<lowMrg<<","<<uppMrg<<"] -> "<<zj,z);
     796          return(-1);
     797        }
    671798      }
    672799      else
    673800      {
    674         warn_cannot_apply("(I) TruncStdGaussian",
     801        //Si alguno de los límites cae fuera de [-K,K] hacemos la intersección
     802        if(lower<-K) { lowMrg=-K; }
     803        if(upper>+K) { uppMrg=+K; }
     804        BNormalDist u01(0,1);
     805        //Calculamos los cuantiles de la N(0,1) en los extremos
     806        double lowF01 = u01.Dist(lowMrg).Value();
     807        double uppF01 = u01.Dist(uppMrg).Value();
     808        //Calculamos el desplazamiento en la métrica probabilística
     809        double difF01 = borderDistance*(uppF01-lowF01);
     810        //Desplazamos los límites hacia el interior
     811        double lowF01_ = lowF01+difF01;
     812        double uppF01_ = uppF01-difF01;
     813        //Tomamos un r uniforme
     814        double r = BUniformDist::Random01().Value();
     815        //Tomamos un u normal truncado en el dominio interior
     816        double u = r*uppF01_ + (1.0-r)*lowF01_;
     817        //Volvemos a la métrica normalizada   
     818        zj = u01.Inverse(u).Value();
     819        if((zj<=lower) ||(zj>=upper))
     820        {
     821          warn_cannot_apply("(I) TruncStdGaussian [Case C.1] ",
     822            BText(" j=")<<j<<
     823            " domain:["<<lower<<","<<upper<<"] -> "<<
     824            " Prob domain["<<lowF01<<","<<uppF01<<"] -> "<<
     825            " Prob interior domain["<<lowF01_<<","<<uppF01_<<"] -> "<<zj,z);
     826          return(-1);
     827        }
     828      }
     829    }
     830    else
     831    {
     832      zj = BNormalDist::Random01().Value();
     833      if((zj<=lower) ||(zj>=upper))
     834      {
     835        warn_cannot_apply("(I) TruncStdGaussian [Case D] ",
    675836          I2("(empty interval",
    676837          "(intervalo vacio")+" ["+BDat(lower).Format("%.16lg")+","+
    677838                                   BDat(upper).Format("%.16lg")+"])",z);
    678         return(-1);
    679839      }
    680840    }
    681 # ifdef USE_BTruncatedNormalDist
    682     if(lower==upper)
    683     {
    684       zj = lower;
    685     }
    686     else if((lower>negInf)||(upper<posInf))
    687     {
    688       if((lower>10) || (upper<-10))
    689       {
    690         double r = BUniformDist::Random01().Value();
    691         zj = r*lower+(1-r)*upper;
    692       }
    693       else
    694       {
    695         BTruncatedNormalDist tn(lower,upper);
    696         zj = tn.Random().Value();
    697         assert((lower<=zj) && (zj<=upper));
    698       //Std(BText("\nBTruncatedNormalDist z[")+j+"]="+zj);
    699       }
    700     }
    701     else
    702     {
    703       zx[j] = BNormalDist::Random01().Value();
    704     //Std(BText("\nBNormalDist z[")+j+"]="+zj);
    705     }
     841
     842
    706843# else
    707844    zj = gsl_rtabnorm_combo(getGslRng(), 0.0, 1.0,
    … …  
    731868////////////////////////////////////////////////////////////////////////////////
    732869  void BVMat::TruncStdGaussian(const BVMat& D, const BVMat& d_,
    733                                const BVMat& z0, int ncol, int burnin)
     870                               const BVMat& z0, int ncol, int burnin,
     871                               double borderDistance)
    734872//Matrix instances
    735873////////////////////////////////////////////////////////////////////////////////
    … …  
    768906    return;
    769907  }
    770   if(burnin<=0 ) { burnin = 1; }
     908  if(burnin<0 ) { burnin = 0; }
    771909  BVMat burn;
    772910  burn.Zeros(nrow, burnin, ESC_blasRdense);
    … …  
    779917    for(k=0; k<burnin; k++, aux+=nrow)
    780918    {
    781       if(trunc_std_gaussian(D, d, b, z)!=0) { return; } 
     919      if(trunc_std_gaussian(D, d, b, z, borderDistance)!=0) { return; } 
    782920      memcpy(aux, z.s_.blasRdense_->x, size_row);
    783921    }
    … …  
    785923    for(k=0; k<ncol; k++, aux+=nrow)
    786924    {
    787       if(trunc_std_gaussian(D, d, b, z)!=0) { return; } 
     925      if(trunc_std_gaussian(D, d, b, z, borderDistance)!=0) { return; } 
    788926      memcpy(aux, z.s_.blasRdense_->x, size_row);
    789927    }
  • tol/btol/vmatrix_type/vmatgra.cpp

    r9e93790 r9f6ab11  
    25112511//--------------------------------------------------------------------
    25122512DeclareContensClass(BVMat, BVMatTemporary, BVMatTruncStdGaussian);
    2513 DefExtOpr(1, BVMatTruncStdGaussian, "TruncStdGaussian", 3, 5,
    2514   "VMatrix VMatrix VMatrix Real Real",
    2515   "(VMatrix D, VMatrix d, VMatrix z0 [, Real ncol=1, Real burnin=0])",
     2513DefExtOpr(1, BVMatTruncStdGaussian, "TruncStdGaussian", 3, 6,
     2514  "VMatrix VMatrix VMatrix Real Real Real",
     2515  "(VMatrix D, VMatrix d, VMatrix z0 "
     2516  "[, Real ncol=1, Real burnin=0, Real borderDistance=0.001])",
    25162517  I2("Creates a random virtual matrix X which ncol columns are distributed as "
    25172518     "independent standard normal truncated into a polytope",
    … …  
    25412542  int ncol = 1;
    25422543  int burn = 0;
     2544  double borderDistance = 0.001;
    25432545  if(Arg(4)) { ncol = (int)Real(Arg(4)); }
    25442546  if(Arg(5)) { burn = (int)Real(Arg(5)); }
    2545   contens_.TruncStdGaussian(D,d,z0,ncol,burn);
     2547  if(Arg(6)) { burn = (int)Real(Arg(6)); }
     2548  contens_.TruncStdGaussian(D,d,z0,ncol,burn,borderDistance);
    25462549  assert(contens_.Check());
    25472550}
Note: See TracChangeset for help on using the changeset viewer.