Quickstart Guide
This guide shows you how to implement cilpy's core interfaces and run a basic
experiment.
The Core Interfaces
To use cilpy, you need to understand two key interfaces:
cilpy.problem.Problem: Defines an optimization problem. It requires the following methods:__init__(self, dimension, bounds, name): Initializes a Problem instance.evaluate(self, solution): Evaluates a candidate solution.is_dynamic(self): Indicates if the problem changes over time.
cilpy.solver.Solver: Defines an optimization algorithm. It requires the following methods:__init__(self, problem, name, constraint_handler, **kwargs): Initializes the solver.step(self): Performs one iteration of the optimization algorithm.get_result(self): Returns the best solution(s) found so far.
Writing your own experiment
Step 1: Implement a Problem
Create a file named my_problem.py. Here, we'll implement the 2D Sphere
function.
# my_problem.py
from typing import List, Tuple
from cilpy.problem import Problem, Evaluation
class MySphere(Problem[List[float], float]):
"""A custom implementation of the Sphere function."""
def __init__(self, dimension: int):
super().__init__(
dimension=dimension,
bounds=([-5.12] * dimension, [5.12] * dimension),
name="MySphere"
)
def evaluate(self, solution: List[float]) -> Evaluation[float]:
"""Calculates the sum of squares of the solution's elements."""
fitness = sum(x**2 for x in solution)
return Evaluation(fitness=fitness)
def is_dynamic(self) -> Tuple[bool, bool]:
"""This problem is not dynamic."""
return (False, False)
Step 2: Implement a Solver
Create a file named my_solver.py. Here, we'll implement a simple Random Search
algorithm.
# my_solver.py
import random
from typing import List, Tuple
from cilpy.problem import Problem, Evaluation
from cilpy.solver import Solver
class RandomSearch(Solver[List[float], float]):
"""A simple solver that generates random solutions."""
def __init__(self, problem: Problem[List[float], float], name: str):
super().__init__(problem, name)
self.best_solution = None
self.best_evaluation = Evaluation(fitness=float('inf'))
def step(self) -> None:
"""Generate one new random solution and update the best."""
# Create a new random solution within the problem's bounds
lower, upper = self.problem.bounds
new_solution = [random.uniform(lower[i], upper[i])
for i in range(self.problem.dimension)]
# Evaluate the new solution
new_evaluation = self.problem.evaluate(new_solution)
# If it's better than the current best, update
if new_evaluation.fitness < self.best_evaluation.fitness:
self.best_solution = new_solution
self.best_evaluation = new_evaluation
def get_result(self) -> List[Tuple[List[float], Evaluation[float]]]:
"""Return the best solution found so far."""
return [(self.best_solution, self.best_evaluation)]
Step 3: Run the Experiment
Now, use the ExperimentRunner to run your new solver on your new problem.
Create run_my_experiment.py.
# run_my_experiment.py
from cilpy.runner import ExperimentRunner
from my_problem import MySphere
from my_solver import RandomSearch
# 1. Define the Problem
problems_to_run = [
MySphere(dimension=2)
]
# 2. Configure the Solver
solver_configs = [
{
"class": RandomSearch,
"params": {"name": "MyRandomSearch"}
}
]
# 3. Set Experiment Parameters
number_of_runs = 5
max_iter = 100
# 4. Create and run the experiment
runner = ExperimentRunner(
problems=problems_to_run,
solver_configurations=solver_configs,
num_runs=number_of_runs,
max_iterations=max_iter
)
runner.run_experiments()
Run this script from your terminal:
python run_my_experiment.py
This will create a MySphere_MyRandomSearch.out.csv file with the experiment's
results.
Using Included Components
You don't always need to create new components. cilpy includes standard
problems and solvers. Here is how you would run the included GA solver on the
included Ackley problem.
# run_included_experiment.py
from cilpy.runner import ExperimentRunner
from cilpy.problem.functions import Ackley # Included problem
from cilpy.solver.ga import GA # Included solver
runner = ExperimentRunner(
problems=[Ackley(dimension=10)],
solver_configurations=[
{
"class": GA,
"params": {
"name": "GA_Standard",
"population_size": 50,
"crossover_rate": 0.8,
"mutation_rate": 0.1,
}
}
],
num_runs=10,
max_iterations=1000
)
runner.run_experiments()