From 0fba5553b4fb47c89f2905397b65ab9aeb28ad1b Mon Sep 17 00:00:00 2001 From: hexjasur <3.15015959e+08+hexjasur@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:26:14 +0000 Subject: [PATCH 1/5] =?UTF-8?q?feat(bvp):=20add=20finite-difference=20Thom?= =?UTF-8?q?as=20solver=20=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an interactive second-order boundary value problem solver with finite-difference discretization, Thomas forward/backward traces, residual checks, plot, and localized UI. --- app/(workspace)/methods/bvp/page.tsx | 31 +++++ components/app-shell.tsx | 10 +- components/bvp-finite-difference-method.tsx | 136 ++++++++++++++++++++ components/dashboard/methods-hub.tsx | 13 ++ lib/bvp-finite-difference.ts | 77 +++++++++++ lib/i18n/locales/en.json | 37 +++++- lib/i18n/locales/ru.json | 37 +++++- lib/i18n/locales/uz.json | 37 +++++- 8 files changed, 371 insertions(+), 7 deletions(-) create mode 100644 app/(workspace)/methods/bvp/page.tsx create mode 100644 components/bvp-finite-difference-method.tsx create mode 100644 lib/bvp-finite-difference.ts diff --git a/app/(workspace)/methods/bvp/page.tsx b/app/(workspace)/methods/bvp/page.tsx new file mode 100644 index 0000000..449240d --- /dev/null +++ b/app/(workspace)/methods/bvp/page.tsx @@ -0,0 +1,31 @@ +import type { Metadata } from 'next'; +import { BvpFiniteDifferenceMethod } from '@/components/bvp-finite-difference-method'; +import { MethodJsonLd } from '@/components/seo/json-ld'; +import { siteConfig } from '@/lib/config'; + +export const metadata: Metadata = { + title: 'Boundary Value Problem Solver | Finite Difference & Thomas Algorithm', + description: 'Solve second-order linear boundary value problems step by step using finite differences and the Thomas tridiagonal algorithm.', + keywords: ['boundary value problem solver', 'finite difference method', 'Thomas algorithm', 'two-point boundary conditions', 'ODE BVP solver'], + alternates: { canonical: '/methods/bvp' }, + openGraph: { + title: 'Finite Difference BVP Solver | Thomas Algorithm', + description: 'Discretize and solve second-order linear boundary value problems, inspect Thomas coefficients, residuals, and the solution graph.', + url: `${siteConfig.url}/methods/bvp`, + }, +}; + +export default function BvpPage() { + return ( + <> + + + + ); +} diff --git a/components/app-shell.tsx b/components/app-shell.tsx index 927f891..e0b9289 100644 --- a/components/app-shell.tsx +++ b/components/app-shell.tsx @@ -87,6 +87,12 @@ export function AppShell({ label: t('nav.sweep'), icon: ArrowRightLeft, }, + { + href: '/methods/bvp', + label: t('nav.bvp'), + icon: Activity, + isNew: true, + }, { href: '/methods/lagrange', label: t('nav.lagrange'), @@ -175,7 +181,9 @@ export function AppShell({ ? t('nav.newtonInterpolation') : pathname.startsWith('/methods/newton') ? t('nav.newton') - : pathname.startsWith('/methods/sweep') + : pathname.startsWith('/methods/bvp') + ? t('nav.bvp') + : pathname.startsWith('/methods/sweep') ? t('nav.sweep') : pathname.startsWith('/methods/lagrange') ? t('nav.lagrange') diff --git a/components/bvp-finite-difference-method.tsx b/components/bvp-finite-difference-method.tsx new file mode 100644 index 0000000..310d232 --- /dev/null +++ b/components/bvp-finite-difference-method.tsx @@ -0,0 +1,136 @@ +'use client'; + +import { useMemo, useState, type FormEvent } from 'react'; +import { Activity, Calculator, Info } from 'lucide-react'; +import { useI18n } from '@/components/i18n-provider'; +import { PsHero, PsMap, PsNote, PsPanel, PsPanelHead, PsStrip } from '@/components/ui/print-stream'; +import { solveBvp, type BvpInput, type BvpResult } from '@/lib/bvp-finite-difference'; + +const INITIAL: BvpInput = { + p: '0', q: '0', f: '0', a: '0', b: '1', intervals: '10', + m0: '1', m1: '0', m2: '0', g0: '1', g1: '0', g2: '1', +}; +const fmt = (value: number) => Number(value.toFixed(6)).toString(); + +function SolutionPlot({ result }: { result: BvpResult }) { + const width = 720; + const height = 240; + const pad = 28; + const ys = result.rows.map((row) => row.y); + const min = Math.min(...ys); + const max = Math.max(...ys); + const span = max - min || 1; + const points = result.rows.map((row, index) => { + const x = pad + (index / Math.max(result.rows.length - 1, 1)) * (width - 2 * pad); + const y = height - pad - ((row.y - min) / span) * (height - 2 * pad); + return `${x},${y}`; + }).join(' '); + return ( +
+ + + + + {result.rows.map((row, index) => { + const x = pad + (index / Math.max(result.rows.length - 1, 1)) * (width - 2 * pad); + const y = height - pad - ((row.y - min) / span) * (height - 2 * pad); + return ; + })} + x = {fmt(result.rows[0].x)} + x = {fmt(result.rows[result.rows.length - 1].x)} + y ∈ [{fmt(min)}, {fmt(max)}] + +
+ ); +} + +export function BvpFiniteDifferenceMethod() { + const { t } = useI18n(); + const [input, setInput] = useState(INITIAL); + const [result, setResult] = useState(null); + const [error, setError] = useState(''); + const update = (key: keyof BvpInput, value: string) => { + setInput((current) => ({ ...current, [key]: value })); + setResult(null); + setError(''); + }; + const calculate = (event: FormEvent) => { + event.preventDefault(); + try { + setResult(solveBvp(input)); + setError(''); + } catch (cause) { + setResult(null); + setError(cause instanceof Error ? cause.message : t('bvp.error')); + } + }; + const fields: Array<{ key: keyof BvpInput; label: string; step?: string }> = [ + { key: 'p', label: 'P(x)' }, { key: 'q', label: 'Q(x)' }, { key: 'f', label: 'f(x)' }, + { key: 'a', label: 'a', step: 'any' }, { key: 'b', label: 'b', step: 'any' }, { key: 'intervals', label: 'n', step: '1' }, + { key: 'm0', label: 'm₀' }, { key: 'm1', label: 'm₁' }, { key: 'm2', label: 'm₂' }, + { key: 'g0', label: 'g₀' }, { key: 'g1', label: 'g₁' }, { key: 'g2', label: 'g₂' }, + ]; + const nodes = result?.rows ?? []; + const backwards = result?.backward ?? []; + const tableHeaders = useMemo(() => ['k', 'xₖ', 'aₖ', 'bₖ', 'cₖ', 'dₖ', 'uₖ', 'vₖ', 'yₖ', 'rₖ'], []); + return ( +
+ + y″ + P(x)y′ + Q(x)y = f(x)} conditionSub={t('bvp.boundaries')} /> + +
+ +
+ + + {!result ?

{t('bvp.empty')}

: <> +

h = ({input.b} − {input.a}) / {input.intervals} = {fmt(result.h)}

+
+ {tableHeaders.map((head) => )}{nodes.map((row) => )}
{head}
{row.index}{fmt(row.x)}{fmt(row.a)}{fmt(row.b)}{fmt(row.c)}{fmt(row.d)}{fmt(row.u)}{fmt(row.v)}{fmt(row.y)}{row.residual.toExponential(2)}
+
+ } +
+ {result && <> + + +

yₖ = uₖ · yₖ₊₁ + vₖ,   yₙ₊₁ = vₙ₊₁

+
{backwards.map((step) =>
{step.nextY === null ? `y${step.index} = v${step.index}` : `y${step.index} = u${step.index} · ${fmt(step.nextY)} + v${step.index}`} = {fmt(step.y)}
)}
+
+ + +
{t('bvp.max_residual')}: {result.maxResidual.toExponential(3)}
+ +
{nodes.map((row) => )}
xₖyₖ
{fmt(row.x)}{fmt(row.y)}
+
+ } +
+
+
+ ); +} diff --git a/components/dashboard/methods-hub.tsx b/components/dashboard/methods-hub.tsx index 9fa1458..1f057b2 100644 --- a/components/dashboard/methods-hub.tsx +++ b/components/dashboard/methods-hub.tsx @@ -72,6 +72,19 @@ const METHODS: MethodDef[] = [ icon: ArrowRightLeft, accentClass: 'text-violet-600 dark:text-violet-400 bg-violet-500/10 border-violet-500/25', }, + { + id: 'bvp', + code: '12 / ODE', + category: 'odes', + categoryKey: 'dashboard.cat_odes', + titleKey: 'nav.bvp', + descKey: 'dashboard.desc_bvp', + href: '/methods/bvp', + formulaTex: "y'' + P(x)y' + Q(x)y = f(x)", + orderTex: 'O(n)', + icon: Activity, + accentClass: 'text-amber-600 dark:text-amber-400 bg-amber-500/10 border-amber-500/25', + }, { id: 'lagrange', code: '04 / INT', diff --git a/lib/bvp-finite-difference.ts b/lib/bvp-finite-difference.ts new file mode 100644 index 0000000..84867d9 --- /dev/null +++ b/lib/bvp-finite-difference.ts @@ -0,0 +1,77 @@ +import { compileMath } from '@/lib/math'; + +export interface BvpInput { + p: string; q: string; f: string; a: string; b: string; intervals: string; + m0: string; m1: string; m2: string; g0: string; g1: string; g2: string; +} +export interface BvpRow { + index: number; x: number; a: number; b: number; c: number; d: number; + pivot: number; u: number; v: number; y: number; residual: number; +} +export interface BvpResult { + h: number; rows: BvpRow[]; + backward: Array<{ index: number; nextY: number | null; y: number }>; + maxResidual: number; +} + +function number(value: string, label: string): number { + const parsed = Number(value); + if (!value.trim() || !Number.isFinite(parsed)) throw new Error(`${label}: finite number required`); + return parsed; +} + +export function solveBvp(input: BvpInput): BvpResult { + const left = number(input.a, 'a'); + const right = number(input.b, 'b'); + const intervals = number(input.intervals, 'n'); + const m0 = number(input.m0, 'm₀'); const m1 = number(input.m1, 'm₁'); const m2 = number(input.m2, 'm₂'); + const g0 = number(input.g0, 'g₀'); const g1 = number(input.g1, 'g₁'); const g2 = number(input.g2, 'g₂'); + if (right <= left) throw new Error('b must be greater than a'); + if (!Number.isInteger(intervals) || intervals < 2 || intervals > 80) throw new Error('n must be an integer from 2 to 80'); + if (m0 === 0 && m1 === 0) throw new Error('Left boundary condition cannot be zero'); + if (g0 === 0 && g1 === 0) throw new Error('Right boundary condition cannot be zero'); + const functions = [input.p, input.q, input.f].map((expression) => { + const compiled = compileMath(expression); + if (!compiled) throw new Error(`Invalid expression: ${expression}`); + return (x: number) => { + const value = Number(compiled.evaluate({ x })); + if (!Number.isFinite(value)) throw new Error(`Expression is not finite at x=${x}`); + return value; + }; + }); + const [P, Q, F] = functions; + const h = (right - left) / intervals; + const coeffs = Array.from({ length: intervals + 1 }, (_, i) => { + if (i === 0) return { a: 0, b: m0 - m1 / h, c: m1 / h, d: m2 }; + if (i === intervals) return { a: -g1 / h, b: g0 + g1 / h, c: 0, d: g2 }; + const x = left + i * h; const p = P(x); + return { a: 1 - h * p / 2, b: -2 + h * h * Q(x), c: 1 + h * p / 2, d: h * h * F(x) }; + }); + const tracedRows: BvpRow[] = []; + coeffs.forEach((row, i) => { + const previous = tracedRows[i - 1]; + const pivot = previous ? row.a * previous.u + row.b : row.b; + const scale = previous ? Math.abs(row.a * previous.u) + Math.abs(row.b) : Math.abs(row.b); + if (!Number.isFinite(pivot) || Math.abs(pivot) <= Math.max(scale, 1) * Number.EPSILON * 64) { + throw new Error(`Thomas pivot is zero or unstable at row ${i + 1}`); + } + const u = -row.c / pivot; + const v = (row.d - (previous ? row.a * previous.v : 0)) / pivot; + if (![u, v].every(Number.isFinite)) throw new Error(`Non-finite Thomas coefficient at row ${i + 1}`); + tracedRows.push({ ...row, index: i + 1, x: left + i * h, pivot, u, v, y: 0, residual: 0 }); + }); + const ys = new Array(tracedRows.length); + ys[ys.length - 1] = tracedRows[tracedRows.length - 1].v; + const backward: BvpResult['backward'] = [{ index: ys.length, nextY: null, y: ys[ys.length - 1] }]; + for (let i = ys.length - 2; i >= 0; i -= 1) { + ys[i] = tracedRows[i].u * ys[i + 1] + tracedRows[i].v; + if (!Number.isFinite(ys[i])) throw new Error(`Non-finite solution at node ${i + 1}`); + backward.push({ index: i + 1, nextY: ys[i + 1], y: ys[i] }); + } + const rows = tracedRows.map((row, i) => ({ + ...row, + y: ys[i], + residual: row.d - (row.a * (ys[i - 1] ?? 0) + row.b * ys[i] + row.c * (ys[i + 1] ?? 0)), + })); + return { h, rows, backward, maxResidual: Math.max(...rows.map((row) => Math.abs(row.residual))) }; +} diff --git a/lib/i18n/locales/en.json b/lib/i18n/locales/en.json index cd9e269..7c15775 100644 --- a/lib/i18n/locales/en.json +++ b/lib/i18n/locales/en.json @@ -18,7 +18,8 @@ "rungeKutta": "Runge–Kutta 4th Order", "learn": "Uzbek learning guides", "newtonInterpolation": "Newton Interpolation", - "adamsPredictor": "Adams Predictor Method" + "adamsPredictor": "Adams Predictor Method", + "bvp": "Finite Difference BVP" }, "about": { "strip": "DOC-002 / ABOUT", @@ -113,7 +114,8 @@ "cat_linear": "Linear systems", "desc_rungeKutta": "Solve a first-order initial value problem with the classical fourth-order Runge–Kutta method.", "desc_newtonInterpolation": "Build the Newton polynomial from divided differences, compare finite differences, and evaluate P(x*) step by step.", - "desc_adamsPredictor": "Solve an initial value problem with RK4 startup steps and the third-order Adams predictor formula." + "desc_adamsPredictor": "Solve an initial value problem with RK4 startup steps and the third-order Adams predictor formula.", + "desc_bvp": "Solve second-order linear boundary value problems with finite differences and a step-by-step Thomas algorithm trace." }, "actions": { "tools_badge": "EXPORT / TOOLS", @@ -846,5 +848,36 @@ "notebook_collapse": "Collapse (key steps)", "notebook_final_ans": "Final Answer", "notebook_ans_desc": "Summary of solution across the interval" + }, + "bvp": { + "eyebrow": "Boundary value problems / 012", + "title": "Finite Difference", + "title_highlight": "BVP Solver", + "lead": "Solve a second-order linear boundary value problem and inspect its discretization, Thomas sweep, residuals, and numerical curve.", + "boundaries": "m₀y(a) + m₁y′(a) = m₂; g₀y(b) + g₁y′(b) = g₂", + "map_eyebrow": "Solution workflow", + "map_title": "Finite differences + Thomas algorithm", + "map_1": "Discretize", + "map_1_desc": "Build the tridiagonal equations at boundary and interior nodes.", + "map_2": "Forward sweep", + "map_2_desc": "Compute the Thomas coefficients uₖ and vₖ row by row.", + "map_3": "Back substitute", + "map_3_desc": "Recover y values, then inspect the residual and graph.", + "input_eyebrow": "Inputs / Boundary conditions", + "input_title": "Problem parameters", + "expression_hint": "Enter Math.js expressions in x (examples: x, sin(x), x^2). Use n equal intervals (2–80).", + "left": "Left boundary", + "right": "Right boundary", + "calculate": "Solve BVP", + "error": "Unable to solve the boundary value problem.", + "note": "Central differences are used for interior derivatives; one-sided differences approximate endpoint derivatives.", + "matrix_eyebrow": "01 / DISCRETIZATION", + "matrix_title": "Tridiagonal system and Thomas coefficients", + "empty": "Set the equation and boundary data, then select Solve BVP.", + "backward_eyebrow": "02 / BACK SUBSTITUTION", + "backward_title": "Recover the solution step by step", + "result_eyebrow": "03 / SOLUTION", + "result_title": "Numerical solution and plot", + "max_residual": "Maximum equation residual" } } diff --git a/lib/i18n/locales/ru.json b/lib/i18n/locales/ru.json index 106df1f..98a91bc 100644 --- a/lib/i18n/locales/ru.json +++ b/lib/i18n/locales/ru.json @@ -18,7 +18,8 @@ "rungeKutta": "Метод Рунге — Кутты 4-го порядка", "learn": "Учебник на узбекском", "newtonInterpolation": "Интерполяция Ньютона", - "adamsPredictor": "Метод предиктора Адамса" + "adamsPredictor": "Метод предиктора Адамса", + "bvp": "Краевая задача (разности)" }, "about": { "strip": "DOC-002 / О ПРОЕКТЕ", @@ -113,7 +114,8 @@ "cat_linear": "Линейные системы", "desc_rungeKutta": "Решение задачи Коши для ОДУ классическим методом Рунге — Кутты четвертого порядка.", "desc_newtonInterpolation": "Постройте многочлен Ньютона по разделённым разностям, сравните конечные разности и пошагово вычислите P(x*).", - "desc_adamsPredictor": "Решите задачу Коши с начальными шагами Рунге — Кутты и формулой предиктора Адамса третьего порядка." + "desc_adamsPredictor": "Решите задачу Коши с начальными шагами Рунге — Кутты и формулой предиктора Адамса третьего порядка.", + "desc_bvp": "Решение линейной краевой задачи второго порядка методом конечных разностей и пошаговой прогонкой Томаса." }, "actions": { "tools_badge": "ЭКСПОРТ / ИНСТРУМЕНТЫ", @@ -846,5 +848,36 @@ "notebook_collapse": "Свернуть (только ключевые)", "notebook_final_ans": "Итоговый ответ", "notebook_ans_desc": "Сводка результатов на расчетном интервале" + }, + "bvp": { + "eyebrow": "Краевые задачи / 012", + "title": "Конечные", + "title_highlight": "разности для КЗ", + "lead": "Решайте линейную краевую задачу второго порядка и изучайте дискретизацию, прогонку Томаса, невязку и график решения.", + "boundaries": "m₀y(a) + m₁y′(a) = m₂; g₀y(b) + g₁y′(b) = g₂", + "map_eyebrow": "Этапы решения", + "map_title": "Конечные разности + алгоритм Томаса", + "map_1": "Дискретизация", + "map_1_desc": "Составление трехдиагональной системы на границах и внутри интервала.", + "map_2": "Прямой ход", + "map_2_desc": "Пошаговый расчет коэффициентов uₖ и vₖ.", + "map_3": "Обратный ход", + "map_3_desc": "Восстановление y, анализ невязки и графика.", + "input_eyebrow": "Ввод / Граничные условия", + "input_title": "Параметры задачи", + "expression_hint": "Введите выражения Math.js от x (например: x, sin(x), x^2). n — отрезков (2–80).", + "left": "Левая граница", + "right": "Правая граница", + "calculate": "Решить задачу", + "error": "Не удалось решить краевую задачу.", + "note": "Внутри интервала используются центральные разности; на концах — односторонние.", + "matrix_eyebrow": "01 / ДИСКРЕТИЗАЦИЯ", + "matrix_title": "Трехдиагональная система и коэффициенты прогонки", + "empty": "Задайте уравнение и граничные условия, затем запустите расчет.", + "backward_eyebrow": "02 / ОБРАТНЫЙ ХОД", + "backward_title": "Пошаговое восстановление решения", + "result_eyebrow": "03 / РЕШЕНИЕ", + "result_title": "Численное решение и график", + "max_residual": "Максимальная невязка" } } diff --git a/lib/i18n/locales/uz.json b/lib/i18n/locales/uz.json index a76b1a8..d9edded 100644 --- a/lib/i18n/locales/uz.json +++ b/lib/i18n/locales/uz.json @@ -18,7 +18,8 @@ "rungeKutta": "Runge–Kutta 4-tartibli usuli", "learn": "Özbekça qöllanma", "newtonInterpolation": "Nyuton interpolyatsiyasi", - "adamsPredictor": "Adams başorat qiluvçi usuli" + "adamsPredictor": "Adams başorat qiluvçi usuli", + "bvp": "Chekli ayirmalar BChM" }, "about": { "strip": "DOC-002 / HAQIDA", @@ -113,7 +114,8 @@ "cat_linear": "Çiziqli sistemalar", "desc_rungeKutta": "Birinçi tartibli Koşi masalasini klassik törtinçi tartibli Runge–Kutta usuli bilan yeçing.", "desc_newtonInterpolation": "Bölingan ayirmalar orqali Nyuton köphadini tuzing, çekli ayirmalarni taqqoslang va P(x*) qiymatini qadam-baqadam hisoblang.", - "desc_adamsPredictor": "Koşi masalasini RK4 boşlanğiç qadamlari va uçinçi tartibli Adams başorat formulasi bilan yeçing." + "desc_adamsPredictor": "Koşi masalasini RK4 boşlanğiç qadamlari va uçinçi tartibli Adams başorat formulasi bilan yeçing.", + "desc_bvp": "2-tartibli chiziqli chegaraviy masalani chekli ayirmalar va qadamma-qadam Thomas haydash usulida yeching." }, "actions": { "tools_badge": "EXPORT / TOOLS", @@ -846,5 +848,36 @@ "notebook_collapse": "Qisqartiriş (asosiy qadamlar)", "notebook_final_ans": "Yakuniy javob", "notebook_ans_desc": "Hisoblangan oraliqdagi natijalar xulosasi" + }, + "bvp": { + "eyebrow": "Chegaraviy masala / 012", + "title": "Chekli ayirmalar", + "title_highlight": "BChM yechuvchisi", + "lead": "2-tartibli chiziqli chegaraviy masalani yeching: diskretlash, Thomas haydash koeffitsiyentlari, qoldiq va yechim grafigini ko‘ring.", + "boundaries": "m₀y(a) + m₁y′(a) = m₂; g₀y(b) + g₁y′(b) = g₂", + "map_eyebrow": "Yechish bosqichlari", + "map_title": "Chekli ayirmalar + Thomas algoritmi", + "map_1": "Diskretlash", + "map_1_desc": "Chegara va ichki nuqtalarda uch diagonalli sistemani tuzish.", + "map_2": "To‘g‘ri yo‘l", + "map_2_desc": "uₖ va vₖ haydash koeffitsiyentlarini ketma-ket hisoblash.", + "map_3": "Teskari yo‘l", + "map_3_desc": "y qiymatlarini topish, qoldiqni va grafikni ko‘rish.", + "input_eyebrow": "Kiritish / Chegaraviy shartlar", + "input_title": "Masala parametrlari", + "expression_hint": "x o‘zgaruvchili Math.js ifodalarni kiriting (masalan: x, sin(x), x^2). n — bo‘linishlar soni (2–80).", + "left": "Chap chegara", + "right": "O‘ng chegara", + "calculate": "Masalani yechish", + "error": "Chegaraviy masalani yechib bo‘lmadi.", + "note": "Ichki nuqtalarda markaziy ayirma, chekka nuqtalarda bir tomonlama ayirma ishlatiladi.", + "matrix_eyebrow": "01 / DISKRETLASH", + "matrix_title": "Uch diagonalli sistema va haydash koeffitsiyentlari", + "empty": "Tenglama va chegaraviy shartlarni kiriting, so‘ng yechishni boshlang.", + "backward_eyebrow": "02 / TESKARI YO‘L", + "backward_title": "Yechimni qadamma-qadam tiklash", + "result_eyebrow": "03 / YECHIM", + "result_title": "Sonli yechim va grafik", + "max_residual": "Maksimal qoldiq" } } From 6c58ba7281f12ce46187c50a38d585b572a46701 Mon Sep 17 00:00:00 2001 From: hexjasur <3.15015959e+08+hexjasur@users.noreply.github.com> Date: Wed, 4 Nov 2026 11:00:59 +0000 Subject: [PATCH 2/5] =?UTF-8?q?fix(bvp):=20improve=20example=20input=20and?= =?UTF-8?q?=20mobile=20layout=20=F0=9F=90=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a one-click equation example, tighten responsive form sizing, and use clearer Uzbek terminology for the boundary value and sweep methods. --- components/bvp-finite-difference-method.tsx | 24 +++++++++++++++------ lib/i18n/locales/en.json | 3 ++- lib/i18n/locales/ru.json | 3 ++- lib/i18n/locales/uz.json | 17 ++++++++------- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/components/bvp-finite-difference-method.tsx b/components/bvp-finite-difference-method.tsx index 310d232..13351e8 100644 --- a/components/bvp-finite-difference-method.tsx +++ b/components/bvp-finite-difference-method.tsx @@ -64,6 +64,11 @@ export function BvpFiniteDifferenceMethod() { setError(cause instanceof Error ? cause.message : t('bvp.error')); } }; + const applyExample = () => { + setInput((current) => ({ ...current, p: '-x', q: '2*x', f: '0.8' })); + setResult(null); + setError(''); + }; const fields: Array<{ key: keyof BvpInput; label: string; step?: string }> = [ { key: 'p', label: 'P(x)' }, { key: 'q', label: 'Q(x)' }, { key: 'f', label: 'f(x)' }, { key: 'a', label: 'a', step: 'any' }, { key: 'b', label: 'b', step: 'any' }, { key: 'intervals', label: 'n', step: '1' }, @@ -75,20 +80,25 @@ export function BvpFiniteDifferenceMethod() { const tableHeaders = useMemo(() => ['k', 'xₖ', 'aₖ', 'bₖ', 'cₖ', 'dₖ', 'uₖ', 'vₖ', 'yₖ', 'rₖ'], []); return (
- + y″ + P(x)y′ + Q(x)y = f(x)} conditionSub={t('bvp.boundaries')} /> -
-