Skip to content

Chebyshev bug #375

Closed
Closed

Description

@mkitti

Via contact@julialang.org:

I see a bug in Chebyshev file in the github repository

cheb.u .= cheb.c .+ β .* cheb.c

is wrong and true form is

cheb.u .= cheb.c .+ β .* cheb.u

in the:
IterativeSolvers.jl/src/chebyshev.jl

Activity

  1. giordano commented on Sep 14, 2026

    @giordano

    More direct link:

    cheb.u .= cheb.c .+ β .* cheb.c

  2. mkitti commented on Sep 14, 2026

    @mkitti
    Author

    AI evaluation:

    Analysis

    This is a valid bug in the Chebyshev iteration recurrence relation.

    Line 45 contains an error in the search direction update:

    cheb.u .= cheb.c .+ β .* cheb.c  # ❌ WRONG - uses cheb.c twice

    Should be:

    cheb.u .= cheb.c .+ β .* cheb.u  # ✅ CORRECT - blends with previous direction

    Why this matters

    The Chebyshev acceleration method relies on a specific recurrence relation to construct optimal search directions. The update should combine:

    • cheb.c: the current preconditioned residual
    • β * cheb.u: a scaled version of the previous search direction

    The current code incorrectly uses β * cheb.c (the current residual scaled twice), which:

    1. Breaks the mathematical correctness of the Chebyshev recurrence
    2. Destroys the convergence guarantees that depend on the proper recurrence
    3. May cause poor/divergent behavior in actual iterations

    This is a straightforward one-character fix that changes c to u on line 45.

    From Github Copilot.

  3. mkitti commented on Sep 14, 2026

    @mkitti
    Author

    AI suggested regression test:

    @testset "Convergence rate" begin
        # Regression test for issue #375: ensures Chebyshev uses correct recurrence u_{k+1} = c + β*u_k
        # (not the buggy c + β*c). This test verifies convergence happens faster than a simple
        # Richardson iteration, which would use c + β*c.
        
        for T in (Float32, Float64)
            # Create a well-conditioned SPD matrix where Chebyshev should converge quickly
            n = 20
            A = Tridiagonal(T.(fill(-1.0, n-1)), T.(fill(2.0, n)), T.(fill(-1.0, n-1)))
            b = ones(T, n)
            x0 = zeros(T, n)
            
            λ_min, λ_max = approx_eigenvalue_bounds(A)
            
            # Run Chebyshev with enough iterations to converge
            x, history = chebyshev!(copy(x0), A, b, λ_min, λ_max, 
                                    reltol=T(1e-6), maxiter=50, log=true, initially_zero=true)
            
            # With the correct recurrence relation, Chebyshev should converge in ~log(1/tol) iterations
            # With the buggy relation (c + β*c), convergence would be much slower
            # For this well-conditioned problem, we expect convergence in roughly 20-30 iterations
            @test niters(history) < 35  # Strict bound to catch regression
            @test history.isconverged
            @test norm(A * x - b) / norm(b) < T(1e-6)
        end
    end
  4. haampie commented on Sep 14, 2026

    @haampie
    Member

    I've merged #367, but it looks like more needs to be done.

  5. added 2 commits that reference this issue on Sep 14, 2026
    bdaac24
    51c6e44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions