package optimizacion;

import java.util.Random;
import operaciones.Matriz;

/**
 * <p>Title: Busquedas aleatorias</p>
 * <p>Description: Hace la minimizacion de una funcion, realizando la busqueda
 * de manera aleatoria</p>
 * <p>Copyright: Copyright (c) 2005</p>
 * <p>Company: UMSNH </p>
 * @author Dr. Felix Calderon Solorio
 * @version 1.0
 */

public class aleatoria {

    double Rangos[][];
    int Npar;
    double T = 100, alfa = 0.99;
    long MaxIter;
    Random azar;

    /**
     * Constructor nulo
     */

    public aleatoria()
    {

    }

    /**
     * Constructor que inicializa los rangos de b�squeda.
     * @param r double[][] rangos dados
     * @param max int M�ximo n�mero de iteraciones
     */

    public aleatoria(double r[][], int max)
    {
        Npar = r.length;
        MaxIter = max;

        Rangos = new double[Npar][2];

        for (int i = 0; i < Npar; i++)
            for (int j = 0; j < 2; j++)
                Rangos[i][j] = r[i][j];
        azar = new Random();
    }

    /**
     * B�squeda totalmente aleatorizada
     * @return double[] m�nimo calculado para la funci�n f(x)
     */

    public double [] busqueda()
    {
        long iter;
        int i;
        double x[] = new double[Npar];
        double xk[] = new double [Npar];

        for(i=0; i<Npar; i++) x[i] = 0;

        for(iter = 0; iter < MaxIter; iter ++)
        {
            Genera_individuo(xk);

            if (iter % 100 == 0) {
                System.out.print("En la iteracion " + iter + " la funcion es " +
                                 funcion(x) + " ");
                imprime(x);
            }
            if (funcion(x) > funcion(xk)) {
                for (i = 0; i < Npar; i++)
                    x[i] = xk[i];
            }
        }
        System.out.print("La solucion en " + iter + " iteraciones es f(x) = " +
                         funcion(x) + " con x = ");
        imprime(x);
        return x;
    }

    /**
     * Genera un inidividuo x de manera aleatoria en los rangos definidos
     * de b�squeda
     * @param x double[] Individuo a generar
     */

    private void Genera_individuo(double x[])
    {
        int j;
        for (j = 0; j < Npar; j++)
            x[j] = azar.nextDouble() * (Rangos[j][1] - Rangos[j][0]) +
                   Rangos[j][0];
    }

    /**
     * Algoritmo de Simulating Annealing
     * @param t double Temperatura inicial
     * @param a double Factor de reduccion [0, 1]
     * @return double[]
     */

    public double[] SA(double t, double a)
    {
        long iter;
        int i;
        double x[] = new double[Npar];
        double xk[] = new double [Npar];
        double df;
        T = t;
        alfa = a;

        for(i=0; i<Npar; i++) x[i] = 0;

        for(iter = 0; iter < MaxIter; iter ++)
        {
            Genera_individuo(xk);

            if (iter % 100 == 0) {
                System.out.print("En la iteracion " + iter + " la funcion es " +
                                 funcion(x) + " ");
                imprime(x);
            }

            df = funcion(xk) - funcion(x);

            if (df < 0) {
                for (i = 0; i < Npar; i++)
                    x[i] = xk[i];
            }
            else {
                if(azar.nextDouble( ) < Math.exp(-df/T) )
                {
                    for (i = 0; i < Npar; i++)
                        x[i] = xk[i];
                }
            }
            T*= alfa;
        }

        System.out.print("La solucion en " + iter + " iteraciones es f(x) = " +
                         funcion(x) + " con x = ");
        imprime(x);

        return x;
    }

    /**
     * Funci�n a minimizar. En este caso la funci�n no realiza nada
     * para sobreescribirla utilizando herencia
     * @param x double[]
     * @return double
     */

    public double funcion(double x[])
    {
        System.out.println("Hola");
        return 0;
    }

    /**
     * Imprime el par�metro x
     * @param x double[]
     */

    public void imprime(double x[])
    {
        int i;

        System.out.print("[");

        for(i=0; i<Npar; i++)
            System.out.print(x[i] + " ");

        System.out.println("]");
    }
}
