Skip to content

Usage Guide

⚠️ Important Notice: This document is AI-generated based on source-code analysis. Although we strive for accuracy, inconsistencies or issues may still exist. We are actively improving and validating all content. If you encounter any problems, please report them promptly.

English Usage Guide

Basic Concepts

The core concepts of Coords-NSGA2 library include:

  1. Problem: Defines the optimization problem's objective functions, constraints, and search region
  2. CoordsNSGA2: The optimizer that executes the NSGA-II algorithm
  3. Region: Defines the valid search space for coordinate points
  4. Constraints: Conditions that limit the feasibility of solutions

Quick Start Example

Here's a complete usage example demonstrating how to optimize the layout of 10 coordinate points:

import numpy as np
from scipy.spatial import distance
from coords_nsga2 import CoordsNSGA2, Problem
from coords_nsga2.spatial import region_from_points

# 1. Define optimization region (polygon)
region = region_from_points([
    [0, 0],
    [1, 0],
    [2, 1],
    [1, 1],
])

# 2. Define objective functions
def objective_1(coords):
    """First objective: maximize coordinate sum"""
    return np.sum(coords[:, 0]) + np.sum(coords[:, 1])

def objective_2(coords):
    """Second objective: maximize point spread"""
    return np.std(coords[:, 0]) + np.std(coords[:, 1])

# 3. Define constraints
spacing = 0.05  # minimum spacing
def constraint_1(coords):
    """Constraint: minimum spacing between points"""
    dist_list = distance.pdist(coords)
    penalty_list = spacing - dist_list[dist_list < spacing]
    return np.sum(penalty_list)

# 4. Create problem instance (supports arbitrary number of objectives)
problem = Problem(
    objectives=[objective_1, objective_2],  # Can be a list of functions, or a single function returning a tuple/list of values
    n_points=10,
    region=region,
    constraints=[constraint_1] # Can be a list of functions, or a single function returning a tuple/list of values
)

# 5. Create optimizer
optimizer = CoordsNSGA2(
    problem=problem,
    pop_size=20,
    prob_crs=0.5,
    prob_mut=0.1
)

# 6. Run optimization
result = optimizer.run(1000)

# 7. View results
print(f"Optimization complete! Result shape: {result.shape}")
print(f"Population size: {len(result)}")
print(f"Points per solution: {result.shape[1]}")
# Visualize optimal layouts for each objective
optimizer.plot.optimal_coords(obj_indices=0)

Region Definition

Create polygon region from point list

from coords_nsga2.spatial import region_from_points

# Define polygon vertices
points = [
    [0, 0],
    [1, 0],
    [2, 1],
    [1, 1],
]
region = region_from_points(points)

Create rectangular region from coordinate bounds

1
2
3
4
from coords_nsga2.spatial import region_from_range

# Define rectangle bounds
region = region_from_range(x_min=0, x_max=10, y_min=0, y_max=5)

Objective Function Definition

Objective functions should accept a numpy array of shape (n_points, 2) as input.

Defining a Single Function Returning Multiple Objective Values

When objective functions have interdependencies or share common calculations, you can define a single function that returns a tuple or list of objective values.

import numpy as np

def combined_objectives(coords):
    """
    Parameters:
        coords: numpy array of shape (n_points, 2)
                each row is a coordinate point [x, y]

    Returns:
        tuple or list: A tuple or list of objective function values.
    """
    # Example: calculate sum of coordinates and spread of points
    obj1_val = np.sum(coords[:, 0]) + np.sum(coords[:, 1])
    obj2_val = np.std(coords[:, 0]) + np.std(coords[:, 1])
    return obj1_val, obj2_val # Or [obj1_val, obj2_val]

Defining Multiple Objective Functions (each returning a scalar)

Alternatively, you can define each objective function separately, with each returning a single scalar value.

def my_objective(coords):
    """
    Parameters:
        coords: numpy array of shape (n_points, 2)
                each row is a coordinate point [x, y]

    Returns:
        float: objective function value
    """
    # Example: calculate average distance to origin
    distances = np.sqrt(coords[:, 0]**2 + coords[:, 1]**2)
    return np.mean(distances)

Constraint Definition

Constraint functions should accept a numpy array of shape (n_points, 2) as input and return penalty values for constraint violations. Return 0 if no constraints are violated.

Defining a Single Function Returning Multiple Constraint Values

Similar to objective functions, you can define a single function that returns a tuple or list of penalty values for multiple constraints.

from scipy.spatial import distance

def combined_constraints(coords):
    """
    Parameters:
        coords: numpy array of shape (n_points, 2)

    Returns:
        tuple or list: A tuple or list of penalty values for constraint violations.
    """
    spacing = 0.05
    dist_list = distance.pdist(coords)

    # Constraint 1: Minimum spacing between points
    penalty1 = np.sum(spacing - dist_list[dist_list < spacing])

    # Constraint 2: All points within unit circle (example, might depend on other calculations)
    distances_to_origin = np.sqrt(coords[:, 0]**2 + coords[:, 1]**2)
    penalty2 = np.sum(distances_to_origin[distances_to_origin > 1] - 1)

    return penalty1, penalty2 # Or [penalty1, penalty2]

Defining Multiple Constraint Functions (each returning a scalar penalty)

Alternatively, you can define each constraint function separately, with each returning a single scalar penalty value.

def my_constraint(coords):
    """
    Parameters:
        coords: numpy array of shape (n_points, 2)

    Returns:
        float: penalty value for constraint violation (0 means no violation)
    """
    # Example: ensure all points are within unit circle
    distances = np.sqrt(coords[:, 0]**2 + coords[:, 1]**2)
    violations = distances[distances > 1] - 1
    return np.sum(violations)

Optimizer Parameters

CoordsNSGA2 Parameter Description

  • problem: Problem instance
  • pop_size: Population size (must be even)
  • prob_crs: Crossover probability (between 0-1)
  • prob_mut: Mutation probability (between 0-1)
  • random_seed: Random seed (for reproducibility)

Problem Parameter Description

  • objectives: Objective function(s). Can be a list of functions (each returning a scalar) or a single function returning multiple objective values (tuple or list).
  • n_points: Number of coordinate points. Can be a fixed integer (e.g., 10) or a list [min, max] to allow the number of points to vary within a range during optimization.
  • region: Region instance defining the valid search space
  • constraints: Constraint function(s) (optional). Can be a list of functions (each returning a scalar penalty value) or a single function returning multiple constraint penalty values (tuple or list).

Parameter Tuning Suggestions

  • Population size: Usually set to 20-100, use larger populations for complex problems
  • Crossover probability: Usually set to 0.5-0.9
  • Mutation probability: Usually set to 0.01-0.1
  • Generations: Set based on problem complexity, usually 100-1000 generations

Result Analysis

After optimization is complete, you can access the following attributes:

# Final population
final_population = optimizer.P

# Objective function values (shape: n_objectives × pop_size)
values = optimizer.values_P
values1 = values[0]
values2 = values[1]

# Optimization history
population_history = optimizer.P_history
values_history = optimizer.values_history  # list of (n_objectives, pop_size) per generation

# Find Pareto optimal solutions (based on last generation objective values)
from coords_nsga2.utils import fast_non_dominated_sort
fronts = fast_non_dominated_sort(optimizer.values_P)
pareto_front = optimizer.P[fronts[0]]

Save and Load

1
2
3
4
5
# Save optimization state
optimizer.save("optimization_result.pkl")

# Load optimization state
optimizer.load("optimization_result.pkl")