La tarea consiste en construir un esquema de inspección por muestreo que equilibre riesgo operativo y confiabilidad. Se parte de una tasa máxima tolerable de defectuosos (p₀), un nivel de confianza deseado (1−α) y un umbral de riesgo de aceptación errónea (β). El tamaño muestral se dteermina mediante aproximación normal a la binomial, ajustando para precisión requerida. El criterio de decisión se establece como el mayor número entero k tal que la probabilidad acumulada P(X ≤ k) supere 1−β bajo p₀. Fórmulas clave:
- Tamaño muestral: n ≈ \frac{z_{\alpha/2}^2 \cdot p_0(1-p_0)}{E^2}, donde E es el margen absoluto de error.
- Límite de rechazo: c = \max\{k \in \mathbb{Z}_{\geq 0} : F_{\text{Bin}(n,p_0)}(k) \geq 1 - \beta\}.
import numpy as np
from scipy.stats import binom
def compute_sampling_plan(p_target=0.08, confidence=0.95, max_rejection_risk=0.07, tolerance=0.04):
z_score = 1.96 if confidence == 0.95 else 2.576
n_est = np.ceil((z_score ** 2 * p_target * (1 - p_target)) / (tolerance ** 2))
n = int(max(n_est, 10)) # mínimo práctico
# Umbral robusto usando percentil inverso
threshold = binom.ppf(1 - max_rejection_risk, n, p_target)
# Simulación Monte Carlo para validar cobertura
simulations = binom.rvs(n=n, p=p_target, size=5000)
acceptance_rate = np.mean(simulations <= threshold)
return {
"sample_size": n,
"rejection_threshold": int(np.floor(threshold)),
"empirical_acceptance": round(acceptance_rate, 3)
}
plan = compute_sampling_plan()
print(f"Tamaño óptimo de muestra: {plan['sample_size']}")
print(f"Umbral de defectuosos: ≤{plan['rejection_threshold']}")
print(f"Tasa empírica de aceptación: {plan['empirical_acceptance']}")
Problema 2: Optimización de Decisiones en Línea de Montaje
Se formula como un problema de programación entera binaria con cuatro variables de decisión: inspección de componente A (x₁), componente B (x₂), producto final (x₃) y desmontaje tras rechazo (x₄). La función objetivo maximiza el beneficio neto, considerando costos variables según el estado de cada variable y penalizaciones por fallos no detectados. Las restricciones incluyen límites de capacidad de prueba y coherencia lógica entre etapas. Modelo formal:
Maximize\ \pi = 56 \cdot (1 - 0.12x₁ - 0.15x₂) \cdot (1 - 0.08x₃) - \left[4(1-x₁)+18(1-x₂)+6+2x₁+3x₂+3x₃+5x₄\right]
sujeto a: x_i \in \{0,1\},\ x₁ + x₂ + x₃ + x₄ \leq 3.
import pulp
model = pulp.LpProblem("Assembly_Line_Optimization", pulp.LpMaximize)
x1 = pulp.LpVariable("inspect_A", cat="Binary")
x2 = pulp.LpVariable("inspect_B", cat="Binary")
x3 = pulp.LpVariable("inspect_final", cat="Binary")
x4 = pulp.LpVariable("disassemble", cat="Binary")
# Función objetivo modificada: incorpora efecto multiplicativo del control de calidad
revenue = 56 * (1 - 0.12*x1 - 0.15*x2) * (1 - 0.08*x3)
costs = (4*(1-x1) + 18*(1-x2) + 6 + 2*x1 + 3*x2 + 3*x3 + 5*x4)
model += revenue - costs
model += x1 + x2 + x3 + x4 <= 3
model.solve(pulp.PULP_CBC_CMD(msg=False))
print(f"Decisión óptima: A={x1.varValue}, B={x2.varValue}, Final={x3.varValue}, Desmontaje={x4.varValue}")
print(f"Beneficio máximo estimado: {pulp.value(model.objective):.2f}")
Problema 3: Gestión de Calidad Multinivel con Subensambles
Extiende el modelo anterior a una cadena con tres niveles: componentes individuales (8 tipos), subconjuntos intermedios (4 agrupaciones), y producto final. Cada nivel puede someterse a verificación independiente. Se introduce una estructura jerárquica de dependencia: la calidad de un subconjunto depende de los componentes que lo integran; la del producto final, de los subconjuntos y componentes directos. Se emplea una formulación de flujo en red con variables binarias por nodo y funciones de costo condicionales. Estructura de calidad compuesta:
- Probabilidad de éxito de subconjunto j: q_j = \prod_{i \in S_j} (1 - d_i \cdot \delta_i), donde d_i es la tasa base de fallo y \delta_i indica si se inspeccionó el componente i.
- Calidad final: Q = q_1 \cdot q_2 \cdot (1 - d_f \cdot x_f), con x_f indicando inspección final.
import pulp
# Nombres simbólicos para claridad
components = [f"C{i}" for i in range(1,9)]
subassemblies = ["SA1", "SA2", "SA3", "SA4"]
final_test = pulp.LpVariable("final_inspect", cat="Binary")
# Variables de decisión
inspect_c = pulp.LpVariable.dicts("inspect_component", components, cat="Binary")
inspect_sa = pulp.LpVariable.dicts("inspect_subassembly", subassemblies, cat="Binary")
prob = pulp.LpProblem("Hierarchical_Quality_Opt", pulp.LpMaximize)
# Costos parametrizados
base_costs = {c: 2.5 for c in components}
test_costs = {c: 1.2 for c in components}
sa_test_cost = 4.0
final_test_cost = 6.5
assembly_cost = 12.0
sale_price = 220.0
# Costo total (linealizado mediante aproximación de primer orden)
total_cost = (
sum(base_costs[c] * (1 - inspect_c[c]) for c in components) +
sum(test_costs[c] * inspect_c[c] for c in components) +
sum(sa_test_cost * inspect_sa[sa] for sa in subassemblies) +
final_test_cost * final_test +
assembly_cost
)
# Ingresos esperados (modelo simplificado con efecto acumulado)
defect_probs = {c: 0.07 + 0.01*i for i,c in enumerate(components)} # variación suave
expected_yield = np.prod([1 - defect_probs[c] * (1 - inspect_c[c]) for c in components[:4]]) * \
np.prod([1 - defect_probs[c] * (1 - inspect_c[c]) for c in components[4:]]) * \
(1 - 0.05 * final_test)
revenue = sale_price * expected_yield
prob += revenue - total_cost
# Restricción de recursos: máximo 5 pruebas simultáneas
prob += sum(inspect_c.values()) + sum(inspect_sa.values()) + final_test <= 5
prob.solve(pulp.PULP_CBC_CMD(msg=False))
print("Resultados óptimos:")
for c in components[:3]:
print(f" {c}: {'Sí' if inspect_c[c].varValue > 0.5 else 'No'}")
for sa in subassemblies[:2]:
print(f" {sa}: {'Sí' if inspect_sa[sa].varValue > 0.5 else 'No'}")
print(f" Prueba final: {'Sí' if final_test.varValue > 0.5 else 'No'}")
Problema 4: Toma de Decisiones Robusta bajo Incertidumbre Paramétrica
Cuando las tasas reales de defectos son desconocidas y solo se estiman mediante muestreo, se incorpora incertidumbre epistémica mediante intervalos de confianza bayesianos o frecuentistas. Se reformula la optimización como un problema de valor esperado: se simulan múltiples escenarios de parámetros compatibles con los datos observados y se maximiza el beneficio promedio. Alternativamente, se aplica optimización robusta minimizando la pérdida en el peor caso dentro de un conjunto de ambigüedad definido por errores de muestreo. Enfoque implementado: Simulación estocástica con distribución posterior beta-binomial.
- Para cada componente con s defectuosos en n muestras, la distribución posterior de p es \text{Beta}(s+1,\ n-s+1).
- Se generan 1000 muestras de p₁,p₂, y se evalúa la función objetivo para cada par.
- La solución óptima se selecciona como aquella que maximiza la media del beneficio simulado.
import numpy as np
from scipy.stats import beta
def simulate_posterior_defect_rates(observed_defects, sample_sizes, n_sim=1000):
"""Genera escenarios realistas de tasas de fallo usando inferencia bayesiana."""
p_samples = []
for d, n in zip(observed_defects, sample_sizes):
dist = beta(d + 1, n - d + 1)
p_samples.append(dist.rvs(size=n_sim))
return np.array(p_samples)
# Datos hipotéticos: 3 defectos en 40 piezas tipo A, 5 en 50 tipo B
p_scenarios = simulate_posterior_defect_rates([3, 5], [40, 50])
# Evaluación robusta del beneficio para combinaciones de decisiones
decisions = [(0,0,0), (1,0,0), (0,1,0), (1,1,0), (1,1,1)]
results = {}
for d1, d2, tf in decisions:
# Beneficio simulado para esta política
yields = (1 - p_scenarios[0])**(1-d1) * (1 - p_scenarios[1])**(1-d2) * (1 - 0.06)**(1-tf)
revenue_sim = 56 * yields
cost_sim = (4*(1-d1) + 18*(1-d2) + 6 + 2*d1 + 3*d2 + 3*tf)
profit_sim = revenue_sim - cost_sim
results[(d1,d2,tf)] = np.mean(profit_sim)
best_policy = max(results, key=results.get)
print(f"Política óptima robusta: Inspeccionar A={best_policy[0]}, B={best_policy[1]}, Final={best_policy[2]}")
print(f"Beneficio esperado: {results[best_policy]:.2f}")