input: Write a python function to optimize a given objective function using PSO with specified parameters.
  assert PSOOptimizer(n_particles=5, dimensions=2, options={'c1': 0.5, 'c2': 0.3, 'w': 0.9}).optimize(lambda x: sum(x**2), iters=10, lb=[-10, -10], ub=[10, 10]) is not None
  assert PSOOptimizer(n_particles=8, dimensions=3, options={'c1': 0.8, 'c2': 0.4, 'w': 0.5}).optimize(lambda x: x[0]**2 + x[1]**2 + x[2]**2, iters=20, lb=[-5, -5, -5], ub=[5, 5, 5]) is not None
output: import numpy as np
  
  class PSOOptimizer:
      def __init__(self, n_particles, dimensions, options):
          self.n_particles = n_particles
          self.dimensions = dimensions
          self.c1 = options['c1']
          self.c2 = options['c2']
          self.w = options['w']
          
      def optimize(self, objective_function, iters, lb, ub):
          # Initialize particle positions and velocities
          positions = np.random.uniform(low=lb, high=ub, size=(self.n_particles, self.dimensions))
          velocities = np.random.uniform(low=-1, high=1, size=(self.n_particles, self.dimensions))
          
          # Initialize personal best positions and global best position
          pbest_positions = positions.copy()
          pbest_scores = np.array([objective_function(p) for p in positions])
          gbest_position = pbest_positions[np.argmin(pbest_scores)]
          
          for _ in range(iters):
              # Update velocities
              r1, r2 = np.random.rand(self.n_particles, self.dimensions), np.random.rand(self.n_particles, self.dimensions)
              cognitive = self.c1 * r1 * (pbest_positions - positions)
              social = self.c2 * r2 * (gbest_position - positions)
              velocities = self.w * velocities + cognitive + social
              
              # Update positions
              positions += velocities
              
              # Apply bounds
              positions = np.clip(positions, lb, ub)
              
              # Update personal best positions
              scores = np.array([objective_function(p) for p in positions])
              better_mask = scores < pbest_scores
              pbest_positions[better_mask] = positions[better_mask]
              pbest_scores[better_mask] = scores[better_mask]
              
              # Update global best position
              if np.min(pbest_scores) < objective_function(gbest_position):
                  gbest_position = pbest_positions[np.argmin(pbest_scores)]
                  
          return gbest_position
  
  # Test assertions
  assert PSOOptimizer(n_particles=5, dimensions=2, options={'c1': 0.5, 'c2': 0.3, 'w': 0.9}).optimize(lambda x: sum(x**2), iters=10, lb=[-10, -10], ub=[10, 10]) is not None
  assert PSOOptimizer(n_particles=8, dimensions=3, options={'c1': 0.8, 'c2': 0.4, 'w': 0.5}).optimize(lambda x: x[0]**2 + x[1]**2 + x[2]**2, iters=20, lb=[-5, -5, -5], ub=[5, 5, 5]) is not None