Skip to content

feat(replacements): p51 - #55

Merged
dchou1618 merged 7 commits into
masterfrom
feature/p51
Jul 26, 2026
Merged

dchou1618 merged 7 commits into
masterfrom
feature/p51

Conversation

@dchou1618

Copy link
Copy Markdown
Owner

No description provided.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add Euler p51 prime digit replacements and centralize sieve utility

✨ Enhancement 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Extract shared prime sieve into a reusable Euler utils module.
• Refactor p50 to use the shared sieve implementation.
• Add a new p51 solver for prime digit replacement families with a basic test hook.
Diagram

graph TD
T["tests/euler/p51_test.py"] --> P51["Algorithms/.../euler/p51.py"] --> U["Algorithms/.../euler/utils.py"]
P50["Algorithms/.../euler/p50.py"] --> U
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Mask-based digit replacement (combinatorics over positions)
  • ➕ Avoids recursion and repeated set unions; easier to reason about complexity
  • ➕ Naturally supports skipping leading-digit replacements that create shorter numbers
  • ➖ More code to generate position masks and apply them
  • ➖ May still require careful de-duplication of generated candidates
2. String/bytearray digit manipulation
  • ➕ Simpler implementation of digit replacement and leading-zero handling
  • ➕ Avoids floating-point math.log for digit counting
  • ➖ Extra conversions between int and str for each candidate
  • ➖ Potentially slower unless optimized/cached

Recommendation: The shared sieve extraction is a good direction and should reduce duplication across Euler solutions. For p51, consider switching to a mask- or string-based replacement generator to make leading-zero behavior explicit and reduce recursion/set-union overhead; also avoid printing from within the solver (return the family or use logging) so tests can assert results deterministically.

Files changed (4) +54 / -16

Enhancement (2) +48 / -0
p51.pyAdd p51 prime digit replacement family search +33/-0

Add p51 prime digit replacement family search

• Introduces digit replacement candidate generation and searches for primes that yield a target-size prime family under digit replacement. Uses 'utils.sieve(n)' to precompute primality up to 'n' and scans primes with an optional 'start_point'.

Algorithms/numerical_methods/euler/p51.py

utils.pyAdd shared prime sieve utility +15/-0

Add shared prime sieve utility

• Adds a reusable 'sieve(n)' implementation returning both a boolean primality table and the list of primes up to 'n'. Intended for reuse by multiple Euler problem solutions.

Algorithms/numerical_methods/euler/utils.py

Refactor (1) +2 / -16
p50.pyRefactor p50 to use shared sieve utility +2/-16

Refactor p50 to use shared sieve utility

• Removes the local sieve implementation and imports 'Algorithms.numerical_methods.euler.utils'. Updates 'consecutive_prime_sum' to call 'utils.sieve(n)' for prime generation.

Algorithms/numerical_methods/euler/p50.py

Tests (1) +4 / -0
p51_test.pyAdd initial p51 test entry point +4/-0

Add initial p51 test entry point

• Adds a basic test that invokes 'prime_digit_replacements' with parameters for the known Euler #51 search region. Currently prints the result rather than asserting an expected value.

tests/euler/p51_test.py

ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

@qodo-code-review

qodo-code-review Bot commented Jul 18, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. p50 sieve symbol removed ✓ Resolved 🐞 Bug ≡ Correctness
Description
Algorithms.numerical_methods.euler.p50 no longer defines/exports sieve, but existing tests still
import it from p50, causing an ImportError during test collection.
Code

Algorithms/numerical_methods/euler/p50.py[L4-16]

-def sieve(n: int):
-    is_prime = [True] * (n + 1)
-    if n >= 0:
-        is_prime[0] = False
-    if n >= 1:
-        is_prime[1] = False
-    primes = []
-    for p in range(2, n + 1):
-        if is_prime[p]:
-            primes.append(p)
-            for v in range(p * p, n + 1, p):
-                is_prime[v] = False
-    return is_prime, primes
+from Algorithms.numerical_methods.euler import utils
Relevance

⭐⭐⭐ High

Team recently fixed p50 correctness issues; breaking tests via ImportError likely addressed (PR54).

PR-#54

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The updated p50.py contains only consecutive_prime_sum and delegates to utils.sieve, while the
existing test suite still imports and calls sieve from p50. This mismatch deterministically
breaks tests.

Algorithms/numerical_methods/euler/p50.py[1-21]
tests/euler/p50_test.py[1-8]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`tests/euler/p50_test.py` imports `sieve` from `Algorithms.numerical_methods.euler.p50`, but this PR removed that function from `p50.py`. This breaks test collection with `ImportError`.

### Issue Context
You introduced `Algorithms.numerical_methods.euler.utils.sieve` and updated `consecutive_prime_sum` to use it, but didn’t preserve the old public API.

### Fix Focus Areas
- Algorithms/numerical_methods/euler/p50.py[1-21]
- tests/euler/p50_test.py[1-12]

### Suggested fix
Either:
1) Preserve backward compatibility by re-exporting:
```py
from Algorithms.numerical_methods.euler.utils import sieve  # re-export
```
or `sieve = utils.sieve`,

OR
2) Update all callers/tests to import `sieve` from `Algorithms.numerical_methods.euler.utils` instead of `p50`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Replacement index can overflow 🐞 Bug ☼ Reliability
Description
prime_digit_replacements indexes is_prime[replacement] without ensuring replacement <= n, but
possible_replacements can generate values larger than the sieve limit, causing IndexError and
aborting the search.
Code

Algorithms/numerical_methods/euler/p51.py[R27-29]

+            for replacement in possible_replacements(p, digit):
+                if is_prime[replacement]:
+                    valid_primes += 1
Relevance

⭐⭐ Medium

Team accepts some runtime-crash fixes (PR54) but often rejects defensive hardening elsewhere;
unclear.

PR-#54
PR-#18

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
utils.sieve(n) returns a list sized n+1, while possible_replacements mutates digits without
reference to n, and prime_digit_replacements indexes the sieve list directly using these mutated
values.

Algorithms/numerical_methods/euler/utils.py[3-15]
Algorithms/numerical_methods/euler/p51.py[5-14]
Algorithms/numerical_methods/euler/p51.py[21-29]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`utils.sieve(n)` builds `is_prime` only for indices `[0..n]`, but `possible_replacements(p, digit)` can produce integers larger than `n`. Indexing `is_prime[replacement]` can raise `IndexError`.

### Issue Context
This is reachable whenever a prime `p <= n` has the same digit-length as `n` (or close to it) and replacements increase `p` beyond `n`.

### Fix Focus Areas
- Algorithms/numerical_methods/euler/p51.py[21-32]
- Algorithms/numerical_methods/euler/p51.py[5-14]
- Algorithms/numerical_methods/euler/utils.py[3-15]

### Suggested fix
Treat out-of-range replacements as non-prime:
```py
for replacement in possible_replacements(p, digit):
   if 0 <= replacement <= n and is_prime[replacement]:
       valid_primes += 1
```
Alternatively, compute the maximum possible replacement value and sieve up to that limit (but that may increase runtime/memory).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Debug print in search ✓ Resolved 🐞 Bug ◔ Observability
Description
prime_digit_replacements prints replacement sets when a match is found, creating unwanted stdout
side effects for library callers and test runs.
Code

Algorithms/numerical_methods/euler/p51.py[R30-32]

+            if valid_primes == prime_family:
+                print(possible_replacements(p, digit))
+                return p
Relevance

⭐⭐⭐ High

Team has accepted removing print/side effects to keep output clean (PR48).

PR-#48

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The function contains an unconditional print(...) right before returning the found prime.

Algorithms/numerical_methods/euler/p51.py[21-33]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`prime_digit_replacements` unconditionally prints to stdout on success, which is a side effect in a utility function.

### Issue Context
This can pollute test output and makes the function harder to reuse as a library call.

### Fix Focus Areas
- Algorithms/numerical_methods/euler/p51.py[30-32]

### Suggested fix
Remove the `print(...)`, or replace it with optional logging / a `verbose: bool = False` flag that controls whether anything is emitted.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Wrong return type annotation ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
possible_replacements is annotated to return List[int] but actually returns a set (uses set
literals and set union), misleading callers and breaking static typing.
Code

Algorithms/numerical_methods/euler/p51.py[R5-14]

+def possible_replacements(n: int, digit: int) -> List[int]:
+    max_digits = math.floor(math.log(n, 10))+1
+    def replace_digit(n: int, digit: int, pos: int):
+        pos_val = (n % (10**pos)) // (10**(pos-1))
+        new_n = n+(digit-pos_val) * (10**(pos-1))
+        if pos == max_digits:
+            return {new_n, n}
+        else:
+            return replace_digit(n, digit, pos+1) | replace_digit(new_n, digit, pos+1)
+    return replace_digit(n, digit, pos=1)
Relevance

⭐⭐ Medium

No clear historical pattern on enforcing type annotations vs runtime behavior in Euler modules.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The function constructs and unions sets, therefore it cannot return a list without an explicit
conversion.

Algorithms/numerical_methods/euler/p51.py[5-14]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`possible_replacements` returns a set, but its signature declares `List[int]`.

### Issue Context
The implementation uses `{...}` and the set union operator `|`, so the runtime return type is `set[int]`.

### Fix Focus Areas
- Algorithms/numerical_methods/euler/p51.py[5-14]

### Suggested fix
Change the return annotation to `Set[int]` (and `from typing import Set`) or to `set[int]` if the repo targets Python 3.9+:
```py
from typing import Set

def possible_replacements(...) -> Set[int]:
   ...
```
Alternatively, convert the result to a list before returning if ordering is desired.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. p51 test asserts nothing 🐞 Bug ⚙ Maintainability
Description
tests/euler/p51_test.py only prints the result and has no assertions, so it will pass even if
prime_digit_replacements returns an incorrect value or None.
Code

tests/euler/p51_test.py[R1-4]

+from Algorithms.numerical_methods.euler.p51 import prime_digit_replacements
+
+def test_sol():
+    print(prime_digit_replacements(n=1000000,prime_family=8,start_point=56007))
Relevance

⭐ Low

Similar “print-based test” improvements were rejected before; team may allow non-asserting/print
tests (PR16).

PR-#16

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new p51 test only prints, while existing Euler tests use assertions to validate exact expected
outputs.

tests/euler/p51_test.py[1-4]
tests/euler/p50_test.py[11-12]
tests/euler/p49_test.py[1-8]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The new test prints output but does not assert correctness, making it ineffective for CI.

### Issue Context
Other Euler tests in this repo assert known expected answers.

### Fix Focus Areas
- tests/euler/p51_test.py[1-4]
- tests/euler/p50_test.py[11-12]
- tests/euler/p49_test.py[3-8]

### Suggested fix
Replace the `print(...)` with assertions, e.g.:
- Assert the expected known answer for the chosen parameters, OR
- At minimum assert the result is not `None` and is within `[2..n]`.
Also remove printing from tests to keep CI output clean.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Qodo Logo

Comment thread Algorithms/numerical_methods/euler/p51.py Outdated
Comment thread Algorithms/numerical_methods/euler/p51.py Outdated
Comment thread Algorithms/numerical_methods/euler/p51.py Outdated
Comment thread Algorithms/numerical_methods/euler/p50.py
@dchou1618
dchou1618 merged commit 8ea06be into master Jul 26, 2026
5 checks passed
@dchou1618
dchou1618 deleted the feature/p51 branch July 26, 2026 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant