baseline: the published sim-numerics artifact as it stands (490 tests, verify_article.py checks all 72 paper numbers against sweep_full.json)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
"""The relaxation parameter: the fourth domain, and the fourth time the same
|
||||
pattern appears.
|
||||
|
||||
omega in SOR is the oldest hand-tuned step length in numerical computing. The
|
||||
similarity form - omega = 1 + cos between successive corrections - lands
|
||||
exactly in the admissible interval [1, 2] with nothing chosen, and it beats
|
||||
Gauss-Seidel five-fold. It loses to a swept omega two-fold.
|
||||
|
||||
A second map, derived from the theory rather than from the geometry, was tried
|
||||
and is worse than the first. Both are pinned: the working one so it is not
|
||||
lost, the refuted one so it is not retried.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from relax.sor import (ContractionOmega, Fixed, SimilarityOmega, poisson_rhs,
|
||||
residual, solve, sweep_gs)
|
||||
from stage23_relaxation import anisotropic, convection, theory_check
|
||||
|
||||
N = 14
|
||||
F = poisson_rhs(N)
|
||||
W_OPT = 2.0 / (1.0 + math.sin(math.pi / (N + 1)))
|
||||
|
||||
|
||||
def test_the_sweep_reproduces_the_sor_theory():
|
||||
"""The instrument before the experiment: for the model problem the SOR
|
||||
spectral radius is exactly omega* - 1."""
|
||||
_w, theory, measured = theory_check(16)
|
||||
assert abs(theory - measured) < 0.02, (theory, measured)
|
||||
|
||||
|
||||
def test_the_similarity_omega_lands_in_the_admissible_interval():
|
||||
"""Range of the similarity and convergence condition of the method
|
||||
coincide, which is why nothing had to be clipped by hand."""
|
||||
r = SimilarityOmega()
|
||||
r.reset()
|
||||
d1 = np.array([1.0, 2.0, 3.0])
|
||||
assert r.next_omega(None, None) == 1.0
|
||||
assert r.next_omega(d1, d1) == pytest.approx(2.0) # identical
|
||||
assert r.next_omega(d1, -d1) == pytest.approx(1.0) # opposed
|
||||
assert r.next_omega(np.array([1.0, 0.0, 0.0]),
|
||||
np.array([0.0, 1.0, 0.0])) == pytest.approx(1.0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("label,coeff", [
|
||||
("poisson", None), ("aniso", anisotropic(N, 0.1))])
|
||||
def test_similarity_beats_gauss_seidel_by_a_wide_margin(label, coeff):
|
||||
gs, _ = solve(F, Fixed(1.0), coeff=coeff)
|
||||
sim, _ = solve(F, SimilarityOmega(), coeff=coeff)
|
||||
assert sim * 3 < gs, (label, sim, gs)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("label,coeff", [
|
||||
("poisson", None), ("aniso", anisotropic(N, 0.1))])
|
||||
def test_and_loses_to_a_swept_omega(label, coeff):
|
||||
"""The other half, stated so the claim is never inflated."""
|
||||
sim, _ = solve(F, SimilarityOmega(), coeff=coeff)
|
||||
best = min(solve(F, Fixed(w), coeff=coeff)[0]
|
||||
for w in (1.2, 1.4, 1.6, 1.8, W_OPT))
|
||||
assert best < sim, (label, best, sim)
|
||||
|
||||
|
||||
def test_the_similarity_rule_over_relaxes():
|
||||
"""The diagnosis, not just the outcome: the cosine between successive SOR
|
||||
corrections sits near 1, so 1 + cos saturates near 2 and the rule picks a
|
||||
larger omega than the optimum."""
|
||||
_sim, mean_w = solve(F, SimilarityOmega())
|
||||
assert mean_w > W_OPT, (mean_w, W_OPT)
|
||||
|
||||
|
||||
def test_the_contraction_map_is_refuted_and_worse():
|
||||
"""The second attempt, pinned so it is not tried again. Undamped
|
||||
feedback pins omega at the limit from the first sweep."""
|
||||
sim, _ = solve(F, SimilarityOmega())
|
||||
con, mean_w = solve(F, ContractionOmega())
|
||||
assert con > sim, (con, sim)
|
||||
assert mean_w > 1.9, mean_w
|
||||
|
||||
|
||||
def test_convection_is_where_it_actually_hurts():
|
||||
"""On a strongly non-symmetric problem Gauss-Seidel is already fast and
|
||||
the rule makes it slower - the one case where the similarity form is not
|
||||
merely second but harmful."""
|
||||
coeff = convection(N, 10.0)
|
||||
gs, _ = solve(F, Fixed(1.0), coeff=coeff)
|
||||
sim, _ = solve(F, SimilarityOmega(), coeff=coeff)
|
||||
assert sim > gs, (sim, gs)
|
||||
Reference in New Issue
Block a user