LSQRR Example — Least Squares Polynomial Fitting

Demonstrates overdetermined polynomial least-squares fitting using linearsystems.lsqrr().

Example Code

"""IMSL LSQRR example: polynomial least-squares fitting.

Generates an overdetermined system (20 equations, 3 unknowns) for fitting
a quadratic polynomial to noisy data, solves with lsqrr, and plots the fit.

True model: b = 1 + 2*t + 3*t^2 + noise

Outputs:
- Table printed to stdout
- SVG plot saved to test_output/example_imsl_lsqrr.svg
"""

from __future__ import annotations

from pathlib import Path
from typing import Dict

import matplotlib.pyplot as plt
import numpy as np

from linearsystems import lsqrr


def run_demo_imsl_lsqrr() -> Dict[str, object]:
    """Run IMSL LSQRR example: overdetermined least-squares polynomial fit.

    Args:
        None

    Returns:
        Dict[str, object]: Result dict with keys ``x`` (np.ndarray — fitted
            polynomial coefficients), ``residual_norm`` (float), ``rank`` (int),
            and ``plot_path`` (str).
    """
    rng = np.random.default_rng(0)
    m = 20
    n = 3
    t = np.linspace(0.0, 1.0, m)
    x_true = np.array([1.0, 2.0, 3.0])
    noise = 0.05 * rng.standard_normal(m)
    b = 1.0 + 2.0 * t + 3.0 * t ** 2 + noise

    # Vandermonde matrix
    a = np.column_stack([np.ones(m), t, t ** 2])

    x, residuals, rank, sv = lsqrr(a, b)
    residual_norm = float(np.linalg.norm(a @ x - b))

    print("\nIMSL LSQRR Example: Overdetermined polynomial least-squares fit")
    print("-" * 55)
    print(f"  Equations m = {m},  unknowns n = {n}")
    print(f"  True coefficients  : {x_true}")
    print(f"  Fitted coefficients: {np.round(x, 6)}")
    print("-" * 55)
    print(f"{'‖Ax-b‖':<30} {residual_norm:.4e}")
    print(f"{'Effective rank':<30} {rank}")
    print(f"{'Singular values':<30} {np.round(sv, 4)}")
    print("-" * 55)

    output_dir = Path("test_output")
    output_dir.mkdir(parents=True, exist_ok=True)
    plot_path = output_dir / "example_imsl_lsqrr.svg"

    t_fine = np.linspace(0.0, 1.0, 200)
    b_true_fine = x_true[0] + x_true[1] * t_fine + x_true[2] * t_fine ** 2
    b_fit_fine = x[0] + x[1] * t_fine + x[2] * t_fine ** 2

    fig, axes = plt.subplots(1, 2, figsize=(13, 5))

    # Left: data + fit
    ax = axes[0]
    ax.scatter(t, b, s=40, color="#1f77b4", zorder=5, label="Noisy data")
    ax.plot(t_fine, b_true_fine, "g--", linewidth=1.5, label="True model")
    ax.plot(t_fine, b_fit_fine, "r-", linewidth=2.0, label="Fitted curve")
    ax.set_xlabel("t")
    ax.set_ylabel("b")
    ax.set_title("LSQRR: Quadratic Polynomial Fit (m=20, n=3)")
    ax.legend()
    ax.grid(True, alpha=0.3)

    # Right: coefficient comparison
    ax2 = axes[1]
    idx = np.arange(n)
    ax2.bar(idx - 0.2, x_true, width=0.35, label="True", color="#2ca02c", alpha=0.85)
    ax2.bar(idx + 0.2, x, width=0.35, label="Fitted", color="#d62728", alpha=0.85)
    ax2.set_xticks(idx)
    ax2.set_xticklabels(["c₀", "c₁", "c₂"])
    ax2.set_title("Coefficient Comparison")
    ax2.set_ylabel("Value")
    ax2.legend()
    ax2.grid(True, axis="y", alpha=0.3)

    fig.tight_layout()
    fig.savefig(plot_path, format="svg")
    plt.close(fig)
    print(f"\nPlot saved to: {plot_path}")

    return {"x": x, "residual_norm": residual_norm, "rank": rank, "plot_path": str(plot_path)}


if __name__ == "__main__":
    run_demo_imsl_lsqrr()

Plot Output

Data points with fitted polynomial curve and coefficient comparison

Fitted polynomial curve through noisy data and recovered coefficient comparison.

Console Output

IMSL LSQRR Example: Overdetermined polynomial least-squares fit
-------------------------------------------------------
  Equations m = 20,  unknowns n = 3
  True coefficients  : [1. 2. 3.]
  Fitted coefficients: [1.035443 1.774627 3.199016]
-------------------------------------------------------
‖Ax-b‖                         1.7200e-01
Effective rank                 3
Singular values                [5.3304 1.6376 0.2552]
-------------------------------------------------------

Plot saved to: test_output\example_imsl_lsqrr.svg