Add Gauss-sum portraits to Dirichlet character pages - #7172
Open
roed-math wants to merge 4 commits into
Open
Conversation
New self-contained module lmfdb/characters/portraits.py draws, for each residue a mod N, the partial Gauss sums S_a(k) as rainbow radial segments (early terms darkened), the complete Gauss sums as dots, and a circle of radius sqrt(N), following Alex Best's demo from the issue; rendered as a single matplotlib LineCollection and embedded via encode_plot in the properties box (the elliptic curve pattern). Computed on the fly for modulus up to 300, skipped above. Hook is a single 4-line call in render_Dirichletwebpage; any portrait failure is logged and swallowed. Verified: complete sums match pari znchargauss to 1e-13 for ~18 odd/even/primitive/imprimitive/trivial characters, |tau_a|=sqrt(N) for primitive chi at coprime a, 27.8 matches the issue's demo image; pages checked via flask test client for N=1..300 and skip for N>300; DirichletCharactersTest (17 tests incl. new test_portrait) green; pyflakes clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Portraits were guarded by a modulus cutoff, but their cost scales with the number of segments drawn, N*phi(N), which is far from monotone in N: the prime 293 draws 85556 of them and takes some eight times as long as the larger 300, whose phi is only 80, and a reviewer measured seconds of latency on the 293.17 page. The cutoff is now on the segment count (25000, which keeps 300 and drops 293), consulted before any character is constructed or any array allocated, and exposed as portrait_complexity/portrait_is_enabled so the policy can be tested without rendering. Completed portraits are kept in a bounded lru_cache(maxsize=64), so repeat visits and crawlers cost microseconds; moduli with no portrait are rejected before the cache, and a failure is not cached. Adds the accessibility and explanatory pieces asked for in review: a stable dirichlet-character-portrait class and alt text on the image, a /Character/Dirichlet/Pictures page rendering the knowl portrait.character.dirichlet, and a "Picture description" entry in the Learn more box, following the number field and Galois group pattern. The knowl itself still has to be created in the knowl database. Also corrects the module docstring, which said every k = 1, ..., N-1 was drawn: only the k coprime to N are, since chi(n) = 0 off the units makes the other stages repeat the segment before them. Tests: complete sums against pari znchargauss for primitive, imprimitive, non-real and composite-modulus characters; |tau_a| = sqrt(N) on units and 0 off them for a primitive character; the N = 1 point data; the 293/300 workload pair; the cache; and the portrait's own class on the character page, rather than the presence of any base64 image. Rendered portraits are byte-identical to before. lmfdb/characters/test_characters.py green (32), pyflakes/pylint/ruff clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
LMFDB uses American spelling, so "maths" becomes "math". The "grey" of the module docstring is left as it is, matching the color="grey" literal it describes and the rest of the plotting code. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3996.
Adds a "portrait" visualization to each individual Dirichlet character homepage, in the properties box alongside the other basic data, following the design proposed in the issue (Alex Best's demo).
For a character chi of modulus N, and every residue a, the partial Gauss sums
S_a(k) = sum_{n<=k} chi(n) e(a n / N)are drawn as rainbow radial segments (early terms darkened), the complete Gauss sumstau_a(chi)as dots, and a grey circle of radiussqrt(N). The coprime dots lie on the circle iff chi is primitive, and rotational/reflective symmetry reveals the order and reality of the character.The plot is a new self-contained module
lmfdb/characters/portraits.pythat renders all segments as a single matplotlibLineCollectionand embeds the result viaencode_plot(the elliptic-curve pattern). The only hook into existing code is a one-line call inrender_Dirichletwebpage.The picture has
N * phi(N)segments, and that count (not the modulus) is what its cost scales with, so that is what is capped: portraits are drawn whenN * phi(N) <= 25000, which keepsN = 300at about 0.1s while dropping prime-like cases such asN = 293, whose 85556 segments take some eight times longer. The check happens before any character is constructed or any array allocated, and is exposed asportrait_complexity/portrait_is_enabledso the policy can be tested without rendering. Completed portraits are kept in a boundedlru_cache(maxsize=64), so a repeat visit costs microseconds; a modulus with no portrait is a quiet no-op that never reaches the cache, and any failure while building one is logged and swallowed, since the picture must never break the page.A new
/Character/Dirichlet/Picturespage and a "Picture description" entry in the Learn more box explain what the picture shows, as for number fields and Galois groups, and the image carries a stableclass="dirichlet-character-portrait"plus alt text. That page renders the knowlportrait.character.dirichlet, which still needs to be created in the knowl database (draft text is in the old PR thread).Tested: the complete Gauss sums agree with pari's
znchargaussto machine precision for primitive, imprimitive, real, non-real and composite-modulus characters;|tau_a| = sqrt(N)on units andtau_a = 0off them for a primitive character; theN = 1special case; the workload cutoff on the non-monotone 293/300 pair; the cache; and the portrait's own CSS class on the character page.Ported from roed-math#38, where the full write-up and comment history live.
🤖 Generated with Claude Code