# Repository Guidelines - Only solution: `EvenPerfectScanner.sln` (console app scanning numeric ranges). - Keep changes confined to the relevant solution/project unless instructed otherwise. - Assume each solution has or will have its own tests and build configuration; avoid cross-project edits unless required. ## Build and Test - Build: `dotnet build EvenPerfectScanner.sln`. - Run only tests related to the modified solution. - Run tests without `--no-build`. - Write tests with xUnit + FluentAssertions. - Confirm test runtimes are reasonable; skip suites expected to run excessively long. - Always apply timeout guards and `Category=Fast` filters when running tests. ## File Editing - Do not use `apply_patch.cs` until TODOs lift the ban; edit files with shell tools and stage via git. - Intended usage (once re-enabled): `dotnet script apply_patch.cs -- [target-directory]`. - Expect the script to run in local/remote Codex environments on Windows and Linux. - Supported options (when allowed): - `--check` - `--ignore-whitespace` - `--ignore-eol` - `--ignore-line-endings` - `--target ` - `--profile` - `--replace-line ` (use `_` for expected to skip validation) - Build patches in standard `git diff` format: - Include `diff --git`, `---`, `+++`, and `@@` headers with numeric ranges. - Exclude `***` or `*** Begin/End Patch` wrappers. - Run `--check` before applying patches; apply only after a successful check. - Keep patches small, precise, and regenerated after each edit; confirm target lines with `Get-Content` or `nl -ba`. - Record exact start lines for each hunk and double-check with `nl -ba`. - Prefer `--replace-line` for single-line edits after capturing the target line number. - Regenerate diffs after successful patch applications and whenever files shift. - Use `--ignore-whitespace` / `--ignore-line-endings` only when validation noise blocks `--check`. - Maintain unique patch filenames and delete applied ones. - Investigate failed hunks immediately and rebuild diffs instead of retrying stale context. - Prefer single-purpose patches. - Use `nl -ba` to show line numbers when needed. - Use four spaces for code block indentation. - Create patches from the repo root with relative paths. - Do not apply changes manually or via other scripts unless modifying `apply_patch.cs`. - If `apply_patch.cs` has issues or lacks features, fix or enhance it and continue using it. ## Test Execution Time Policy - Estimate runtimes before launching tests or samples. - Do not run tests expected to exceed 2 minutes unless explicitly authorized. - Never impose the two-minute guard on benchmarks or profiling runs; let them finish unless obviously stuck. - Keep timeouts external to the test code. - Use targeted filters such as `--filter FullyQualifiedName~` or `--filter "FullyQualifiedName=Namespace.Class.Method"`. - Keep GPU-heavy tests minimal; skip kernels needing >2 minutes for compile/warmup. - In local Codex tasks, run only fast, newly added tests and list recommended existing tests instead. ### 120-second Guard Examples - Windows (PowerShell): - `$proj = ".csproj"` - `$filter = 'FullyQualifiedName~SomeTests'` - `$job = Start-Job -ScriptBlock { param($p,$f) dotnet test $p -c Debug --filter $f } -ArgumentList $proj,$filter` - `if (-not (Wait-Job $job -Timeout 120)) { Stop-Job $job; throw 'Test run exceeded 120s timeout.' }` - `Receive-Job $job` - Linux/macOS (bash): - `timeout 120s dotnet test .csproj -c Debug --filter "Category=Fast&FullyQualifiedName~SomeTests"` - Always specify `timeout 120s` (or shorter) and include `Category=Fast` in the filter. - Treat exit code 124 as a timeout. - Codex/agent runs: wrap `dotnet test` commands in shell guards above. - Filter examples: `--filter "FullyQualifiedName~PrimeTesterGcdTests"`, `--filter "FullyQualifiedName=EvenPerfectBitScanner.Tests.ResultsFileNameTests.BuildResultsFileName_contains_the_range"`. ## Coding Standards - Use four-space indentation; increase one level per nested block. - Indent wrapped parameters/expressions by two indentation units. - Reuse existing variables when prior values are obsolete; call out meaning changes in comments to keep intent clear and register pressure low. - Avoid try/finally blocks solely for resource release unless omitting finally harms clarity or maintainability; ensure every path releases resources, but consider only successful execution. In case of errors the program must crash. - Limit the divisor cycle cache to one in-memory block plus the on-disk snapshot; recompute on misses, discard transient results, and avoid background generation or extra caches. - Write code, comments, commit messages, branch names, and PR descriptions in American English. - Preserve relevant TODO notes and explanatory comments unless invalid. - Prefer structs/classes with public fields over auto-properties for hot-path data holders. - Pass mutable structs as parameters with the `in` modifier whenever the call site and usage allow it (skip when constraints such as lambda captures require a copy). - Omit the `in` modifier when passing immutable structs as parameters. - Remove or extend trivial wrapper methods that only call another method. - Use ThreadStaticPools instead of ArrayPool. Add missing pieces to it, if needed. ## Performance Checklist - Favor dedicated kernels over flag-controlled/parameterized ones; duplicate code when it improves speed. - Remove `if` statements inside hot loops when possible. - Replace runtime flags in hot paths with dedicated method variants. - Reuse variables instead of allocating new ones; document meaning changes. - Extract functionality into separate classes and place reusable parts in `*.Core` projects. - Rent arrays from `ArrayPool` when stack allocation is impractical and return them after use. - Provide cancellation-aware and cancellation-free variants of hot methods; handle cancellation in outer scopes. - Prefer `for` loops over `foreach` to avoid enumerator allocations. - Declare loop control variables outside loops and reuse them. - Cache arrays, static/read-only arrays, and collection counts in locals before loops. - Declare variables together outside loops when feasible and reuse them. - Avoid repeated casting within loops by precomputing or using wider variables. ## GPU Notes - ILGPU 1.5.3 checks: `%` and integer division supported for 32-bit/64-bit integers; `UInt128` remains unsupported inside kernels. Use the `GpuUInt128` struct for GPU-side emulation and extend it whenever required arithmetic helpers are missing. - Arithmetic in GPU kernels covers only 32-bit and 64-bit primitives; rely on `GpuUInt128` together with its read-only counterpart `ReadOnlyGpuUInt128` to emulate 128-bit behavior. - CPU code should default to `UInt128` instead of `GpuUInt128` unless the same calculation executes millions or billions of times, in which case prefer mutable `GpuUInt128` when benchmarks show no material regression; benchmark summaries and recommendations live in `Benchmarks.md`. - GPU kernels should favor mutable `GpuUInt128` and `ReadOnlyGpuUInt128` when the necessary operations exist on the accelerator and benchmarks do not show a dramatic advantage for `UInt128`. - Perform conversions from `GpuUInt128` or other structs to `ReadOnlyGpuUInt128` outside hot loops whenever possible; push the conversion toward the top of the call chain to avoid repeated costs. - For each numeric type, review available helpers in `UIntExtensions`, `ULongExtensions`, `UInt128Extensions`, and `GpuUInt128`; add new operations to the extension class or struct that matches the type. - Arrays/vectors of `bool` unsupported; use `byte`. - `UInt128` multiplication, division, bit shifts unsupported in kernels; implement manually. - GPU context pooling supported and recommended. - Numeric probe results (ILGPU 1.5.3, CPU accelerator): - `System.Numerics.BigInteger`: unsupported (`InternalCompilerException`). - `PeterO.Numbers.EInteger`: unsupported (`InternalCompilerException`). - `PeterO.Numbers.ERational`: unsupported (`InternalCompilerException`, lacks remainder API). - Prefer XMath in GPU calculations over Math or BitOperations. ## Patch Preparation Reminders - Manually review every patch before `--check`; remove unintended whitespace noise. - Capture context with `nl -ba` before composing each hunk; include ≥3 context lines when available. - Normalize trailing whitespace early or rely on ignore flags temporarily, then rerun without ignores to confirm the final diff. - Regenerate patches from scratch after working tree changes; avoid editing old diffs. - Note that the parser ignores blank metadata lines between headers/hunks; keep headers compact unless tools add blanks. ## apply_patch.cs Profiling Snapshot (2025-10-04) - `dotnet script apply_patch.cs -- --profile --check /tmp/agents_todo_update.diff`. - Sample patch: 2 files, 4 hunks, 31 lines, 3468 bytes. - Timings: read 0.45 ms, parse 2.96 ms, apply 2.96 ms. - Next focus: stream the patch reader and reuse pooled buffers to reduce parse/apply cost. ## Mersenne Divisor Guidance - Prime divisor `q` of `2^p - 1` satisfies `q ≡ 1 (mod 2p)` with minimal `q = 2p + 1` for `k = 1`. - Target for at least `p` in `[138,000,000, 200,000,000]`, minimal `q < 400,000,001` (29 bits). - Target for at least `p = 600,000,000`, minimal `q ≤ 1,200,000,001` (31 bits). - Larger `k` values can grow `q` up to nearly `2^p - 1`; plan heuristics/storage for wider integers even though the noted bit widths cover the first admissible divisors. - Worst-case divisor width: `p - 1` bits (`⌊(2^p - 1) / 2⌋ = 2^{p-1} - 1`). - `k_max ≈ 2^{p-2} / p` for large `p`. ## Practical Kernel Guidance - Use native `%` and `/` for 32-bit/64-bit integers when efficient. - For `UInt128` in kernels, avoid `%`/`/`; prefer Montgomery/Barrett or Mersenne folding. - Prefer Mersenne folding for `2^p - 1` moduli to remove branches in hot loops. ## Heuristic Multiply-Shift Benchmarks (2025-10-04) - Run `dotnet run -c Release --project tools/HeuristicMultiplyShiftTiming/HeuristicMultiplyShiftTiming.csproj` to compare `ULongExtensions` helpers without the BenchmarkDotNet harness. - Average ns per call over 200,000,000 iterations (identical checksums): - `NearOverflowShift`: `MultiplyShiftRight` ≈ 2.37 ns, shift-first ≈ 4.71 ns, naive ≈ 0.85 ns. - `HalfRange`: `MultiplyShiftRight` ≈ 2.11 ns, shift-first ≈ 4.15 ns, naive ≈ 0.70 ns. - `MixedBits`: `MultiplyShiftRight` ≈ 1.43 ns, shift-first ≈ 2.83 ns, naive ≈ 0.60 ns. - `Sparse`: `MultiplyShiftRight` ≈ 1.57 ns, shift-first ≈ 2.84 ns, naive ≈ 0.59 ns. - Shift-first doubles CPU cost but stays within 64-bit arithmetic and is the GPU fallback when avoiding `UInt128` overflow.