This is a sample taken from my upcoming book about CI-based optimization. Should you be interested in this, I can start posting more, and if you have any questions on this, feel free to contact me.
import numpy as np import matplotlib.pyplot as plt def init_generator(num_variable, pop_size, min_val, max_val): '''num_variable = Choromo size or number of variables; pop_size = population_size''' return np.random.uniform(low=min_val,high=max_val,size=(pop_size,num_variable)) def selection(pop, obj_func, R, minimizing=True, method='ranking selection'): '''pop = population_set, obj_func = Objective function or cost function, R = number of parents you want to select, method = {'roulette wheel', ranking selection', 'tournament selection'} Roulette wheel cannot be used for minimization because of the scaling. Furthermore, it also cannot be used when there are negative or null fitnesses because their probability would be negative or null.''' if method == 'ranking selection': of = np.apply_along_axis(func1d=obj_func,axis=1,arr=pop) index = np.argsort(of) if minimizing:a return pop[index][:R] else: return pop[index[::-1]][:R] elif method == 'roulette wheel': try: if not minimizing: of = np.apply_along_axis(func1d=obj_func,axis=1,arr=pop) selection_prob = of/np.sum(of) pop_index = np.random.choice(a=np.arange(len(pop)),size=R,replace=True,p=selection_prob) return pop[pop_index] else: raise TypeError except: raise TypeError('Roulette wheel cannot be used for minimization, nor negative or null fitnesses value.') elif method == 'tournament selection': index=np.random.choice(a=np.arange(len(pop)),size=R,replace=True) return pop[index] else: raise NameError(f'method {method} is not defined.') def cross_over(pop,pc,method='uniform'): '''method = {'one_point', 'two_points', 'uniform'} Note that to use two points methods you have to have at least have four variables.''' index = np.random.uniform(size=len(pop)) selected_parents = pop[index<=pc] parents_indeces = np.random.randint(0,len(selected_parents),size=(2,len(selected_parents)//2)) parents_1, parents_2 = selected_parents[parents_indeces[0]], selected_parents[parents_indeces[1]] if method == 'one_point': C = np.random.randint(pop.shape[1]-1) crossover_index = np.where(np.arange(pop.shape[1])<=C,0,1) childs_1 = np.where(crossover_index,parents_1,parents_2) childs_2 = np.where(crossover_index,parents_2,parents_1) childs = np.concatenate((childs_1,childs_2),axis=0) return childs elif method == 'two_points': if pop.shape[1]>=4: C1 = np.random.randint(1,pop.shape[1]/2) C2 = np.random.randint(pop.shape[1]/2,pop.shape[1]-1) crossover_index = np.where((np.arange(pop.shape[1])<C1)|(np.arange(pop.shape[1])>C2),0,1) childs_1 = np.where(crossover_index,parents_1,parents_2) childs_2 = np.where(crossover_index,parents_2,parents_1) childs = np.concatenate((childs_1,childs_2),axis=0) return childs else: raise ValueError('To use two points methods you have to have at least four variables.') elif method == 'uniform': crossover_index = np.random.randint(0,2,pop.shape[1]) childs_1 = np.where(crossover_index,parents_1,parents_2) childs_2 = np.where(crossover_index,parents_2,parents_1) childs = np.concatenate((childs_1,childs_2),axis=0) return childs else: raise NameError(f'method {method} is not defined.') def mutation(pop,pm,min_val,max_val,current_iteration,iteration,d0,method='uniform'): '''method = {'uniform', 'nonuniform'}''' indeces = np.random.uniform(size=pop.shape)<pm if method == 'uniform': mutated_values = init_generator(pop.shape[1],pop.shape[0],min_val,max_val) mutated_pop = np.where(indeces,mutated_values,pop) return mutated_pop elif method == 'nonuniform': mutated_values = init_generator(pop.shape[1],pop.shape[0],min_val,max_val) d=d0*((iteration-current_iteration)/iteration) mutated_pop = np.where(indeces,np.random.uniform(pop-d,pop+d),pop) return mutated_pop else: raise NameError(f'method {method} is not defined.') def GA_algorithem(pop_size,num_variable,obj_func,R, min_val,max_val,pm=.2,pc=.7, d0=2, iteration=1000,minimizing=True, full_result=False,selection_method='ranking selection', crossover_method='uniform',mutation_method='uniform'): '''selection_method = {'roulette wheel', 'ranking selection', 'tournament selection'} crossover_method = {'one_point', 'two_points', 'uniform'} mutation_method = {'uniform', 'nonuniform'}''' results=np.zeros(iteration) NFE=np.zeros(iteration) NFE_value=0 pop=init_generator(num_variable,pop_size,min_val,max_val) for i in range(iteration): selected_parents=selection(pop,obj_func,R,minimizing=minimizing,method=selection_method) if selection_method=='ranking selection': NFE_value+=pop_size childs=cross_over(selected_parents,pc,method=crossover_method) mutated_childs=mutation(pop,pm,min_val,max_val,current_iteration=i, iteration=iteration,d0=d0,method=mutation_method) all_results=np.concatenate((pop,childs,mutated_childs),axis=0) pop=selection(all_results,obj_func,pop_size,minimizing) NFE_value+=len(all_results) results[i]=obj_func(pop[0]) NFE[i]=NFE_value if not full_result: return pop[0], obj_func(pop[0]) else: return pop[0], obj_func(pop[0]), results, NFE