01 · Una decisión dentro del código
Los parámetros también son variables de optimización
Muchos programas exponen decisiones numéricas: tamaño de lote, cantidad de hilos, nivel de compresión, capacidad de una caché, número de iteraciones o intervalo entre actualizaciones. Elegirlas por costumbre puede desperdiciar recursos o degradar el resultado.
Representaremos con x un parámetro configurable y con J(x) el costo que queremos minimizar. El significado de «costo» depende del problema: puede ser tiempo, memoria, consumo, error o una combinación de varias métricas.
02 · Del sistema al modelo
Un ciclo de optimización reproducible
- Elegir el parámetro controlable
x. - Definir las métricas observables y sus unidades.
- Fijar el dominio factible y las restricciones duras.
- Construir o ajustar una función objetivo
J(x). - Hallar y clasificar los candidatos matemáticos.
- Traducir la solución a valores admitidos por el programa.
- Validar con mediciones nuevas y monitorear cambios.
El ciclo puede repetirse cuando cambian los datos, el hardware, la carga o los requisitos del producto.
03 · Qué significa «mejor»
Rendimiento, memoria y calidad
Una optimización útil comienza con métricas precisas. Por ejemplo:
| Dimensión | Métrica posible | Objetivo |
|---|---|---|
| Rendimiento | latencia p95 en milisegundos | minimizar |
| Capacidad | solicitudes por segundo | maximizar |
| Memoria | máximo residente en MiB | minimizar o acotar |
| Calidad | error, pérdida o tasa de fallos | minimizar |
| Consumo | energía por operación | minimizar |
«El programa se siente rápido» no es una función objetivo. «Minimizar la latencia p95 con menos de 512 MiB y error menor que 2 %» sí describe una decisión comprobable.
04 · Una sola métrica
Objetivo simple y restricciones duras
Cuando existe una prioridad clara, conviene mantener un objetivo único. Si T(x) es la latencia, podemos plantear:
M representa memoria y E error. Las cotas no son preferencias: cualquier valor que las viole queda fuera del dominio factible.
Este enfoque conserva una interpretación directa y evita esconder un incumplimiento grave detrás de una mejora en otra métrica.
05 · Varios objetivos
Construir una función de costo compuesta
Si los compromisos son graduales, podemos convertir todas las métricas a costos y formar una suma ponderada:
Los símbolos con tilde indican métricas normalizadas. Los pesos no son «constantes mágicas»: expresan cuánto sacrificio en una dimensión aceptamos para mejorar otra.
- Una métrica que queremos maximizar puede transformarse en costo, por ejemplo
−R(x)o1/R(x). - Todos los pesos deben ser no negativos si cada término representa una penalización.
- Multiplicar todos los pesos por la misma constante cambia la escala de
J, pero no su mínimo.
06 · Comparar magnitudes
Normalizar antes de sumar
No tiene sentido sumar directamente 180 milisegundos, 400 MiB y 0,03 de error. Además, la métrica con los números más grandes dominaría el cálculo por una elección accidental de unidades.
Una normalización sencilla usa un valor de referencia:
Así los términos son adimensionales. Otra alternativa es medir la variación relativa respecto de una configuración base. La fórmula elegida y sus referencias deben guardarse junto con el experimento.
07 · Modelo de trabajo
Esfuerzo computacional frente a error
Supongamos que x representa una cantidad de pasadas, muestras o unidades de esfuerzo. Más esfuerzo reduce el error, pero aumenta el consumo de tiempo y memoria. En el intervalo 4 ≤ x ≤ 100 usamos:
El primer término decrece cada vez más lentamente. El segundo crece linealmente. El mínimo equilibra el beneficio marginal de aumentar el esfuerzo con su costo marginal.
08 · Solución analítica
Derivar, resolver y clasificar
La condición estacionaria es:
Descartamos x=−40 porque el esfuerzo no puede ser negativo. Para x>0:
La función es estrictamente convexa; por lo tanto, el punto estacionario es el único mínimo. Además, 40 pertenece al intervalo factible.
09 · Leer el resultado
Igualar cambios marginales
En x=40, los dos términos valen:
Más importante que esa igualdad de niveles es la igualdad de magnitudes marginales:
Una pequeña mejora adicional en calidad compensa exactamente el aumento local del costo de recursos. Antes de 40 domina la mejora de calidad; después domina la penalización de recursos.
10 · Restricciones activas
Cuando el óptimo queda fuera del dominio
Para el modelo general J(x)=a/x+kx, con a,k>0, el candidato es:
Si el programa solo admite L ≤ x ≤ U, la solución continua se recorta al intervalo:
Por ejemplo, con un límite de memoria que impone x≤32, el mínimo factible está en x=32, aunque J′(32)<0. La frontera impide seguir mejorando el objetivo.
11 · Del cálculo a la configuración
Parámetros enteros y valores permitidos
Muchos parámetros no son continuos. Un número de hilos debe ser entero; un tamaño de bloque puede admitir solo potencias de dos; una biblioteca puede ofrecer una lista cerrada de niveles.
Después de obtener x*, se evalúan los valores permitidos cercanos. Si solo se aceptan potencias de dos, alrededor de 40 comparamos:
La mejor configuración disponible es x=32. Redondear a ciegas no alcanza cuando el conjunto permitido tiene saltos o la función es asimétrica.
12 · Qué tan estable es la decisión
Análisis de sensibilidad
En x*=√(a/k), aumentar la penalización de recursos k desplaza el óptimo hacia valores menores. Aumentar la importancia de la calidad a lo desplaza hacia valores mayores.
| k | x* | Lectura |
|---|---|---|
0,03 | 63,25 | los recursos son relativamente baratos |
0,075 | 40 | modelo base |
0,12 | 31,62 | los recursos pesan más |
Si varios valores tienen costos casi iguales, conviene elegir el más simple, robusto o económico de operar. Una cifra decimal extra en el óptimo no implica una mejora relevante.
13 · Datos reales
Benchmarking sin engañarse
Las funciones de un sistema real suelen estimarse con mediciones. Para que el modelo sea confiable:
- usar una carga representativa y fijar versiones, hardware y configuración;
- hacer calentamiento antes de medir código con JIT, cachés o pools;
- repetir ejecuciones y registrar dispersión, no solo el promedio;
- separar datos de ajuste y validación;
- aleatorizar el orden de configuraciones para reducir sesgos temporales;
- medir percentiles de latencia cuando importan los casos lentos.
Una curva suave es una aproximación de observaciones ruidosas. El mínimo estimado debe validarse contra configuraciones vecinas mediante nuevas ejecuciones.
14 · Exploración interactiva
Laboratorio: calidad frente a recursos
Modificá el esfuerzo y la penalización por recursos. El punto amarillo indica el mínimo continuo para el valor actual de k.
Ajuste de un parámetro
J(x) = 120/x + 0,075x
La configuración seleccionada coincide con el mínimo continuo.
El gráfico compara la penalización por error, la penalización por recursos y su suma en el intervalo de 4 a 100.
Preguntas para explorar
- Mové
xa ambos lados de 40. ¿Qué término domina el costo? - Aumentá
k. ¿Por qué el mínimo se desplaza hacia la izquierda? - Compará el costo del óptimo con los enteros vecinos.
- Si solo se admitieran 8, 16, 32, 64 y 100, ¿qué valor elegirías?
15 · Implementación
Calcular el óptimo y respetar el dominio
function costo(x, calidad = 120, recursos = 0.075) {
if (x <= 0) return Infinity;
return calidad / x + recursos * x;
}
function optimoContinuo({ calidad = 120, recursos = 0.075, min = 4, max = 100 } = {}) {
if (calidad <= 0 || recursos <= 0 || min <= 0 || min > max) {
throw new RangeError("Parámetros inválidos");
}
const candidato = Math.sqrt(calidad / recursos);
const x = Math.min(max, Math.max(min, candidato));
return { x, costo: costo(x, calidad, recursos), candidato };
}
console.log(optimoContinuo());
// { x: 40, costo: 6, candidato: 40 }
Elegir entre configuraciones permitidas
function costo(x, calidad = 120, recursos = 0.075) {
if (x <= 0) return Infinity;
return calidad / x + recursos * x;
}
function mejorPermitido(valores, funcionCosto) {
if (valores.length === 0) throw new Error("No hay configuraciones");
return valores.reduce((mejor, x) => {
const actual = { x, costo: funcionCosto(x) };
return actual.costo < mejor.costo ? actual : mejor;
}, { x: null, costo: Infinity });
}
const permitidos = [8, 16, 32, 64, 100];
console.log(mejorPermitido(permitidos, x => costo(x)));
// { x: 32, costo: 6.15 }
16 · Lo que el modelo no garantiza
No todas las curvas son suaves o unimodales
En software aparecen discontinuidades por recolección de basura, paginación, vectorización, límites de caché o cambios de algoritmo. También puede haber varios mínimos locales y mesetas.
Si las mediciones contradicen la forma supuesta, no debemos forzar el cálculo diferencial. Una búsqueda en grilla, un modelo por tramos o un método sin derivadas puede ser más apropiado. El siguiente tema desarrollará la búsqueda exhaustiva.
Además, optimizar una carga fija puede producir sobreajuste: la configuración ganadora del benchmark quizá no generalice a producción.
17 · Comprensión
Confusiones frecuentes
«Solo hay que minimizar el tiempo promedio»
El promedio puede ocultar latencias extremas, errores o un consumo de memoria inaceptable. La métrica debe reflejar el requisito real.
«Puedo sumar métricas aunque tengan unidades distintas»
Primero deben normalizarse o convertirse mediante costos comparables; de lo contrario, la escala elegida domina el resultado.
«Los pesos son objetivos»
Los pesos codifican preferencias. Conviene documentarlos y estudiar cómo cambia la solución al modificarlos.
«J′(x)=0 siempre entrega la configuración final»
Genera un candidato continuo. Hay que comprobar clasificación, fronteras, restricciones y valores discretos admitidos.
«Una medición por configuración es suficiente»
El ruido del sistema puede invertir diferencias pequeñas. Se necesitan repeticiones y una validación independiente.
«El óptimo durará para siempre»
La carga, el hardware y el programa cambian. El ajuste debe monitorearse y repetirse cuando dejan de cumplirse sus supuestos.
18 · Práctica guiada
Ejercicios de aplicación
Ejercicio 1: localizar el mínimo
Sea J(x)=200/x+0,08x, con 5≤x≤80. Hallá el candidato continuo.
Ver solución
J′(x)=−200/x²+0,08. Entonces x²=2500 y x=50. Como J″(x)=400/x³>0, es el mínimo.
Ejercicio 2: frontera activa
En el ejercicio anterior, una restricción de memoria obliga a usar x≤32. ¿Cuál es el mínimo factible?
Ver respuesta
En [5,32] la función todavía decrece, de modo que el mínimo factible es la frontera x=32.
Ejercicio 3: conjunto discreto
Para el modelo principal, compará x=32 y x=48.
Ver solución
J(32)=120/32+0,075·32=6,15. J(48)=120/48+0,075·48=6,1. Entre ambos, conviene 48, aunque ninguno coincide con el mínimo continuo.
Ejercicio 4: transformar un objetivo
Si R(x)>0 es el rendimiento que queremos maximizar, mencioná dos formas de expresarlo como costo.
Ver respuesta
Podemos minimizar −R(x) o 1/R(x). No son equivalentes al combinarlas con otros términos, por lo que debe elegirse la transformación según la interpretación deseada.
Ejercicio 5: diseñar un experimento
¿Por qué conviene alternar aleatoriamente el orden de las configuraciones durante un benchmark?
Ver respuesta
Porque temperatura, carga de fondo, cachés u otras condiciones pueden cambiar con el tiempo. Aleatorizar evita asociar sistemáticamente ese cambio con valores crecientes o decrecientes del parámetro.
19 · Síntesis
Ideas para recordar
- Un parámetro de programa se convierte en una variable de decisión.
- Las métricas deben ser observables, tener unidades y representar el requisito real.
- Las restricciones duras delimitan el dominio factible.
- Las métricas de una suma ponderada deben normalizarse.
- Los pesos expresan preferencias y requieren análisis de sensibilidad.
- La solución continua debe traducirse al conjunto de configuraciones admitidas.
- Las mediciones necesitan repeticiones, control del entorno y validación.
- Si la curva real no es suave, corresponde usar otro método de búsqueda.
En el próximo tema construiremos una búsqueda exhaustiva sobre una grilla, útil cuando no conocemos la derivada o solo podemos evaluar el programa.