// TechBlog.jsx // Stack: Next.js (React) + Tailwind CSS // Font: JetBrains Mono — add to _document.js or layout.js: // const MONO = "'JetBrains Mono', monospace"; const rewardData = [ { outcome: "SORT_CORRECT", reward: "+8.0", desc: "Fruit stored OR Waste crushed", pos: true, fatal: false }, { outcome: "SORT_INCORRECT", reward: "-8.0", desc: "Waste stored OR Fruit crushed", pos: false, fatal: false }, { outcome: "EPISODE_SUCCESS", reward: "+15.0", desc: "All 10 items processed successfully", pos: true, fatal: false }, { outcome: "SYSTEM_FAILURE", reward: "-20.0", desc: "Storage overflow OR out of energy", pos: false, fatal: true }, ]; const stateVars = [ { key: "storage_count", range: "0 – 6", desc: "Items currently in the buffer" }, { key: "energy_left", range: "0 – 4", desc: "Remaining power units for the batch" }, { key: "item_type", range: "Fruit | Waste", desc: "Identity of the item on the belt" }, ]; const actions = [ { id: "0", name: "STORE", cost: "1 Energy", desc: "Move item into the storage buffer" }, { id: "1", name: "CRUSH", cost: "1 Energy", desc: "Destroy the item — cannot be undone" }, ]; const hyperparams = [ { sym: "α", name: "Learning Rate", val: "0.10", desc: "How fast old Q-values are overwritten" }, { sym: "γ", name: "Discount Factor", val: "0.95", desc: "Weight given to future rewards" }, { sym: "ε", name: "Exploration", val: "0.30", desc: "Initial probability of a random action" }, ]; /* ── Shared primitives ───────────────────────────────── */ function Tag({ children, variant = "default" }) { const s = { default: { bg: "#0f0f0f", border: "#1f1f1f", color: "#525252" }, blue: { bg: "#0c1528", border: "#1e3a8a", color: "#60a5fa" }, green: { bg: "#051407", border: "#14532d", color: "#4ade80" }, orange: { bg: "#130800", border: "#431407", color: "#fb923c" }, red: { bg: "#120404", border: "#450a0a", color: "#f87171" }, }[variant]; return ( {children} ); } function InlineCode({ children }) { return ( {children} ); } function SectionLabel({ num, title }) { return (
{String(num).padStart(2, "0")} {title}
); SectionLabel} function CodeBlock({ filename, code }) { return (
{filename}
python
      
); } function FigureBlock({ num, title, src, alt, caption }) { return (
FIG {num} {title}
(e.currentTarget.style.borderColor = "#1e3a8a")} onMouseLeave={(e) => (e.currentTarget.style.borderColor = "#181818")} > {alt}

{caption}

); } /* ── Main component ──────────────────────────────────── */ export default function TechBlog() { const bellmanCode = [ `def update_q(state, action, reward, next_state):`, ` # Bellman equation — core update rule`, ` best_next = max(Q[next_state].values())`, ` td_error = reward + γ * best_next - Q[state][action]`, ` Q[state][action] += α * td_error`, ``, `def choose_action(state, epsilon):`, ` # ε-greedy: explore early, exploit when confident`, ` if random() < epsilon:`, ` return random_action() # explore`, ` return argmax(Q[state]) # exploit`, ``, `# Hyperparameters`, `α = 0.10 # learning rate`, `γ = 0.95 # discount factor`, `ε = 0.30 # initial exploration rate`, ].join("\n"); return (
{/* Dot grid overlay */}
{/* Top edge glow */}
{/* ── TERMINAL TOPBAR ── */}
~/sortiq/docs/rl-inference.md
{/* ── BREADCRUMB ── */}
research / reinforcement-learning / decision-kernels
{/* ── HERO ── */}
v1.0.0 — stable build

Sortiq
RL Inference
Tabular Q-Learning Under Constraints

A pedagogical environment for studying RL fundamentals. Unlike standard classification, Sortiq forces an agent to learn the relationship between{" "} state management and{" "} long-term survival — physical constraints make naive policies fail immediately.

{/* ── QUICK STATS ── */}
{[ { val: "15K", label: "Training Episodes", accent: "#3b82f6" }, { val: "10", label: "Items per Batch", accent: "#a855f7" }, { val: "+8.0", label: "Max Reward / Sort", accent: "#22c55e" }, ].map(({ val, label, accent }) => (
{val}
{label}
))}
{/* ── 01. PURPOSE ── */}

Sortiq was built as a pedagogical RL environment. Unlike standard classification — where the only goal is accuracy — Sortiq introduces{" "} physical constraints, forcing the agent to manage a storage buffer and energy budget simultaneously. Naive "always store" policies crash immediately. The agent must learn{" "} survivability before it can learn accuracy.

{/* ── 02. ENVIRONMENT ── */}
{/* State space */}
State Space
{["variable", "range", "description"].map((h) => ( {h} ))}
{stateVars.map((s, i) => (
(e.currentTarget.style.background = "#080808")} onMouseLeave={(e) => (e.currentTarget.style.background = "transparent")} > {s.key} {s.range} {s.desc}
))}
{/* Action space */}
Action Space
{actions.map((a) => (
(e.currentTarget.style.borderColor = "#1e3a8a")} onMouseLeave={(e) => (e.currentTarget.style.borderColor = "#1a1a1a")} >
Action {a.id} {a.name}

{a.desc}

cost: {a.cost}
))}
{/* Constraints */}
⚠ Critical Constraints

Storage Bottleneck — Buffer is exactly 6 units. A 7th item triggers an immediate system crash with a −20.0 penalty.

Energy Budget — Agent starts with 4 units to process 10 items. It cannot simply store everything — every action must be deliberate.

{/* ── 03. REWARD ── */}

System death is penalized far more heavily than classification errors — teaching the agent that{" "} survival is the prerequisite for performance.

{["outcome", "reward", "description"].map((h) => ( {h} ))}
{rewardData.map((r, i) => (
(e.currentTarget.style.background = "#080808")} onMouseLeave={(e) => (e.currentTarget.style.background = "transparent")} > {r.outcome} {r.reward} {r.desc}
))}
// state = (storage_count, energy_left, item_type)
{/* ── 04. AGENT ARCHITECTURE ── */}

The agent uses Tabular Q-Learning — a 3D Q-Table where each cell holds the expected future reward of taking a specific action in a specific state. No neural networks, no approximation. Pure classical RL — every Q-value is looked up directly.

{/* Hyperparams */}
{hyperparams.map((h) => (
{h.name}
{h.val}
{h.desc}
{h.sym}
))}
{/* ── 05. DATASET ── */}

The "dataset" is a stochastic stream of items generated by the environment at runtime — not a static file. This ensures the agent encounters a diverse range of resource states such as high_storage / low_energy vs. low_storage / high_energy, testing the robustness of its policy across edge cases rather than memorising a fixed sequence.

{/* ── 06. PERFORMANCE ── */}
{/* Score comparison chips */}
{[ { label: "Random Baseline", val: "~−12.0", color: "#f87171", sub: "avg reward — frequent crashes" }, { label: "Trained Agent", val: "~+58.0", color: "#4ade80", sub: "avg reward — near-perfect policy" }, ].map((s) => (
{s.label}
{s.val}
{s.sub}
))}
{/* ── FOOTER ── */}
Sortiq RL Engine  ·  Durgaprasad Reddy
Q-Learning MDP Python Tabular RL Bellman
); }