// Bayes.java

package lt.ktu.gmj.methods;

import lt.ktu.gmj.*;

public class Bayes extends IPMethodBase {
 static private final int NOT_SEC_POINT = 0;
 static private final int SEC_POINT = 1;
 static private final int PAR1 = 10;
 static private final int PAR2 = 50;
 static private final double VAL = 1e-6;
 static private final double COEF=100*1e-16;
 static private final double RMAX=0.5*Double.MAX_VALUE;

 private Point x2;
 private Point mz;
 private int   ix;

 public Bayes ()
 {
   iterations=100;
   initialPoints=5;
 }

 public void run (ResultLogger logger, Task task)
 {
   Domain domain=task.domain ();
   Result result=new Result();
   ix = NOT_SEC_POINT;

    for (int iteration=0; iteration<initialPoints; iteration++)
    {
      Point pt=new LPPoint (domain, iteration);
      Result r=new Result (iteration, pt, task.f(pt));
      logger.log (r);

       if (r.value < result.value)
        result=r;
     }

     for (int iteration=initialPoints; iteration<iterations; iteration++)
     {
       Point pt = mig2f2 (logger, task, result, iteration);
       Result r=new Result (iteration, pt, task.f(pt));
       logger.log (r);

       if (r.value < result.value)
        result=r;
      }

   logger.logResult (result);
 }

 private Point mig2f2 (ResultLogger logger, Task task, Result result, int m)
 {
   Point z=null;
   Domain domain=task.domain ();

   int k2 = Math.min(PAR2, Math.max(PAR1, m)) * domain.dimensions().length;
   double fmin = 0;
   double ffm = 0;

    if (ix == NOT_SEC_POINT)
    {
      x2=new RandomPoint(domain);
      k2--;
      ix = SEC_POINT;
    }
   double f2 = fiap1 (x2, logger, fmin, result, m);

   for (int k=0; k<k2; k++)
    {
      mz=new RandomPoint(domain);
      double fi = fiap1 (mz, logger, fmin, result, m);

       if (k==0)
       {
          if (fi >= f2) { z=x2; x2=mz; ffm=f2; fmin=f2=fi; }
                   else { z=mz; ffm=fi; fmin=f2; }
       }
       else
       {
         if (fi < f2)
         {
           if (fi < ffm) { x2=z; z=mz; fmin=f2=ffm; ffm=fi; }
                    else { x2=mz; fmin=f2=fi; }
         }
       }
    }

   return z;
 }

 private double fiap1 (Point x, ResultLogger logger, double fmin, Result result, int m)
 {
   double fm0=logger.iterationResult(0).value;
   double fmC=result.value;
   double yk  = fmC - Math.max (VAL, COEF * Math.abs (fmC));
   double fii = Math.min (RMAX, RMAX / (fm0 - yk));

   for (int j=0; j<m; j++)
   {
     Result jResult=logger.iterationResult(j);
     double dd = x.distance (jResult.point);
     double d = dd*dd;
     double pp = jResult.value - yk;

      if (d < Math.min(RMAX, pp*fii))
      {
        fii = d / pp;
         if (fii <= -fmin) return -fii;
      }
   }

   return -fii;
 }

}


