import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import distance
from coords_nsga2 import CoordsNSGA2, Problem
from coords_nsga2.spatial import region_from_range
# Define the monitoring area
region = region_from_range(0, 20, 0, 15)
# Define objective functions
def objective_coverage(coords):
"""Maximize coverage area"""
coverage_radius = 3.0
x_grid, y_grid = np.meshgrid(np.linspace(0, 20, 50), np.linspace(0, 15, 40))
grid_points = np.column_stack([x_grid.ravel(), y_grid.ravel()])
covered_points = 0
for grid_point in grid_points:
distances = np.sqrt(np.sum((coords - grid_point)**2, axis=1))
if np.any(distances <= coverage_radius):
covered_points += 1
return covered_points / len(grid_points) # Coverage ratio
def objective_energy_efficiency(coords):
"""Maximize energy efficiency (minimize total transmission distance)"""
center = np.array([10, 7.5])
distances = np.sqrt(np.sum((coords - center)**2, axis=1))
total_distance = np.sum(distances)
return -total_distance # Negative sign because we maximize
# Define constraints
def constraint_sensor_spacing(coords):
"""Minimum spacing between sensors"""
dist_list = distance.pdist(coords)
min_spacing = 2.0
violations = min_spacing - dist_list[dist_list < min_spacing]
return np.sum(violations)
def constraint_battery_life(coords):
"""Battery-life constraint (based on distance to the center node)"""
center = np.array([10, 7.5])
distances = np.sqrt(np.sum((coords - center)**2, axis=1))
max_distance = 12.0
violations = distances[distances > max_distance] - max_distance
return np.sum(violations)
# Create the problem
problem = Problem(
objectives=[objective_coverage, objective_energy_efficiency],
n_points=8, # 8 sensors
region=region,
constraints=[constraint_sensor_spacing, constraint_battery_life]
)
# Create the optimizer
optimizer = CoordsNSGA2(
problem=problem,
pop_size=40,
prob_crs=0.6,
prob_mut=0.03
)
# Run the optimization
result = optimizer.run(600)
# Visualize the results
plt.figure(figsize=(16, 12))
# Plot monitoring area and sensor deployment
plt.subplot(2, 3, 1)
x, y = region.exterior.xy
plt.fill(x, y, alpha=0.1, fc='lightgreen', ec='green', label='Monitoring Area')
from coords_nsga2.utils import fast_non_dominated_sort
fronts = fast_non_dominated_sort(optimizer.values_P)
pareto_solutions = result[fronts[0]]
# Plot the first Pareto-optimal solution
best_solution = pareto_solutions[0]
plt.scatter(best_solution[:, 0], best_solution[:, 1],
c='red', marker='s', s=200, label='Sensors')
coverage_radius = 3.0
for sensor in best_solution:
circle = plt.Circle(sensor, coverage_radius, alpha=0.2, fc='blue')
plt.gca().add_patch(circle)
plt.scatter(10, 7.5, c='black', marker='*', s=300, label='Center Node')
plt.title('Sensor Network Deployment')
plt.xlabel('X Coordinate')
plt.ylabel('Y Coordinate')
plt.legend()
plt.grid(True)
# Plot objective-function space
plt.subplot(2, 3, 2)
plt.scatter(optimizer.values_P[0], optimizer.values_P[1], alpha=0.6, label='All Solutions')
plt.scatter(optimizer.values_P[0][fronts[0]], optimizer.values_P[1][fronts[0]],
c='red', s=100, label='Pareto Front')
plt.title('Objective Function Space')
plt.xlabel('Coverage Rate')
plt.ylabel('Energy Efficiency')
plt.legend()
plt.grid(True)
# Plot optimization history
plt.subplot(2, 3, 3)
best_coverage = [np.max(vals[0]) for vals in optimizer.values_history]
best_energy = [np.max(vals[1]) for vals in optimizer.values_history]
plt.plot(best_coverage, label='Best Coverage')
plt.plot(best_energy, label='Best Energy Efficiency')
plt.title('Optimization History')
plt.xlabel('Generation')
plt.ylabel('Best Objective Value')
plt.legend()
plt.grid(True)
# Plot population diversity
plt.subplot(2, 3, 4)
diversity_coverage = [np.std(vals[0]) for vals in optimizer.values_history]
diversity_energy = [np.std(vals[1]) for vals in optimizer.values_history]
plt.plot(diversity_coverage, label='Coverage Diversity')
plt.plot(diversity_energy, label='Energy Diversity')
plt.title('Population Diversity')
plt.xlabel('Generation')
plt.ylabel('Standard Deviation')
plt.legend()
plt.grid(True)
# Plot population averages
plt.subplot(2, 3, 5)
avg_coverage = [np.mean(vals[0]) for vals in optimizer.values_history]
avg_energy = [np.mean(vals[1]) for vals in optimizer.values_history]
plt.plot(avg_coverage, label='Average Coverage')
plt.plot(avg_energy, label='Average Energy Efficiency')
plt.title('Population Average')
plt.xlabel('Generation')
plt.ylabel('Average Objective Value')
plt.legend()
plt.grid(True)
# Plot Pareto front
plt.subplot(2, 3, 6)
pareto_coverage = optimizer.values_P[0][fronts[0]]
pareto_energy = optimizer.values_P[1][fronts[0]]
plt.scatter(pareto_coverage, pareto_energy, c='red', s=100)
plt.title('Pareto Front')
plt.xlabel('Coverage Rate')
plt.ylabel('Energy Efficiency')
plt.grid(True)
plt.tight_layout()
plt.show()
# Output summary
print("Sensor-network deployment optimization completed")
print(f"Found {len(pareto_solutions)} Pareto-optimal solutions")
print(f"Best coverage: {np.max(optimizer.values_P[0]):.4f}")
print(f"Best energy efficiency: {np.max(optimizer.values_P[1]):.4f}")