import { createCobbDouglas, type Preference } from "../../../../engine/micro/preferences"; import { createInKindBudget, type BudgetConstraint, } from "../../../../engine/micro/constraints"; import { analyzeInKindVsCash, type InKindAnalysisResult, } from "../../../../engine/micro/welfare"; import { defineScenario } from "../../../types"; import { InKindVsCashExplain } from "./explain"; export interface InKindVsCashParams extends Record { alpha: number; transfer: number; } export interface InKindVsCashResult { analysis: InKindAnalysisResult; pref: Preference; budgetInKind: BudgetConstraint; isDistorted: boolean; bindingThresholdT: number; cashEquivalent: number; deadweightLoss: number; } export const inkindVsCashScenario = defineScenario< InKindVsCashParams, InKindVsCashResult >({ meta: { id: "micro.consumer.inkind_vs_cash", domain: "bridge", category: "consumer", chapter: "PR Ch.3 • Hình 3.17", title: "Trợ cấp hiện vật và trợ cấp tiền mặt", subtitle: "Quỹ ủy thác giáo dục của Jane Doe (Hình 3.17) và Chương trình Tem phiếu thực phẩm", source: "Pindyck, R. S., & Rubinfeld, D. L. (2015). Kinh tế học vi mô (Ấn bản thứ 8, Chương 3, tr. 67, 68, 91). NXB Kinh tế TP.HCM.", notebook_id: "e8a30630-0df2-4932-8740-9ffe7d8882bc", tags: [ "Cầu nối Vi • Vĩ mô", "Người tiêu dùng", "Trợ cấp hiện vật", "Tem phiếu thực phẩm", "Tổn thất phúc lợi", ], inputBanner: [ { label: "Thu nhập gốc I0", value: "100 USD" }, { label: "Giá Px", value: "1 USD" }, { label: "Giá Py", value: "1 USD" }, { label: "Đặc trưng", value: "Chỉ được chi trợ cấp cho hàng hóa X" }, ], }, params: { alpha: { id: "alpha", label: "Tỷ trọng chi tiêu tự nguyện cho X (α)", symbol: "\\alpha", min: 0.15, max: 0.6, step: 0.05, default: 0.3, unit: "tỷ trọng", marks: [ { value: 0.25, label: "0.25 (Tem phiếu)" }, { value: 0.3, label: "0.30 (Học bổng Jane)" }, { value: 0.5, label: "0.50 (Cân bằng)" }, ], description: "Tỷ lệ chi tiêu tự nguyện vào hàng hóa X khi được tự do nhận tiền mặt.", }, transfer: { id: "transfer", label: "Quy mô khoản trợ cấp T", symbol: "T", min: 20, max: 140, step: 5, default: 80, unit: "USD", marks: [ { value: 30, label: "30" }, { value: 40, label: "40" }, { value: 70, label: "70" }, { value: 80, label: "80" }, { value: 140, label: "140" }, ], description: "Mệnh giá trợ cấp bằng hiện vật cấp phát cho người tiêu dùng.", }, }, presets: { jane_trust_distorted: { id: "jane_trust_distorted", label: "Quỹ học bổng Jane: T = 80 (Méo mó)", badge: "DWL = 7.73", params: { alpha: 0.3, transfer: 80 }, }, jane_trust_nonbinding: { id: "jane_trust_nonbinding", label: "Quỹ học bổng Jane: T = 40 (Tương đương)", badge: "DWL = 0", params: { alpha: 0.3, transfer: 40 }, }, food_stamps_distorted: { id: "food_stamps_distorted", label: "Tem phiếu thực phẩm: T = 70 (Méo mó)", badge: "DWL = 9.49", params: { alpha: 0.25, transfer: 70 }, }, food_stamps_nonbinding: { id: "food_stamps_nonbinding", label: "Tem phiếu thực phẩm: T = 30 (Tương đương)", badge: "DWL = 0", params: { alpha: 0.25, transfer: 30 }, }, }, model: (params) => { const analysis = analyzeInKindVsCash({ alpha: params.alpha, I0: 100, transfer: params.transfer, Px: 1, Py: 1, }); const pref = createCobbDouglas({ alpha: params.alpha, productForm: false }); const budgetInKind = createInKindBudget({ I0: 100, transfer: params.transfer, Px: 1, Py: 1, }); return { analysis, pref, budgetInKind, isDistorted: analysis.isDistorted, bindingThresholdT: analysis.bindingThresholdT, cashEquivalent: analysis.cashEquivalent, deadweightLoss: analysis.deadweightLoss, }; }, view: (result, params) => { const { pointA, pointB, pointC } = result.analysis; const isDistorted = result.isDistorted; const T = params.transfer; const pref = result.pref; return { graph: { title: "Đồ thị Trợ cấp Hiện vật so với Trợ cấp Tiền mặt", subtitle: "So sánh điểm gãy B (Hiện vật) và điểm tiếp xúc C (Tiền mặt)", xAxis: { label: "Hàng hóa X (Giáo dục / Thực phẩm)", unit: "USD", max: 260, step: 40, }, yAxis: { label: "Hàng hóa khác Y (Nhà ở, Chi tiêu khác)", unit: "USD", max: 260, step: 40, }, legends: [ { label: "Đường ngân sách gốc", color: "#94a3b8", style: "dashed" }, { label: "Ngân sách hiện vật (Gãy khúc)", color: "#4f46e5", style: "solid" }, { label: "Mở rộng tiền mặt", color: "#059669", style: "dashed" }, { label: "Đường bàng quan gốc UA", color: "#94a3b8", style: "dashed" }, { label: "Đường bàng quan hiện vật UB", color: "#4f46e5", style: "solid" }, ...(isDistorted ? [ { label: "Đường bàng quan tiền mặt UC", color: "#059669", style: "dashed" as const, }, ] : []), ], regions: [ { id: "feasible-region", points: result.budgetInKind.vertices, fill: "#6366f1", opacity: 0.08, label: "Tập khả thi hiện vật", }, ], polylines: [ { id: "orig-budget", points: [ { x: 0, y: 100 }, { x: 100, y: 0 }, ], color: "#94a3b8", width: 2, dashed: true, label: "Ngân sách gốc", }, { id: "cash-extension", points: [ { x: 0, y: 100 + T }, { x: T, y: 100 }, ], color: "#059669", width: 2, dashed: true, label: "Mở rộng tiền mặt", }, { id: "effective-budget", points: result.budgetInKind.boundaryPoints, color: "#4f46e5", width: 3, label: "Ngân sách hiện vật", }, ], curves: [ { id: "curve-ua", fn: (x) => { const y = pref.indifferenceY(pointA.utility, x); return y !== null && y >= 0 && y <= 260 ? y : null; }, xMin: 5, xMax: 240, color: "#94a3b8", width: 1.5, dashed: true, label: "UA: " + pointA.utility.toFixed(1), labelAtX: 110, }, { id: "curve-ub", fn: (x) => { const y = pref.indifferenceY(pointB.utility, x); return y !== null && y >= 0 && y <= 260 ? y : null; }, xMin: 10, xMax: 240, color: "#4f46e5", width: 2.2, label: "UB: " + pointB.utility.toFixed(1), labelAtX: 170, }, ...(isDistorted ? [ { id: "curve-uc", fn: (x: number) => { const y = pref.indifferenceY(pointC.utility, x); return y !== null && y >= 0 && y <= 260 ? y : null; }, xMin: 10, xMax: 240, color: "#059669", width: 2.2, dashed: true, label: "UC: " + pointC.utility.toFixed(1), labelAtX: 130, }, ] : []), ], guides: [ { id: "guide-a", point: { x: pointA.x, y: pointA.y }, color: "#94a3b8", labelX: "XA: " + pointA.x.toFixed(0), labelY: "YA: " + pointA.y.toFixed(0), }, { id: "guide-b", point: { x: pointB.x, y: pointB.y }, color: "#4f46e5", labelX: "XB: " + pointB.x.toFixed(0), labelY: "YB: " + pointB.y.toFixed(0), }, ...(isDistorted ? [ { id: "guide-c", point: { x: pointC.x, y: pointC.y }, color: "#059669", labelX: "XC: " + pointC.x.toFixed(1), labelY: "YC: " + pointC.y.toFixed(1), }, ] : []), { id: "guide-transfer", verticalX: T, color: "#e11d48", dashed: true, topLabel: "Trợ cấp T: " + T, }, ], arrows: isDistorted ? [ { id: "shift-bc", from: { x: pointB.x, y: pointB.y }, to: { x: pointC.x, y: pointC.y }, color: "#059669", label: "Ưu tiên tiền mặt", }, ] : [], points: [ { id: "pt-a", x: pointA.x, y: pointA.y, label: "A", sublabel: "(" + pointA.x.toFixed(0) + ", " + pointA.y.toFixed(0) + ")", color: "#94a3b8", labelOffset: { dx: -18, dy: -18 }, }, { id: "pt-b", x: pointB.x, y: pointB.y, label: "B", sublabel: "(" + pointB.x.toFixed(0) + ", " + pointB.y.toFixed(0) + ")", color: "#4f46e5", labelOffset: { dx: 16, dy: -14 }, }, ...(isDistorted ? [ { id: "pt-c", x: pointC.x, y: pointC.y, label: "C", sublabel: "(" + pointC.x.toFixed(1) + ", " + pointC.y.toFixed(1) + ")", color: "#059669", labelOffset: { dx: -18, dy: 16 }, }, ] : []), ], tooltipEvaluator: (x, y) => [ { label: "Thỏa dụng U", value: ( Math.pow(x, params.alpha) * Math.pow(y, 1 - params.alpha) ).toFixed(2), }, { label: "Chi phí", value: (x + y).toFixed(0) + " USD", }, ], }, stats: [ { id: "point-b", label: "Hiện vật (Điểm B)", value: "(" + pointB.x.toFixed(0) + ", " + pointB.y.toFixed(0) + ")", subtext: "UB: " + pointB.utility.toFixed(1) + " • MRS: " + pointB.mrs.toFixed(2), color: isDistorted ? "rose" : "emerald", }, { id: "point-c", label: "Tiền mặt (Điểm C)", value: "(" + pointC.x.toFixed(1) + ", " + pointC.y.toFixed(1) + ")", subtext: "UC: " + pointC.utility.toFixed(1) + " • MRS: " + pointC.mrs.toFixed(2), color: "emerald", }, { id: "cash-equiv", label: "Tiền mặt tương đương (CE)", value: result.cashEquivalent.toFixed(2) + " USD", subtext: "Giá trị phúc lợi thực nhận", color: "blue", }, { id: "dwl", label: "Tổn thất phúc lợi (DWL)", value: result.deadweightLoss.toFixed(2) + " USD", delta: { value: result.deadweightLoss.toFixed(2), direction: isDistorted ? "down" : "neutral", }, subtext: isDistorted ? "Tổn thất do ép tiêu dùng" : "Không méo mó", color: isDistorted ? "rose" : "emerald", }, ], steps: [ { stepNumber: 1, title: "Xác định điểm cân bằng tự nguyện gốc A", latexFormula: "X_A = \\alpha \\cdot I_0 = " + params.alpha.toFixed(2) + " \\times 100, \\quad Y_A = (1 - \\alpha) \\cdot I_0", explanation: "Khi chưa có trợ cấp, người tiêu dùng tự phân bổ thu nhập ban đầu I0 = 100 USD theo tỷ trọng ưa thích.", resultText: "A(" + pointA.x.toFixed(1) + ", " + pointA.y.toFixed(1) + ") với UA = " + pointA.utility.toFixed(2), }, { stepNumber: 2, title: "Tính toán ngưỡng bắt đầu gây méo mó T*", latexFormula: "T^* = \\frac{\\alpha}{1 - \\alpha} \\cdot I_0 = \\frac{" + params.alpha.toFixed(2) + "}{" + (1 - params.alpha).toFixed(2) + "} \\times 100", explanation: "Ngưỡng quy mô trợ cấp mà tại đó lượng tiêu dùng mong muốn tự do vừa đúng bằng khoản trợ cấp hiện vật.", resultText: "T* = " + result.bindingThresholdT.toFixed(2) + " USD", }, { stepNumber: 3, title: "Xác định điểm hiện vật B và điểm tiền mặt C", latexFormula: "B(T, I_0) \\quad \\text{vs} \\quad C(\\alpha(I_0 + T), (1 - \\alpha)(I_0 + T))", explanation: isDistorted ? "Do T = " + T + " USD lớn hơn T* = " + result.bindingThresholdT.toFixed(2) + " USD, người thụ hưởng bị kẹt tại đỉnh gãy B, trong khi tiền mặt cho phép chuyển sang C." : "Do T = " + T + " USD nhỏ hơn hoặc bằng T*, điểm B trùng khít với C và không gây ra méo mó hành vi.", resultText: "UB = " + pointB.utility.toFixed(2) + "; UC = " + pointC.utility.toFixed(2), }, { stepNumber: 4, title: "Tính toán giá trị tiền mặt tương đương và DWL", latexFormula: "\\text{DWL} = T - \\text{CE} = T - [E(P_X, P_Y, U_B) - I_0]", explanation: "Chênh lệch giữa chi phí thực của ngân sách chính phủ và giá trị tiền mặt mà người thụ hưởng cảm nhận được.", resultText: "CE = " + result.cashEquivalent.toFixed(2) + " USD; DWL = " + result.deadweightLoss.toFixed(2) + " USD", }, ], comparison: { headers: [ "Tiêu chí", "Gốc (Điểm A)", "Hiện vật (Điểm B)", "Tiền mặt (Điểm C)", ], rows: [ { criterion: "Rổ hàng (X, Y)", baseValue: "(" + pointA.x.toFixed(1) + ", " + pointA.y.toFixed(1) + ")", currentValue: "(" + pointB.x.toFixed(1) + ", " + pointB.y.toFixed(1) + ")", cashValue: "(" + pointC.x.toFixed(1) + ", " + pointC.y.toFixed(1) + ")", note: isDistorted ? "Hiện vật bị ép dư thừa X" : "Hiện vật trùng khít tiền mặt", }, { criterion: "Mức thỏa dụng U", baseValue: pointA.utility.toFixed(2), currentValue: pointB.utility.toFixed(2), cashValue: pointC.utility.toFixed(2), note: isDistorted ? "Tiền mặt đem lại thỏa dụng cao hơn" : "Hai hình thức đạt thỏa dụng ngang nhau", }, { criterion: "Tỷ lệ MRS", baseValue: pointA.mrs.toFixed(2), currentValue: pointB.mrs.toFixed(2), cashValue: pointC.mrs.toFixed(2), note: isDistorted ? "MRS_B nhỏ hơn 1.00: Thèm muốn Y" : "Đạt cân bằng tiếp xúc hoàn hảo", }, { criterion: "Giá trị phúc lợi", baseValue: "100.00 USD", currentValue: result.cashEquivalent.toFixed(2) + " USD", cashValue: (100 + T).toFixed(2) + " USD", note: isDistorted ? "Tổn thất " + result.deadweightLoss.toFixed(2) + " USD" : "Bảo toàn 100% ngân sách", }, ], }, statusBanner: isDistorted ? { text: "Khoản trợ cấp T = " + T + " USD vượt trên ngưỡng tự nguyện " + result.bindingThresholdT.toFixed(2) + " USD. Người nhận bị kẹt tại đỉnh gãy B, đạt UB = " + pointB.utility.toFixed(2) + " < UC = " + pointC.utility.toFixed(2) + ". Tổn thất phúc lợi là " + result.deadweightLoss.toFixed(2) + " USD.", type: "warning", } : { text: "Khoản trợ cấp T = " + T + " USD nhỏ hơn hoặc bằng ngưỡng tự nguyện " + result.bindingThresholdT.toFixed(2) + " USD. Điểm B trùng khít với C (UB = UC = " + pointB.utility.toFixed(2) + "), không gây méo mó hành vi.", type: "success", }, bridgeLinks: [ { title: "Chính sách chuyển giao thu nhập và Số nhân tài khóa", domain: "macro", description: "Trong mô hình IS:LM, trợ cấp tiền mặt kích thích tiêu dùng thông qua khuynh hướng tiêu dùng biên MPC, trong khi trợ cấp hiện vật tác động trực tiếp vào cơ cấu sản xuất một ngành.", }, ], footnote: "U(X, Y) dạng Cobb:Douglas chuẩn hóa; ngân sách hiện vật: Y <= 100 với X <= T và X + Y <= 100 + T.", }; }, explain: InKindVsCashExplain, });