import numpy as np

class Particle:
    def __init__(self, bounds):
        self.position = np.array([np.random.uniform(low, high) for low, high in bounds])
        self.velocity = np.array([0.0 for _ in bounds])
        self.best_position = self.position.copy()
        self.best_score = float('inf')

    def update_velocity(self, global_best_position, inertia, cognitive, social):
        r1, r2 = np.random.rand(2)
        cognitive_velocity = cognitive * r1 * (self.best_position - self.position)
        social_velocity = social * r2 * (global_best_position - self.position)
        self.velocity = inertia * self.velocity + cognitive_velocity + social_velocity

    def update_position(self, bounds):
        self.position += self.velocity
        for i, (low, high) in enumerate(bounds):
            if self.position[i] < low:
                self.position[i] = low
            elif self.position[i] > high:
                self.position[i] = high

def pso(objective_function, bounds, num_particles, max_iter, inertia=0.5, cognitive=1.5, social=1.5):
    particles = [Particle(bounds) for _ in range(num_particles)]
    global_best_position = particles[0].position.copy()
    global_best_score = float('inf')

    for _ in range(max_iter):
        for particle in particles:
            score = objective_function(particle.position)
            if score < particle.best_score:
                particle.best_score = score
                particle.best_position = particle.position.copy()
            if score < global_best_score:
                global_best_score = score
                global_best_position = particle.position.copy()

        for particle in particles:
            particle.update_velocity(global_best_position, inertia, cognitive, social)
            particle.update_position(bounds)

    return global_best_position, global_best_score

# 例として、2次関数の最小値を求める
def objective_function(x):
    return (x[0] - 1.0)**2 + (x[1] + 2)**2

bounds = [(-10, 10), (-10, 10)]
num_particles = 30
max_iter = 100

best_position, best_score = pso(objective_function, bounds, num_particles, max_iter)
print(f"Best position: {best_position}")
print(f"Best score: {best_score}")
