Перебрать коэффициенты полинома, построенного из строки в JavaScript

TL;DR: мне нужен способ создать полином из некоторых заданных координат таким образом, чтобы можно было перебирать его коэффициенты и, возможно, даже позволять оценивать полином в любой заданной точке.

Я работаю над созданием грубого алгоритма на JavaScript/TypeScript для обязательств KZG, и один из шагов этого алгоритма включает в себя умножение коэффициентов полинома, построенного для некоторой заданной строки, на структурированную ссылочную строку (SRS), возведенную в соответствующую степень.

В любом случае, по сути, это означает, что мне нужно перебрать все коэффициенты этого вновь построенного многочлена (по крайней мере, я думаю, что мне нужно это сделать, я открыт для предложений здесь).

Я пытаюсь добиться следующего:

  1. Возьмите входную строку
  2. Преобразуйте строку в координаты на плоскости координат XY.
  3. Вычислите многочлен, который проходит через эти координаты
  4. **Перебрать коэффициенты этого полинома **<-- здесь я застрял
  5. (необязательно) оценить полином в заданной точке Z <- было бы здорово, если бы это все еще было возможно наряду с предыдущим требованием

Я застрял на шаге 4).

Я знаю, как построить многочлен из заданной строки в JS/TS с использованием интерполяции Лагранжа, но у меня возникают трудности с извлечением его коэффициентов, которые мне нужны, чтобы иметь возможность умножать их с помощью SRS.

Ниже приведен мой алгоритм интерполяции Лагранжа — обратите внимание, что он может решить 5) для меня, но я не вижу очевидного способа получить из него точные коэффициенты:

type Point = { x: number; y: number };

// The function basically reconstructs the whole Lagrange Polynomial each time
// it needs to evaluate it at some given point `newX`, which is a problem as
// there is no way to extract the coefficients.
function lagrangeInterpolation(points: Point[], newX: number) {
  const n = points.length;
  let newY = 0;

  for (let i = 0; i < n; i++) {
    let { x, y } = points[i];

    let term = y;
    for (let j = 0; j < n; j++) {
      if (i !== j) {
        let { x: xj } = points[j];
        term = (term * (newX - xj)) / (x - xj);
      }
    }
    newY = newY + term;
  }

  return newY;
}

Может быть, другой алгоритм интерполяции позволил бы вычислить точные коэффициенты?

Я не смог найти ни одной библиотеки JS, которая бы решала именно эту проблему. Ближайшими из них мне удалось найти следующие, но они пока неприменимы для решения этой задачи:

  • полином -> проблема: библиотека не имеет встроенного способа возврата коэффициентов и не может принять полином типа Лагранжа в качестве входных данных и сократить его, чтобы можно было извлекать коэффициенты с помощью регулярного выражения.
  • nerdamer-prime -> проблема: библиотека может взять любой многочлен и сократить его, но она не гарантирует порядок членов (отсортированный по степени x), что затрудняет извлечение коэффициентов с помощью регулярного выражения (невозможно определить какой коэффициент связан с какой степенью x); у него также нет встроенного способа получения коэффициентов.

На этом шаге вы не застряли: «Вычислите полином, проходящий через эти координаты». Как? Можете ли вы добавить входы и ожидаемые результаты? Я предполагаю, что вы хотите протестировать все возможные полиномы?

user24714692 16.05.2024 19:44

Посмотрите это и эту ссылку.

user24714692 16.05.2024 19:50
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
2
70
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать матричный метод, описанный @guest в Коэффициенты полиномов Лагранжа.

Для этого вам понадобится функция, вычисляющая определитель матрицы. Для этого вы можете использовать метод исключения Гаусса.

Вот реализация:

function determinant(mat) { // Gaussian elimination method
    const n = mat.length;
    let det = 1;
    for (let r = 0; r < n; r++) {
        let r2 = r;
        while (!mat[r2][r]) {
            r2++;
            if (r2 >= mat.length) return 0;
        }
        const row = mat[r2];
        if (r2 !== r) { // Swap rows
            mat[r2] = mat[r];
            mat[r] = row;
            det = -det;
        }
        let div = row[r];
        if (!div) return 0;
        det *= div;
        for (let c = r; c < n; c++) row[c] /= div;
        for (let r2 = r+1; r2 < n; r2++) {
            const row2 = mat[r2];
            const mul = row2[r];
            for (let c = r; c < n; c++) {
                row2[c] -= mul * row[c]; 
            }
        }
    }
    return det;
}

// Similar to https://math.stackexchange.com/a/3253643/341715
function lagrangeInterpolationCoefficients(points) {
    const lagrangeDet = (j) => determinant(points.map((_, i) => 
        points.map(([a, b]) => i == j ? b : a ** i)
    ));
    const denom = lagrangeDet(-1);
    return points.map((_, j) => lagrangeDet(j) / denom);
}

const coefficientsToFunction = (coefficients) =>
    x => coefficients.reduce((sum, coeff, i) => sum + coeff * x**i, 0);

// Simple (imperfect) rendering of the polynomial:
const coefficientsToString = (coefficients) =>
    coefficients.map((coeff, i) => `${coeff}x^${i}`)
                .reverse().join(" + ")
                .replace(/x\^0|\^1\b|\b0x\^\d+/g, "")
                .replaceAll("+ -", "- ");

// Demo
const points = [[0, -1], [1, 1], [3, 8], [4, 10]];
const coefficients = lagrangeInterpolationCoefficients(points);
console.info("f(x)  = ", coefficientsToString(coefficients));
const f = coefficientsToFunction(coefficients);

// Verify that the created function returns 
//    the correct results for the given points
for (const [x, y] of points) {
    console.info({x, y, "f(x)": f(x)});
}

Это понятный и понятный алгоритм, спасибо. Я только что добавил недостающий \ рядом с последним ^ в предоставленное вами регулярное выражение (\b0x^\d+ должно быть \b0x\^\d+), теперь отлично работает.

Nesh 17.05.2024 08:18

Исправленный! Рад, что этот ответ вам пригодится.

trincot 17.05.2024 08:26

Другие вопросы по теме