/** * Norton-Bass Multigenerational Diffusion Model * * Mathematical engine for forecasting transceiver technology adoption. * Based on Norton & Bass (1987, Management Science). * * Key equations: * Bass: f(t) / [1 - F(t)] = p + q * F(t) * Logistic: S(t) = L / (1 + e^(-k(t - t0))) * * Parameters: * p = Innovation coefficient (~0.03 for network hardware) * q = Imitation coefficient (~0.3–0.5) * m = Total market potential (addressable port shipments) */ /** Technology generation definition */ export interface TechGeneration { readonly name: string; // e.g. "100G QSFP28" readonly speedGbps: number; readonly formFactor: string; readonly introYear: number; // Year first shipped commercially readonly peakYear: number; // Year of peak shipments (estimated) readonly p: number; // Innovation coefficient readonly q: number; // Imitation coefficient readonly m: number; // Market potential (millions of ports) readonly k: number; // Logistic growth rate readonly t0: number; // Inflection point year } /** Hype Cycle phases per Gartner methodology */ export type HypeCyclePhase = | "INNOVATION_TRIGGER" | "PEAK_OF_INFLATED_EXPECTATIONS" | "TROUGH_OF_DISILLUSIONMENT" | "SLOPE_OF_ENLIGHTENMENT" | "PLATEAU_OF_PRODUCTIVITY" | "LEGACY_DECLINE"; /** Result of a hype cycle computation */ export interface HypeCycleResult { readonly technology: string; readonly phase: HypeCyclePhase; readonly phaseLabel: string; readonly positionPct: number; // 0–100 on the hype cycle curve readonly adoptionPct: number; // Current market adoption % readonly compositeScore: number; // 0–100 readonly forecast: AdoptionForecast; readonly metrics: PhaseMetrics; } export interface AdoptionForecast { readonly currentYear: number; readonly yearsToPlateauFromNow: number; readonly peakShipmentYear: number; readonly cumulativeAdoptionPct: number; readonly yearlyAdoptionPct: number; readonly fiveYearProjection: ReadonlyArray<{ year: number; adoptionPct: number; phase: HypeCyclePhase }>; } export interface PhaseMetrics { readonly shipmentShare: number; // 0–1 readonly aspDeclineRate: number; // % per year readonly standardsMaturity: number; // 0–100 readonly interopLevel: number; // 0–100 readonly vendorCount: number; readonly vendorTrend: "increasing" | "stable" | "decreasing"; readonly mediaHypeIndex: number; // 0–100 } // ============================================================ // Known technology generations (seed data, March 2026) // ============================================================ export const TECH_GENERATIONS: ReadonlyArray = [ { name: "1G SFP", speedGbps: 1, formFactor: "SFP", introYear: 2001, peakYear: 2012, p: 0.03, q: 0.38, m: 500, k: 0.45, t0: 2008, }, { name: "10G SFP+", speedGbps: 10, formFactor: "SFP+", introYear: 2006, peakYear: 2018, p: 0.03, q: 0.42, m: 600, k: 0.50, t0: 2014, }, { name: "40G QSFP+", speedGbps: 40, formFactor: "QSFP+", introYear: 2010, peakYear: 2019, p: 0.025, q: 0.35, m: 150, k: 0.40, t0: 2016, }, { name: "25G SFP28", speedGbps: 25, formFactor: "SFP28", introYear: 2015, peakYear: 2022, p: 0.04, q: 0.45, m: 200, k: 0.55, t0: 2019, }, { name: "100G QSFP28", speedGbps: 100, formFactor: "QSFP28", introYear: 2014, peakYear: 2024, p: 0.03, q: 0.40, m: 400, k: 0.48, t0: 2020, }, { name: "400G QSFP-DD", speedGbps: 400, formFactor: "QSFP-DD", introYear: 2020, peakYear: 2027, p: 0.035, q: 0.50, m: 300, k: 0.52, t0: 2025, }, { name: "800G OSFP", speedGbps: 800, formFactor: "OSFP", introYear: 2023, peakYear: 2029, p: 0.04, q: 0.55, m: 250, k: 0.55, t0: 2027, }, { name: "1.6T OSFP-XD", speedGbps: 1600, formFactor: "OSFP-XD", introYear: 2025, peakYear: 2032, p: 0.03, q: 0.45, m: 180, k: 0.48, t0: 2030, }, ]; // Special tech entries (not speed-generational) export const SPECIAL_TECHS: ReadonlyArray = [ { name: "CPO", speedGbps: 1600, formFactor: "CPO", introYear: 2024, peakYear: 2033, p: 0.02, q: 0.30, m: 50, k: 0.35, t0: 2031, }, { name: "LPO", speedGbps: 800, formFactor: "LPO", introYear: 2024, peakYear: 2029, p: 0.035, q: 0.48, m: 100, k: 0.50, t0: 2027, }, { name: "400ZR Coherent", speedGbps: 400, formFactor: "QSFP-DD", introYear: 2021, peakYear: 2026, p: 0.04, q: 0.50, m: 80, k: 0.55, t0: 2024, }, ]; // ============================================================ // Core Bass Diffusion Functions // ============================================================ /** * Bass diffusion: cumulative adoption F(t) * * F(t) = (1 - e^(-(p+q)*t)) / (1 + (q/p)*e^(-(p+q)*t)) */ export function bassCumulativeAdoption( t: number, p: number, q: number, ): number { const pq = p + q; const exp = Math.exp(-pq * t); return (1 - exp) / (1 + (q / p) * exp); } /** * Bass diffusion: instantaneous adoption rate f(t) * * f(t) = ((p+q)^2 / q) * (e^(-(p+q)*t) / (1 + (q/p)*e^(-(p+q)*t))^2) */ export function bassAdoptionRate( t: number, p: number, q: number, ): number { const pq = p + q; const exp = Math.exp(-pq * t); const denominator = 1 + (q / p) * exp; return (pq * pq / q) * (exp / (denominator * denominator)); } /** * Logistic adoption curve: S(t) = L / (1 + e^(-k*(t - t0))) */ export function logisticAdoption( year: number, L: number, k: number, t0: number, ): number { return L / (1 + Math.exp(-k * (year - t0))); } // ============================================================ // Phase Classification Engine // ============================================================ export function classifyPhase(metrics: PhaseMetrics): HypeCyclePhase { const { shipmentShare, aspDeclineRate, standardsMaturity, vendorTrend, mediaHypeIndex } = metrics; if (shipmentShare < 0.01 && standardsMaturity < 30) { return "INNOVATION_TRIGGER"; } if (shipmentShare < 0.05 && mediaHypeIndex > 70 && vendorTrend === "increasing") { return "PEAK_OF_INFLATED_EXPECTATIONS"; } if (aspDeclineRate > 30 && vendorTrend === "decreasing" && mediaHypeIndex < 40) { return "TROUGH_OF_DISILLUSIONMENT"; } if ( shipmentShare >= 0.05 && shipmentShare <= 0.30 && aspDeclineRate >= 10 && aspDeclineRate <= 25 && (vendorTrend === "stable" || vendorTrend === "increasing") ) { return "SLOPE_OF_ENLIGHTENMENT"; } if (shipmentShare > 0.30 && aspDeclineRate < 10) { return "PLATEAU_OF_PRODUCTIVITY"; } // Fallback: use composite score approach return compositePhaseClassification(metrics); } /** * Composite score phase classification * * Phase_Score = 0.30 * Normalize(PortShipment_share) * + 0.20 * Normalize(ASP_decline_rate) * + 0.15 * Normalize(Standards_maturity) * + 0.15 * Normalize(InteropValidation_level) * + 0.10 * Normalize(VendorCount_trajectory) * + 0.10 * Normalize(MediaSentiment_score) */ function compositePhaseClassification(metrics: PhaseMetrics): HypeCyclePhase { const score = 0.30 * normalize(metrics.shipmentShare, 0, 0.5) + 0.20 * normalize(metrics.aspDeclineRate, 0, 50) + 0.15 * normalize(metrics.standardsMaturity, 0, 100) + 0.15 * normalize(metrics.interopLevel, 0, 100) + 0.10 * (metrics.vendorTrend === "increasing" ? 0.3 : metrics.vendorTrend === "stable" ? 0.6 : 0.9) + 0.10 * normalize(100 - metrics.mediaHypeIndex, 0, 100); if (score < 0.15) return "INNOVATION_TRIGGER"; if (score < 0.30) return "PEAK_OF_INFLATED_EXPECTATIONS"; if (score < 0.45) return "TROUGH_OF_DISILLUSIONMENT"; if (score < 0.70) return "SLOPE_OF_ENLIGHTENMENT"; return "PLATEAU_OF_PRODUCTIVITY"; } function normalize(value: number, min: number, max: number): number { return Math.max(0, Math.min(1, (value - min) / (max - min))); } // ============================================================ // Phase position on the hype cycle curve (0–100) // ============================================================ const PHASE_POSITIONS: Record = { INNOVATION_TRIGGER: [0, 15], PEAK_OF_INFLATED_EXPECTATIONS: [15, 30], TROUGH_OF_DISILLUSIONMENT: [30, 50], SLOPE_OF_ENLIGHTENMENT: [50, 80], PLATEAU_OF_PRODUCTIVITY: [80, 95], LEGACY_DECLINE: [95, 100], }; const PHASE_LABELS: Record = { INNOVATION_TRIGGER: "Innovation Trigger", PEAK_OF_INFLATED_EXPECTATIONS: "Peak of Inflated Expectations", TROUGH_OF_DISILLUSIONMENT: "Trough of Disillusionment", SLOPE_OF_ENLIGHTENMENT: "Slope of Enlightenment", PLATEAU_OF_PRODUCTIVITY: "Plateau of Productivity", LEGACY_DECLINE: "Legacy / Decline", }; // ============================================================ // Main computation: compute hype cycle for a technology // ============================================================ export function computeHypeCycle( tech: TechGeneration, currentYear: number = new Date().getFullYear(), overrideMetrics?: Partial, ): HypeCycleResult { // Time since introduction const t = currentYear - tech.introYear; const tNorm = Math.max(0, t); // Bass diffusion adoption const cumulativeAdoption = bassCumulativeAdoption(tNorm, tech.p, tech.q); const adoptionRate = bassAdoptionRate(tNorm, tech.p, tech.q); // Logistic adoption (port shipments) const logisticShipments = logisticAdoption(currentYear, tech.m, tech.k, tech.t0); const shipmentShare = logisticShipments / 1000; // Normalize to 0–1 range (1000M total market) // Estimate metrics from model const yearsAfterIntro = currentYear - tech.introYear; const yearsToPeak = tech.peakYear - tech.introYear; const progressRatio = yearsAfterIntro / yearsToPeak; const metrics: PhaseMetrics = { shipmentShare: overrideMetrics?.shipmentShare ?? Math.min(0.5, shipmentShare), aspDeclineRate: overrideMetrics?.aspDeclineRate ?? estimateAspDecline(progressRatio), standardsMaturity: overrideMetrics?.standardsMaturity ?? estimateStandardsMaturity(progressRatio), interopLevel: overrideMetrics?.interopLevel ?? estimateInteropLevel(progressRatio), vendorCount: overrideMetrics?.vendorCount ?? estimateVendorCount(progressRatio), vendorTrend: overrideMetrics?.vendorTrend ?? estimateVendorTrend(progressRatio), mediaHypeIndex: overrideMetrics?.mediaHypeIndex ?? estimateMediaHype(progressRatio), }; const phase = classifyPhase(metrics); // Check for legacy/decline const finalPhase = (currentYear > tech.peakYear + 8 && metrics.shipmentShare < 0.05) ? "LEGACY_DECLINE" : phase; // Position on curve (0-100) const [phaseMin, phaseMax] = PHASE_POSITIONS[finalPhase]; const intraPhaseProgress = Math.min(1, cumulativeAdoption); const positionPct = phaseMin + (phaseMax - phaseMin) * intraPhaseProgress; // Composite score const compositeScore = Math.round( 0.30 * normalize(metrics.shipmentShare, 0, 0.5) * 100 + 0.20 * normalize(metrics.aspDeclineRate, 0, 50) * 100 + 0.15 * normalize(metrics.standardsMaturity, 0, 100) * 100 + 0.15 * normalize(metrics.interopLevel, 0, 100) * 100 + 0.10 * (metrics.vendorTrend === "increasing" ? 30 : metrics.vendorTrend === "stable" ? 60 : 90) + 0.10 * (100 - metrics.mediaHypeIndex) ); // 5-year forecast const fiveYearProjection = Array.from({ length: 5 }, (_, i) => { const futureYear = currentYear + i + 1; const futureT = futureYear - tech.introYear; const futureAdoption = bassCumulativeAdoption(futureT, tech.p, tech.q); const futureProgressRatio = (futureYear - tech.introYear) / yearsToPeak; const futureMetrics: PhaseMetrics = { ...metrics, shipmentShare: Math.min(0.5, logisticAdoption(futureYear, tech.m, tech.k, tech.t0) / 1000), aspDeclineRate: estimateAspDecline(futureProgressRatio), vendorTrend: estimateVendorTrend(futureProgressRatio), }; return { year: futureYear, adoptionPct: Math.round(futureAdoption * 100), phase: (futureYear > tech.peakYear + 8 && futureMetrics.shipmentShare < 0.05) ? "LEGACY_DECLINE" as HypeCyclePhase : classifyPhase(futureMetrics), }; }); return { technology: tech.name, phase: finalPhase, phaseLabel: PHASE_LABELS[finalPhase], positionPct: Math.round(positionPct), adoptionPct: Math.round(cumulativeAdoption * 100), compositeScore, forecast: { currentYear, yearsToPlateauFromNow: Math.max(0, tech.peakYear + 3 - currentYear), peakShipmentYear: tech.peakYear, cumulativeAdoptionPct: Math.round(cumulativeAdoption * 100), yearlyAdoptionPct: Math.round(adoptionRate * 100), fiveYearProjection, }, metrics, }; } // ============================================================ // Estimation heuristics (from model parameters) // ============================================================ function estimateAspDecline(progressRatio: number): number { // ASP decline accelerates through Trough, stabilizes at Plateau if (progressRatio < 0.3) return 5; // Early: slow decline if (progressRatio < 0.6) return 35; // Peak/Trough: rapid decline if (progressRatio < 1.0) return 15; // Slope: moderate decline return 5; // Plateau: minimal decline } function estimateStandardsMaturity(progressRatio: number): number { if (progressRatio < 0.2) return 20; // Draft standards if (progressRatio < 0.5) return 60; // Published, some revisions if (progressRatio < 0.8) return 85; // Mature standards return 95; // Fully mature } function estimateInteropLevel(progressRatio: number): number { if (progressRatio < 0.3) return 25; // Limited interop testing if (progressRatio < 0.6) return 55; // Growing interop if (progressRatio < 0.9) return 80; // Broad interop return 95; // Universal interop } function estimateVendorCount(progressRatio: number): number { if (progressRatio < 0.3) return 5; if (progressRatio < 0.6) return 15; if (progressRatio < 1.0) return 25; return 20; // Consolidation } function estimateVendorTrend(progressRatio: number): "increasing" | "stable" | "decreasing" { if (progressRatio < 0.5) return "increasing"; if (progressRatio < 1.2) return "stable"; return "decreasing"; } function estimateMediaHype(progressRatio: number): number { // Hype peaks early (Peak of Inflated Expectations) if (progressRatio < 0.15) return 40; // Innovation: moderate buzz if (progressRatio < 0.30) return 85; // Peak: maximum hype if (progressRatio < 0.50) return 25; // Trough: hype collapse if (progressRatio < 0.80) return 50; // Slope: balanced coverage return 30; // Plateau: boring = good } // ============================================================ // Compute all technologies at once // ============================================================ export function computeAllHypeCycles( currentYear: number = new Date().getFullYear(), ): ReadonlyArray { const allTechs = [...TECH_GENERATIONS, ...SPECIAL_TECHS]; return allTechs.map((tech) => computeHypeCycle(tech, currentYear)); } export function findTechnology(query: string): TechGeneration | undefined { const q = query.toLowerCase(); const allTechs = [...TECH_GENERATIONS, ...SPECIAL_TECHS]; return allTechs.find((t) => t.name.toLowerCase().includes(q) || q.includes(t.speedGbps.toString()) || q.includes(t.formFactor.toLowerCase()) ); }