Skip to Content

BPOLY

Overview

The BPOLY function constructs a piecewise polynomial in the Bernstein basis, allowing for smooth interpolation between specified breakpoints using Bernstein polynomials. This is useful in numerical analysis, computer graphics, and engineering for representing curves and surfaces with desirable properties such as smoothness and stability. The polynomial between each pair of breakpoints xix_i and xi+1x_{i+1} is expressed as:

S(x)=a=0kca,ib(a,k;x)S(x) = \sum_{a=0}^{k} c_{a,i} \, b(a, k; x)

where kk is the degree of the polynomial, ca,ic_{a,i} are the Bernstein coefficients for interval ii, and b(a,k;x)b(a, k; x) is the Bernstein basis polynomial:

b(a,k;x)=(ka)ta(1t)ka,t=xxixi+1xib(a, k; x) = \binom{k}{a} \, t^a \, (1-t)^{k-a}, \quad t = \frac{x - x_i}{x_{i+1} - x_i}

This wrapper exposes the core arguments c, x, x_eval, and extrapolate from scipy.interpolate.BPoly while fixing the interpolation axis to 0 and requiring the breakpoints to be supplied as a single-column table. For more details, see the SciPy BPoly documentation  and Wikipedia: Bernstein polynomial .

This example function is provided as-is without any representation of accuracy.

Usage

To use the function in Excel:

=BPOLY(c, x, x_eval, [extrapolate])
  • c (2D list, required): Bernstein coefficients of shape (degree + 1, number of intervals). Each row must have the same number of columns and contain only finite numeric values.
  • x (2D list, required): Breakpoints as a single-column table of shape (number of intervals + 1, 1). Values must be finite and strictly monotonic (all increasing or all decreasing).
  • x_eval (2D list, required): Points at which to evaluate the polynomial, given as a single-column table with finite numeric values.
  • extrapolate (bool or string (enum), optional, default=True): Whether to extrapolate outside the breakpoint range. Valid options: TRUE, FALSE, or the string periodic for periodic extrapolation.

The function returns a 2D list of evaluated values (float) with one column, or an error message (string) if the input is invalid.

Examples

Example 1: Quadratic Bernstein Polynomial

This example constructs a quadratic polynomial on the interval [0, 1, 2, 3] with coefficients 1, 2, 3, and evaluates it at the breakpoints.

Inputs:

cxx_evalextrapolate
12300True
11
22
33

Excel formula:

=BPOLY({1,2,3}, {0;1;2;3}, {0;1;2;3})

Expected output:

Result
1.000
2.000
3.000
3.000

Example 2: Cubic Bernstein Polynomial with Two Intervals

Inputs:

cxx_evalextrapolate
012300True
12340.250.25
0.50.5
0.750.75
11

Excel formula:

=BPOLY({0,1,2,3;1,2,3,4}, {0;0.25;0.5;0.75;1}, {0;0.25;0.5;0.75;1})

Expected output:

Result
0.000
1.000
2.000
3.000
4.000

Example 3: No Extrapolation

Inputs:

cxx_evalextrapolate
12300False
11
22
33

Excel formula:

=BPOLY({1,2,3}, {0;1;2;3}, {0;1;2;3}, FALSE)

Expected output:

Result
1.000
2.000
3.000
3.000

Example 4: Periodic Extrapolation

Inputs:

cxx_evalextrapolate
12300”periodic”
11
22
33

Excel formula:

=BPOLY({1,2,3}, {0;1;2;3}, {0;1;2;3}, "periodic")

Expected output:

Result
1.000
2.000
3.000
1.000

Python Code

from typing import List, Union import numpy as np from scipy.interpolate import BPoly as scipy_bpoly Scalar = Union[float, int, bool, str, None] MatrixInput = Union[Scalar, List[List[Scalar]]] def bpoly( c: MatrixInput, x: MatrixInput, x_eval: MatrixInput, extrapolate: bool | str = True, ) -> list[list[float]] | str: """ Construct a piecewise polynomial in the Bernstein basis and evaluate it at specified points. Args: c: 2D list of Bernstein coefficients, shape (degree + 1, number of intervals). Each row must have the same number of columns. Scalars are treated as a single-row 2D list. x: 2D list of breakpoints, shape (number of intervals + 1, 1). Values must be strictly monotonic (all increasing or all decreasing). Scalars are treated as a 2D column with one row per breakpoint. x_eval: 2D list of points at which to evaluate the polynomial, shape (n, 1). Scalars are treated as a 2D column with one row per evaluation point. extrapolate: Bool or str, optional. Whether to extrapolate outside the breakpoints. If 'periodic', uses periodic extrapolation. Default is True. Returns: 2D list of evaluated values (float), or an error message (str) if input is invalid. This example function is provided as-is without any representation of accuracy. """ # Normalize scalar inputs into 2D list form def _wrap_scalar_to_matrix(value: MatrixInput) -> MatrixInput: if isinstance(value, list): return value return [[value]] c_wrapped = _wrap_scalar_to_matrix(c) x_wrapped = _wrap_scalar_to_matrix(x) x_eval_wrapped = _wrap_scalar_to_matrix(x_eval) # Validate c if not isinstance(c_wrapped, list) or not c_wrapped: return "Invalid input: c must be a 2D list with at least one row." if not all(isinstance(row, list) and row for row in c_wrapped): return "Invalid input: c must be a 2D list without empty rows." if len({len(row) for row in c_wrapped}) != 1: return "Invalid input: c must have rows of equal length." # Validate x if not isinstance(x_wrapped, list) or not x_wrapped: return "Invalid input: x must be a 2D column vector (list of lists)." if not all(isinstance(row, list) and len(row) == 1 for row in x_wrapped): return "Invalid input: x must be a 2D column vector (list of lists, each with one value)." # Validate x_eval if not isinstance(x_eval_wrapped, list) or not x_eval_wrapped: return "Invalid input: x_eval must be a 2D column vector (list of lists)." if not all(isinstance(row, list) and len(row) == 1 for row in x_eval_wrapped): return "Invalid input: x_eval must be a 2D column vector (list of lists, each with one value)." # Validate extrapolate argument if not (isinstance(extrapolate, bool) or (isinstance(extrapolate, str) and extrapolate == "periodic")): return "Invalid input: extrapolate must be a bool or 'periodic'." # Ensure consistent interval configuration try: c_array = np.array([[float(item) for item in row] for row in c_wrapped], dtype=float) except (TypeError, ValueError): return "Invalid input: c must contain numeric values." if c_array.ndim != 2: return "Invalid input: c must be a 2D list." if not np.all(np.isfinite(c_array)): return "Invalid input: c must contain finite numeric values." # The second dimension corresponds to intervals n_intervals = c_array.shape[1] if n_intervals < 1: return "Invalid input: c must define at least one interval." try: x_array = np.array([[float(row[0]) for row in x_wrapped]], dtype=float).flatten() except (TypeError, ValueError): return "Invalid input: x must contain numeric values." if not np.all(np.isfinite(x_array)): return "Invalid input: x must contain finite numeric values." if x_array.size != n_intervals + 1: return "Invalid input: x must have (number of intervals + 1) rows." # Ensure the breakpoint sequence is strictly monotonic diffs = np.diff(x_array) if diffs.size == 0 or not (np.all(diffs > 0) or np.all(diffs < 0)): return "Invalid input: x must be strictly monotonic (all increasing or all decreasing)." try: x_eval_array = np.array([[float(row[0]) for row in x_eval_wrapped]], dtype=float).flatten() except (TypeError, ValueError): return "Invalid input: x_eval must contain numeric values." if not np.all(np.isfinite(x_eval_array)): return "Invalid input: x_eval must contain finite numeric values." # Evaluate the polynomial and guard against non-finite values try: poly = scipy_bpoly(c_array, x_array, extrapolate=extrapolate) y_values = poly(x_eval_array) except Exception as exc: return f"scipy.interpolate.BPoly error: {exc}" if not np.all(np.isfinite(y_values)): return "Invalid result: scipy.interpolate.BPoly returned non-finite values." # Convert the result to a 2D list for Excel compatibility return [[float(val)] for val in y_values.tolist()]

Example Workbook

Link to Workbook 

Last updated on