Untitled
unknown
plain_text
a year ago
14 kB
5
Indexable
Never
from ctypes import * from py_interface import * import json import os import random import asyncio import numpy as np PARTICLES_COUNT = 10 MAX_ITERATIONS = 20 DEFAULT_COGNITIVE_PARAMETER = 2.0 DEFAULT_SOCIAL_PARAMETER = 2.0 DEFAULT_INERTIA_WEIGHT = 0.8 GLOBAL_OUTPUT_PATH = os.path.dirname(__file__) + '/../../simulation_output' PARAMETERS_INDEXES = ['ttlStart', 'ttlIncrement', 'ttlThreshold', 'rreqRetries', 'nodeTraversalTime', 'activeRouteTimeout', 'netDiameter', 'maxQueueLength', 'allowedHelloLoss'] PARAMETERS_BOUNDS = { 'ttlStart': { 'min': 1.0, 'max': 10.0 }, 'ttlIncrement': { 'min': 1.0, 'max': 10.0 }, 'ttlThreshold': { 'min': 1.0, 'max': 20.0 }, 'rreqRetries': { 'min': 1.0, 'max': 10.0 }, 'nodeTraversalTime': { 'min': 10.0, 'max': 1000.0 }, 'activeRouteTimeout': { 'min': 1.0, 'max': 30.0 }, 'netDiameter': { 'min': 15.0, 'max': 100.0 }, 'maxQueueLength': { 'min': 1.0, 'max': 100 }, 'allowedHelloLoss': { 'min': 1.0, 'max': 10.0 }, } os.chdir(os.path.dirname(__file__)) global_best_positions_simulations = [] global_best_costs_simulations = [] class Env(Structure): _pack_ = 1 _fields_ = [ ('ttlStart', c_int), ('ttlIncrement', c_int), ('ttlThreshold', c_int), ('rreqRetries', c_int), ('nodeTraversalTime', c_double), ('activeRouteTimeout', c_int), ('netDiameter', c_int), ('maxQueueLength', c_int), ('allowedHelloLoss', c_int) ] class Act(Structure): _pack_ = 1 _fields_ = [ ('packetDeliveryRatio', c_double) ] class Particle: def __init__(self, params): self.position = np.array([params['ttlStart'], params['ttlIncrement'], params['ttlThreshold'], params['rreqRetries'], params['nodeTraversalTime'], params['activeRouteTimeout'], params['netDiameter'], params['maxQueueLength'], params['allowedHelloLoss']]) self.velocity = np.zeros_like(self.position) self.best_position = self.position.copy() self.best_cost = 1001 def update_velocity(self, global_best_position): """ Update velocity of particle. :param global_best_position: set of parameters, that have best position in n-dimensional space """ for j in range(len(self.position)): r1 = np.random.rand() r2 = np.random.rand() cognitive_component = DEFAULT_COGNITIVE_PARAMETER * r1 * (self.best_position[j] - self.position[j]) social_component = DEFAULT_SOCIAL_PARAMETER * r2 * (global_best_position[j] - self.position[j]) self.velocity[j] = DEFAULT_INERTIA_WEIGHT * self.velocity[j] + cognitive_component + social_component def update_position(self): """ Update position of particle - set value for each parameter in set of parameters. """ for j in range(len(self.position)): self.position[j] += self.velocity[j] self.position[j] = check_parameter_bounds(PARAMETERS_INDEXES[j], self.position[j]) def update_cost(self, cost): """ Update best_cost and best_position of particle if cost is lower than the previous one. :param cost: calculated cost from simulation """ # if cost < self.best_cost: # self.best_cost = cost # self.best_position = self.position if cost < self.best_cost: self.best_cost = cost self.best_position = self.position class PSO: def __init__(self, entry_particles): self.global_best_cost = 1001 self.global_best_position = entry_particles[0].best_position self.particles = entry_particles async def fitness_function(self, iteration): """ Fitness function of PSO implementation which runs 10 simulations sequentially. :param iteration: Number of iteration of PSO algorithm. """ print(f"Running {iteration} iteration of PSO algorithm.") coroutines = [] simulations_iteration = 0 mempool_keys, memblock_keys = generate_simulations_memory_parameters() for simulation in convert_particles_array_to_ns3_settings_array(self.particles): simulation['pathOfOutput'] = os.path.dirname(__file__) + '/../../simulation_output' + str( simulations_iteration) + '.json' coroutine = run_simulation(mempool_keys[simulations_iteration], memblock_keys[simulations_iteration], simulation) coroutines.append(coroutine) simulations_iteration += 1 sim_results = await asyncio.gather(*coroutines) simulation_outputs = [] for i in range(10): f = open(os.path.dirname(__file__) + '/../../simulation_output' + str(i) + '.json') data = json.load(f) simulation_outputs.append(data) costs = calculate_costs(simulation_outputs) best_cost, best_set_of_parameters = find_best_cost(costs, convert_particles_array_to_ns3_settings_array( self.particles)) if best_cost < self.global_best_cost: self.global_best_cost = best_cost self.global_best_position = best_set_of_parameters global_best_positions_simulations.append(best_set_of_parameters) global_best_costs_simulations.append(best_cost) iteration = 0 for particle in self.particles: particle.update_velocity(convert_ns3_settings_to_array(self.global_best_position)) particle.update_position() particle.update_cost(costs[iteration]) iteration += 1 async def run(self): """ Runs fitness function in number of iterations set by MAX_ITERATIONS and evaluates results of implemented algorithm. """ simulations_results = [] for pso_iteration in range(MAX_ITERATIONS): simulations_results.append(await self.fitness_function(pso_iteration)) print('Global best cost is: ' + str(self.global_best_cost)) print('Global best position is: ' + str(self.global_best_position)) #print('Global best costs: ' + str(global_best_costs_simulations)) #print('Global best positions: ' + str(global_best_positions_simulations)) def generate_simulations_memory_parameters(): """ Generate memory parameters for simulations according to count of particles from range 1000-10000. :return: Generated mempool_keys and memblock_keys for ns3 simulations. """ generatedNumbers = random.sample(range(1000, 10000), PARTICLES_COUNT * 2) mempool_keys = generatedNumbers[:10] memblock_keys = generatedNumbers[10:] return mempool_keys, memblock_keys def check_parameter_bounds(parameter_type, value): """ Check if new parameter value fits into bounds for this parameter. If not, set closest possible value. :param parameter_type: Name of parameter. :param value: New value of parameter. :return: Correct new value of parameter. """ if value < PARAMETERS_BOUNDS[parameter_type]['min']: value = PARAMETERS_BOUNDS[parameter_type]['min'] elif value > PARAMETERS_BOUNDS[parameter_type]['max']: value = PARAMETERS_BOUNDS[parameter_type]['max'] return value async def run_simulation(mempool_key, memblock_key, ns3Settings): """ Run new ns3 simulation via ns3-ai class Experiment and wait till the simulation is not finished. :param mempool_key: Integer value for mempool_key from range 1000-10000. :param memblock_key: Integer value for memblock_key from range 1000-10000. :param ns3Settings: Set of parameters for AODV protocol. :return: Results of simulation. """ mem_size = 4096 exp = Experiment(mempool_key, mem_size, 'bp-pso13', '../../') exp.reset() pro = exp.run(setting=ns3Settings, show_output=True) pro_wait = pro.wait() if not type(pro_wait) is int: await pro.wait() return pro def calculate_costs(results_of_simulations): """ Calculate costs for each simulation run in one iteration of PSO algorithm. :param results_of_simulations: Array of results of simulations consisting from PDR, Delay and Average Throughput. :return: Array of calculated costs. """ costs = [] for result_of_simulation in results_of_simulations: pdr = result_of_simulation["PDR"] delay = result_of_simulation["EtE"] throughput = result_of_simulation["avgThroughput"] w_pdr = 0.4 w_delay = 0.3 w_throughput = 0.3 cost = w_pdr * (1 - pdr / 100) + w_delay * delay + w_throughput * throughput costs.append(cost) return costs def find_best_cost(costs, simulations_ns3_params): """ Find best cost in array of costs. :param costs: Array of costs. :param simulations_ns3_params: Array of parameters for each simulation. :return: Lowest cost and the corresponding set of parameters. """ lowest_cost = min(costs) lowest_cost_index = costs.index(lowest_cost) return lowest_cost, simulations_ns3_params[lowest_cost_index] def convert_ns3_settings_to_array(params): """ Convert object of simulation parameters to array form which is used for representation of particle position in n-dimensional space. :param params: Object of simulation parameters. :return: Particle position in n-dimensional space. """ return np.array([params['ttlStart'], params['ttlIncrement'], params['ttlThreshold'], params['rreqRetries'], params['nodeTraversalTime'], params['activeRouteTimeout'], params['netDiameter'], params['maxQueueLength'], params['allowedHelloLoss']]) def convert_particle_to_ns3_settings(pso_particle): """ Convert array of particle position to object of simulation parameters. :param pso_particle: Array of particle position. :return: Object that represents simulation parameters. """ return { 'ttlStart': pso_particle.position[0], 'ttlIncrement': pso_particle.position[1], 'ttlThreshold': pso_particle.position[2], 'rreqRetries': pso_particle.position[3], 'nodeTraversalTime': pso_particle.position[4], 'activeRouteTimeout': pso_particle.position[5], 'netDiameter': pso_particle.position[6], 'maxQueueLength': pso_particle.position[7], 'allowedHelloLoss': pso_particle.position[8] } def convert_particles_array_to_ns3_settings_array(pso_particles_array): """ Convert array of particles to array of simulations parameters. :param pso_particles_array: Array of particles. :return: Array of parameters for simulations. """ ns3_settings_array = [] for pso_particle in pso_particles_array: ns3_settings_array.append(convert_particle_to_ns3_settings(pso_particle)) return ns3_settings_array def convert_ns3_settings_to_particle(ns3_settings): """ Convert array of parameters for simulations to new particle. :param ns3_settings: Array of parameters for many simulations. :return: Object of particle. """ return Particle(ns3_settings) def convert_ns3_settings_array_to_particles_array(ns3_settings_array): """ Convert array of set of parameters for simulations to array of particles. :param ns3_settings_array: Array of set of parameters for simulations. :return: Array of particles. """ particles_array = [] for ns3_settings in ns3_settings_array: particles_array.append(convert_ns3_settings_to_particle(ns3_settings['ns3Settings'])) return particles_array async def main(): mempool_keys, memblock_keys = generate_simulations_memory_parameters() simulationsNs3Params = [] for i in range(10): ns3Settings = { 'ttlStart': random.uniform(1.0, 10.0), 'ttlIncrement': random.uniform(1.0, 10.0), 'ttlThreshold': random.uniform(1.0, 20.0), 'rreqRetries': random.uniform(1.0, 10.0), 'nodeTraversalTime': random.uniform(10.0, 1000.0), 'activeRouteTimeout': random.uniform(1.0, 10.0), 'netDiameter': random.uniform(10.0, 50.0), 'maxQueueLength': random.uniform(1.0, 10.0), 'allowedHelloLoss': random.uniform(1.0, 10.0), 'pathOfOutput': os.path.dirname(__file__) + '/../../simulation_output' + str(i) + '.json' } simulationsNs3Params.append( {'mempool_key': mempool_keys[i], 'memblock_key': memblock_keys[i], 'ns3Settings': ns3Settings}) particles = [] for i in range(PARTICLES_COUNT): params = { 'ttlStart': simulationsNs3Params[i]['ns3Settings']['ttlStart'], 'ttlIncrement': simulationsNs3Params[i]['ns3Settings']['ttlIncrement'], 'ttlThreshold': simulationsNs3Params[i]['ns3Settings']['ttlThreshold'], 'rreqRetries': simulationsNs3Params[i]['ns3Settings']['rreqRetries'], 'nodeTraversalTime': simulationsNs3Params[i]['ns3Settings']['nodeTraversalTime'], 'activeRouteTimeout': simulationsNs3Params[i]['ns3Settings']['activeRouteTimeout'], 'netDiameter': simulationsNs3Params[i]['ns3Settings']['netDiameter'], 'maxQueueLength': simulationsNs3Params[i]['ns3Settings']['maxQueueLength'], 'allowedHelloLoss': simulationsNs3Params[i]['ns3Settings']['allowedHelloLoss'] } particle = Particle(params) particles.append(particle) pso = PSO(convert_ns3_settings_array_to_particles_array(simulationsNs3Params)) await pso.run() asyncio.run(main())