Skip to content

Conversation

richardcsuwandi
Copy link

This PR introduces a faster non-dominated sorting algorithm that leverages geometric properties to reduce complexity from O(N^2) to O(N log N), resulting in up to 60.92x faster performance for bi-objective problems.

Before (O(N^2) for all cases):

# Original algorithm for all objective counts
for i in range(n):
    for j in range(i + 1, n):
        rel = M[i, j]  # Full dominance matrix calculation
        if rel == 1:
            is_dominating[i].append(j)
            n_dominated[j] += 1
        elif rel == -1:
            is_dominating[j].append(i)
            n_dominated[i] += 1

After (O(N log N) for bi-objective, O(N^2) for others):

# Specialized algorithm for bi-objective problems
if n_objectives == 2:
    return _fast_biobjective_nondominated_sort(F)  # O(N log N) algorithm
else:
    # Fall back to optimized original approach for multi-objective

📊 Performance Results

Size Original (s) Evolved (s) Speedup
50 0.000328 0.000036 9.00x
100 0.001024 0.000078 13.18x
500 0.034089 0.000842 40.49x
1000 0.104040 0.002246 46.33x
2000 0.278000 0.004547 60.92x

Average speedup: 33.98x

Added comprehensive performance test (test_comparison.py) that:

  • Uses the same interface as the original pymoo implementation
  • Tests with actual bi-objective optimization scenarios
  • Verifies identical results between original and optimized methods
  • Demonstrates performance improvements across multiple problem sizes

This PR introduces a faster non-dominated sorting algorithm that leverages geometric properties to reduce complexity from O(N^2) to O(N log N), resulting in up to 60.92x faster performance for bi-objective problems.

  Before (O(N^2) for all cases):
  ```python
  # Original algorithm for all objective counts
  for i in range(n):
      for j in range(i + 1, n):
          rel = M[i, j]  # Full dominance matrix calculation
          if rel == 1:
              is_dominating[i].append(j)
              n_dominated[j] += 1
          elif rel == -1:
              is_dominating[j].append(i)
              n_dominated[i] += 1
  ```

  After (O(N log N) for bi-objective, O(N^2) for others):
  ```python
  # Specialized algorithm for bi-objective problems
  if n_objectives == 2:
      return _fast_biobjective_nondominated_sort(F)  # O(N log N) algorithm
  else:
      # Fall back to optimized original approach for multi-objective
  ```

📊 Performance Results

| Size | Original (s) | Evolved (s) | Speedup |
|------|--------------|-------------|---------|
| 50   | 0.000328     | 0.000036    | 9.00x   |
| 100  | 0.001024     | 0.000078    | 13.18x  |
| 500  | 0.034089     | 0.000842    | 40.49x  |
| 1000 | 0.104040     | 0.002246    | 46.33x  |
| 2000 | 0.278000     | 0.004547    | 60.92x  |
|------|--------------|-------------|---------|

Average speedup: 33.98x

Added comprehensive performance test (`test_comparison.py`) that:

- Uses the same interface as the original `pymoo` implementation
- Tests with actual bi-objective optimization scenarios
- Verifies identical results between original and optimized methods
- Demonstrates performance improvements across multiple problem sizes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant