Fix false-positive in check_primality on degenerate random specialization#525
Closed
ChrisRackauckas-Claude wants to merge 1 commit into
Closed
Conversation
check_primality(polys, extra_relations) substitutes the non-leader variables of each generator with random integers, then tests whether the characteristic polynomial of a generic multiplication operator on the resulting zero-dimensional quotient is irreducible. The random specialization could land on a point where a generator's leading coefficient (w.r.t. its leader) vanishes, dropping that generator's degree in its leader. When every generator collapses to degree 1, the quotient ring becomes 1-dimensional, its charpoly is a degree-1 (hence trivially irreducible) polynomial, and the routine reports the ideal as prime even when it is not. This is a soundness bug: for the io_projections issue-SciML#132 case the ideal is not prime, yet ~6/500 RNG seeds drove check_primality(proj) to return true. It surfaced as a master red on the julia-pre (1.13.0-rc1) Core lane, whose changed global-RNG stream happened to hit such a draw at test/bodies/io_projections.jl:55 (`@test !check_primality(proj)`). Fix: only accept random specializations that preserve every generator's degree in its leader, i.e. that stay on the open set where the leading coefficients do not vanish (the set the ideal is implicitly saturated at, per the docstring). Resample otherwise, with a bounded retry. The extra_relations are evaluated at the same point, matching the previous behavior. Verified on Julia 1.13.0-rc1: false-positive rate over seeds 0..499 drops from 6/500 to 0/500; io_projections body 10/10 (was 9/1); positive case check_primality(proj, [projection_poly]) 50/50 true. No regression on Julia 1.12: io_projections 10/10, check_primality_zerodim 5/5. Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collaborator
|
Thanks! |
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.
Ignore until reviewed by @ChrisRackauckas.
Problem
The master
tests / Core (julia pre, ubuntu-latest)lane is red. The only failure istest/bodies/io_projections.jl:55:The
projideal for the issue-#132 PK/PD model is not prime, so the test asserts!check_primality(proj). The function returnedtrue, failing the test. This is the prerelease (Julia 1.13.0-rc1) lane only; 1.10/1.11/1.12 pass.Root cause (a real soundness bug, not version-specific)
check_primality(polys, extra_relations)specializes every non-leader variable of each generator to a random integer (rand(1:100)), then asks whether the characteristic polynomial of a generic multiplication operator on the resulting zero-dimensional quotient is irreducible.Each generator here is degree 2 in its leader (
y1(t)_2,y2(t)_3), with a non-constant leading coefficient in the other variables. When the random point makes a leading coefficient vanish, the generator drops to degree 1. When all generators collapse to degree 1, the quotient ring becomes 1-dimensional, its charpoly is degree 1 (trivially irreducible), and the routine reports the (non-prime) ideal as prime — a false positive.Reproduced on 1.13.0-rc1: over seeds
0..499,check_primality(proj)returnstruefor 6 of them (e.g. 30, 169, 305, 393, 488, 496). The 1.13 RNG stream change merely caused the un-seeded global RNG to land on such a draw by the time the test reached line 55; the bug is RNG-dependent and present on every version.For a bad seed the Groebner basis specializes to
[y1(t)_2 - c1, y2(t)_3 - c2](quotient dim 1, irreducible degree-1 charpoly →true); for a good seed it is[y1(t)_2^2 + ..., y2(t)_3^2 + ...](quotient dim 4, charpoly factors →false).Fix
Only accept random specializations that preserve each generator's degree in its leader — i.e. stay on the open set where the leading coefficients do not vanish (precisely the set the ideal is "saturated at the leading coefficient", per the docstring). Resample otherwise, with a bounded retry.
extra_relationsare evaluated at the same point, unchanged behavior.Verification (run locally)
Julia 1.13.0-rc1:
0..499: 6/500 → 0/500io_projectionsbody: 10/10 (was 9 pass / 1 fail)check_primality(proj, [projection_poly]): 50/50 true (unchanged)0..299: 0/300 true (correct)Julia 1.12 (no regression):
io_projectionsbody: 10/10check_primality_zerodimbody: 5/5 (subroutine untouched)🤖 Generated with Claude Code