Centralize optimizer demo blocks to eliminate 800+ lines of duplication#44
Centralize optimizer demo blocks to eliminate 800+ lines of duplication#44
Conversation
Co-authored-by: Anselmoo <13209783+Anselmoo@users.noreply.github.com>
Co-authored-by: Anselmoo <13209783+Anselmoo@users.noreply.github.com>
Co-authored-by: Anselmoo <13209783+Anselmoo@users.noreply.github.com>
Co-authored-by: Anselmoo <13209783+Anselmoo@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR successfully centralizes optimizer demonstration code by introducing a new opt/demo.py module with a run_demo() function. The refactoring eliminates over 774 lines of duplicated code across 109 optimizer files by replacing inconsistent 5-15 line demo blocks with a standardized 3-line pattern.
Key changes include:
- New centralized demo module with consistent output formatting
- Standardized demo blocks across all single-objective optimizers
- Test coverage for the demo functionality
- README documentation with usage examples
Reviewed changes
Copilot reviewed 113 out of 113 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
opt/demo.py |
New centralized demo runner with run_demo() function providing standardized demo execution for all optimizers |
opt/test/test_demo.py |
Test suite covering basic usage, custom functions, bounds, and kwargs parameters |
pyproject.toml |
Added linting exceptions for demo.py to allow TC002 (third-party import in TYPE_CHECKING block) and ANN401 (Any type annotation) |
README.md |
Added Quick Demo section with programmatic and CLI usage examples |
opt/swarm_intelligence/*.py (57 files) |
Replaced custom demo blocks with standardized run_demo() calls and removed now-unused shifted_ackley imports |
opt/social_inspired/*.py (4 files) |
Replaced custom demo blocks with standardized run_demo() calls and removed now-unused imports |
opt/probabilistic/*.py (6 files) |
Replaced custom demo blocks with standardized run_demo() calls and removed now-unused imports |
opt/physics_inspired/*.py (4 files) |
Replaced custom demo blocks with standardized run_demo() calls and removed now-unused imports |
opt/metaheuristic/*.py (16 files) |
Replaced custom demo blocks with standardized run_demo() calls and removed now-unused imports |
opt/gradient_based/*.py (11 files) |
Replaced custom demo blocks with standardized run_demo() calls and removed now-unused imports |
opt/evolutionary/*.py (6 files) |
Replaced custom demo blocks with standardized run_demo() calls and removed now-unused imports |
opt/classical/*.py (9 files) |
Replaced custom demo blocks with standardized run_demo() calls and removed now-unused imports |
Comments suppressed due to low confidence (2)
opt/test/test_demo.py:5
- Import of 'pytest' is not used.
opt/test/test_demo.py:8 - Import of 'shifted_ackley' is not used.
| optimizer = optimizer_class( | ||
| func=func, | ||
| dim=dim, | ||
| lower_bound=lower_bound, | ||
| upper_bound=upper_bound, | ||
| max_iter=max_iter, | ||
| **kwargs, | ||
| ) | ||
|
|
||
| best_solution, best_fitness = optimizer.search() |
There was a problem hiding this comment.
The run_demo function does not handle cases where an optimizer might fail during instantiation or execution. Consider adding error handling to provide a more helpful error message when optimizers with incompatible signatures or parameters fail. For example, if an optimizer requires additional mandatory parameters beyond the standard set, the error message should guide users on how to provide them.
| optimizer = optimizer_class( | |
| func=func, | |
| dim=dim, | |
| lower_bound=lower_bound, | |
| upper_bound=upper_bound, | |
| max_iter=max_iter, | |
| **kwargs, | |
| ) | |
| best_solution, best_fitness = optimizer.search() | |
| try: | |
| optimizer = optimizer_class( | |
| func=func, | |
| dim=dim, | |
| lower_bound=lower_bound, | |
| upper_bound=upper_bound, | |
| max_iter=max_iter, | |
| **kwargs, | |
| ) | |
| except TypeError as exc: | |
| raise TypeError( | |
| f"Failed to instantiate optimizer {optimizer_class.__name__}. " | |
| "This often happens when the optimizer's __init__ signature does not match " | |
| "the parameters provided by run_demo. If the optimizer requires additional " | |
| "mandatory arguments, pass them as keyword arguments to run_demo via **kwargs. " | |
| f"Provided extra keyword arguments: {sorted(kwargs.keys())}. " | |
| f"Original error: {exc}" | |
| ) from exc | |
| except Exception as exc: # pragma: no cover - defensive programming | |
| raise RuntimeError( | |
| f"Unexpected error while instantiating optimizer {optimizer_class.__name__}: {exc}" | |
| ) from exc | |
| try: | |
| best_solution, best_fitness = optimizer.search() | |
| except Exception as exc: | |
| raise RuntimeError( | |
| f"Error while running search() for optimizer {optimizer_class.__name__}. " | |
| "Check that all required parameters were provided and are valid. " | |
| f"Original error: {exc}" | |
| ) from exc |
|
|
||
| from __future__ import annotations | ||
|
|
||
| import pytest |
There was a problem hiding this comment.
The test imports pytest but never uses it. This import can be removed to clean up the code.
| import pytest | ||
|
|
||
| from opt.benchmark.functions import rosenbrock | ||
| from opt.benchmark.functions import shifted_ackley |
There was a problem hiding this comment.
The test imports shifted_ackley but never uses it since the default parameter is used instead. This import can be removed for cleaner code.
| def test_run_demo_basic(): | ||
| """Test basic demo functionality.""" | ||
| best_solution, best_fitness = run_demo(ParticleSwarm, max_iter=10) | ||
|
|
||
| # Check return types | ||
| assert best_solution is not None | ||
| assert isinstance(best_fitness, float) | ||
|
|
||
| # Check solution dimensions | ||
| assert len(best_solution) == 2 | ||
|
|
||
|
|
||
| def test_run_demo_custom_function(): | ||
| """Test demo with custom function.""" | ||
| best_solution, best_fitness = run_demo( | ||
| ParticleSwarm, func=sphere, max_iter=10 | ||
| ) | ||
|
|
||
| assert best_solution is not None | ||
| assert isinstance(best_fitness, float) | ||
|
|
||
|
|
||
| def test_run_demo_custom_bounds(): | ||
| """Test demo with custom bounds.""" | ||
| best_solution, best_fitness = run_demo( | ||
| ParticleSwarm, | ||
| func=rosenbrock, | ||
| lower_bound=-5.0, | ||
| upper_bound=5.0, | ||
| dim=3, | ||
| max_iter=10, | ||
| ) | ||
|
|
||
| assert len(best_solution) == 3 | ||
| assert isinstance(best_fitness, float) | ||
|
|
||
|
|
||
| def test_run_demo_with_kwargs(): | ||
| """Test demo with additional optimizer kwargs.""" | ||
| best_solution, best_fitness = run_demo( | ||
| ParticleSwarm, | ||
| max_iter=10, | ||
| population_size=20, | ||
| c1=2.0, | ||
| c2=2.0, | ||
| ) | ||
|
|
||
| assert best_solution is not None | ||
| assert isinstance(best_fitness, float) |
There was a problem hiding this comment.
While the test suite covers basic functionality, it would be beneficial to add tests that verify the output format (checking that the print statements produce the expected structure) and test error cases, such as passing an invalid optimizer class or incompatible parameters.
Each of 117 optimizer files contained nearly identical
if __name__ == "__main__":blocks with inconsistent parameters and output formatting. This creates maintenance overhead and makes systematic improvements impossible.Changes
New
opt/demo.pymodule withrun_demo()function providing standardized demo executionUpdated 109 optimizer files to use centralized demo
shifted_ackleywith sensible defaultsTest coverage for demo module with 4 test cases covering basic usage, custom functions, bounds, and kwargs
README documentation added Quick Demo section with programmatic and CLI examples
Usage
Before:
After:
Output format:
Impact
Original prompt
if __name__ == "__main__":blocks with centralized demo runner #41✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.