🏛️ Perceptrón Multicapa — XOR Solver
Demostración interactiva de cómo una red neuronal resuelve el problema XOR
1. Selecciona las entradas
📊 Ecuaciones en tiempo real
z1 = 20·0 + (-20)·0 + (-10) = -10.0
h1 = ReLU(z1) = max(0, -10.0) = 0.0
z2 = (-20)·0 + 20·0 + (-10) = -10.0
h2 = ReLU(z2) = max(0, -10.0) = 0.0
z3 = 20·0.0 + 20·0.0 + (-30) = -30.0
y = σ(z3) = 1 / (1 + e-(-30.0)) = 0.0000 = 0.0%
Como 0.0% < 50%, el veredicto es 0.
📋 Tabla de verdad dinámica
| A | B | XOR esperado | MLP predice | Resultado |
|---|---|---|---|---|
| 0 | 0 | 0 | — | — |
| 0 | 1 | 1 | — | — |
| 1 | 0 | 1 | — | — |
| 1 | 1 | 0 | — | — |
🧠 ¿Por qué funciona?
El Perceptrón Multicapa resuelve XOR mediante un equipo de especialistas:
Especialista 1 (h1): Detecta (1,0)
Se activa solo cuando A=1 y B=0. Con los pesos [20, -20] y sesgo -10:
• Si A=1, B=0: 20·1 + (-20)·0 - 10 = 10 → ReLU(10) = 10 ✅
• Si A=0, B=1: 20·0 + (-20)·1 - 10 = -30 → ReLU(-30) = 0 ❌
Especialista 2 (h2): Detecta (0,1)
Se activa solo cuando A=0 y B=1. Con los pesos [-20, 20] y sesgo -10:
• Si A=0, B=1: (-20)·0 + 20·1 - 10 = 10 → ReLU(10) = 10 ✅
• Si A=1, B=0: (-20)·1 + 20·0 - 10 = -30 → ReLU(-30) = 0 ❌
Coordinador (y): Suma los especialistas
Con pesos [20, 20] y sesgo -30:
• Si exactamente UNO se activa (XOR=1): 20·10 + 20·0 - 30 = 170 → σ(170) ≈ 100%
• Si ninguno se activa (0,0): 20·0 + 20·0 - 30 = -30 → σ(-30) ≈ 0% ✅
📐 ¿Por qué XOR no es linealmente separable?
No existe una sola línea recta que separe los puntos rojos (XOR=1) de los verdes (XOR=0).
Por eso un Perceptrón Simple (una sola neurona) no puede resolver XOR.
El MLP usa dos neuronas ocultas para crear dos fronteras de decisión.
💾 Código standalone descargable
A continuación se muestra el código fuente completo del emulador standalone del Perceptrón Multicapa, listo para copiar, guardar y ejecutar sin conexión a internet.
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Perceptrón Multicapa - XOR Solver | Proyecto WWW</title>
<!--
============================================================
PERCEPTRÓN MULTICAPA (MLP) - XOR SOLVER - VERSIÓN STANDALONE
============================================================
Archivo autocontenido para Proyecto WWW.
Instrucciones:
1. Copie todo este archivo.
2. Péguelo en un editor de texto (Bloc de notas, VSCode, etc.).
3. Guárdelo como "perceptron-multilayer.html".
4. Ábralo con cualquier navegador (Chrome, Firefox, Edge).
No requiere conexión a internet ni instalación de software.
Autor: Jorge Verón Schenone - Proyecto WWW
https://www.proyectowww.com.ar/
Licencia: Creative Commons Attribution-ShareAlike 4.0 International
https://creativecommons.org/licenses/by-sa/4.0/deed.es
Usted es libre de:
- Compartir — copiar y redistribuir el material en cualquier medio o formato
- Adaptar — remezclar, transformar y construir a partir del material
para cualquier propósito, incluso comercialmente.
Bajo los siguientes términos:
- Atribución — Debe otorgar el crédito correspondiente, proporcionar un enlace
a la licencia e indicar si se realizaron cambios.
- CompartirIgual — Si remezcla, transforma o crea a partir del material, debe
distribuir su contribución bajo la misma licencia que el original.
Más recursos en:
- CLARA Prototype: https://proyectowww-it.blogspot.com/2026/06/claraclear.html
- Artículo completo: https://www.proyectowww.com.ar/2026/06/creencias-en-transformacion-perceptron.html
============================================================
-->
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Georgia', serif;
line-height: 1.6;
color: #2c3e50;
background: #f5f5f5;
padding: 1.25rem;
max-width: 62.5rem;
margin: 0 auto;
}
/* ============================================
CABECERA CON VÍNCULOS
============================================ */
.header-links {
text-align: center;
margin-bottom: 0.9375rem;
font-size: 0.85em;
color: #666;
}
.header-links a {
color: #1e3c72;
text-decoration: none;
font-weight: bold;
}
.header-links a:hover {
text-decoration: underline;
}
.header-links span {
margin: 0 0.5rem;
color: #ccc;
}
.container {
background: white;
padding: 1.875rem;
border-radius: 0.5rem;
box-shadow: 0 0.125rem 0.625rem rgba(0,0,0,0.1);
}
h1 {
color: #1e3c72;
text-align: center;
margin-bottom: 0.625rem;
font-size: 2em;
}
.subtitle {
text-align: center;
color: #666;
font-style: italic;
margin-bottom: 1.875rem;
}
/* Selector de inputs */
.input-selector {
background: #f8f9fa;
padding: 1.25rem;
border-radius: 0.5rem;
margin-bottom: 1.5625rem;
border: 0.125rem solid #e0e0e0;
}
.input-selector h3 {
color: #1e3c72;
margin-bottom: 0.9375rem;
font-size: 1.2em;
}
.xor-buttons {
display: flex;
gap: 0.625rem;
margin-bottom: 0.9375rem;
flex-wrap: wrap;
}
.xor-btn {
flex: 1;
min-width: 5rem;
padding: 0.75rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 0.375rem;
cursor: pointer;
font-size: 1em;
font-weight: bold;
transition: transform 0.2s, box-shadow 0.2s;
}
.xor-btn:hover {
transform: translateY(-0.125rem);
box-shadow: 0 0.25rem 0.75rem rgba(102, 126, 234, 0.4);
}
.xor-btn.active {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.checkboxes {
display: flex;
gap: 1.875rem;
align-items: center;
padding: 0.9375rem;
background: white;
border-radius: 0.375rem;
}
.checkbox-group {
display: flex;
align-items: center;
gap: 0.625rem;
}
.checkbox-group label {
font-weight: bold;
font-size: 1.1em;
color: #1e3c72;
}
.checkbox-group input[type="checkbox"] {
width: 1.5rem;
height: 1.5rem;
cursor: pointer;
}
/* SVG de la red */
.network-container {
background: #fafafa;
padding: 1.25rem;
border-radius: 0.5rem;
margin-bottom: 1.5625rem;
border: 0.125rem solid #e0e0e0;
}
svg {
width: 100%;
height: auto;
display: block;
}
.neuron {
transition: all 0.3s ease;
}
.neuron-circle {
stroke: #333;
stroke-width: 2;
transition: fill 0.3s ease;
}
.neuron-label {
font-family: 'Courier New', monospace;
font-size: 1rem;
font-weight: bold;
text-anchor: middle;
dominant-baseline: middle;
pointer-events: none;
}
.neuron-value {
font-family: 'Courier New', monospace;
font-size: 0.875rem;
text-anchor: middle;
dominant-baseline: middle;
fill: #666;
pointer-events: none;
}
.connection {
stroke-width: 3;
transition: stroke 0.3s ease, stroke-width 0.3s ease;
}
.weight-label {
font-family: 'Courier New', monospace;
font-size: 0.75rem;
fill: #333;
cursor: help;
}
/* Panel de ecuaciones */
.equations-panel {
background: #e8f5e9;
padding: 1.25rem;
border-radius: 0.5rem;
margin-bottom: 1.5625rem;
border-left: 0.25rem solid #4caf50;
font-family: 'Courier New', monospace;
}
.equations-panel h3 {
color: #2e7d32;
margin-bottom: 0.9375rem;
font-family: 'Georgia', serif;
}
.equation-line {
margin: 0.5rem 0;
font-size: 0.95em;
line-height: 1.8;
}
.equation-line strong {
color: #1e3c72;
}
/* Resultado */
.result-box {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 1.25rem;
border-radius: 0.5rem;
text-align: center;
margin-bottom: 1.5625rem;
font-size: 1.3em;
font-weight: bold;
}
.result-box.correct {
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
}
.result-box.incorrect {
background: linear-gradient(135deg, #eb3349 0%, #f45c43 100%);
}
/* Botón de cálculo completo */
.calculation-toggle {
width: 100%;
padding: 0.9375rem;
background: #f8f9fa;
border: 0.125rem solid #dee2e6;
border-radius: 0.5rem;
cursor: pointer;
font-size: 1em;
font-weight: bold;
color: #495057;
transition: all 0.3s ease;
margin-bottom: 0.625rem;
}
.calculation-toggle:hover {
background: #e9ecef;
border-color: #adb5bd;
}
.calculation-details {
display: none;
background: #fff3cd;
padding: 1.25rem;
border-radius: 0.5rem;
border-left: 0.25rem solid #ffc107;
margin-bottom: 1.5625rem;
font-family: 'Courier New', monospace;
font-size: 0.9em;
}
.calculation-details.visible {
display: block;
}
.calc-step {
margin: 0.625rem 0;
padding: 0.625rem;
background: white;
border-radius: 0.25rem;
}
/* Tabla de verdad */
.truth-table-container {
margin-bottom: 1.5625rem;
}
.truth-table-container h3 {
color: #1e3c72;
margin-bottom: 0.9375rem;
}
.truth-table {
width: 100%;
border-collapse: collapse;
background: white;
border-radius: 0.5rem;
overflow: hidden;
box-shadow: 0 0.125rem 0.5rem rgba(0,0,0,0.1);
}
.truth-table th {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 0.75rem;
text-align: center;
font-weight: bold;
}
.truth-table td {
padding: 0.75rem;
text-align: center;
border-bottom: 0.0625rem solid #e0e0e0;
}
.truth-table tr:hover {
background: #f8f9fa;
}
.truth-table .tested {
background: #e8f5e9;
font-weight: bold;
}
.truth-table .pending {
color: #999;
font-style: italic;
}
.check-mark {
color: #4caf50;
font-size: 1.3em;
}
.cross-mark {
color: #f44336;
font-size: 1.3em;
}
/* Sección explicativa */
.explanation-section {
background: #f3e5f5;
padding: 1.25rem;
border-radius: 0.5rem;
margin-bottom: 1.5625rem;
border-left: 0.25rem solid #9c27b0;
}
.explanation-section h3 {
color: #6a1b9a;
margin-bottom: 0.9375rem;
}
.explanation-section p {
margin: 0.625rem 0;
line-height: 1.8;
}
.specialist-box {
background: white;
padding: 0.9375rem;
border-radius: 0.375rem;
margin: 0.9375rem 0;
border-left: 0.1875rem solid #9c27b0;
}
.specialist-box h4 {
color: #6a1b9a;
margin-bottom: 0.625rem;
}
/* Diagrama XOR no lineal */
.nonlinear-diagram {
background: #fff8e1;
padding: 1.25rem;
border-radius: 0.5rem;
margin-bottom: 1.5625rem;
border-left: 0.25rem solid #ff9800;
}
.nonlinear-diagram h3 {
color: #e65100;
margin-bottom: 0.9375rem;
}
/* Tooltips */
.tooltip-gen {
position: relative;
color: #d68910;
text-decoration: none;
font-weight: 500;
border-bottom: 0.0625rem dotted #d68910;
cursor: help;
}
.tooltip-gen:hover {
color: #3498db;
border-bottom: 0.0625rem solid #3498db;
}
.tooltip-gen:hover::after {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #2c3e50;
color: #ecf0f1;
padding: 0.5rem 0.75rem;
border-radius: 0.375rem;
white-space: normal;
z-index: 1000;
font-size: 0.85em;
max-width: 18.75rem;
width: max-content;
line-height: 1.4;
box-shadow: 0 0.25rem 0.75rem rgba(0,0,0,0.3);
font-weight: normal;
text-align: left;
}
.tooltip-gen:hover::before {
content: '';
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
border: 0.375rem solid transparent;
border-top-color: #2c3e50;
}
/* Instrucciones */
.instructions {
background: #e3f2fd;
padding: 1.25rem;
border-radius: 0.5rem;
border-left: 0.25rem solid #2196f3;
margin-top: 1.875rem;
}
.instructions h3 {
color: #1565c0;
margin-bottom: 0.9375rem;
}
.instructions ol {
margin-left: 1.25rem;
}
.instructions li {
margin: 0.5rem 0;
}
/* Footer con licencia */
.license-footer {
margin-top: 1.875rem;
padding-top: 1.25rem;
border-top: 0.0625rem solid #e0e0e0;
font-size: 0.8em;
color: #888;
text-align: center;
line-height: 1.6;
}
.license-footer a {
color: #1e3c72;
text-decoration: none;
}
.license-footer a:hover {
text-decoration: underline;
}
/* Responsive */
@media (max-width: 48rem) {
.container {
padding: 0.9375rem;
}
h1 {
font-size: 1.5em;
}
.xor-buttons {
flex-direction: column;
}
.checkboxes {
flex-direction: column;
gap: 0.9375rem;
}
.equation-line {
font-size: 0.85em;
}
}
</style>
</head>
<body>
<div class="header-links">
<a href="https://proyectowww-it.blogspot.com/2026/06/claraclear.html" target="_blank" rel="noopener">← CLARA Prototype</a>
<span>|</span>
<a href="https://www.proyectowww.com.ar/" target="_blank" rel="noopener">Proyecto WWW</a>
<span>|</span>
<a href="https://www.proyectowww.com.ar/2026/06/creencias-en-transformacion-perceptron.html" target="_blank" rel="noopener">Artículo completo</a>
</div>
<div class="container">
<h1>🏛️ Perceptrón Multicapa — XOR Solver</h1>
<p class="subtitle">Demostración interactiva de cómo una red neuronal resuelve el problema XOR</p>
<!-- Selector de inputs -->
<div class="input-selector">
<h3>1. Selecciona las entradas</h3>
<div class="xor-buttons">
<button class="xor-btn" onclick="setXOR(0,0)">0, 0 → 0</button>
<button class="xor-btn" onclick="setXOR(0,1)">0, 1 → 1</button>
<button class="xor-btn" onclick="setXOR(1,0)">1, 0 → 1</button>
<button class="xor-btn" onclick="setXOR(1,1)">1, 1 → 0</button>
</div>
<div class="checkboxes">
<div class="checkbox-group">
<label>Entrada A:</label>
<input type="checkbox" id="inputA" onchange="updateNetwork()">
</div>
<div class="checkbox-group">
<label>Entrada B:</label>
<input type="checkbox" id="inputB" onchange="updateNetwork()">
</div>
</div>
</div>
<!-- Red neuronal SVG -->
<div class="network-container">
<svg viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg">
<!-- Conexiones -->
<line id="conn-A-h1" class="connection" x1="150" y1="150" x2="400" y2="150" stroke="#ccc"/>
<line id="conn-A-h2" class="connection" x1="150" y1="150" x2="400" y2="250" stroke="#ccc"/>
<line id="conn-B-h1" class="connection" x1="150" y1="250" x2="400" y2="150" stroke="#ccc"/>
<line id="conn-B-h2" class="connection" x1="150" y1="250" x2="400" y2="250" stroke="#ccc"/>
<line id="conn-h1-y" class="connection" x1="400" y1="150" x2="650" y2="200" stroke="#ccc"/>
<line id="conn-h2-y" class="connection" x1="400" y1="250" x2="650" y2="200" stroke="#ccc"/>
<!-- Pesos con tooltips -->
<text id="weight-A-h1" class="weight-label tooltip-gen" x="275" y="130" text-anchor="middle" data-tooltip="Peso de A hacia h1: 20. Un valor positivo indica que cuando A=1, h1 tiende a activarse.">w=20</text>
<text id="weight-A-h2" class="weight-label tooltip-gen" x="275" y="270" text-anchor="middle" data-tooltip="Peso de A hacia h2: -20. Un valor negativo indica que cuando A=1, h2 tiende a desactivarse.">w=-20</text>
<text id="weight-B-h1" class="weight-label tooltip-gen" x="275" y="170" text-anchor="middle" data-tooltip="Peso de B hacia h1: -20. Un valor negativo indica que cuando B=1, h1 tiende a desactivarse.">w=-20</text>
<text id="weight-B-h2" class="weight-label tooltip-gen" x="275" y="230" text-anchor="middle" data-tooltip="Peso de B hacia h2: 20. Un valor positivo indica que cuando B=1, h2 tiende a activarse.">w=20</text>
<text id="weight-h1-y" class="weight-label tooltip-gen" x="525" y="160" text-anchor="middle" data-tooltip="Peso de h1 hacia y: 20. Ambos especialistas aportan con igual fuerza al coordinador.">w=20</text>
<text id="weight-h2-y" class="weight-label tooltip-gen" x="525" y="240" text-anchor="middle" data-tooltip="Peso de h2 hacia y: 20. Ambos especialistas aportan con igual fuerza al coordinador.">w=20</text>
<!-- Neuronas de entrada -->
<g class="neuron" id="neuron-A">
<circle class="neuron-circle" cx="150" cy="150" r="35" fill="#e3f2fd"/>
<text class="neuron-label" x="150" y="150">A</text>
<text class="neuron-value" x="150" y="175" id="value-A">0</text>
</g>
<g class="neuron" id="neuron-B">
<circle class="neuron-circle" cx="150" cy="250" r="35" fill="#e3f2fd"/>
<text class="neuron-label" x="150" y="250">B</text>
<text class="neuron-value" x="150" y="275" id="value-B">0</text>
</g>
<!-- Neuronas ocultas -->
<g class="neuron" id="neuron-h1">
<circle class="neuron-circle" cx="400" cy="150" r="35" fill="#fff3e0"/>
<text class="neuron-label" x="400" y="150">h1</text>
<text class="neuron-value" x="400" y="175" id="value-h1">0</text>
</g>
<g class="neuron" id="neuron-h2">
<circle class="neuron-circle" cx="400" cy="250" r="35" fill="#fff3e0"/>
<text class="neuron-label" x="400" y="250">h2</text>
<text class="neuron-value" x="400" y="275" id="value-h2">0</text>
</g>
<!-- Neurona de salida -->
<g class="neuron" id="neuron-y">
<circle class="neuron-circle" cx="650" cy="200" r="40" fill="#fce4ec"/>
<text class="neuron-label" x="650" y="200">y</text>
<text class="neuron-value" x="650" y="225" id="value-y">0%</text>
</g>
<!-- Etiquetas de capa -->
<text x="150" y="50" text-anchor="middle" font-size="14" fill="#666" font-weight="bold">Capa de entrada</text>
<text x="400" y="50" text-anchor="middle" font-size="14" fill="#666" font-weight="bold">Capa oculta</text>
<text x="650" y="50" text-anchor="middle" font-size="14" fill="#666" font-weight="bold">Salida</text>
<!-- Sesgos con tooltips -->
<text x="400" y="100" text-anchor="middle" font-size="12" fill="#999" class="tooltip-gen" data-tooltip="Sesgo de h1: -10. Umbral que la neurona debe superar para activarse.">b1 = -10</text>
<text x="400" y="310" text-anchor="middle" font-size="12" fill="#999" class="tooltip-gen" data-tooltip="Sesgo de h2: -10. Umbral que la neurona debe superar para activarse.">b2 = -10</text>
<text x="650" y="280" text-anchor="middle" font-size="12" fill="#999" class="tooltip-gen" data-tooltip="Sesgo de y: -30. Valor negativo que evita que la salida se active cuando ningún especialista lo hace.">b3 = -30</text>
</svg>
</div>
<!-- Panel de ecuaciones -->
<div class="equations-panel">
<h3>📊 Ecuaciones en tiempo real</h3>
<div class="equation-line" id="eq-h1">
<strong>h1</strong> = ReLU(20·A + (-20)·B + (-10)) = ReLU(<span id="calc-h1">-10</span>) = <span id="result-h1">0</span>
</div>
<div class="equation-line" id="eq-h2">
<strong>h2</strong> = ReLU((-20)·A + 20·B + (-10)) = ReLU(<span id="calc-h2">-10</span>) = <span id="result-h2">0</span>
</div>
<div class="equation-line" id="eq-y">
<strong>y</strong> = σ(20·h1 + 20·h2 + (-30)) = σ(<span id="calc-y">-30</span>) = <span id="result-y">0%</span>
</div>
</div>
<!-- Resultado -->
<div class="result-box" id="result-box">
XOR(0, 0) = 0 ✓
</div>
<!-- Botón de cálculo completo -->
<button class="calculation-toggle" onclick="toggleCalculation()">
📝 Mostrar cálculo completo [▼]
</button>
<div class="calculation-details" id="calculation-details">
<div class="calc-step">
<strong>Paso 1: Calcular activación de h1</strong><br>
z1 = w₁₁·A + w₁₂·B + b1<br>
z1 = 20·<span class="val-A">0</span> + (-20)·<span class="val-B">0</span> + (-10)<br>
z1 = <span class="calc-z1">-10.0</span><br>
h1 = ReLU(z1) = max(0, <span class="calc-z1">-10.0</span>) = <span class="calc-h1">0.0</span>
</div>
<div class="calc-step">
<strong>Paso 2: Calcular activación de h2</strong><br>
z2 = w₂₁·A + w₂₂·B + b2<br>
z2 = (-20)·<span class="val-A">0</span> + 20·<span class="val-B">0</span> + (-10)<br>
z2 = <span class="calc-z2">-10.0</span><br>
h2 = ReLU(z2) = max(0, <span class="calc-z2">-10.0</span>) = <span class="calc-h2">0.0</span>
</div>
<div class="calc-step">
<strong>Paso 3: Calcular salida y</strong><br>
z3 = w₃₁·h1 + w₃₂·h2 + b3<br>
z3 = 20·<span class="calc-h1">0.0</span> + 20·<span class="calc-h2">0.0</span> + (-30)<br>
z3 = <span class="calc-z3">-30.0</span><br>
y = σ(z3) = 1 / (1 + e<sup>-(-30.0)</sup>) = <span class="calc-y">0.0000</span><br>
y = <span class="calc-y-pct">0.0%</span>
</div>
</div>
<!-- Tabla de verdad -->
<div class="truth-table-container">
<h3>📋 Tabla de verdad dinámica</h3>
<table class="truth-table">
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>XOR esperado</th>
<th>MLP predice</th>
<th>Resultado</th>
</tr>
</thead>
<tbody id="truth-table-body">
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
<td class="pending">—</td>
<td class="pending">—</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
<td>1</td>
<td class="pending">—</td>
<td class="pending">—</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
<td>1</td>
<td class="pending">—</td>
<td class="pending">—</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>0</td>
<td class="pending">—</td>
<td class="pending">—</td>
</tr>
</tbody>
</table>
</div>
<!-- Sección explicativa -->
<div class="explanation-section">
<h3>🧠 ¿Por qué funciona?</h3>
<p>El Perceptrón Multicapa resuelve XOR mediante un <strong>equipo de especialistas</strong>:</p>
<div class="specialist-box">
<h4>Especialista 1 (h1): Detecta (1,0)</h4>
<p>Se activa solo cuando A=1 y B=0. Con los pesos [20, -20] y sesgo -10:</p>
<p>• Si A=1, B=0: 20·1 + (-20)·0 - 10 = 10 → ReLU(10) = 10 ✅</p>
<p>• Si A=0, B=1: 20·0 + (-20)·1 - 10 = -30 → ReLU(-30) = 0 ❌</p>
</div>
<div class="specialist-box">
<h4>Especialista 2 (h2): Detecta (0,1)</h4>
<p>Se activa solo cuando A=0 y B=1. Con los pesos [-20, 20] y sesgo -10:</p>
<p>• Si A=0, B=1: (-20)·0 + 20·1 - 10 = 10 → ReLU(10) = 10 ✅</p>
<p>• Si A=1, B=0: (-20)·1 + 20·0 - 10 = -30 → ReLU(-30) = 0 ❌</p>
</div>
<div class="specialist-box">
<h4>Coordinador (y): Suma los especialistas</h4>
<p>Con pesos [20, 20] y sesgo -30:</p>
<p>• Si exactamente UNO se activa (XOR=1): 20·10 + 20·0 - 30 = 170 → σ(170) ≈ 100%</p>
<p>• Si ninguno se activa (0,0): 20·0 + 20·0 - 30 = -30 → σ(-30) ≈ 0% ✅</p>
</div>
</div>
<!-- Diagrama XOR no lineal -->
<div class="nonlinear-diagram">
<h3>📐 ¿Por qué XOR no es linealmente separable?</h3>
<svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg" style="max-width: 25rem; margin: 0 auto; display: block;">
<!-- Ejes -->
<line x1="50" y1="250" x2="350" y2="250" stroke="#333" stroke-width="2"/>
<line x1="50" y1="250" x2="50" y2="50" stroke="#333" stroke-width="2"/>
<text x="360" y="255" font-size="14" fill="#333">A</text>
<text x="30" y="40" font-size="14" fill="#333">B</text>
<!-- Puntos -->
<circle cx="100" cy="200" r="12" fill="#4caf50"/>
<text x="100" y="225" text-anchor="middle" font-size="12" fill="#333">(0,0)→0</text>
<circle cx="300" cy="100" r="12" fill="#4caf50"/>
<text x="300" y="85" text-anchor="middle" font-size="12" fill="#333">(1,1)→0</text>
<circle cx="100" cy="100" r="12" fill="#f44336"/>
<text x="100" y="85" text-anchor="middle" font-size="12" fill="#333">(0,1)→1</text>
<circle cx="300" cy="200" r="12" fill="#f44336"/>
<text x="300" y="225" text-anchor="middle" font-size="12" fill="#333">(1,0)→1</text>
<!-- Línea intentando separar -->
<line x1="80" y1="150" x2="320" y2="150" stroke="#ff9800" stroke-width="2" stroke-dasharray="5,5"/>
<text x="200" y="140" text-anchor="middle" font-size="11" fill="#ff9800">¿Una sola línea?</text>
<!-- Leyenda -->
<circle cx="80" cy="280" r="8" fill="#f44336"/>
<text x="95" y="285" font-size="11" fill="#333">XOR = 1</text>
<circle cx="200" cy="280" r="8" fill="#4caf50"/>
<text x="215" y="285" font-size="11" fill="#333">XOR = 0</text>
</svg>
<p style="text-align: center; margin-top: 0.9375rem; color: #e65100;">
<strong>No existe una sola línea recta que separe los puntos rojos (XOR=1) de los verdes (XOR=0).</strong><br>
Por eso un Perceptrón Simple (una sola neurona) no puede resolver XOR.<br>
El MLP usa dos neuronas ocultas para crear <strong>dos fronteras de decisión</strong>.
</p>
</div>
<!-- Instrucciones -->
<div class="instructions">
<h3>💾 Instrucciones de uso</h3>
<ol>
<li>Guarda este archivo HTML en tu computadora (Ctrl+S o Cmd+S)</li>
<li>Ábrelo con cualquier navegador web (Chrome, Firefox, Safari, Edge)</li>
<li>No requiere conexión a internet ni instalación de software</li>
<li>Funciona en Windows, macOS, Linux, Android, iOS</li>
<li>Experimenta con diferentes combinaciones de A y B</li>
<li>Observa cómo cambian las activaciones y los pesos de las conexiones</li>
</ol>
</div>
</div>
<!-- Footer con licencia -->
<div class="license-footer">
<p>
<a href="https://proyectowww-it.blogspot.com/"><strong>C.L.A.R.A.</strong></a> — Clear Lexical Analysis & Reasoning Aid<br>
Parte de <a href="https://www.proyectowww.com.ar/" target="_blank" rel="noopener">Proyecto WWW</a> (Versión en español) · Part of <a href="https://proyectowww-en.blogspot.com/" target="_blank" rel="noopener">Proyecto WWW</a> (English version).<br>
<a href="https://www.proyectowww.com.ar/contrato" target="_blank" rel="noopener">Condiciones de uso</a> · <a href="https://proyectowww-en.blogspot.com/contrato" target="_blank" rel="noopener">Terms of use</a>
</p>
<p style="margin-top:0.625rem;opacity:0.8;">
<span>© 2026 <a href="https://www.proyectowww.com.ar/2012/05/autor.html" target="_blank" rel="noopener noreferrer">Jorge Verón Schenone</a></span>
</p>
</div>
<script>
// Pesos preentrenados para XOR
var weights = {
w11: 20,
w12: -20,
w21: -20,
w22: 20,
w31: 20,
w32: 20,
b1: -10,
b2: -10,
b3: -30
};
function relu(x) { return Math.max(0, x); }
function sigmoid(x) { return 1 / (1 + Math.exp(-x)); }
function updateNetwork() {
var A = document.getElementById('inputA').checked ? 1 : 0;
var B = document.getElementById('inputB').checked ? 1 : 0;
document.getElementById('value-A').textContent = A;
document.getElementById('value-B').textContent = B;
var z1 = weights.w11 * A + weights.w12 * B + weights.b1;
var h1 = relu(z1);
var z2 = weights.w21 * A + weights.w22 * B + weights.b2;
var h2 = relu(z2);
document.getElementById('value-h1').textContent = h1.toFixed(1);
document.getElementById('value-h2').textContent = h2.toFixed(1);
var h1Color = h1 > 0 ? 'rgba(76, 175, 80, ' + Math.min(h1/10, 1) + ')' : '#fff3e0';
var h2Color = h2 > 0 ? 'rgba(76, 175, 80, ' + Math.min(h2/10, 1) + ')' : '#fff3e0';
document.querySelector('#neuron-h1 circle').setAttribute('fill', h1Color);
document.querySelector('#neuron-h2 circle').setAttribute('fill', h2Color);
var z3 = weights.w31 * h1 + weights.w32 * h2 + weights.b3;
var y = sigmoid(z3);
document.getElementById('value-y').textContent = (y * 100).toFixed(1) + '%';
var yColor = y > 0.5 ? 'rgba(76, 175, 80, ' + y + ')' : 'rgba(244, 67, 54, ' + (1-y) + ')';
document.querySelector('#neuron-y circle').setAttribute('fill', yColor);
updateConnectionColor('conn-A-h1', weights.w11, A * h1);
updateConnectionColor('conn-A-h2', weights.w21, A * h2);
updateConnectionColor('conn-B-h1', weights.w12, B * h1);
updateConnectionColor('conn-B-h2', weights.w22, B * h2);
updateConnectionColor('conn-h1-y', weights.w31, h1 * y);
updateConnectionColor('conn-h2-y', weights.w32, h2 * y);
document.getElementById('calc-h1').textContent = z1.toFixed(1);
document.getElementById('result-h1').textContent = h1.toFixed(1);
document.getElementById('calc-h2').textContent = z2.toFixed(1);
document.getElementById('result-h2').textContent = h2.toFixed(1);
document.getElementById('calc-y').textContent = z3.toFixed(1);
document.getElementById('result-y').textContent = (y * 100).toFixed(1) + '%';
updateDetailedCalculation(A, B, z1, h1, z2, h2, z3, y);
var predicted = y > 0.5 ? 1 : 0;
var expected = A ^ B;
var correct = predicted === expected;
var resultBox = document.getElementById('result-box');
resultBox.textContent = 'XOR(' + A + ', ' + B + ') = ' + predicted + ' ' + (correct ? '\u2713' : '\u2717');
resultBox.className = 'result-box ' + (correct ? 'correct' : 'incorrect');
updateTruthTable(A, B, predicted, expected, correct);
}
function updateConnectionColor(connId, weight, activation) {
var conn = document.getElementById(connId);
var intensity = Math.min(Math.abs(activation) / 10, 1);
if (weight > 0) {
conn.setAttribute('stroke', 'rgba(76, 175, 80, ' + intensity + ')');
} else {
conn.setAttribute('stroke', 'rgba(244, 67, 54, ' + intensity + ')');
}
conn.setAttribute('stroke-width', 2 + intensity * 3);
}
function updateDetailedCalculation(A, B, z1, h1, z2, h2, z3, y) {
var elsA = document.querySelectorAll('.val-A');
for (var i = 0; i < elsA.length; i++) elsA[i].textContent = A;
var elsB = document.querySelectorAll('.val-B');
for (var i = 0; i < elsB.length; i++) elsB[i].textContent = B;
var elsZ1 = document.querySelectorAll('.calc-z1');
for (var i = 0; i < elsZ1.length; i++) elsZ1[i].textContent = z1.toFixed(1);
var elsH1 = document.querySelectorAll('.calc-h1');
for (var i = 0; i < elsH1.length; i++) elsH1[i].textContent = h1.toFixed(1);
var elsZ2 = document.querySelectorAll('.calc-z2');
for (var i = 0; i < elsZ2.length; i++) elsZ2[i].textContent = z2.toFixed(1);
var elsH2 = document.querySelectorAll('.calc-h2');
for (var i = 0; i < elsH2.length; i++) elsH2[i].textContent = h2.toFixed(1);
var elsZ3 = document.querySelectorAll('.calc-z3');
for (var i = 0; i < elsZ3.length; i++) elsZ3[i].textContent = z3.toFixed(1);
var elsY = document.querySelectorAll('.calc-y');
for (var i = 0; i < elsY.length; i++) elsY[i].textContent = y.toFixed(4);
var elsYPct = document.querySelectorAll('.calc-y-pct');
for (var i = 0; i < elsYPct.length; i++) elsYPct[i].textContent = (y * 100).toFixed(1) + '%';
}
var testedCases = {};
function updateTruthTable(A, B, predicted, expected, correct) {
var rows = document.querySelectorAll('.truth-table tbody tr');
var rowIndex = A * 2 + B;
if (rowIndex >= rows.length) return;
var row = rows[rowIndex];
row.classList.add('tested');
row.cells[3].textContent = predicted;
row.cells[3].classList.remove('pending');
row.cells[4].innerHTML = correct ? '<span class="check-mark">✓</span>' : '<span class="cross-mark">✗</span>';
row.cells[4].classList.remove('pending');
}
function setXOR(A, B) {
document.getElementById('inputA').checked = A === 1;
document.getElementById('inputB').checked = B === 1;
var btns = document.querySelectorAll('.xor-btn');
for (var i = 0; i < btns.length; i++) btns[i].classList.remove('active');
var btnIndex = A * 2 + B;
document.querySelectorAll('.xor-btn')[btnIndex].classList.add('active');
updateNetwork();
}
function toggleCalculation() {
var details = document.getElementById('calculation-details');
details.classList.toggle('visible');
var button = document.querySelector('.calculation-toggle');
button.textContent = details.classList.contains('visible') ? '📝 Ocultar cálculo completo [▲]' : '📝 Mostrar cálculo completo [▼]';
}
updateNetwork();
</script>
</body>
</html>
Funciona en cualquier navegador. No requiere instalación ni conexión a internet.