Troubleshooting - adylagad/CSCI-561_Genetic-Algorithm GitHub Wiki
Troubleshooting Guide
Solutions to common problems and issues.
๐จ Installation Issues
ModuleNotFoundError: No module named 'genetic_algorithm'
Error:
ModuleNotFoundError: No module named 'genetic_algorithm'
Cause: Running from wrong directory
Solution:
# Make sure you're in project root
cd CSCI-561_Genetic-Algorithm
python main.py # Not in subdirectory!
# Check current directory
pwd # Should end in CSCI-561_Genetic-Algorithm
Python version too old
Error:
SyntaxError: invalid syntax (type hints)
Cause: Python < 3.7
Solution:
# Check version
python --version
# Upgrade Python (macOS)
brew install [email protected]
# Or use python3
python3 main.py
๐ Runtime Errors
FileNotFoundError: input/input1.txt
Error:
FileNotFoundError: [Errno 2] No such file or directory: 'input/input1.txt'
Cause: Missing input file or wrong directory
Solution 1: Check file exists
ls input/input1.txt
# Should show the file
Solution 2: Provide correct path
config = GAConfig(input_file="path/to/your/input.txt")
Solution 3: Create input file
# Create directory
mkdir input
# Create file
echo "3
0 0 0
1 0 0
0 1 0" > input/test.txt
ValueError: Invalid tour
Error:
ValueError: Tour contains duplicate cities
Cause: Operator created invalid tour
Solution: Check custom operators
def crossover(self, parent1: Tour, parent2: Tour) -> Tour:
offspring = ...
# Validate before returning
assert len(offspring) == len(parent1)
assert len(set(offspring)) == len(offspring) # No duplicates
assert set(offspring) == set(parent1) # Same cities
return offspring
TypeError: 'NoneType' object is not iterable
Error:
TypeError: 'NoneType' object is not iterable
Cause: Operator returned None instead of valid result
Solution:
def mutate(self, tour: Tour) -> Tour:
mutated = tour.copy()
# ... mutation logic ...
return mutated # Make sure to return!
๐ Performance Issues
Algorithm not improving
Symptoms:
Generation 0: 120,000
Generation 1000: 118,000
Generation 2000: 117,500
Generation 3000: 117,000 # Barely improving!
Diagnosis:
# Check improvement rate
initial = 120000
final = 117000
improvement = (initial - final) / initial * 100
print(f"Improvement: {improvement:.1f}%")
# Should be >50%
Solutions:
1. Verify operators are working:
# Test crossover
parent1 = [0, 1, 2, 3, 4]
parent2 = [4, 3, 2, 1, 0]
offspring = crossover.cross(parent1, parent2)
print(f"Offspring: {offspring}")
# Should be different from parents
# Test mutation
original = [0, 1, 2, 3, 4]
mutated = mutation.mutate([original])[0]
print(f"Original: {original}")
print(f"Mutated: {mutated}")
# Should be different (usually)
2. Check fitness calculation:
# Lower cost should = higher fitness
tour1_cost = 50000
tour2_cost = 60000
fitness1 = 1 / tour1_cost
fitness2 = 1 / tour2_cost
assert fitness1 > fitness2, "Fitness calculation wrong!"
3. Increase exploration:
config = GAConfig(
mutation_rate=0.10, # Higher mutation
population_size_multiplier=2.0 # Larger population
)
Converges too quickly (premature convergence)
Symptoms:
Generation 0: 120,000
Generation 100: 60,000
Generation 200: 58,000
Generation 300: 57,900 # Stuck early!
...
Generation 3000: 57,900 # No more improvement
Diagnosis:
convergence_gen = stats['convergence_generation']
total_gen = stats['total_generations']
ratio = convergence_gen / total_gen
if ratio < 0.3:
print("โ ๏ธ Converging too fast!")
Solutions:
1. Increase diversity:
config = GAConfig(
population_size_multiplier=1.5, # Bigger population
mutation_rate=0.05 # More mutation
)
2. Use tournament selection:
# Less selection pressure
selection = TournamentSelection(tournament_size=3)
crossover = OrderCrossover(selection)
3. Reduce elitism (advanced):
# In GeneticAlgorithm.evolve()
# Keep fewer elite individuals
elite_count = int(0.05 * population_size) # Only 5%
Poor solution quality
Symptoms: Final cost is very high
Expected benchmarks (500 cities):
- Good: <50,000
- Acceptable: 50,000-55,000
- Poor: >55,000
Solutions:
1. Run longer:
config = GAConfig(number_of_generations=10000)
2. Better initialization:
initializer = NearestNeighborInitializer() # Not Random
3. Better crossover:
crossover = PMXCrossover(selection) # Try PMX instead of Order
4. Tune parameters:
config = GAConfig(
population_size_multiplier=2.0,
mutation_rate=0.03,
number_of_generations=5000
)
Taking too long
Symptoms: Runtime exceeds expectations
Benchmarks (500 cities):
- Expected: 3-5 minutes
- Slow: >10 minutes
- Very slow: >20 minutes
Diagnosis:
import cProfile
# Profile code
cProfile.run('ga.run(cities, tour_size)')
# Look for bottlenecks
Solutions:
1. Reduce parameters:
config = GAConfig(
population_size_multiplier=0.5, # Smaller population
number_of_generations=1000, # Fewer generations
convergence_threshold=100 # Stop earlier
)
2. Use faster operators:
# OrderCrossover is faster than PMX
crossover = OrderCrossover(selection)
# SwapMutation is fastest
mutation = SwapMutation(mutation_rate=0.02)
3. Reduce logging:
config = GAConfig(
log_interval=500, # Log less frequently
verbose=False # Disable verbose output
)
๐งช Testing Issues
Tests failing
Error:
FAILED (failures=5)
Solution 1: Check you haven't modified core code
git status # See what changed
git diff main.py # See differences
Solution 2: Check Python version
python --version
# Should be 3.7+
Solution 3: Run specific test
python -m unittest test_ga.TestGeneticAlgorithm.test_ga_improves_solution
Random test failures
Symptoms: Tests pass sometimes, fail sometimes
Cause: Stochastic nature of GA
Solution: Set random seed
def test_my_function(self):
random.seed(42) # Fixed seed
result = ga.run(cities, tour_size)
# Now deterministic
๐ง Configuration Issues
JSON configuration not loading
Error:
JSONDecodeError: Expecting value
Solution: Validate JSON syntax
# Check JSON is valid
python -m json.tool config/my_config.json
# Common issues:
# - Trailing commas
# - Missing quotes
# - Wrong brackets
Valid JSON example:
{
"mutation_rate": 0.05,
"number_of_generations": 5000
}
Configuration not taking effect
Problem: Changed config but no difference
Solution: Verify config is loaded
config = GAConfig(mutation_rate=0.10)
print(f"Mutation rate: {config.mutation_rate}")
# Should print: 0.10
# Make sure you're using this config
ga = GeneticAlgorithm(config=config, ...)
๐ Output Issues
Statistics showing 'N/A' or None
Problem: Statistics dict has None values
Solution: Check algorithm ran completely
try:
result = ga.run(cities, tour_size)
stats = ga.get_statistics()
print(stats) # Should have all values
except Exception as e:
print(f"Error: {e}")
Tour has wrong format
Problem: Tour doesn't match expected format
Solution: Understand tour representation
# Tour is list of city INDICES (not coordinates)
tour = [0, 2, 1, 3] # Visit city 0, then 2, then 1, then 3
# To get coordinates:
tour_coords = [cities[i] for i in tour]
# [(x0,y0,z0), (x2,y2,z2), (x1,y1,z1), (x3,y3,z3)]
๐ Debugging Strategies
Enable debug logging
config = GAConfig(log_level="DEBUG", verbose=True)
Output:
DEBUG - Reading input from: input/input1.txt
DEBUG - Loaded 500 cities
DEBUG - Initializing population...
DEBUG - Generation 0: Best = 62308.19, Avg = 85432.11
...
Add print statements
def cross(self, parent1: Tour, parent2: Tour) -> Tour:
print(f"Parent1: {parent1[:5]}...") # First 5 cities
offspring = ...
print(f"Offspring: {offspring[:5]}...")
return offspring
Validate intermediate results
# After initialization
print(f"Initial population size: {len(population)}")
print(f"Initial best cost: {min_cost}")
# After each generation
print(f"Gen {gen}: Best={best_cost:.2f}, Avg={avg_cost:.2f}")
# After evolution
print(f"Final best: {final_cost:.2f}")
print(f"Improvement: {(initial - final) / initial * 100:.1f}%")
Use assertions
def validate_tour(tour: Tour, expected_size: int):
"""Validate tour is correct."""
assert len(tour) == expected_size, f"Wrong size: {len(tour)}"
assert len(set(tour)) == expected_size, "Duplicate cities!"
assert min(tour) == 0, "City indices should start at 0"
assert max(tour) == expected_size - 1, "City index out of range"
# Use it
validate_tour(offspring, len(cities))
๐ Still Having Issues?
Check these resources
- FAQ - Common questions
- Configuration Reference - Parameter details
- API Reference - Function documentation
- Performance Tuning - Optimization guide
Report a bug
If you found a bug:
-
Check it's reproducible:
random.seed(42) # Run code -
Create minimal example:
# Simplest code that shows the bug -
Open GitHub issue with:
- Error message
- Code to reproduce
- Python version
- Operating system
Quick checklist:
- In correct directory?
- Python 3.7+?
- Input file exists?
- Operators return valid tours?
- Configuration loaded?
- Tried default config?
- Checked FAQ?