/** * Các họ hàm thỏa dụng (Preferences) cho Kinh tế học Vi mô. * Không chứa DOM hay React. */ export interface Preference { type: "cobb_douglas" | "shifted_cobb_douglas" | "perfect_substitutes" | "perfect_complements"; alpha: number; shift?: number; productForm?: boolean; utility(x: number, y: number): number; mrs(x: number, y: number): number; indifferenceY(u: number, x: number): number | null; indirectUtility(Px: number, Py: number, I: number): number; expenditure(Px: number, Py: number, u: number): number; formulaLatex: string; label: string; } export interface CobbDouglasOptions { alpha: number; productForm?: boolean; } export function createCobbDouglas({ alpha, productForm = false }: CobbDouglasOptions): Preference { if (productForm) { // Dạng tích U = X * Y (Module 1 và Module 2 với alpha = 0.5) return { type: "cobb_douglas", alpha: 0.5, productForm: true, utility(x: number, y: number): number { if (x < 0 || y < 0) return 0; return x * y; }, mrs(x: number, y: number): number { if (x <= 0) return Infinity; return y / x; }, indifferenceY(u: number, x: number): number | null { if (x <= 0 || u < 0) return null; return u / x; }, indirectUtility(Px: number, Py: number, I: number): number { if (Px <= 0 || Py <= 0 || I <= 0) return 0; return (I / (2 * Px)) * (I / (2 * Py)); }, expenditure(Px: number, Py: number, u: number): number { if (u < 0) return 0; return 2 * Math.sqrt(Px * Py * u); }, formulaLatex: "U(X, Y) = X \\cdot Y", label: "Cobb:Douglas dạng tích (U = X · Y)", }; } // Dạng chuẩn hóa U = X^alpha * Y^(1 - alpha) (Module 3B với alpha bất kỳ) const a = alpha; const b = 1 - alpha; return { type: "cobb_douglas", alpha, productForm: false, utility(x: number, y: number): number { if (x < 0 || y < 0) return 0; return Math.pow(x, a) * Math.pow(y, b); }, mrs(x: number, y: number): number { if (x <= 0) return Infinity; return (a / b) * (y / x); }, indifferenceY(u: number, x: number): number | null { if (x <= 0 || u < 0) return null; // y = (u / x^alpha)^(1 / (1 - alpha)) return Math.pow(u / Math.pow(x, a), 1 / b); }, indirectUtility(Px: number, Py: number, I: number): number { if (Px <= 0 || Py <= 0 || I <= 0) return 0; return Math.pow((a * I) / Px, a) * Math.pow((b * I) / Py, b); }, expenditure(Px: number, Py: number, u: number): number { if (u <= 0) return 0; const unitCost = Math.pow(a / Px, a) * Math.pow(b / Py, b); return u / unitCost; }, formulaLatex: `U(X, Y) = X^{${alpha}} Y^{${Math.round((1 - alpha) * 100) / 100}}`, label: "Cobb:Douglas chuẩn hóa", }; } export interface ShiftedCobbDouglasOptions { alpha: number; shift?: number; } export function createShiftedCobbDouglas({ alpha, shift = 10, }: ShiftedCobbDouglasOptions): Preference { const a = alpha; const b = 1 - alpha; const s = shift; return { type: "shifted_cobb_douglas", alpha, shift: s, utility(x: number, y: number): number { const effX = x + s; const effY = y + s; if (effX < 0 || effY < 0) return 0; return Math.pow(effX, a) * Math.pow(effY, b); }, mrs(x: number, y: number): number { const effX = x + s; const effY = y + s; if (effX <= 0) return Infinity; return (a / b) * (effY / effX); }, indifferenceY(u: number, x: number): number | null { const effX = x + s; if (effX <= 0 || u < 0) return null; // u = (x + s)^a * (y + s)^b => y + s = (u / (x + s)^a)^(1 / b) return Math.pow(u / Math.pow(effX, a), 1 / b) - s; }, indirectUtility(Px: number, Py: number, I: number): number { const effIncome = I + Px * s + Py * s; if (effIncome <= 0 || Px <= 0 || Py <= 0) return 0; return Math.pow((a * effIncome) / Px, a) * Math.pow((b * effIncome) / Py, b); }, expenditure(Px: number, Py: number, u: number): number { if (u <= 0) return 0; const unitCost = Math.pow(a / Px, a) * Math.pow(b / Py, b); const effIncome = u / unitCost; return Math.max(0, effIncome - Px * s - Py * s); }, formulaLatex: `U(X, Y) = (X + ${s})^{${alpha}} (Y + ${s})^{${Math.round((1 - alpha) * 100) / 100}}`, label: "Shifted Cobb:Douglas (Stone:Geary dịch chuyển)", }; } export function createPerfectSubstitutes(alpha: number, beta: number): Preference { return { type: "perfect_substitutes", alpha: alpha / (alpha + beta), utility(x: number, y: number): number { return alpha * Math.max(0, x) + beta * Math.max(0, y); }, mrs(): number { return alpha / beta; }, indifferenceY(u: number, x: number): number | null { if (beta <= 0) return null; return (u - alpha * x) / beta; }, indirectUtility(Px: number, Py: number, I: number): number { return Math.max((alpha * I) / Px, (beta * I) / Py); }, expenditure(Px: number, Py: number, u: number): number { return Math.min((u * Px) / alpha, (u * Py) / beta); }, formulaLatex: `U(X, Y) = ${alpha}X + ${beta}Y`, label: "Hàng hóa thay thế hoàn hảo", }; } export function createPerfectComplements(alpha: number, beta: number): Preference { return { type: "perfect_complements", alpha: alpha / (alpha + beta), utility(x: number, y: number): number { return Math.min(alpha * Math.max(0, x), beta * Math.max(0, y)); }, mrs(): number { return 0; }, indifferenceY(u: number, x: number): number | null { if (alpha * x < u) return null; return u / beta; }, indirectUtility(Px: number, Py: number, I: number): number { return I / (Px / alpha + Py / beta); }, expenditure(Px: number, Py: number, u: number): number { return u * (Px / alpha + Py / beta); }, formulaLatex: `U(X, Y) = \\min(${alpha}X, ${beta}Y)`, label: "Hàng hóa bổ sung hoàn hảo", }; }