Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions Algorithm_tests/math_tests/mobius_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Import the mobius function
import sys
import unittest

# For importing from different folders
# OBS: This is supposed to be done with automated testing, hence relative to folder we want to import from
sys.path.append("Algorithms/math/mobius")

# If run from local:
# sys.path.append('../../Algorithms/math/mobius')

from mobius import mobius


class TestMobius(unittest.TestCase):
"""Test cases for the Mobius function."""

def test_mobius_one(self):
"""Test μ(1) = 1 (special case, zero prime factors)."""
self.assertEqual(mobius(1), 1)

def test_mobius_prime_two(self):
"""Test μ(2) = -1 (single prime factor)."""
self.assertEqual(mobius(2), -1)

def test_mobius_prime_three(self):
"""Test μ(3) = -1 (single prime factor)."""
self.assertEqual(mobius(3), -1)

def test_mobius_prime_large(self):
"""Test μ(17) = -1 (single prime factor - larger prime)."""
self.assertEqual(mobius(17), -1)

def test_mobius_two_primes(self):
"""Test μ(6) = 1 (two distinct prime factors: 2 × 3)."""
self.assertEqual(mobius(6), 1)

def test_mobius_two_primes_alternative(self):
"""Test μ(10) = 1 (two distinct prime factors: 2 × 5)."""
self.assertEqual(mobius(10), 1)

def test_mobius_three_primes(self):
"""Test μ(30) = -1 (three distinct prime factors: 2 × 3 × 5)."""
self.assertEqual(mobius(30), -1)

def test_mobius_three_primes_alternative(self):
"""Test μ(42) = -1 (three distinct prime factors: 2 × 3 × 7)."""
self.assertEqual(mobius(42), -1)

def test_mobius_four_primes(self):
"""Test μ(210) = 1 (four distinct prime factors: 2 × 3 × 5 × 7)."""
self.assertEqual(mobius(210), 1)

def test_mobius_five_primes(self):
"""Test μ(2310) = -1 (five distinct prime factors: 2 × 3 × 5 × 7 × 11)."""
self.assertEqual(mobius(2310), -1)

def test_mobius_squared_prime_four(self):
"""Test μ(4) = 0 (4 = 2², has squared factor)."""
self.assertEqual(mobius(4), 0)

def test_mobius_squared_prime_nine(self):
"""Test μ(9) = 0 (9 = 3², has squared factor)."""
self.assertEqual(mobius(9), 0)

def test_mobius_squared_factor_twelve(self):
"""Test μ(12) = 0 (12 = 2² × 3, has squared factor)."""
self.assertEqual(mobius(12), 0)

def test_mobius_squared_factor_eighteen(self):
"""Test μ(18) = 0 (18 = 2 × 3², has squared factor)."""
self.assertEqual(mobius(18), 0)

def test_mobius_squared_factor_large(self):
"""Test μ(72) = 0 (72 = 2³ × 3², has squared factors)."""
self.assertEqual(mobius(72), 0)

def test_mobius_squared_factor_hundred(self):
"""Test μ(100) = 0 (100 = 2² × 5², has squared factors)."""
self.assertEqual(mobius(100), 0)

def test_mobius_square_free_fifteen(self):
"""Test μ(15) = 1 (15 = 3 × 5, two distinct primes)."""
self.assertEqual(mobius(15), 1)

def test_mobius_square_free_thirtyfive(self):
"""Test μ(35) = 1 (35 = 5 × 7, two distinct primes)."""
self.assertEqual(mobius(35), 1)

def test_mobius_square_free_oneohfive(self):
"""Test μ(105) = -1 (105 = 3 × 5 × 7, three distinct primes)."""
self.assertEqual(mobius(105), -1)

def test_mobius_invalid_zero(self):
"""Test that μ(0) raises ValueError."""
with self.assertRaises(ValueError):
mobius(0)

def test_mobius_invalid_negative(self):
"""Test that μ(-5) raises ValueError."""
with self.assertRaises(ValueError):
mobius(-5)

def test_mobius_invalid_float(self):
"""Test that μ(3.5) raises ValueError."""
with self.assertRaises(ValueError):
mobius(3.5)

def test_mobius_invalid_string(self):
"""Test that μ('10') raises ValueError."""
with self.assertRaises(ValueError):
mobius('10')


if __name__ == "__main__":
print("Running Mobius function tests:")
unittest.main()
95 changes: 95 additions & 0 deletions Algorithms/math/mobius/mobius.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""
The Mobius function μ(n) is an important function in number theory.

Definition:
- μ(n) = 1 if n is a square-free positive integer with an even number of prime factors.
- μ(n) = -1 if n is a square-free positive integer with an odd number of prime factors.
- μ(n) = 0 if n has a squared prime factor (i.e., n is not square-free).

A number is square-free if it is not divisible by any perfect square other than 1.

Examples:
- μ(1) = 1 (by definition, 1 has zero prime factors, which is even)
- μ(2) = -1 (2 has one prime factor: 2, which is odd)
- μ(6) = 1 (6 = 2 × 3, two distinct prime factors, which is even)
- μ(12) = 0 (12 = 2² × 3, has a squared factor 2²)
- μ(30) = -1 (30 = 2 × 3 × 5, three distinct prime factors, which is odd)

Time complexity: O(sqrt(n))
Space complexity: O(1)

Programmed by [Your Name]
* 2026-01-24 Initial implementation
"""


def mobius(n):
"""
Calculate the Mobius function μ(n) for a given positive integer n.

Args:
n (int): A positive integer

Returns:
int: The Mobius function value (1, -1, or 0)

Raises:
ValueError: If n is not a positive integer

Examples:
>>> mobius(1)
1
>>> mobius(2)
-1
>>> mobius(6)
1
>>> mobius(12)
0
>>> mobius(30)
-1
"""
if not isinstance(n, int) or n < 1:
raise ValueError("n must be a positive integer")

# Special case: μ(1) = 1
if n == 1:
return 1

prime_factor_count = 0

# Check for factor 2
if n % 2 == 0:
prime_factor_count += 1
n //= 2
# If 2 appears more than once, n is not square-free
if n % 2 == 0:
return 0

# Check for odd factors from 3 onwards
i = 3
while i * i <= n:
if n % i == 0:
prime_factor_count += 1
n //= i
# If this prime appears more than once, n is not square-free
if n % i == 0:
return 0
i += 2

# If n > 1, then it's a prime factor
if n > 1:
prime_factor_count += 1

# Return 1 if even number of prime factors, -1 if odd
return 1 if prime_factor_count % 2 == 0 else -1


if __name__ == "__main__":
# Test examples
test_cases = [1, 2, 3, 6, 12, 30, 42, 105, 210]

print("Mobius Function Examples:")
print("-" * 40)
for num in test_cases:
result = mobius(num)
print(f"μ({num:3d}) = {result:2d}")