24. Evaluación de funciones discretas

Evaluar una función significa calcular su valor para una entrada concreta. Es la operación más básica sobre funciones y la que conecta directamente la definición matemática con la ejecución de un programa.

24.1 Introducción

Una función puede estar definida de varias formas: como lista de pares, como fórmula, como tabla o como regla por casos. En todos los casos, evaluar la función significa encontrar el único valor b asociado a una entrada a dada.

En funciones discretas, el dominio es finito, lo que permite recorrerlo completamente y construir tablas de valores explícitas.

24.2 Evaluación desde una lista de pares

Cuando la función está definida como conjunto de pares, evaluar f(a) significa buscar el par cuya primera componente es a y devolver la segunda.

const f = [[1, 'rojo'], [2, 'azul'], [3, 'verde'], [4, 'rojo']];

function evaluar(funcion, a) {
  const par = funcion.find(([x]) => x === a);
  if (par === undefined) throw new Error(`${a} no está en el dominio`);
  return par[1];
}

console.log(evaluar(f, 1)); // 'rojo'
console.log(evaluar(f, 3)); // 'verde'
console.log(evaluar(f, 4)); // 'rojo'

24.3 Evaluación desde una fórmula

Cuando la función está definida por una expresión matemática, evaluarla significa sustituir el valor en la fórmula y calcular el resultado.

f : {0, 1, 2, 3, 4, 5} → ℤ f(n) = n² - 2n + 1
const dominio = [0, 1, 2, 3, 4, 5];

function f(n) {
  return n * n - 2 * n + 1;
}

// Evaluar en un punto
console.log(f(3)); // 4

// Recorrer todo el dominio
for (const n of dominio) {
  console.log(`f(${n}) = ${f(n)}`);
}
// f(0) = 1
// f(1) = 0
// f(2) = 1
// f(3) = 4
// f(4) = 9
// f(5) = 16

24.4 Construir la tabla de valores completa

Para funciones discretas es posible y útil construir la tabla completa de pares recorriendo todo el dominio.

const dominio = [0, 1, 2, 3, 4, 5];

function f(n) {
  return n * n - 2 * n + 1;
}

// Construir todos los pares (a, f(a))
const tabla = dominio.map(a => [a, f(a)]);

console.log(tabla);
// [[0,1],[1,0],[2,1],[3,4],[4,9],[5,16]]

// Calcular la imagen a partir de la tabla
const imagen = [...new Set(tabla.map(([, b]) => b))];
console.log('Imagen:', imagen); // [1, 0, 4, 9, 16]

24.5 Funciones definidas por casos

Una función por casos asigna reglas distintas según el valor de la entrada. La condición de función sigue siendo válida: cada entrada cae en exactamente un caso y produce exactamente una salida.

f : {-3, -2, -1, 0, 1, 2, 3} → ℤ f(n) = n + 10 si n < 0 0 si n = 0 n² si n > 0
const dominio = [-3, -2, -1, 0, 1, 2, 3];

function f(n) {
  if (n < 0) return n + 10;
  if (n === 0) return 0;
  return n * n;
}

for (const n of dominio) {
  console.log(`f(${n}) = ${f(n)}`);
}
// f(-3) = 7
// f(-2) = 8
// f(-1) = 9
// f(0)  = 0
// f(1)  = 1
// f(2)  = 4
// f(3)  = 9

24.6 Evaluación sobre conjuntos no numéricos

El dominio de una función discreta no tiene que ser numérico. Puede ser cualquier conjunto finito: palabras, colores, estados, etiquetas, objetos.

// f asigna a cada día de la semana su abreviatura
const f = new Map([
  ['lunes',     'Lun'],
  ['martes',    'Mar'],
  ['miércoles', 'Mié'],
  ['jueves',    'Jue'],
  ['viernes',   'Vie'],
  ['sábado',    'Sáb'],
  ['domingo',   'Dom']
]);

function evaluar(funcion, entrada) {
  if (!funcion.has(entrada)) throw new Error(`${entrada} no está en el dominio`);
  return funcion.get(entrada);
}

console.log(evaluar(f, 'lunes'));    // 'Lun'
console.log(evaluar(f, 'viernes')); // 'Vie'

// Recorrer todo el dominio
for (const [dia, abrev] of f) {
  console.log(`${dia} → ${abrev}`);
}

24.7 Verificar que una evaluación es consistente

Al evaluar sobre todo el dominio, podemos verificar que la relación generada cumple la condición de función: cada elemento del dominio tiene exactamente una imagen.

function construirYVerificar(dominio, f) {
  const pares = [];
  const errores = [];

  for (const a of dominio) {
    try {
      const b = f(a);
      pares.push([a, b]);
    } catch (e) {
      errores.push(`Sin imagen para ${a}`);
    }
  }

  if (errores.length > 0) {
    console.log('Errores:', errores);
    return null;
  }

  console.log('Tabla completa:', pares);
  return pares;
}

const dominio = [1, 2, 3, 4];

construirYVerificar(dominio, n => n % 2 === 0 ? 'par' : 'impar');
// Tabla completa: [[1,'impar'],[2,'par'],[3,'impar'],[4,'par']]

24.8 Evaluación con composición

Evaluar una composición (g ∘ f)(a) equivale a evaluar primero f en a, y luego evaluar g en el resultado.

(g ∘ f)(a) = g(f(a))
const dominio = [1, 2, 3, 4, 5];

// f: entero → string de paridad
function f(n) {
  return n % 2 === 0 ? 'par' : 'impar';
}

// g: paridad → emoji
function g(paridad) {
  return paridad === 'par' ? '✓' : '✗';
}

// Composición g ∘ f
function gof(n) {
  return g(f(n));
}

for (const n of dominio) {
  console.log(`(g∘f)(${n}) = g(f(${n})) = g('${f(n)}') = '${gof(n)}'`);
}
// (g∘f)(1) = g(f(1)) = g('impar') = '✗'
// (g∘f)(2) = g(f(2)) = g('par')   = '✓'
// ...

24.9 Tabla comparativa de formas de definir una función

Forma de definición Cómo se evalúa Ventaja Limitación
Lista de pares Buscar el par con primera componente a Explícita, sin ambigüedad Solo funciona para dominios finitos pequeños
Fórmula Sustituir a en la expresión Compacta y generalizable Requiere que la expresión esté bien definida en todo el dominio
Tabla (Map) Consultar la clave a Eficiente para dominios arbitrarios Hay que almacenar todos los pares
Por casos Evaluar la condición y aplicar la rama correcta Permite reglas distintas por zona del dominio Los casos deben ser mutuamente excluyentes y exhaustivos

24.10 Evaluar la imagen de un subconjunto

A veces interesa calcular la imagen de un subconjunto del dominio, no de todo el dominio. Esto se usa en análisis de alcanzabilidad y en restricciones de funciones.

const dominio = [1, 2, 3, 4, 5, 6];

function f(n) {
  return n * n % 7; // resto al dividir n² por 7
}

function imagenDeSubconjunto(subdominio, funcion) {
  return [...new Set(subdominio.map(funcion))];
}

const pares   = dominio.filter(n => n % 2 === 0); // [2, 4, 6]
const impares = dominio.filter(n => n % 2 !== 0); // [1, 3, 5]

console.log('Imagen de pares:', imagenDeSubconjunto(pares, f));
// [4, 2, 1]  (4²%7=2, 16%7=2 → [4,2] → corrección: 4%7=4, 16%7=2, 36%7=1)
console.log('Imagen de impares:', imagenDeSubconjunto(impares, f));
// [1, 2, 4]
console.log('Imagen total:', imagenDeSubconjunto(dominio, f));
// [1, 2, 4]

24.11 Errores comunes

  • Evaluar una función fuera de su dominio: el resultado no está definido y puede producir errores en tiempo de ejecución.
  • En funciones por casos, dejar un caso sin cubrir o que dos casos se solapen para alguna entrada.
  • Confundir f(a) (un valor) con f (la función completa).
  • Al componer, evaluar en orden inverso: (g ∘ f)(a) = g(f(a)), no f(g(a)).
  • Suponer que una fórmula definida para todos los reales es automáticamente válida en el dominio discreto declarado.

24.12 Qué debes recordar de este tema

  • Evaluar f(a) significa encontrar el único b asociado a a en la definición de f.
  • Las funciones discretas pueden definirse como pares, fórmulas, tablas o reglas por casos.
  • En todos los casos, cada entrada debe producir exactamente una salida.
  • Recorrer todo el dominio permite construir la tabla completa de valores.
  • La composición se evalúa de dentro hacia afuera: primero f, luego g.
  • En funciones por casos, los casos deben ser exhaustivos y mutuamente excluyentes.

24.13 Conclusión

La evaluación es la operación fundamental sobre funciones. Saber evaluar correctamente, independientemente de cómo esté definida la función, es el primer paso para trabajar con imágenes, verificar propiedades y construir tablas de valores completas.

En el próximo tema estudiaremos la representación tabular de funciones: cómo organizar y visualizar la tabla de valores de una función discreta de forma sistemática.