Búsqueda ternaria
Un algoritmo de búsqueda ternaria es una técnica en ciencias de la computación para hallar los extremos de una función (máximo o mínimo) de una función unimodal. Una búsqueda ternaria determina que el extremo que se busca, no puede estar en el primer tercio del dominio o que no puede estar en el último tercio del dominio, luego se repite el proceso en los dos tercios restantes. Una búsqueda ternaria es un ejemplo de un Algoritmo divide y vencerás (ver Algoritmo de búsqueda).
Función
Supongamos que estamos buscando un máximo de f(x) y sabemos que el máximo se encuentra en algún lugar entre A y B. Para que el algoritmo sea aplicable debe haber un valor x tal que
- para todo a,b con A ≤ a < b ≤ x, tenemos que f(a) < f(b), y
- para todo a,b con x ≤ a < b ≤ B, tenemos que f(a) > f(b).
Algoritmo
Sea f(x) una función unimodal en el intervalo [l; r]. Tomamos dos puntos m1 y m2 en este segmento: l < m1 < m2 < r. Entonces, hay tres posibilidades:
- Si f(m1) < f(m2), entonces el máximo requerido no puede ubicarse en el lado izquierdo - [l; m1]. Esto significa que el máximo debe buscarse en el intervalo [m1;r]
- Si f(m1) > f(m2), de manera similar al anterior caso. Ahora, el máximo requerido no puede estar en el lado derecho - [m2; r], así que debe buscarse en el segmento [l; m2]
- Si f(m1) = f(m2), entonces la búsqueda debe realizarse en [m1; m2], pero este caso se puede atribuir a cualquiera de los dos anteriores (para simplificar el código). Tarde o temprano, la longitud del segmento será un poco menor que una constante predeterminada, y el proceso podrá detenerse.
Puntos de partición m1 y m2:
- m1 = l + (r-l)/3
- m2 = r - (r-l)/3
- Tiempo de ejecución
Algoritmo Recursivo
en lenguaje Python:
def BusquedaTernaria(f, l, r, absolutePrecision):
'''
l y r son los límites actuales;
el máximo está entre ellos;
absolutePrecision es el nivel de precisión
'''
if abs(r - l) < absolutePrecision:
return (l + r)/2
m1 = (2*l + r)/3
m2 = (l + 2*r)/3
if f(m1) < f(m2):
return BúsquedaTernaria(f, m1, r, absolutePrecision)
else:
return BúsquedaTernaria(f, l, m2, absolutePrecision)
en lenguaje C:
double BusquedaTernaria(double f[] ,int l ,int r ,double absolutePrecision )
{
//l y r son los límites actuales;
//el máximo está entre ellos;
//absolutePrecision es una constante predeterminada
if(r-l <= absolutePrecision)
{
return ( l + r ) / 2.0;
}
else
{
int m1 = ( 2 * l + r ) / 3;
int m2 = ( l + 2 * r ) / 3;
if(f[m1]< f[m2])
{
return BusquedaTernaria( f , m1 , r , absolutePrecision );
}
else
{
return BusquedaTernaria ( f , l , m2 , absolutePrecision );
}
}
}
Algoritmo Iterativo
en lenguaje Python:
from typing import Callable, Tuple
def trisection(f: Callable, bracket: Tuple[float, float, float], xtol=0.001, maxiter=100) -> Tuple[float, int, int]:
"""Recibe una funcion f, una tupla bracket que define un bracket de f y, a partir de dicho bracket, devuelve
una tupla r, nit, nfev con un minimo aproximado r y el numeros de iteraciones y de evaluaciones de f
necesarias para encontrarlo mediante el método de triseccion
Args:
f (Callable): función a evaluar
bracket (Tuple[float, float, float]): bracket sobre el que buscar el mínimo
xtol (float, optional): margen de error mínimo. Por defecto es 0.001.
maxiter (int, optional): número de iteraciones máximas del algoritmo. Por defecto es 100.
Raises:
Exception: se ha superado el número maximo de iteraciones
ValueError: el bracket no cumple las condiciones de orden
Returns:
Tuple[float, int, int]: tupla con la raiz, en numero de iteraciones y el numero de evaluaciones de
la funcion
"""
a, b, c = bracket
if not (a < b < c) and not (f(a) > f(b) and f(b) < f(c)):
raise ValueError('Incorrect bracket')
nit = 0 # Número de iteraciones
nfev = 0 # Número de evaluaciones de la función
while abs(c - a) > xtol and nit <= maxiter:
nit += 1
nfev += 2 # Evaluamos la función en dos nuevos puntos
# Calculamos los puntos intermedios
x1 = a + (c - a) / 3
x2 = c - (c - a) / 3
f1 = f(x1)
f2 = f(x2)
if f1 < f2:
c = x2
else:
a = x1
if nit >= maxiter:
raise Exception("El número máximo de iteraciones permitidas ha sido excedido.")
r = (a + c) / 2
return r, nit, nfev
en lenguaje C:
double BusquedaTernaria(double f[] ,int l ,int r ,double absolutePrecision )
{
//Buscar el máximo de la función unimodal f () dentro de [l, r]
//Para encontrar el mínimo, invierta la instrucción if / else o invierta la comparación.
bool b=true;
while(b==true)
{
if( r - l <= absolutePrecision)
{
b=false;
return ( l + r) / 2;
}
int m1 = ( 2 * l + r ) / 3;
int m2 = ( l + 2 * r ) / 3;
if(f[m1]< f[m2])
{
l = m1;
}
else
{
r = m2;
}
}
}
Referencias
Enlaces externos
- Esta obra contiene una traducción derivada de «Ternary search» de Wikipedia en inglés, publicada por sus editores bajo la Licencia de documentación libre de GNU y la Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.