-
Notifications
You must be signed in to change notification settings - Fork 5
Number Theory Library #1
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
base: main
Are you sure you want to change the base?
Conversation
…265e59-merged Robust Mathematical Utilities: Prime Operations and GCD Optimization
WalkthroughThis update introduces three new source modules: one for computing the greatest common divisor (GCD) using prime factorization, one for checking if a number is prime, and one for performing prime factorization. Corresponding test files are added for each module, covering a variety of input scenarios, edge cases, and error handling using unit tests. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant GCDCalculator
participant PrimeFactorization
participant PrimeChecker
User->>GCDCalculator: gcd_prime_factors(a, b)
GCDCalculator->>PrimeFactorization: get_prime_factors(a)
GCDCalculator->>PrimeFactorization: get_prime_factors(b)
GCDCalculator-->>User: GCD result
User->>PrimeChecker: is_prime(n)
PrimeChecker-->>User: True/False
User->>PrimeFactorization: prime_factorization(n)
PrimeFactorization-->>User: List of prime factors
Poem
Note ⚡️ AI Code Reviews for VS Code, Cursor, WindsurfCodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback. Note ⚡️ Faster reviews with cachingCodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure ✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 3
🧹 Nitpick comments (8)
src/prime_checker.py (1)
23-27: Consider using Python'sall()function for better readability.The current loop-based implementation can be simplified using Python's
all()function with a generator expression. This makes the code more concise and potentially more readable.- # Optimization: check divisibility up to square root of the number - for i in range(2, int(number**0.5) + 1): - if number % i == 0: - return False - - return True + # Optimization: check divisibility up to square root of the number + return all(number % i != 0 for i in range(2, int(number**0.5) + 1))tests/test_prime_checker.py (5)
7-8: Use implicit boolean comparison instead of explicit comparison to True.Python style guides recommend using the implicit boolean value of expressions rather than comparing directly to True/False.
- assert is_prime(prime) == True, f"{prime} should be prime" + assert is_prime(prime), f"{prime} should be prime"🧰 Tools
🪛 Ruff (0.11.9)
8-8: Avoid equality comparisons to
True; useif is_prime(prime):for truth checksReplace with
is_prime(prime)(E712)
13-14: Use implicit boolean comparison instead of explicit comparison to False.Similar to the previous comment, it's more Pythonic to use the implicit boolean value.
- assert is_prime(non_prime) == False, f"{non_prime} should not be prime" + assert not is_prime(non_prime), f"{non_prime} should not be prime"🧰 Tools
🪛 Ruff (0.11.9)
14-14: Avoid equality comparisons to
False; useif not is_prime(non_prime):for false checksReplace with
not is_prime(non_prime)(E712)
16-18: Use implicit boolean comparison instead of explicit comparison to True.For consistent style, use the implicit boolean check.
- assert is_prime(104729) == True, "Large prime number not recognized" + assert is_prime(104729), "Large prime number not recognized"🧰 Tools
🪛 Ruff (0.11.9)
18-18: Avoid equality comparisons to
True; useif is_prime(104729):for truth checksReplace with
is_prime(104729)(E712)
20-22: Use implicit boolean comparison instead of explicit comparison to False.Again, avoiding explicit comparison to False improves code style.
- assert is_prime(100000) == False, "Large non-prime number not detected" + assert not is_prime(100000), "Large non-prime number not detected"🧰 Tools
🪛 Ruff (0.11.9)
22-22: Avoid equality comparisons to
False; useif not is_prime(100000):for false checksReplace with
not is_prime(100000)(E712)
24-26: Use implicit boolean comparison instead of explicit comparison to False.For consistency, modify this comparison too.
- assert is_prime(-7) == False, "Negative numbers should not be prime" + assert not is_prime(-7), "Negative numbers should not be prime"🧰 Tools
🪛 Ruff (0.11.9)
26-26: Avoid equality comparisons to
False; useif not is_prime(-7):for false checksReplace with
not is_prime(-7)(E712)
tests/test_prime_factorization.py (1)
33-40: Simplify the is_prime helper functionThe implementation is correct, but can be simplified using a list comprehension as suggested by static analysis.
-def is_prime(n: int) -> bool: - """Helper function to check if a number is prime.""" - if n < 2: - return False - for i in range(2, int(n**0.5) + 1): - if n % i == 0: - return False - return True +def is_prime(n: int) -> bool: + """Helper function to check if a number is prime.""" + if n < 2: + return False + return all(n % i != 0 for i in range(2, int(n**0.5) + 1))🧰 Tools
🪛 Ruff (0.11.9)
37-40: Use
return all(n % i != 0 for i in range(2, int(n ** 0.5) + 1))instead offorloopReplace with
return all(n % i != 0 for i in range(2, int(n ** 0.5) + 1))(SIM110)
src/gcd_calculator.py (1)
1-2: Remove unused importThe
Uniontype is imported but not used in the code.-from typing import List, Union +from typing import List from math import sqrt🧰 Tools
🪛 Ruff (0.11.9)
1-1:
typing.Unionimported but unusedRemove unused import:
typing.Union(F401)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting
📒 Files selected for processing (6)
src/gcd_calculator.py(1 hunks)src/prime_checker.py(1 hunks)src/prime_factorization.py(1 hunks)tests/test_gcd_calculator.py(1 hunks)tests/test_prime_checker.py(1 hunks)tests/test_prime_factorization.py(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
tests/test_gcd_calculator.py (1)
src/gcd_calculator.py (2)
gcd_prime_factors(43-91)get_prime_factors(4-41)
tests/test_prime_factorization.py (1)
src/prime_factorization.py (1)
prime_factorization(3-47)
🪛 Ruff (0.11.9)
tests/test_prime_checker.py
8-8: Avoid equality comparisons to True; use if is_prime(prime): for truth checks
Replace with is_prime(prime)
(E712)
14-14: Avoid equality comparisons to False; use if not is_prime(non_prime): for false checks
Replace with not is_prime(non_prime)
(E712)
18-18: Avoid equality comparisons to True; use if is_prime(104729): for truth checks
Replace with is_prime(104729)
(E712)
22-22: Avoid equality comparisons to False; use if not is_prime(100000): for false checks
Replace with not is_prime(100000)
(E712)
26-26: Avoid equality comparisons to False; use if not is_prime(-7): for false checks
Replace with not is_prime(-7)
(E712)
src/prime_checker.py
24-28: Use return all(number % i != 0 for i in range(2, int(number ** 0.5) + 1)) instead of for loop
Replace with return all(number % i != 0 for i in range(2, int(number ** 0.5) + 1))
(SIM110)
src/gcd_calculator.py
1-1: typing.Union imported but unused
Remove unused import: typing.Union
(F401)
tests/test_prime_factorization.py
37-40: Use return all(n % i != 0 for i in range(2, int(n ** 0.5) + 1)) instead of for loop
Replace with return all(n % i != 0 for i in range(2, int(n ** 0.5) + 1))
(SIM110)
🔇 Additional comments (21)
src/prime_checker.py (2)
16-17: LGTM! Good input validation.The function correctly validates the input type by checking if it's an integer and raises a TypeError with a clear error message.
19-21: LGTM! Correct handling of special cases.The function properly handles the case where the number is less than 2 by returning False, which is correct as numbers less than 2 are not prime.
src/prime_factorization.py (6)
16-18: LGTM! Good input type validation.The function correctly validates that the input is an integer type.
20-21: LGTM! Good input value validation.The function properly checks that the input is a positive integer, raising a ValueError with a clear error message if not.
23-25: LGTM! Correct handling of special case for n=1.Returning an empty list for n=1 is mathematically correct, as 1 has no prime factors.
30-33: LGTM! Efficient handling of factor 2.Handling the factor 2 separately is an optimization that allows subsequent checking of only odd numbers, reducing the number of iterations.
35-41: LGTM! Good implementation of odd factor checking.This algorithm efficiently checks odd factors by starting at 3 and incrementing by 2, examining only odd numbers. The loop condition correctly uses
factor * factor <= nto optimize the search range.
43-45: LGTM! Properly handles the remaining prime factor.After checking divisibility by smaller factors, if n > 2 remains, it must be a prime factor itself. This step correctly appends it to the factors list.
tests/test_prime_checker.py (1)
28-37: LGTM! Comprehensive testing of invalid input types.The tests properly check that TypeError is raised for various non-integer inputs (string, float, None). This helps ensure robust input validation.
tests/test_gcd_calculator.py (5)
4-9: LGTM! Good basic test coverage for prime factorization.The tests cover various typical cases and verify the expected prime factors. The test for input 1 correctly checks that it returns [1], which matches the implementation in the gcd_calculator.py module.
11-16: LGTM! Proper testing of edge cases.The tests correctly verify that ValueError is raised for invalid inputs (0 and negative numbers), which matches the implementation requirements.
18-25: LGTM! Comprehensive GCD testing for typical cases.The tests cover various GCD scenarios including numbers with common factors, coprime numbers, and special cases with zeros. This ensures the function works correctly across different input patterns.
27-31: LGTM! Good handling of negative numbers.These tests verify that the GCD function correctly handles negative inputs by taking their absolute values, which is the expected mathematical behavior.
33-36: LGTM! Testing with large numbers.Testing the function with large numbers and different scenarios (coprime large numbers and multiples) helps verify both correctness and performance for more challenging inputs.
tests/test_prime_factorization.py (6)
1-2: Good import practices!The necessary modules are properly imported: pytest for testing functionalities and the function under test from the correct module.
4-7: Well-structured basic test cases!These test cases cover different composite numbers with various combinations of prime factors. Good verification of the core functionality.
9-12: Appropriate prime number testing!These tests verify that prime numbers return a list containing only themselves, which is a key property of the prime factorization function.
14-16: Important edge cases covered!Testing edge cases like 1 (which should return an empty list) and 2 (the smallest prime) ensures the function handles boundary conditions correctly.
18-21: Great validation approach for complex cases!Testing a larger number (84) and verifying that all factors are prime adds an additional validation layer that goes beyond just comparing expected outputs.
23-31: Comprehensive invalid input handling!Tests cover all expected error cases: zero, negative numbers, and non-integer inputs. Good use of pytest.raises to verify the correct exceptions are raised.
src/gcd_calculator.py (1)
43-91: Well-implemented GCD via prime factorizationThe implementation correctly:
- Handles special cases (zeros and negative numbers)
- Uses prime factorization to find the GCD
- Properly counts factor occurrences
- Computes the result using the minimum power of each common factor
This approach is mathematically sound, though more complex than the Euclidean algorithm. It's a good educational example of GCD calculation using prime factorization.
| TypeError: If the input is not an integer. | ||
| ValueError: If the input is less than 2. |
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.
Fix docstring inconsistency with implementation.
The docstring states that a ValueError will be raised if the input is less than 2, but the actual implementation returns False for numbers less than 2 rather than raising an exception.
- ValueError: If the input is less than 2.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| TypeError: If the input is not an integer. | |
| ValueError: If the input is less than 2. | |
| TypeError: If the input is not an integer. |
🤖 Prompt for AI Agents
In src/prime_checker.py around lines 12 to 13, the docstring incorrectly states
that a ValueError is raised for inputs less than 2, but the code actually
returns False for these inputs. Update the docstring to reflect that the
function returns False for numbers less than 2 instead of raising a ValueError,
ensuring the documentation matches the implementation.
| import pytest | ||
| from src.gcd_calculator import gcd_prime_factors, get_prime_factors | ||
|
|
||
| def test_get_prime_factors(): | ||
| # Test basic prime factorization | ||
| assert get_prime_factors(12) == [2, 2, 3] | ||
| assert get_prime_factors(15) == [3, 5] | ||
| assert get_prime_factors(7) == [7] | ||
| assert get_prime_factors(1) == [1] | ||
|
|
||
| def test_prime_factors_edge_cases(): | ||
| # Test edge cases | ||
| with pytest.raises(ValueError): | ||
| get_prime_factors(0) | ||
| with pytest.raises(ValueError): | ||
| get_prime_factors(-5) | ||
|
|
||
| def test_gcd_prime_factors(): | ||
| # Test various GCD scenarios | ||
| assert gcd_prime_factors(48, 18) == 6 | ||
| assert gcd_prime_factors(54, 24) == 6 | ||
| assert gcd_prime_factors(17, 23) == 1 # Coprime numbers | ||
| assert gcd_prime_factors(0, 5) == 5 | ||
| assert gcd_prime_factors(5, 0) == 5 | ||
| assert gcd_prime_factors(0, 0) == 0 | ||
|
|
||
| def test_gcd_with_negative_numbers(): | ||
| # Test GCD with negative numbers | ||
| assert gcd_prime_factors(-48, 18) == 6 | ||
| assert gcd_prime_factors(48, -18) == 6 | ||
| assert gcd_prime_factors(-48, -18) == 6 | ||
|
|
||
| def test_gcd_large_numbers(): | ||
| # Test large numbers | ||
| assert gcd_prime_factors(1234567, 7654321) == 1 # Coprime large numbers | ||
| assert gcd_prime_factors(1000000, 10000) == 10000 No newline at end of file |
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.
💡 Verification agent
🧩 Analysis chain
Consider adding tests for the special case of get_prime_factors(1).
The function's implementation returns [1] for input 1, which is correctly tested. However, it's worth noting that mathematically, 1 is not considered a prime number and typically has no prime factors. This implementation detail should be documented if this is the intended behavior.
🌐 Web query:
Is 1 a prime number? Does 1 have prime factors?
💡 Result:
No, 1 is not a prime number, and it does not have any prime factors.
Why 1 Is Not Prime
For a number to be classified as prime, it must have exactly two positive factors: 1 and itself[2]. The number 1 only has one positive factor, which is 1 itself[2][4]. Since it has fewer than two factors, it fails to meet the definition of a prime number.
Another way to understand this is through the formal definition: a prime number is a natural number greater than 1 that cannot be written as the product of two smaller natural numbers[1]. The number 1 is specifically excluded from being prime by this definition.
In mathematical classifications, 1 is considered:
- Neither prime nor composite[2][4]
- A unit[9]
- A natural number
- An odd number
- A rational number
- A positive integer
- A whole number[2]
Historical Perspective
The classification of 1 as non-prime wasn't always universal. Historically, some mathematicians considered 1 to be prime. However, the definition was standardized to exclude 1 primarily because including it would break an important property of prime numbers: the unique prime factorization theorem[3].
If 1 were considered prime, then the prime factorization of any number would not be unique. For example, 6 could be written as:
- 2 × 3
- 2 × 3 × 1
- 2 × 3 × 1 × 1 × 1...
This would make prime factorizations infinitely variable and not unique[3].
Prime Factors of 1
The number 1 has no prime factors[9]. This is consistent with the fact that:
- Prime factorization involves breaking a number down into a product of prime numbers
- The number 1 cannot be broken down further
- 1 itself is not prime, so it cannot be its own prime factor
The smallest prime number is 2, which is also the only even prime number[7].
Citations:
- 1: https://en.wikipedia.org/wiki/Prime_number
- 2: https://byjus.com/maths/is-1-a-prime-number/
- 3: https://www.wgtn.ac.nz/science/ask-a-researcher/is-1-a-prime-number
- 4: https://www.cuemath.com/numbers/is-1-a-prime-number/
- 5: https://www.splashlearn.com/math-vocabulary/algebra/prime-number
- 6: https://www.cuemath.com/numbers/prime-factorization/
- 7: https://blog.targettestprep.com/is-1-a-prime-number/
- 8: https://www.hpmuseum.org/cgi-bin/archv019.cgi?read=171248
- 9: https://en.wikipedia.org/wiki/Table_of_prime_factors
- 10: https://www.ck12.org/flexi/cbse-math/prime-factorization/is-1-a-prime-factor/
Document special-case behavior of get_prime_factors(1)
Although your tests correctly assert that get_prime_factors(1) == [1], mathematically 1 has no prime factors and is neither prime nor composite. To avoid confusion for future maintainers, please explicitly document this design choice (or consider returning an empty list instead).
• In src/gcd_calculator.py, update the get_prime_factors docstring:
def get_prime_factors(n):
- """Return the list of prime factors of n."""
+ """
+ Return the list of prime factors of n.
+
+ Note: By design, get_prime_factors(1) returns [1],
+ even though 1 has no prime factors in standard mathematics.
+ """
# ...Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/gcd_calculator.py around the get_prime_factors function, the current
implementation returns [1] for input 1, which is mathematically inaccurate since
1 has no prime factors. Update the function's docstring to explicitly document
this special-case behavior, clarifying that returning [1] for input 1 is an
intentional design choice to avoid confusion for future maintainers. Optionally,
consider modifying the function to return an empty list for input 1 if you
prefer strict mathematical correctness.
| def get_prime_factors(n: int) -> List[int]: | ||
| """ | ||
| Decompose a number into its prime factors. | ||
|
|
||
| Args: | ||
| n (int): The number to factorize (must be a positive integer) | ||
|
|
||
| Returns: | ||
| List[int]: A list of prime factors | ||
|
|
||
| Raises: | ||
| ValueError: If input is less than 1 | ||
| """ | ||
| if n < 1: | ||
| raise ValueError("Input must be a positive integer") | ||
|
|
||
| # Handle special cases | ||
| if n == 1: | ||
| return [1] | ||
|
|
||
| factors = [] | ||
|
|
||
| # Check for 2 as a factor | ||
| while n % 2 == 0: | ||
| factors.append(2) | ||
| n //= 2 | ||
|
|
||
| # Check for odd prime factors | ||
| for i in range(3, int(sqrt(n)) + 1, 2): | ||
| while n % i == 0: | ||
| factors.append(i) | ||
| n //= i | ||
|
|
||
| # If n is a prime greater than 2 | ||
| if n > 2: | ||
| factors.append(n) | ||
|
|
||
| return factors |
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.
🛠️ Refactor suggestion
Inconsistency in prime factorization behavior for input 1
The implementation is well-structured and efficient, handling special cases and using optimizations like separate handling for the factor 2. However, there's an inconsistency with the prime_factorization function from the other module:
- This
get_prime_factorsreturns[1]for input 1 - The
prime_factorizationfunction returns[]for input 1
This inconsistency could lead to confusion. Consider aligning the behavior with the other function.
# Handle special cases
if n == 1:
- return [1]
+ return []Note: Mathematically, 1 is not a prime number and has no prime factors, so returning an empty list is more accurate.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def get_prime_factors(n: int) -> List[int]: | |
| """ | |
| Decompose a number into its prime factors. | |
| Args: | |
| n (int): The number to factorize (must be a positive integer) | |
| Returns: | |
| List[int]: A list of prime factors | |
| Raises: | |
| ValueError: If input is less than 1 | |
| """ | |
| if n < 1: | |
| raise ValueError("Input must be a positive integer") | |
| # Handle special cases | |
| if n == 1: | |
| return [1] | |
| factors = [] | |
| # Check for 2 as a factor | |
| while n % 2 == 0: | |
| factors.append(2) | |
| n //= 2 | |
| # Check for odd prime factors | |
| for i in range(3, int(sqrt(n)) + 1, 2): | |
| while n % i == 0: | |
| factors.append(i) | |
| n //= i | |
| # If n is a prime greater than 2 | |
| if n > 2: | |
| factors.append(n) | |
| return factors | |
| def get_prime_factors(n: int) -> List[int]: | |
| """ | |
| Decompose a number into its prime factors. | |
| Args: | |
| n (int): The number to factorize (must be a positive integer) | |
| Returns: | |
| List[int]: A list of prime factors | |
| Raises: | |
| ValueError: If input is less than 1 | |
| """ | |
| if n < 1: | |
| raise ValueError("Input must be a positive integer") | |
| # Handle special cases | |
| if n == 1: | |
| return [] | |
| factors = [] | |
| # Check for 2 as a factor | |
| while n % 2 == 0: | |
| factors.append(2) | |
| n //= 2 | |
| # Check for odd prime factors | |
| for i in range(3, int(sqrt(n)) + 1, 2): | |
| while n % i == 0: | |
| factors.append(i) | |
| n //= i | |
| # If n is a prime greater than 2 | |
| if n > 2: | |
| factors.append(n) | |
| return factors |
🤖 Prompt for AI Agents
In src/gcd_calculator.py around lines 4 to 41, the get_prime_factors function
returns [1] for input 1, which is inconsistent with the other module's
prime_factorization function that returns an empty list for input 1. To fix
this, modify the function to return an empty list when n is 1 instead of [1],
aligning the behavior with the other function and reflecting the mathematical
fact that 1 has no prime factors.
Bounty Specification
Create a comprehensive number theory library by implementing functions that build upon each other
Completed Issues
Build a Number Theory Library
Create a comprehensive number theory library by implementing functions that build upon each other
PR: View Changes
Summary by CodeRabbit
New Features
Tests