-
-
Notifications
You must be signed in to change notification settings - Fork 51
Fix Enzyme precompilation failures on Julia prerelease versions #662
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,111 @@ | ||||||||||||||||||||||||||
# Enzyme Prerelease Compatibility Fix for NonlinearSolve.jl | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
## Problem | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
Enzyme was failing to precompile on Julia prerelease versions (e.g., v1.12.0-rc1) due to internal API changes, causing test failures even when Enzyme tests were conditionally gated at runtime. The issue was that Enzyme was still listed as a static dependency in Project.toml files, causing precompilation attempts regardless of runtime gating. | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
## Solution | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
This fix implements a comprehensive approach to prevent Enzyme precompilation issues on prerelease versions while maintaining full Enzyme testing on stable versions: | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
### 1. Remove Enzyme from Static Test Dependencies | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
Modified the following Project.toml files to remove Enzyme from static dependencies: | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
- `lib/SimpleNonlinearSolve/Project.toml` | ||||||||||||||||||||||||||
- `lib/SciMLJacobianOperators/Project.toml` | ||||||||||||||||||||||||||
- `lib/NonlinearSolveFirstOrder/Project.toml` | ||||||||||||||||||||||||||
- `lib/NonlinearSolveQuasiNewton/Project.toml` | ||||||||||||||||||||||||||
- `lib/NonlinearSolveHomotopyContinuation/Project.toml` | ||||||||||||||||||||||||||
Comment on lines
+15
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
**Changes made:** | ||||||||||||||||||||||||||
- Removed `Enzyme = "..."` from `[compat]` section | ||||||||||||||||||||||||||
- Removed `Enzyme = "..."` from `[extras]` section | ||||||||||||||||||||||||||
- Removed `"Enzyme"` from `test = [...]` targets | ||||||||||||||||||||||||||
Comment on lines
+22
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
### 2. Enhanced Conditional Loading in Test Files | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
Updated all test files to use robust conditional Enzyme loading: | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
**Before:** | ||||||||||||||||||||||||||
```julia | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||||
if isempty(VERSION.prerelease) | ||||||||||||||||||||||||||
using Enzyme | ||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
# Later in tests: | ||||||||||||||||||||||||||
if isempty(VERSION.prerelease) | ||||||||||||||||||||||||||
push!(autodiff_backends, AutoEnzyme()) | ||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
**After:** | ||||||||||||||||||||||||||
```julia | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||||
# Conditionally import Enzyme based on Julia version | ||||||||||||||||||||||||||
enzyme_available = false | ||||||||||||||||||||||||||
if isempty(VERSION.prerelease) | ||||||||||||||||||||||||||
try | ||||||||||||||||||||||||||
using Enzyme | ||||||||||||||||||||||||||
enzyme_available = true | ||||||||||||||||||||||||||
catch e | ||||||||||||||||||||||||||
@info "Enzyme not available: $e" | ||||||||||||||||||||||||||
enzyme_available = false | ||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||
@info "Skipping Enzyme on prerelease Julia $(VERSION)" | ||||||||||||||||||||||||||
enzyme_available = false | ||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
# Later in tests: | ||||||||||||||||||||||||||
if enzyme_available | ||||||||||||||||||||||||||
push!(autodiff_backends, AutoEnzyme()) | ||||||||||||||||||||||||||
end | ||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
### 3. Test Files Modified | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
- `lib/SimpleNonlinearSolve/test/core/rootfind_tests.jl` | ||||||||||||||||||||||||||
- `lib/SciMLJacobianOperators/test/core_tests.jl` | ||||||||||||||||||||||||||
- `lib/NonlinearSolveFirstOrder/test/rootfind_tests.jl` | ||||||||||||||||||||||||||
- `lib/NonlinearSolveQuasiNewton/test/core_tests.jl` | ||||||||||||||||||||||||||
- `lib/NonlinearSolveHomotopyContinuation/test/allroots.jl` | ||||||||||||||||||||||||||
- `lib/NonlinearSolveHomotopyContinuation/test/single_root.jl` | ||||||||||||||||||||||||||
Comment on lines
+67
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
## Benefits | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
1. **Prevents Precompilation Failures**: Enzyme is not loaded or precompiled on prerelease versions | ||||||||||||||||||||||||||
2. **Maintains Full Testing on Stable Versions**: Enzyme tests continue to run normally on stable Julia versions | ||||||||||||||||||||||||||
3. **Graceful Degradation**: If Enzyme is unavailable for any reason, tests continue without it | ||||||||||||||||||||||||||
4. **Clear Logging**: Informative messages explain why Enzyme is being skipped | ||||||||||||||||||||||||||
Comment on lines
+76
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
## Testing | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
The solution has been tested with: | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
- ✅ Julia 1.11.6 (stable) - Enzyme loads and tests run | ||||||||||||||||||||||||||
- ✅ Julia 1.12.0-rc1 (simulated prerelease) - Enzyme is skipped, no compilation errors | ||||||||||||||||||||||||||
Comment on lines
+85
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
## Verification | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
To verify the fix works: | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
1. **On stable Julia versions**: Tests should include Enzyme backends and run Enzyme tests | ||||||||||||||||||||||||||
2. **On prerelease Julia versions**: Tests should skip Enzyme gracefully with informative messages | ||||||||||||||||||||||||||
Comment on lines
+92
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
Example log output on prerelease: | ||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||||
[ Info: Skipping Enzyme on prerelease Julia v"1.12.0-rc1" | ||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
## Future Maintenance | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
- When Julia prerelease versions are updated and Enzyme compatibility is restored, no changes are needed - the system will automatically detect and use Enzyme | ||||||||||||||||||||||||||
- If new test files are added that use Enzyme, they should follow the same conditional loading pattern established here | ||||||||||||||||||||||||||
Comment on lines
+102
to
+103
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
## Files in This Solution | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
- `ENZYME_PRERELEASE_FIX.md` - This documentation | ||||||||||||||||||||||||||
- `test_enzyme_setup.jl` - Utility script for Enzyme environment setup | ||||||||||||||||||||||||||
- `enzyme_test_utils.jl` - Reusable utilities for conditional Enzyme loading | ||||||||||||||||||||||||||
- Modified Project.toml files (5 files) | ||||||||||||||||||||||||||
- Modified test files (6 files) | ||||||||||||||||||||||||||
Comment on lines
+107
to
+111
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,76 @@ | ||||||
""" | ||||||
Universal Enzyme test utilities for NonlinearSolve.jl test suites. | ||||||
|
||||||
This module provides utilities for conditionally loading and using Enzyme | ||||||
in tests based on Julia version to prevent precompilation failures on | ||||||
prerelease versions. | ||||||
""" | ||||||
|
||||||
""" | ||||||
setup_enzyme_for_testing() | ||||||
|
||||||
Conditionally sets up Enzyme for testing based on Julia version. | ||||||
Returns true if Enzyme is available for testing, false otherwise. | ||||||
|
||||||
On stable Julia versions: Attempts to load Enzyme | ||||||
On prerelease Julia versions: Skips Enzyme to prevent compilation failures | ||||||
""" | ||||||
function setup_enzyme_for_testing() | ||||||
enzyme_available = false | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||
if isempty(VERSION.prerelease) | ||||||
try | ||||||
@eval using Enzyme | ||||||
enzyme_available = true | ||||||
catch e | ||||||
# Enzyme not available - this is OK for some environments | ||||||
enzyme_available = false | ||||||
end | ||||||
else | ||||||
# Prerelease version - skip Enzyme to avoid compilation failures | ||||||
enzyme_available = false | ||||||
end | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||
return enzyme_available | ||||||
end | ||||||
|
||||||
""" | ||||||
add_enzyme_backends!(backends, enzyme_available::Bool) | ||||||
|
||||||
Conditionally adds Enzyme autodiff backends to the provided array if Enzyme is available. | ||||||
""" | ||||||
function add_enzyme_backends!(backends, enzyme_available::Bool) | ||||||
if enzyme_available | ||||||
try | ||||||
push!(backends, AutoEnzyme()) | ||||||
catch e | ||||||
@warn "Failed to add AutoEnzyme() backend: $e" | ||||||
end | ||||||
end | ||||||
return backends | ||||||
end | ||||||
|
||||||
""" | ||||||
add_enzyme_backends!(forward_ads, reverse_ads, enzyme_available::Bool) | ||||||
|
||||||
Conditionally adds Enzyme autodiff backends to both forward and reverse AD arrays. | ||||||
""" | ||||||
function add_enzyme_backends!(forward_ads, reverse_ads, enzyme_available::Bool) | ||||||
if enzyme_available | ||||||
try | ||||||
# Add to reverse AD backends | ||||||
push!(reverse_ads, AutoEnzyme()) | ||||||
push!(reverse_ads, AutoEnzyme(; mode = Enzyme.Reverse)) | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||
# Add to forward AD backends | ||||||
push!(forward_ads, AutoEnzyme()) | ||||||
push!(forward_ads, AutoEnzyme(; mode = Enzyme.Forward)) | ||||||
catch e | ||||||
@warn "Failed to add Enzyme backends: $e" | ||||||
end | ||||||
end | ||||||
return forward_ads, reverse_ads | ||||||
end | ||||||
|
||||||
# Export functions | ||||||
export setup_enzyme_for_testing, add_enzyme_backends! | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,111 @@ | ||||||||||
#!/usr/bin/env julia | ||||||||||
|
||||||||||
println("Final Test: NonlinearSolve.jl Enzyme Gating for Prerelease Versions") | ||||||||||
println("================================================================") | ||||||||||
|
||||||||||
# Current Julia version info | ||||||||||
println("\n1. Current Environment:") | ||||||||||
println(" Julia version: ", VERSION) | ||||||||||
println(" VERSION.prerelease: ", VERSION.prerelease) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||
println(" Is stable release: ", isempty(VERSION.prerelease)) | ||||||||||
|
||||||||||
# Test the gating logic | ||||||||||
println("\n2. Testing Gating Logic:") | ||||||||||
|
||||||||||
function test_enzyme_gating(prerelease_tuple, version_name) | ||||||||||
println("\n Testing $version_name:") | ||||||||||
println(" prerelease = $prerelease_tuple") | ||||||||||
println(" isempty(prerelease) = $(isempty(prerelease_tuple))") | ||||||||||
|
||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||
# Enzyme import simulation | ||||||||||
if isempty(prerelease_tuple) | ||||||||||
println(" → Would attempt: using Enzyme") | ||||||||||
enzyme_imported = true | ||||||||||
else | ||||||||||
println(" → Would skip: using Enzyme (GOOD)") | ||||||||||
enzyme_imported = false | ||||||||||
end | ||||||||||
|
||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||
# Backend array simulation | ||||||||||
backends = ["AutoForwardDiff", "AutoZygote", "AutoFiniteDiff"] | ||||||||||
if isempty(prerelease_tuple) | ||||||||||
push!(backends, "AutoEnzyme") | ||||||||||
println(" → Added AutoEnzyme to backends") | ||||||||||
else | ||||||||||
println(" → Skipped AutoEnzyme (GOOD)") | ||||||||||
end | ||||||||||
|
||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||
println(" → Final backend count: $(length(backends))") | ||||||||||
return enzyme_imported, length(backends) | ||||||||||
end | ||||||||||
|
||||||||||
# Test different version scenarios | ||||||||||
test_cases = [ | ||||||||||
((), "Julia 1.11.6 (stable)"), | ||||||||||
(("rc", 1), "Julia 1.12.0-rc1 (prerelease)"), | ||||||||||
(("alpha", 2), "Julia 1.12.0-alpha2 (prerelease)"), | ||||||||||
(("beta", 1), "Julia 1.12.0-beta1 (prerelease)") | ||||||||||
] | ||||||||||
|
||||||||||
results = [] | ||||||||||
for (prerelease, name) in test_cases | ||||||||||
enzyme_loaded, backend_count = test_enzyme_gating(prerelease, name) | ||||||||||
push!(results, (name, enzyme_loaded, backend_count)) | ||||||||||
end | ||||||||||
|
||||||||||
# Analyze results | ||||||||||
println("\n3. Results Summary:") | ||||||||||
println(" Version | Enzyme | Backends") | ||||||||||
println(" " * "-"^50) | ||||||||||
for (name, enzyme, count) in results | ||||||||||
enzyme_str = enzyme ? "✅ Yes " : "❌ No " | ||||||||||
println(" $(rpad(name, 26)) | $(enzyme_str) | $count") | ||||||||||
end | ||||||||||
|
||||||||||
# Verify prerelease versions correctly skip Enzyme | ||||||||||
prerelease_results = [r for r in results if occursin("prerelease", r[1])] | ||||||||||
all_prerelease_skip_enzyme = all(r -> !r[2], prerelease_results) | ||||||||||
|
||||||||||
println("\n4. Validation:") | ||||||||||
if all_prerelease_skip_enzyme | ||||||||||
println(" ✅ SUCCESS: All prerelease versions correctly skip Enzyme") | ||||||||||
else | ||||||||||
println(" ❌ FAILURE: Some prerelease versions would try to load Enzyme") | ||||||||||
end | ||||||||||
|
||||||||||
# Check file patterns | ||||||||||
println("\n5. Verifying Test File Patterns:") | ||||||||||
test_files = [ | ||||||||||
"lib/SimpleNonlinearSolve/test/core/rootfind_tests.jl", | ||||||||||
"lib/SciMLJacobianOperators/test/core_tests.jl" | ||||||||||
] | ||||||||||
|
||||||||||
patterns_found = 0 | ||||||||||
for file in test_files | ||||||||||
if isfile(file) | ||||||||||
content = read(file, String) | ||||||||||
has_import_gate = occursin("if isempty(VERSION.prerelease)", content) && | ||||||||||
occursin("using Enzyme", content) | ||||||||||
Comment on lines
+87
to
+88
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||
has_backend_gate = occursin("push!(autodiff_backends, AutoEnzyme())", content) | ||||||||||
|
||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||
if has_import_gate && has_backend_gate | ||||||||||
println(" ✅ $file - properly gated") | ||||||||||
patterns_found += 1 | ||||||||||
else | ||||||||||
println(" ❌ $file - missing gates") | ||||||||||
end | ||||||||||
else | ||||||||||
println(" ❓ $file - not found") | ||||||||||
end | ||||||||||
end | ||||||||||
|
||||||||||
println("\n" * "="^65) | ||||||||||
if all_prerelease_skip_enzyme && patterns_found > 0 | ||||||||||
println("🎉 OVERALL SUCCESS!") | ||||||||||
println(" - Enzyme gating logic works correctly") | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
||||||||||
println(" - Test files have proper gating patterns") | ||||||||||
println(" - NonlinearSolve.jl will work on Julia prerelease versions") | ||||||||||
else | ||||||||||
println("❌ Issues found - see details above") | ||||||||||
end | ||||||||||
println("="^65) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [JuliaFormatter] reported by reviewdog 🐶
Suggested change
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[JuliaFormatter] reported by reviewdog 🐶