├── .gitignore ├── ConventionalDistillationColumn ├── PSO_Algorithm.py ├── Test_Column.hsc ├── Test_Column_ObjFnc.py ├── column_algorithm.py ├── hyInterface.py ├── main_Column.py ├── print_pso.py └── pso_column.py ├── LICENSE ├── PSO ├── 1D │ ├── 1D-Python-PSO-algorithm-viz.ipynb │ └── img │ │ └── PSS-Example-1D.gif ├── 2D │ ├── 2D-Python-PSO-algorithm-viz.ipynb │ ├── ackley_convergent │ │ ├── ackley_2D_0.png │ │ ├── ackley_2D_1.png │ │ ├── ackley_2D_10.png │ │ ├── ackley_2D_11.png │ │ ├── ackley_2D_12.png │ │ ├── ackley_2D_13.png │ │ ├── ackley_2D_14.png │ │ ├── ackley_2D_15.png │ │ ├── ackley_2D_16.png │ │ ├── ackley_2D_17.png │ │ ├── ackley_2D_18.png │ │ ├── ackley_2D_19.png │ │ ├── ackley_2D_2.png │ │ ├── ackley_2D_20.png │ │ ├── ackley_2D_21.png │ │ ├── ackley_2D_22.png │ │ ├── ackley_2D_23.png │ │ ├── ackley_2D_24.png │ │ ├── ackley_2D_25.png │ │ ├── ackley_2D_26.png │ │ ├── ackley_2D_27.png │ │ ├── ackley_2D_28.png │ │ ├── ackley_2D_29.png │ │ ├── ackley_2D_3.png │ │ ├── ackley_2D_4.png │ │ ├── ackley_2D_5.png │ │ ├── ackley_2D_6.png │ │ ├── ackley_2D_7.png │ │ ├── ackley_2D_8.png │ │ └── ackley_2D_9.png │ ├── img │ │ ├── PSO_Ackley.gif │ │ ├── PSO_Example1.gif │ │ ├── PSO_Rana.gif │ │ ├── PSO_odd_square.gif │ │ └── PSO_salomon.gif │ ├── optitestfuns.py │ ├── plotPSO.py │ └── test_plot.ipynb ├── nD │ ├── .ipynb_checkpoints │ │ └── test_plot-checkpoint.ipynb │ ├── DemoAckley.py │ ├── MATLAB │ │ ├── DemoAckley.m │ │ ├── F_Ackley.m │ │ ├── ftest1d.m │ │ ├── ftest2d.m │ │ ├── ftest3d.m │ │ └── pso_v3.m │ ├── img │ │ ├── 1D │ │ │ ├── ackley_1D.png │ │ │ ├── griewangk_1D.png │ │ │ ├── odd_square_1D.png │ │ │ ├── rastrigin_1D.png │ │ │ └── salomon_1D.png │ │ └── 2D │ │ │ ├── ackley_2D.png │ │ │ ├── griewangk_2D.png │ │ │ ├── odd_square_2D.png │ │ │ ├── rana_2D.png │ │ │ ├── rastrigin_2D.png │ │ │ ├── salomon_2D.png │ │ │ └── schwefel_2D.png │ ├── optitestfuns.py │ ├── plotPSO.py │ ├── print_pso.py │ ├── pso.py │ ├── test_plot.ipynb │ ├── test_pso.py │ └── tictoc.py └── talk-structure ├── PyConES-2016.md ├── README.md ├── Slides - PyconES 2016 - Simulation-Based Optimization Using PSO.pdf └── optimizacion-estocastica-python.png /.gitignore: -------------------------------------------------------------------------------- 1 | PSO/1D/.ipynb_checkpoints 2 | PSO/2D/.ipynb_checkpoints 3 | PSO/.idea/dictionaries/cacheme.xml 4 | *.xml 5 | *.iml 6 | *.pyc 7 | PSO/.ipynb_checkpoints/Python-algorithm-checkpoint.ipynb 8 | PSO/nD/.ipynb_checkpoints/test_plot-checkpoint.ipynb -------------------------------------------------------------------------------- /ConventionalDistillationColumn/PSO_Algorithm.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import numpy as np 4 | import time 5 | import datetime as dt 6 | 7 | from print_pso import print_results 8 | 9 | 10 | 11 | def pso_gbest(objfnc, lb, ub, intVar, *arg): 12 | '''Standard PSO algorithm (gbest) for minimizing a n dimensional function 13 | Input argurments: 14 | objfnc: objective function 15 | lb: array containing lower bound on independent variables (len of array determines the dimensions) 16 | ub: array containing upper bound on independent variables (len of array determines the dimensions) 17 | intVar: array containing the index of the interger (indpendent) variables 18 | 19 | returns: Result Class 20 | Result.best_fitness = gbest_fitness 21 | Result.x_best = gbest_x 22 | Result.iterations = n_iter 23 | Result.FO_eval = FO_eval 24 | Result.error_x = error_x 25 | Result.error_fnc = error_fnc 26 | Result.exit = termination 27 | 28 | Author: Juan Javaloyes Antón & FJ Navarro-Brull (Sept 2016) 29 | License: BSD-CL 3 javaloyes.juan@gmail.com 30 | More info at: https://github.com/CAChemE/stochastic-optimization 31 | ''' 32 | 33 | Problem = arg[0] 34 | 35 | # >>>>>>>>>>>>>>>>>>>>>>>>>>[ PSO OPTIONS ]>>>>>>>>>>>>>>>>>>>> User inputs 36 | # * Population size 37 | swarm_size = 20 # number of the swarm particles 38 | 39 | # * Termination Conditions 40 | maxIter = 30 # maximum number of iterations 41 | maxFO = 1e5 # maximun number of function evaluations 42 | 43 | maxIterNoImprov = 1e5 # maximun number of iterations without improving the objective function 44 | maxTime = 1e5 # time limit in seconds [s] [or np.finfo(np.float64).max for realmax] 45 | 46 | tol_x = 1e-5 # tolerance in x (norm 2) 47 | tol_fnc = 1e-5 # tolerance in objective function 48 | 49 | # * PSO parameters 50 | inertia_w = 0.72 # Inertia weigth 51 | acceleration_c1 = 1.49 # Acceleration coefficient (cognitive) 52 | acceleration_c2 = 1.49 # Acceleraton coefficient (social) 53 | v_max = 2 # Maximun velocity in absolute value 54 | break_coeff = 0.05 # Break factor for the worst particle 55 | Red_acceleration_c1 = 2 # Reduction factor of accelaration c1 coefficient for the worst particle 56 | 57 | 58 | # * Algorithm options 59 | print_freq = 1 60 | plotPSO = 'on' 61 | # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> End inputs 62 | 63 | 64 | # ········· PARTICLE SWARM OPTIMIZATION ALGORITHM CODE ···················· 65 | 66 | # # Preprocessing Operations ############################################## 67 | n_variables = np.size(lb) # number of variables 68 | lb = np.array(lb) 69 | ub = np.array(ub) 70 | 71 | lb_original = np.copy(lb) # copy of original bounds for plotting 72 | ub_original = np.copy(ub) 73 | 74 | 75 | # # Initialization ####################################################### 76 | 77 | # 01. Set new bounds on the integer variables ----------------------------- 78 | # NOTE1: Bounds on integer variables must be integer numbers 79 | # NOTE2: New bounds are established in order to give the same probability 80 | # to the variable bounds when round MATLAB function is used. 81 | 82 | if np.ndim(intVar)>=1: 83 | lb[intVar] = lb[intVar] - 0.49 84 | ub[intVar] = ub[intVar] + 0.49 85 | 86 | # 02. Set the initial position of the particles --------------------------- 87 | aux1 = (ub - lb) 88 | x = np.outer(lb, np.ones(swarm_size)) + \ 89 | np.outer(aux1, np.ones(swarm_size))*np.random.rand(n_variables, swarm_size) 90 | 91 | # * Round intger variables 92 | x[intVar,:] = np.rint(x[intVar,:]) 93 | 94 | # 03. Set initial velocity for particles ---------------------------------- 95 | v = np.zeros((n_variables, swarm_size)) 96 | 97 | # 04. Evaluation of each particle ----------------------------------------- 98 | # NOTE3: It is not possible to perform a vectorized version since our 99 | # objective function can be a black box (e.g. process simulator) 100 | 101 | start_initialization = dt.datetime.now() 102 | tic_initialization = time.time() 103 | 104 | fval = np.zeros((swarm_size)) 105 | for iParticle in range(swarm_size): 106 | fval[iParticle] = objfnc(x[:,iParticle], Problem) 107 | 108 | 109 | # 05. Best particle position and global best particle position and fitness- 110 | pbest_x = np.copy(x) 111 | pbest_fitness = np.copy(fval) 112 | 113 | gbest_fitness = np.min(fval) 114 | gbest_ind = np.argmin(fval) 115 | gbest_x = x[:,gbest_ind] 116 | 117 | toc_initialization = time.time() - tic_initialization 118 | 119 | stop_initialization = dt.datetime.now() 120 | elapsed_time_initialization = (stop_initialization - start_initialization).microseconds 121 | 122 | # 06. Worst particle in each iteration ---------------------------------------- 123 | 124 | pworst_fitness = np.max(fval) 125 | pworst_ind = np.argmax(fval) 126 | pworst_x = x[:,pworst_ind] 127 | 128 | error_x = np.linalg.norm(pworst_x - gbest_x, ord = 2) 129 | error_fnc = np.linalg.norm(pworst_fitness - gbest_fitness) 130 | 131 | # 07. Print results 132 | print_results(1, swarm_size, gbest_fitness, pworst_fitness, 133 | error_fnc, error_x, swarm_size, n_variables, intVar, 134 | print_freq) 135 | 136 | # 08. Plot objective function and paticles for 2D and 3D test functions 137 | 138 | 139 | # ######################################################################### 140 | # ####### Main Body of the Algorithm ### ################################## 141 | # ######################################################################### 142 | 143 | # * Control parameters & Preallocation arrays 144 | n_iter = 1 145 | timeLimit = toc_initialization 146 | FO_eval = swarm_size 147 | iter_fitness_improvement = 0 148 | 149 | v_new = np.copy(v) 150 | x_new = np.copy(x) 151 | x_plot = np.copy(x) 152 | 153 | 154 | 155 | while 1: 156 | start_iter_time = time.time() 157 | 158 | for iP in range(swarm_size): 159 | 160 | # 09. Update velocity for all particles ----------------------------------- 161 | if n_iter > 1 and iP == pworst_ind: 162 | v_new[:,iP] = break_coeff * inertia_w * v[:,iP] + \ 163 | acceleration_c1 * np.random.rand(1,n_variables) * (pbest_x[:,iP] - x[:,iP])/Red_acceleration_c1 + \ 164 | acceleration_c2 * np.random.rand(1,n_variables) * (gbest_x - x[:,iP]) 165 | else: 166 | v_new[:,iP] = inertia_w * v[:,iP] + \ 167 | acceleration_c1 * np.random.rand(1,n_variables) * (pbest_x[:,iP] - x[:,iP]) + \ 168 | acceleration_c2 * np.random.rand(1,n_variables) * (gbest_x - x[:,iP]) 169 | # end if 170 | 171 | # 10. Velocity control -------------------------------------------------------- 172 | v_new[v_new > v_max] = v_max 173 | v_new[v_new < -v_max] = -v_max 174 | 175 | # 11. Update position for all particlespbes ----------------------------------- 176 | x_new[:,iP] = x[:,iP] + v_new[:,iP] 177 | 178 | # 12. Position control ---------------------------------------------------- 179 | # * Lower bound 180 | x_new[:,iP] = (x_new[:,iP] < lb) * lb + (x_new[:,iP] >= lb) *x_new[:,iP] 181 | 182 | # * Upper bound 183 | x_new[:,iP] = (x_new[:,iP] > ub) * ub + (x_new[:,iP] <= ub)*x_new[:,iP] 184 | 185 | # 13. Round integer variables to the nearest integer ---------------------- 186 | # NOTE4: we need an aux var for the position in order to round the integer 187 | # variables keeping unalterd x_new for next iterations 188 | x_iP = np.copy(x_new[:,iP]) 189 | 190 | x_iP[intVar] = np.rint(x_iP[intVar]) 191 | 192 | x_plot[:,iP] = x_iP # for plotting 193 | 194 | # 14. Function evaluation ---------------------------------------------------- 195 | fval[iP] = objfnc(x_iP, Problem) 196 | 197 | # 15. Update personal best particle (pbest) so far ---------------------------- 198 | if fval[iP] < pbest_fitness[iP]: 199 | pbest_fitness[iP] = fval[iP] 200 | pbest_x[:,iP] = x_iP 201 | 202 | # 16. Update global best particle (gbest) --------------------------------- 203 | if pbest_fitness[iP] < gbest_fitness: 204 | gbest_fitness = pbest_fitness[iP] 205 | gbest_x = x_iP 206 | iter_fitness_improvement = 0 207 | else: 208 | iter_fitness_improvement = iter_fitness_improvement + 1 209 | 210 | stop_iter_time = time.time() - start_iter_time 211 | 212 | # ============================================================================= 213 | # end for loop in range of swarm size 214 | # ============================================================================= 215 | 216 | # 17. Uptdate Control parameters 217 | 218 | n_iter = n_iter + 1 219 | 220 | FO_eval = FO_eval + swarm_size 221 | timeLimit = timeLimit + stop_iter_time 222 | 223 | # * Worst particle in each iteration 224 | pworst_fitness = np.max(pbest_fitness) 225 | pworst_ind = np.argmax(pbest_fitness) 226 | pworst_x = pbest_x[:,pworst_ind] 227 | 228 | error_x = np.linalg.norm(pworst_x - gbest_x, ord = 2) 229 | error_fnc = np.linalg.norm(pworst_fitness - gbest_fitness) 230 | 231 | # 18. Print iteration results 232 | print_results(n_iter, FO_eval, gbest_fitness, pworst_fitness, 233 | error_fnc, error_x, swarm_size, n_variables, intVar, 234 | print_freq) 235 | 236 | # 19. Plot Particles and Objective Function ------------------------------- 237 | 238 | # 20. Check Termination Criterias ----------------------------------------- 239 | 240 | if n_iter >= maxIter: 241 | termination = 'Stop due to maximum number of major iterations.' 242 | break 243 | elif FO_eval >= maxFO: 244 | termination = 'Stop due to maximum number of function evaluations.' 245 | break 246 | elif iter_fitness_improvement >= maxIterNoImprov: 247 | termination = 'Number of generations without fitness improvement Reached. The objective function is under specified tolerance' 248 | break 249 | elif timeLimit >= maxTime: 250 | termination = 'The solver was interrupted because it reached the time limit.' 251 | break 252 | # elif error_fnc <= tol_fnc: 253 | # termination = ' The objective function is under specified tolerance ' 254 | # break 255 | # elif error_x <= tol_x: 256 | # termination = ' The tolerance between best and worst particles is under specification' 257 | # break 258 | 259 | 260 | # 21. Position and velocity for next iteration 261 | x = np.copy(x_new) 262 | v = np.copy(v_new) 263 | # ============================================================================= 264 | # end while loop 265 | # ============================================================================= 266 | 267 | class Result: 268 | pass 269 | 270 | Result.best_fitness = gbest_fitness 271 | Result.x_best = gbest_x 272 | Result.iterations = n_iter 273 | Result.FO_eval = FO_eval 274 | Result.error_x = error_x 275 | Result.error_fnc = error_fnc 276 | Result.exit = termination 277 | 278 | return Result 279 | 280 | # end def 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | -------------------------------------------------------------------------------- /ConventionalDistillationColumn/Test_Column.hsc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/ConventionalDistillationColumn/Test_Column.hsc -------------------------------------------------------------------------------- /ConventionalDistillationColumn/Test_Column_ObjFnc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import numpy as np 4 | import os 5 | """ 6 | % ------------------------------------------------------------------------- 7 | % SIMULATION-BASED OPTIMIZATION OF A SINGLE CONVENTIONAL DISTILLATION 8 | % COLUMN USING THE PARTICLE SWARM OPTIMIZATION ALGORITHEM 9 | %-------------------------------------------------------------------------- 10 | % Juan Javaloyes Antón. Sep 2016 v.3 11 | %-------------------------------------------------------------------------- 12 | % # 05 # Total Annual Cost 13 | %-------------------------------------------------------------------------- 14 | """ 15 | 16 | def tac_column(Problem): 17 | """ 18 | # ### >> Total Annual Cost << Conventional Distillation Column ######## 19 | # - Investment costs: 20 | # * Tower 21 | # * Trays 22 | # * Reboiler 23 | # * Condenser 24 | # - Operating Costs 25 | # * Heating Steam 26 | # * Cooling Water 27 | #---------------------------------------------------------------------- 28 | """ 29 | 30 | 31 | # 01 # Recover Hysys Objects from structure Problem 32 | HyObject = Problem.HyObject # Main Aspen Hysys Objects 33 | MaterialStream = HyObject.MaterialStream # Column material streams 34 | EnergyStream = HyObject.EnergyStream # Column energy streams 35 | 36 | # 02 # Import Data from Aspen Hysys Model 37 | NT = HyObject.DistColumn.Main_TS.NumberOfTrays # Column Active Trays 38 | 39 | TD = MaterialStream.Distillate.Temperature.GetValue('C') # Distillate Temperature 40 | TB = MaterialStream.Bottoms.Temperature.GetValue('C') # Residue Temperature 41 | 42 | Qcond = EnergyStream.Qcond.HeatFlow.GetValue('kW') # Condenser duty 43 | Qreb = EnergyStream.Qreb.HeatFlow.GetValue('kW') # Reboiler Duty 44 | 45 | # 03 # Run Aspen Hysys Script "Col_diam_V8.SCP" to update column diameter 46 | # Problem.HyObject.HyCase.Application.PlayScript(os.path.abspath('Column_Diameter.SCP')) 47 | column_diameter = max( HyObject.HyCase.UtilityObjects.Item('Tray Sizing-1').DiameterValue) # [m] 48 | 49 | # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<< User Inputs 50 | # # Equipment and Utility Parameter Cost ################################## 51 | 52 | # * Global parameters 53 | CEPIC_Actual = 576.1 # Annual Index 2014 54 | CEPIC_2001 = 397 # Base Annual Index 55 | UpdateFactor = CEPIC_Actual/CEPIC_2001 56 | 57 | # * Annualization Factor parameters *************************************** 58 | i = 0.1 # interest_rate 59 | n = 8 # equipment life time yrs 60 | 61 | 62 | # * Utility Costs ********************************************************* 63 | WATER = 0.354 * (1/1e9) * 3600 * 1e3 # $/GJ [30 ºC to 40-45 ºC] (R.Turton 4º Ed. Table 8.3) ==> [$ /kW·h] 64 | STEAM = 14.04 * (1/1e9) * 3600 * 1e3 # $/GJ Low Pressure Steam [5barg, 160ºC] (R.Turton 4º Ed. Table 8.3) ==> [$ /kW·h] 65 | YEAR = 8000 # Operating hours per year 66 | 67 | # * Equip Cost Constants (K). See Appendix A - R .Turton ****************** 68 | Ktray = np.array([2.9949, 0.4465, 0.3961]) # Trays (sieves) Area m2 69 | Ktower = np.array([3.4974, 0.4485, 0.1074]) # Towers (tray) Volume m3 70 | Khx = np.array([4.3247, -0.3030, 0.1634]) # Heat Echangers (fixed tube) Area m2 71 | 72 | # * Bare module Cost Factor: direct and indirect costs for each unit ****** 73 | FBMtray = 1 # Table A.6 & Figure A.9 (Trays - sieve trays) 74 | FBMtower = (2.25 + 1.82 * 1.0) # Table A.4 & Figure A.8 (Process vessels - vertical (including towers)) 75 | FBMhx = (1.63 + 1.66 * 1.3) # Table A.4 & Figure A.8 (fixed tube sheet) 76 | 77 | # * Cooler **************************************************************** 78 | Ucooler = 800 # [W/(m2 K)] 79 | Twin = 30 # Temperatura Entrada Agua Refrigeración Condensador [ºC] 80 | Twout = 40 # Temperatura Salida Agua Refrigeración Condensador [ºC] 81 | 82 | # * Heater **************************************************************** 83 | Uheater = 820 # [W/(m2 K)] 84 | Tstm = 160 # Low Pressure Steam temperature (R.Turton 4º Ed. Table 8.3) 85 | 86 | # Tower Column 87 | tray_Spacing = 0.6096 # [m] 88 | 89 | # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> # END Equipment and Utility Parameter Cost 90 | 91 | # 04 # Operating Cost ######################################################## 92 | 93 | # * Cooling Water Cost [$/yr] ********************************************* 94 | coolingWater_Cost = Qcond * WATER * YEAR 95 | 96 | # * Steam Cost [$/yr] ***************************************************** 97 | Steam_Cost = Qreb * STEAM * YEAR 98 | 99 | # 05 # Capital Cost ########################################################## 100 | 101 | # * Column dimensions 102 | column_area = np.pi * np.square(column_diameter) / 4 # Sieve area [m2] 103 | column_heigh = (3 + NT) * tray_Spacing # Tower Heigh [m] 104 | column_volume = column_area * column_heigh # Volume Tower [m3] 105 | 106 | # * Column Shell ********************************************************** 107 | # Purchase cost for base conditions 108 | column_Cp0 = 10**( Ktower[0] + Ktower[1] * np.log10(column_volume) + 109 | Ktower[2] * (np.log10(column_volume)**2)) 110 | 111 | # Bare Module cost 112 | column_CBM_old = column_Cp0 * FBMtower 113 | column_CBM = column_CBM_old * UpdateFactor # [$] ====================== 114 | 115 | 116 | # * Column trays ********************************************************** 117 | # Purchase cost for base conditions 118 | tray_Cp0 = 10**( Ktray[0] + Ktray[1] * np.log10(column_area) + 119 | Ktray[2] * (np.log10(column_area)**2)) 120 | # Tray factor 121 | if NT < 20: 122 | Fq = 10**(0.4771 + 0.0816 * np.log10(NT) - 0.3473 * (np.log10(NT))**2) 123 | else: 124 | Fq = 1 125 | 126 | 127 | # Bare Module cost 128 | tray_CBM_old = tray_Cp0 * FBMtray * Fq 129 | tray_CBM = tray_CBM_old * NT * UpdateFactor # [$] ================ 130 | 131 | 132 | # * Column Condenser ****************************************************** 133 | inc_T_cond = ((TD - Twout) - (TD - Twin))/ np.log ((TD - Twout)/(TD - Twin)) 134 | condenser_area = Qcond/(Ucooler * inc_T_cond) * 1e3 # *1e3 porque U esta en W. 135 | 136 | # Purchase cost for base conditions 137 | condenser_Cp0 = 10**( Khx[0] + Khx[1] * np.log10(condenser_area) + 138 | Khx[2] * (np.log10(condenser_area)**2)) 139 | 140 | # Bare Module cost 141 | condenser_CBM_old = condenser_Cp0 * FBMhx 142 | condenser_CBM = condenser_CBM_old * UpdateFactor # [$] ================ 143 | 144 | 145 | # * Column Reboiler ******************************************************* 146 | inc_T_reb = Tstm - TB 147 | reboiler_area = Qreb/(Uheater * inc_T_reb) * 1e3 # *1e3 porque U esta en W. 148 | 149 | # Purchase cost for base conditions 150 | reboiler_Cp0 = 10**( Khx[0] + Khx[1] * np.log10(reboiler_area) + 151 | Khx[2] * (np.log10(reboiler_area)**2)) 152 | 153 | # Bare Module cost 154 | reboiler_CBM_old = reboiler_Cp0 * FBMhx 155 | reboiler_CBM = reboiler_CBM_old * UpdateFactor # [$] ================== 156 | 157 | 158 | # 06 # Total Annual Cost ##################################################### 159 | 160 | # * Total Operating Cost 161 | Cop = coolingWater_Cost + Steam_Cost 162 | 163 | # * Total Capital Cost 164 | Ccap = column_CBM + tray_CBM + condenser_CBM + reboiler_CBM 165 | 166 | # * Annualization factor (R. Smith) 167 | F = i*(1 + i)**n /((1 + i)**n - 1); 168 | 169 | # * TAC =================================================================== 170 | TAC = (Cop + Ccap * F) * 1e-6 # [MM $/yr] 171 | # ============================================== END TAC calculations ##### 172 | 173 | class ColumnCost: 174 | pass 175 | ColumnCost.CoolingWater = coolingWater_Cost 176 | ColumnCost.Stea = Steam_Cost 177 | ColumnCost.Shell = column_CBM 178 | ColumnCost.Trays = tray_CBM 179 | ColumnCost.condenser = condenser_CBM 180 | ColumnCost.reboiler = reboiler_CBM 181 | ColumnCost.F = F 182 | ColumnCost.TAC = TAC 183 | 184 | return (ColumnCost) -------------------------------------------------------------------------------- /ConventionalDistillationColumn/column_algorithm.py: -------------------------------------------------------------------------------- 1 | 2 | # -*- coding: utf-8 -*- 3 | 4 | from Test_Column_ObjFnc import tac_column 5 | import time 6 | """ 7 | % ------------------------------------------------------------------------- 8 | % SIMULATION-BASED OPTIMIZATION OF A SINGLE CONVENTIONAL DISTILLATION 9 | % COLUMN USING THE PARTICLE SWARM OPTIMIZATION ALGORITHM 10 | %-------------------------------------------------------------------------- 11 | % Juan Javaloyes Antón. Sep 2016 v.3 12 | %-------------------------------------------------------------------------- 13 | % # 04 # Distillation column model 14 | %-------------------------------------------------------------------------- 15 | """ 16 | 17 | def distColumn_model(x, Problem): 18 | 19 | # Independent Variables 20 | RR = x[0] # * RR: Reflux Ratio 21 | BR = x[1] # * BR: Boilup Ratio 22 | 23 | NR = x[2] # * NR: Number of active trays in rectifying section 24 | NS = x[3] # * NS: Number of active trays in stripping section 25 | 26 | 27 | HyObject = Problem.HyObject # Recover Hysys Objects from structure Problem 28 | NT = (NR + NS) + 1 # Total number of active trays 29 | Feed_S = NR + 1 # Feed location 30 | 31 | # 01 Change Column Topology and Column specifications (degrees of freedom) 32 | HyObject = Problem.HyObject # Recover Hysys Objects from structure Problem 33 | 34 | # Total number of active trays 35 | HyObject.DistColumn.Main_TS.NumberOfTrays = NT 36 | 37 | # Feed location 38 | HyObject.DistColumn.Main_TS.SpecifyFeedLocation(HyObject.DistColumn.FeedMainTS, Feed_S) 39 | 40 | # Reflux Ratio 41 | HyObject.DistColumn.Column.ColumnFlowsheet.Specifications.Item('Reflux Ratio').GoalValue = RR 42 | 43 | # Boilup Ratio 44 | HyObject.DistColumn.Column.ColumnFlowsheet.Specifications.Item('Boilup Ratio').GoalValue = BR 45 | 46 | # 02 Run Aspen Hysys model with new topology 47 | HyObject.DistColumn.ColumnFlowsheet.Run() # Run Aspen Hysy model 48 | # time.sleep(0.3) 49 | 50 | # 03 Check model convergence 51 | RunStatus = HyObject.HyApp.ActiveDocument.Flowsheet.Operations.Item(0).ColumnFlowsheet.CfsConverged 52 | 53 | if RunStatus == 1: 54 | 55 | # 04 Compute the Total Annual Cost of the Distillation Column 56 | ColumnCost = tac_column(Problem) # from Test_Column_ObjFnc 57 | 58 | # 05 Check purity constraints 59 | Tol_dist = 0.001 # Molar Fraction Impurites 60 | Bz_Bottoms = 0.001 61 | Comp_frac_Tol_dist = HyObject.MaterialStream.Distillate.ComponentMolarFractionValue[1] 62 | Comp_frac_Bz_Bott = HyObject.MaterialStream.Bottoms.ComponentMolarFractionValue[0] 63 | 64 | if Comp_frac_Tol_dist > Tol_dist: 65 | w1 = (Comp_frac_Tol_dist - Tol_dist)*1e5 66 | else: 67 | w1 = 0 68 | 69 | if Comp_frac_Bz_Bott > Bz_Bottoms: 70 | w2 = (Comp_frac_Bz_Bott - Bz_Bottoms)*1e5 71 | else: 72 | w2 = 0 73 | 74 | # Total Annual Cost + penalty terms 75 | 76 | TAC = ColumnCost.TAC + w1 + w2 77 | else: # In case model does not converge 78 | 79 | 80 | TAC = 1e5 81 | return (TAC) 82 | -------------------------------------------------------------------------------- /ConventionalDistillationColumn/hyInterface.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import os 4 | import win32com.client as win32 5 | 6 | """ 7 | 8 | 9 | # ------------------------------------------------------------------------- 10 | # SIMULATION-BASED OPTIMIZATION OF A SINGLE CONVENTIONAL DISTILLATION 11 | # COLUMN USING THE PARTICLE SWARM OPTIMIZATION ALGORITHM 12 | #-------------------------------------------------------------------------- 13 | # Juan Javaloyes Antón. Sep 2016 14 | #-------------------------------------------------------------------------- 15 | # # 03 # Aspen Hysys Python Interface - Conventional Distillation Column Test 16 | #-------------------------------------------------------------------------- 17 | 18 | """ 19 | 20 | 21 | 22 | # >>>>>>>>>>>>>>>[ Aspen Hysys - Python Interface ]>>>>>>>>>>>>>>> > User inputs 23 | # Aspen Hysys file name 24 | #hy_filename = 'Test_Column.hsc' 25 | #hy_best_model_filename = 'Best_Column.hsc' 26 | #hy_visible = 1 27 | 28 | # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >End inputs 29 | 30 | def hy_Dist_Col_Object(Problem, *varargin): 31 | 32 | hy_filename = Problem.hy_filename 33 | hy_best_model_filename = Problem.hy_best_model_filename 34 | hy_visible = Problem.hy_visible 35 | 36 | # 01 Full path to Aspen Hysys File & Best Solution Hysys File 37 | 38 | hyFilePath = os.path.abspath(hy_filename) 39 | hy_beswt_solution_FilePath = os.path.abspath(hy_best_model_filename) 40 | 41 | # 02 Initialize Aspen Hysys application 42 | print(' # Connecting to the Aspen Hysys App ... ') 43 | HyApp = win32.Dispatch('HYSYS.Application') 44 | 45 | # 03 Open Aspen Hysys File 46 | # HyCase = HyApp.SimulationCases.Open(hyFilePath) 47 | 48 | HyCase = HyApp.ActiveDocument 49 | 50 | # 04 Aspen Hysys Environment Visible 51 | HyCase.Visible = hy_visible 52 | 53 | 54 | # 05 Aspen Hysys File Name 55 | HySysFile = HyCase.Title.Value 56 | print(' ') 57 | print('HySys File: ---------- ', HySysFile) 58 | 59 | # 06 Aspen Hysys Fluid Package Name 60 | package_name = HyCase.Flowsheet.FluidPackage.PropertyPackageName 61 | print('HySys Fluid Package: --- ', package_name) 62 | print(' ') 63 | 64 | 65 | ### Access to Main Aspen Hysys Objects ######################################### 66 | # ----------------------------------------------------------------------------- 67 | 68 | # 07 Main Aspen Hysys Document Objects 69 | HySolver = HyCase.Solver # Access to Hysys Solver 70 | # HyFlowsheet = HyCase.Flowsheet # Access to main Flowsheet 71 | HyOperations = HyCase.Flowsheet.Operations # Access to the Unit Operations 72 | HyMaterialStream = HyCase.Flowsheet.MaterialStreams # Access to the material streams 73 | HyEnergyStream = HyCase.Flowsheet.EnergyStreams # Access to the energy streams 74 | 75 | 76 | # 08 Access to Distillation Column Environment 77 | 78 | # Interfacing with the Aspen Hysys Objects needed to compute the Total 79 | # Annual Cost of the Conventional Distillation Column # 80 | 81 | # 08.1 Access to Hysys Distillation Column and Column Flowsheet 82 | Column_Name = HyOperations.Names[0] 83 | class DistColumn: 84 | pass 85 | DistColumn.Column = HyOperations.Item(Column_Name) 86 | DistColumn.ColumnFlowsheet = DistColumn.Column.ColumnFlowsheet 87 | 88 | # 08.1.1 Access to Column objects 89 | DistColumn.Specifications = DistColumn.ColumnFlowsheet.Specifications # RR/BR/.... 90 | DistColumn.Operations = DistColumn.ColumnFlowsheet.Operations # Main TS/Reboiler/Condenser 91 | DistColumn.FeedStreams = DistColumn.ColumnFlowsheet.FeedStreams # Access to Feed Streams (material and energy) for the Column Environment (Main TS, Reboiler y Condenser) 92 | 93 | # 08.1.1.1 Access to Main TS of the distillation column (Column Environment) 94 | DistColumn.Main_TS = DistColumn.ColumnFlowsheet.Operations.Item('Main TS') # Access to Main TS in Column Environment 95 | 96 | # 08.1.1.2 Access to Feed stream object of the Main Tray Section 97 | DistColumn.FeedMainTS = DistColumn.FeedStreams.Item('Feed') 98 | 99 | # 08.2. Material Streams 100 | class MaterialStream: 101 | pass 102 | 103 | MaterialStream.Distillate = HyMaterialStream.Item('Distillate') 104 | MaterialStream.Bottoms = HyMaterialStream.Item('Bottoms') 105 | 106 | # 08.3. Energy Streams 107 | class EnergyStream: 108 | pass 109 | 110 | EnergyStream.Qreb = HyEnergyStream.Item('Qreb') 111 | EnergyStream.Qcond = HyEnergyStream.Item('Qcond') 112 | 113 | # 09 ...: HYSYS OBJECTS :... 114 | class HyObject: 115 | pass 116 | 117 | HyObject.HyApp = HyApp 118 | HyObject.HyCase = HyCase 119 | HyObject.DistColumn = DistColumn 120 | HyObject.MaterialStream = MaterialStream 121 | HyObject.EnergyStream = EnergyStream 122 | HyObject.HySolver = HySolver 123 | HyObject.CDC_model_Root = hy_beswt_solution_FilePath # Full Path to Best Solution Aspen Hysys file 124 | HyObject.folder_paht = hy_beswt_solution_FilePath[0:-len(hy_best_model_filename)] # Folder Path 125 | 126 | print( '# Aspen Hysys - Python Interface has been Established....') 127 | return(HyObject) 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /ConventionalDistillationColumn/main_Column.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from pso_column import distCol_optimization 4 | 5 | """ 6 | # ------------------------------------------------------------------------- 7 | # SIMULATION-BASED OPTIMIZATION OF A SINGLE CONVENTIONAL DISTILLATION 8 | # COLUMN USING THE PARTICLE SWARM OPTIMIZATION ALGORITHEM 9 | #-------------------------------------------------------------------------- 10 | # Juan Javaloyes Antón / FJ Navarro-Brull (Sept 2016) 11 | # License: BSD-CL 3 javaloyes.juan@gmail.com 12 | # More info at: https://github.com/CAChemE/stochastic-optimization 13 | #-------------------------------------------------------------------------- 14 | # # 01 # Main Script 15 | #-------------------------------------------------------------------------- 16 | #------------------------------------------------------------------------- 17 | # Conventional Distillation Column Superstructure 18 | # 19 | # 20 | # ---- 21 | # _ _ _ _ _ _ _| | 22 | # | | | 23 | # | ---- 24 | # -------- | D 25 | # | |<------------------------> 26 | # |...... | 27 | # | ......| NR_lb < NR < NR_up 28 | # |...... | 29 | # F | ------| ---- Fixed Trays 30 | # ----------> |------ | .... Conditional Trays 31 | # | ------| 32 | # |...... | 33 | # | ......| NS_lb < NS < NS_up 34 | # |...... | 35 | # | |<---------| 36 | # -------- | 37 | # | | 38 | # | ---- B 39 | # _ _ _ _ _ _ | |---------------> 40 | # | | 41 | # ---- 42 | #-------------------------------------------------------------------------- 43 | 44 | # List of files 45 | # ---------------------------------------------------------------------------------------------------------------------------------------------------| 46 | # Nº Name Description | Notes | 47 | # ---------------------------------------------------------------------------------------------------------------------------------------------------| 48 | # #01 ...... Test_Column ........... Main script | User Inputs | 49 | # ---------------------------------------------------------------------------------------------------------------------------------------------------| 50 | # #02 ...... pso_column ............ Call to hyInterface to start the | | 51 | # connection with Aspen Hysys and runs the | Do not modify | 52 | # pso_gbest algorithm | | 53 | # ---------------------------------------------------------------------------------------------------------------------------------------------------| 54 | # #03 ...... hyInterface .......... Aspen Hysys - Python Interface | If some labels of the Aspen Hysys model are modify, user must | 55 | # | modify also this function. | 56 | # ---------------------------------------------------------------------------------------------------------------------------------------------------| 57 | # #04 ...... tac_column ........ Calculates TAC (total annual cost) | User can modify economic parameters or cost correlations. | 58 | # of the conv. distillation column | This functions is within the Test_Column_ObjFnc.py file | 59 | #----------------------------------------------------------------------------------------------------------------------------------------------------| 60 | # #05 ...... print_results ... print main results in screen | Function is inside the file named print_pso.py | 61 | #----------------------------------------------------------------------------------------------------------------------------------------------------| 62 | # #06 ...... PSO_Algorithm ... Includes Global Best version of the | User can modify PSO Algorithm parameters | | 63 | #----------------------------------------------------------------------------------------------------------------------------------------------------| 64 | 65 | """ 66 | # # User inputs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 67 | 68 | # # 01 Hysys file name 69 | hy_filename = 'Test_Column.hsc' 70 | 71 | # # 02 72 | hy_best_model_filename = 'Best_Solution_Test_Column.hsc' 73 | 74 | # # 03 Bounds on the conditional trays 75 | # RR BR NR NS 76 | lb = [1, 1, 10, 10] 77 | ub = [2, 2, 30, 30] 78 | 79 | # # 04 Binary variables index 80 | IntVars = [2, 3] 81 | 82 | # # 05 Aspen Hysys Graphical User Interface Visible 83 | hy_visible = 1 # [1 ==> Visible 0 ==> No Visible] 84 | 85 | 86 | # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<< END 87 | 88 | 89 | # # Problem Structure ----------------------------------------------------- 90 | class Problem: 91 | pass 92 | 93 | Problem.hy_filename = hy_filename 94 | Problem.hy_best_model_filename = hy_best_model_filename 95 | Problem.lb = lb 96 | Problem.ub = ub 97 | Problem.IntVars = IntVars 98 | Problem.hy_visible = hy_visible 99 | 100 | 101 | # # Run PSO ############################################################### 102 | Result = distCol_optimization(Problem) # from pso_column 103 | print('Obj_fnc = ', Result.best_fitness) 104 | print('x_best = ', Result.x_best) 105 | #---------------------------------------------------------------------- end -------------------------------------------------------------------------------- /ConventionalDistillationColumn/print_pso.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def print_results(iter, FO_evaluations, gbest, pworst, 4 | error_fnc, error_x, swarm_size, n_variables, 5 | intVar, print_freq): 6 | """ 7 | Auxiliary function to print PSO results 8 | 9 | :param iter: numer of iteration 10 | :param FO_evaluations: 11 | :param gbest: global best particle 12 | :param pworst: worst particle 13 | :param error_fnc: normalized error of the obj function ||pworst_fitness - gbest_fitness|| 14 | :param error_x: normalized error of the obj function ||pworst_position - gbest_position|| 15 | :param swarm_size: number of particles 16 | :param n_variables: number of dimmesions 17 | :param intVar: array or list containing the indexes for the variables that must be integers 18 | :param print_freq: frequency with the number of iterations that prints 19 | :return: 20 | """ 21 | intVar = np.array(intVar) 22 | 23 | if iter == 1: 24 | print(' \n') 25 | print('# STANDARD PARTICLE SWARM OPTIMIZATION ALGORITHM - gbest version ### \n') 26 | print(' * Swarm size ................. {}'.format(swarm_size)) 27 | print(' * # continuous variables ..... {}'.format(n_variables - np.size(intVar))) 28 | print(' * # integer variables ....... {}'.format(np.size(intVar))) 29 | print(' \n') 30 | 31 | 32 | if (iter == 1) or (iter/(print_freq) == round(iter/print_freq)): 33 | if (iter == 1) or (iter/(print_freq*20) == round(iter/(print_freq))): 34 | print(' --------------------------------------------------------------------------------------------\n') 35 | print(' Iteration \t FO_evals \t gBest Fitness \t pWorst Fitness\t error_FO \t error_x\n') 36 | print(' --------------------------------------------------------------------------------------------\n') 37 | 38 | 39 | print('{:8.0f} \t {:5.0f} \t {:15.3e} \t {:11.3e} \t {:11.3e} \t {:6.3e}'.format( 40 | iter, FO_evaluations, gbest, pworst, error_fnc, error_x)) 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ConventionalDistillationColumn/pso_column.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import time 3 | 4 | 5 | from hyInterface import hy_Dist_Col_Object 6 | from PSO_Algorithm import pso_gbest 7 | from column_algorithm import distColumn_model 8 | 9 | """ 10 | 11 | # ------------------------------------------------------------------------- 12 | # SIMULATION-BASED OPTIMIZATION OF A SINGLE CONVENTIONAL DISTILLATION 13 | # COLUMN USING THE PARTICLE SWARM OPTIMIZATION ALGORITHEM 14 | #-------------------------------------------------------------------------- 15 | # Juan Javaloyes Antón. Sep 2016 16 | #-------------------------------------------------------------------------- 17 | # # 02 # Main function with the calls to Aspen Hysys Objects and PSO 18 | #-------------------------------------------------------------------------- 19 | 20 | """ 21 | 22 | def distCol_optimization(Problem): 23 | 24 | 25 | # 01 Interface between Aspen Hysys and Matlab 26 | HyObject = hy_Dist_Col_Object(Problem) # from hiInterface 27 | 28 | Problem.HyObject = HyObject 29 | 30 | # 02 Run Optimization model 31 | lb = Problem.lb 32 | ub = Problem.ub 33 | IntVars = Problem.IntVars 34 | 35 | t_start = time.time() 36 | 37 | Result = pso_gbest(distColumn_model, lb, ub, IntVars, Problem ) # #### PSO #### 38 | 39 | t_stop = time.time() - t_start 40 | 41 | # 03 Print Results 42 | Result.etime = t_stop 43 | 44 | # printResult_cdc(Result, Problem) 45 | return(Result) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Computer Aided Chemical Engineering 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of stochastic-optimization nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /PSO/1D/img/PSS-Example-1D.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/1D/img/PSS-Example-1D.gif -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_0.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_1.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_10.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_11.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_12.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_13.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_14.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_15.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_16.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_17.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_18.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_19.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_2.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_20.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_21.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_22.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_23.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_24.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_25.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_26.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_27.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_28.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_29.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_3.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_4.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_5.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_6.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_7.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_8.png -------------------------------------------------------------------------------- /PSO/2D/ackley_convergent/ackley_2D_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/ackley_convergent/ackley_2D_9.png -------------------------------------------------------------------------------- /PSO/2D/img/PSO_Ackley.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/img/PSO_Ackley.gif -------------------------------------------------------------------------------- /PSO/2D/img/PSO_Example1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/img/PSO_Example1.gif -------------------------------------------------------------------------------- /PSO/2D/img/PSO_Rana.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/img/PSO_Rana.gif -------------------------------------------------------------------------------- /PSO/2D/img/PSO_odd_square.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/img/PSO_odd_square.gif -------------------------------------------------------------------------------- /PSO/2D/img/PSO_salomon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/2D/img/PSO_salomon.gif -------------------------------------------------------------------------------- /PSO/2D/optitestfuns.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | def ackley(x): 6 | """Ackley n-dimensional function 7 | 8 | Params: 9 | x = numpy array or list containing the independent variables 10 | returns y = objective function value 11 | 12 | Best solution: 13 | f(x_i*) = y = 0 (i dimensions) 14 | x_i* = 0 15 | 16 | -30 <= x_i <= 30 17 | """ 18 | 19 | 20 | x = np.array(x) # converts list to numpy array 21 | n = x.size # n-dimensions of the vector 22 | 23 | y = -20 * np.exp(-0.2 * (1 / n * np.sum(x ** 2)) ** 0.5) + \ 24 | -np.exp(1 / n * np.sum(np.cos(2 * np.pi * x))) + 20 + np.exp(1) 25 | 26 | return y 27 | 28 | 29 | def griewangk(x): 30 | """Griewank n-dimensional function 31 | 32 | Params: 33 | x = numpy array or list containing the independent variables 34 | returns y = objective function value 35 | 36 | Best solution: 37 | f(x_i*) = y = 0 (i dimensions) 38 | x_i* = 0 39 | 40 | -100 <= x_i <= 100 41 | """ 42 | 43 | x = np.array(x) # converts list to numpy array 44 | n = x.size # n-dimensions of the vector 45 | j = np.arange(n) 46 | 47 | y = 1/4000 * np.sum(x**2) - np.prod(np.cos(x/(j + 1)**0.5)) + 1 48 | 49 | return y 50 | 51 | def rastrigin(x): 52 | """Rastrigin n-dimensional function 53 | 54 | Params: 55 | x = numpy array or list containing the independent variables 56 | returns y = objective function value 57 | 58 | Best solution: 59 | f(x_i*) = y = 0 (i dimensions) 60 | x_i* = 0 61 | 62 | -5.12 <= x_i <= 5.12 63 | """ 64 | 65 | x = np.array(x) # converts list to numpy array 66 | n = x.size # n-dimensions of the vector 67 | 68 | y = np.sum(x**2 - 10*np.cos(2*np.pi*x)+10) 69 | 70 | return y 71 | 72 | def salomon(x): 73 | """Salomon n-dimensional function 74 | 75 | Params: 76 | x = numpy array or list containing the independent variables 77 | returns y = objective function value 78 | 79 | Best solution: 80 | f(x_i*) = y = 0 (i dimensions) 81 | x_i* = 0 82 | 83 | -100 <= x_i <= 100 84 | """ 85 | 86 | x = np.array(x) # converts list to numpy array 87 | n = x.size # n-dimensions of the vector 88 | 89 | x_norm = np.sqrt(np.sum(x**2)) 90 | 91 | y = -np.cos(2*np.pi*x_norm) + 0.1*x_norm+1 92 | 93 | return y 94 | 95 | def odd_square(x): 96 | """Whitley n-dimensional function 97 | 98 | Params: 99 | x = numpy array or list containing the independent variables 100 | returns y = objective function value 101 | 102 | Best solution: 103 | f(x_i*) = y = -1.14383 (i dimensions) 104 | x_i* = many solutions near b 105 | 106 | -5*pi <= x_i <= 5*pi 107 | """ 108 | 109 | x = np.array(x) # converts list to numpy array 110 | n = x.size # n-dimensions of the vector 111 | 112 | assert n<=10, "Error: more than 10 dimensions were given, you need to modify function params to run" 113 | b = np.array([1, 1.3, 0.8, -0.4, -1.3, 1.6, -0.2, -0.6, 0.5, 1.4, 114 | 1, 1.3, 0.8, -0.4, -1.3, 1.6, -0.2, -0.6, 0.5, 1.4]) 115 | 116 | b = b[0:n] 117 | 118 | d = n*np.max((x-b)**2) 119 | h = np.sum((x-b)**2) 120 | 121 | y = -np.exp(-d/(2*np.pi))*np.cos(np.pi*d)*(1 + (0.02*h)/(d+0.01)) 122 | 123 | return y 124 | 125 | def schwefel(x): 126 | """Schwefel n-dimensional function 127 | 128 | Params: 129 | x = numpy array or list containing the independent variables 130 | returns y = objective function value 131 | 132 | Best solution: 133 | f(x_i*) = y = -418.983 (i dimensions) 134 | x_i* = 420.968746 135 | 136 | -500 <= x_i <= 500 137 | """ 138 | 139 | x = np.array(x) # converts list to numpy array 140 | n = x.size # n-dimensions of the vector 141 | 142 | y = -1/n*np.sum(x*np.sin(np.sqrt(np.abs(x)))) 143 | 144 | return y 145 | 146 | def rana(x): 147 | """Rana n-dimensional function 148 | 149 | Params: 150 | x = numpy array or list containing the independent variables 151 | returns y = objective function value 152 | 153 | Best solution: 154 | f(x_i*) = y = -511.708 (i dimensions) 155 | x_i* = -512 156 | 157 | -512 <= x_i <= 512 158 | """ 159 | 160 | x = np.array(x) # converts list to numpy array 161 | n = x.size # n-dimensions of the vector 162 | assert n>=2, "Error: Rana function requires at least 2D" 163 | 164 | #import pdb; pdb.set_trace() 165 | 166 | x_j = x[:-1] 167 | x_j1 = x[1:] 168 | alpha = np.sqrt(np.abs(x_j1+1-x_j)) 169 | beta = np.sqrt(np.abs(x_j1+1+x_j)) 170 | 171 | fo = np.sum(x_j*np.sin(alpha)*np.cos(beta)+x_j1*np.cos(alpha)*np.sin(beta)) 172 | 173 | return fo 174 | 175 | -------------------------------------------------------------------------------- /PSO/2D/plotPSO.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from mpl_toolkits.mplot3d import Axes3D 4 | 5 | plt.style.use('bmh') 6 | 7 | 8 | def plotPSO_2D(function, limits=([-5,5],[-5,5]), 9 | particles_xy=([],[]), particles_uv=([],[]), 10 | n_points=100, *arg): 11 | """Creates a figure of 1x2 with a 3D projection representation of a 2D function and a its projection 12 | 13 | Params: 14 | function: a 2D or nD objective function 15 | limits: define the bounds of the function 16 | particles_xy a tuple contatining 2 lists with the x and y coordinate of the particles 17 | particles_xy a tuple contatining 2 lists with the u and v velocities of the particles 18 | n_points: number of points where the function is evaluated to be plotted, the bigger the finner""" 19 | 20 | 21 | # Grid points 22 | x_lo = limits[0][0] 23 | x_up = limits[0][1] 24 | y_lo = limits[1][0] 25 | y_up = limits[1][1] 26 | 27 | assert x_lo=1: 75 | z_particles = np.zeros(n_particles) 76 | 77 | for i in range(n_particles): 78 | z_particles[i] = function((x_particles[i],y_particles[i])) 79 | 80 | # Plot particles over the function 81 | ax1.scatter(x_particles, y_particles, z_particles, 82 | s=50, c='magenta', 83 | depthshade=False, zorder=1000) 84 | 85 | z_particles_projection = z_cut_plane*np.ones(n_particles) 86 | 87 | # Plot particles below the function (projection) 88 | ax1.scatter(x_particles, y_particles, z_particles_projection, 89 | s=50, c='red', 90 | depthshade=False, zorder=1000) 91 | 92 | 93 | # 2D projection (right figure) 94 | ax2 = fig.add_subplot(1, 2, 2) 95 | 96 | # Projection of function 97 | cf2d = ax2.contourf(XX,YY,ZZ, 98 | zdir='z', offset=z_cut_plane, 99 | cmap=plt.cm.viridis, zorder=1) 100 | 101 | # Particles (2D) 102 | if n_particles>=1: 103 | ax2.scatter(x_particles, y_particles, 104 | s=50, c='red', zorder=2) 105 | 106 | if n_velocities>=1: 107 | ax2.quiver(x_particles,y_particles,u_particles,v_particles, 108 | angles='xy', scale_units='xy', scale=1) 109 | 110 | tag_particles = range(n_particles) 111 | 112 | for j, txt in enumerate(tag_particles): 113 | ax2.annotate(txt, (x_particles[j],y_particles[j]), zorder=3) 114 | 115 | 116 | ax2.set_title('xy plane') 117 | fig.colorbar(cf2d, shrink=1) 118 | 119 | #plt.savefig(function.__name__+'_2D', bbox_inches='tight') 120 | #plt.show() 121 | 122 | 123 | 124 | return fig, (ax1, ax2) 125 | 126 | def plotPSO_1D(function, limits=([-5,5]), particles_coordinates=([]), particles_velocities=([]), n_points=100, *arg): 127 | """Returns and shows a figure of a 2D representation of a 1D function 128 | 129 | Params: 130 | function: a 2D or nD objective function 131 | limits: define the bounds of the function 132 | particles_coordinates: a tuple contatining 2 lists with the x and y coordinate of the particles 133 | particles_velocities: a tuple contatining 2 lists with the u and v velocities of the particles 134 | n_points: number of points where the function is evaluated to be plotted, the bigger the finner""" 135 | 136 | # Grid points 137 | x_lo = limits[0] 138 | x_up = limits[1] 139 | 140 | x = np.linspace(x_lo, x_up, n_points) # x coordinates of the grid 141 | z = np.zeros(n_points) 142 | 143 | for i in range(n_points): 144 | z[i] = function(x[i]) 145 | 146 | fig = plt.figure() 147 | ax = fig.add_subplot(111) # 111 stands for subplot(nrows, ncols, plot_number) 148 | ax.plot(x,z, zorder=1) 149 | 150 | particles_coordinates = np.array(particles_coordinates) 151 | particles_velocities = np.array(particles_velocities) 152 | 153 | assert particles_coordinates.ndim <=1, \ 154 | "Arrays containing particle coordinates have more than 1 dimmension" 155 | 156 | if particles_coordinates.shape[0] is not 0: 157 | x_particles = particles_coordinates 158 | n_particles = x_particles.shape[0] 159 | 160 | z_particles = np.zeros(n_particles) 161 | 162 | 163 | for i in range(n_particles): 164 | z_particles[i] = function(x_particles[i]) 165 | 166 | # Plot particles over the function 167 | ax.scatter(x_particles, z_particles, 168 | s=50, c='red', zorder=2) 169 | 170 | if particles_velocities.shape[0] is not 0: 171 | u_particles = particles_velocities 172 | 173 | n_velocities = u_particles.shape[0] 174 | 175 | v_particles = np.zeros(n_particles) 176 | 177 | ax1.quiver(x_particles,z_particles,u_particles,v_particles, 178 | angles='xy', scale_units='xy', scale=1) 179 | 180 | tag_particles = range(n_particles) 181 | 182 | for j, txt in enumerate(tag_particles): 183 | ax1.annotate(txt, (x_particles[j,i],z_particles[j,i])) 184 | 185 | 186 | 187 | ax.set_xlabel('$x$') 188 | ax.set_ylabel('$y$') 189 | 190 | ax.set_title(function.__name__) 191 | 192 | #plt.savefig(function.__name__+'_1D', bbox_inches='tight') 193 | plt.show() 194 | 195 | return fig, ax -------------------------------------------------------------------------------- /PSO/nD/DemoAckley.py: -------------------------------------------------------------------------------- 1 | from pso import pso 2 | from optitestfuns import ackley 3 | import unittest 4 | import math 5 | 6 | 7 | intVar = [] 8 | result = pso(ackley, [-5,-5], [5,5], intVar) 9 | 10 | print(result.exit) 11 | print('x_opt: {}'.format(result.xopt)) 12 | print('FO: {:2e}'.format(result.FO)) -------------------------------------------------------------------------------- /PSO/nD/MATLAB/DemoAckley.m: -------------------------------------------------------------------------------- 1 | 2 | IntVar = []; 3 | R = pso_v3(@F_Ackley,[-5;-1],[5;1],IntVar) 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PSO/nD/MATLAB/F_Ackley.m: -------------------------------------------------------------------------------- 1 | function y = F_Ackley(x,varargin) 2 | 3 | n = length(x); 4 | y = -20*exp(-0.2*(1/n*sum(x.^2))^0.5) - ... 5 | exp(1/n*sum(cos(2*pi*x))) + 20 + exp(1); -------------------------------------------------------------------------------- /PSO/nD/MATLAB/ftest1d.m: -------------------------------------------------------------------------------- 1 | x = -2:0.01:2; 2 | y = zeros(1,length(x)); 3 | 4 | for i = 1:length(x) 5 | y(i) = F_Ackley(x(i)); 6 | end 7 | 8 | plot(x,y) 9 | -------------------------------------------------------------------------------- /PSO/nD/MATLAB/ftest2d.m: -------------------------------------------------------------------------------- 1 | x = -2:1:2; 2 | y = -2:1:2; 3 | X = zeros(length(x),length(y)); 4 | Y = zeros(length(x),length(y)); 5 | Z = zeros(length(x),length(y)); 6 | 7 | for i = 1:length(x) 8 | for j = 1:length(y) 9 | X(i,j) = x(i,j); 10 | Y(i,j) = y(i,j); 11 | Z(i,j) = F_Ackley([x(i),y(i)]); 12 | end 13 | end 14 | 15 | plot3(X,Y,Z) 16 | -------------------------------------------------------------------------------- /PSO/nD/MATLAB/ftest3d.m: -------------------------------------------------------------------------------- 1 | x = -2:0.1:2; 2 | y = -2:0.1:2; 3 | z = -2:0.1:2; 4 | 5 | [X,Y,Z] = meshgrid(x, y, z); 6 | 7 | C = zeros(length(x),length(y),length(z)); 8 | 9 | for i = 1:length(X) 10 | for j = 1:length(Y) 11 | for k = 1:length(Z) 12 | C(i,j,k) = F_Ackley(X(i,j,k),Y(i,j,k),Z(i,j,k)); 13 | end 14 | end 15 | end 16 | 17 | i = 1; 18 | scatter3( X(i,j,k),Y(i,j,k),Z(i,j,k),10,C(i,j,k),'filled') 19 | hold on 20 | 21 | for i = 1:length(X) 22 | for j = 1:length(Y) 23 | for k = 1:length(Z) 24 | scatter3( X(i,j,k),Y(i,j,k),Z(i,j,k),10,C(i,j,k),'filled'); 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /PSO/nD/MATLAB/pso_v3.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/MATLAB/pso_v3.m -------------------------------------------------------------------------------- /PSO/nD/img/1D/ackley_1D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/1D/ackley_1D.png -------------------------------------------------------------------------------- /PSO/nD/img/1D/griewangk_1D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/1D/griewangk_1D.png -------------------------------------------------------------------------------- /PSO/nD/img/1D/odd_square_1D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/1D/odd_square_1D.png -------------------------------------------------------------------------------- /PSO/nD/img/1D/rastrigin_1D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/1D/rastrigin_1D.png -------------------------------------------------------------------------------- /PSO/nD/img/1D/salomon_1D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/1D/salomon_1D.png -------------------------------------------------------------------------------- /PSO/nD/img/2D/ackley_2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/2D/ackley_2D.png -------------------------------------------------------------------------------- /PSO/nD/img/2D/griewangk_2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/2D/griewangk_2D.png -------------------------------------------------------------------------------- /PSO/nD/img/2D/odd_square_2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/2D/odd_square_2D.png -------------------------------------------------------------------------------- /PSO/nD/img/2D/rana_2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/2D/rana_2D.png -------------------------------------------------------------------------------- /PSO/nD/img/2D/rastrigin_2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/2D/rastrigin_2D.png -------------------------------------------------------------------------------- /PSO/nD/img/2D/salomon_2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/2D/salomon_2D.png -------------------------------------------------------------------------------- /PSO/nD/img/2D/schwefel_2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/PSO/nD/img/2D/schwefel_2D.png -------------------------------------------------------------------------------- /PSO/nD/optitestfuns.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | def ackley(x): 6 | """Ackley n-dimensional function 7 | 8 | Params: 9 | x = numpy array or list containing the independent variables 10 | returns y = objective function value 11 | 12 | Best solution: 13 | f(x_i*) = y = 0 (i dimensions) 14 | x_i* = 0 15 | 16 | -30 <= x_i <= 30 17 | """ 18 | 19 | 20 | x = np.array(x) # converts list to numpy array 21 | n = x.size # n-dimensions of the vector 22 | 23 | y = -20 * np.exp(-0.2 * (1 / n * np.sum(x ** 2)) ** 0.5) + \ 24 | -np.exp(1 / n * np.sum(np.cos(2 * np.pi * x))) + 20 + np.exp(1) 25 | 26 | return y 27 | 28 | 29 | def griewangk(x): 30 | """Griewank n-dimensional function 31 | 32 | Params: 33 | x = numpy array or list containing the independent variables 34 | returns y = objective function value 35 | 36 | Best solution: 37 | f(x_i*) = y = 0 (i dimensions) 38 | x_i* = 0 39 | 40 | -100 <= x_i <= 100 41 | """ 42 | 43 | x = np.array(x) # converts list to numpy array 44 | n = x.size # n-dimensions of the vector 45 | j = np.arange(n) 46 | 47 | y = 1/4000 * np.sum(x**2) - np.prod(np.cos(x/(j + 1)**0.5)) + 1 48 | 49 | return y 50 | 51 | def rastrigin(x): 52 | """Rastrigin n-dimensional function 53 | 54 | Params: 55 | x = numpy array or list containing the independent variables 56 | returns y = objective function value 57 | 58 | Best solution: 59 | f(x_i*) = y = 0 (i dimensions) 60 | x_i* = 0 61 | 62 | -5.12 <= x_i <= 5.12 63 | """ 64 | 65 | x = np.array(x) # converts list to numpy array 66 | n = x.size # n-dimensions of the vector 67 | 68 | y = np.sum(x**2 - 10*np.cos(2*np.pi*x)+10) 69 | 70 | return y 71 | 72 | def salomon(x): 73 | """Salomon n-dimensional function 74 | 75 | Params: 76 | x = numpy array or list containing the independent variables 77 | returns y = objective function value 78 | 79 | Best solution: 80 | f(x_i*) = y = 0 (i dimensions) 81 | x_i* = 0 82 | 83 | -100 <= x_i <= 100 84 | """ 85 | 86 | x = np.array(x) # converts list to numpy array 87 | n = x.size # n-dimensions of the vector 88 | 89 | x_norm = np.sqrt(np.sum(x**2)) 90 | 91 | y = -np.cos(2*np.pi*x_norm) + 0.1*x_norm+1 92 | 93 | return y 94 | 95 | def odd_square(x): 96 | """Whitley n-dimensional function 97 | 98 | Params: 99 | x = numpy array or list containing the independent variables 100 | returns y = objective function value 101 | 102 | Best solution: 103 | f(x_i*) = y = -1.14383 (i dimensions) 104 | x_i* = many solutions near b 105 | 106 | -5*pi <= x_i <= 5*pi 107 | """ 108 | 109 | x = np.array(x) # converts list to numpy array 110 | n = x.size # n-dimensions of the vector 111 | 112 | assert n<=10, "Error: more than 10 dimensions were given, you need to modify function params to run" 113 | b = np.array([1, 1.3, 0.8, -0.4, -1.3, 1.6, -0.2, -0.6, 0.5, 1.4, 114 | 1, 1.3, 0.8, -0.4, -1.3, 1.6, -0.2, -0.6, 0.5, 1.4]) 115 | 116 | b = b[0:n] 117 | 118 | d = n*np.max((x-b)**2) 119 | h = np.sum((x-b)**2) 120 | 121 | y = -np.exp(-d/(2*np.pi))*np.cos(np.pi*d)*(1 + (0.02*h)/(d+0.01)) 122 | 123 | return y 124 | 125 | def schwefel(x): 126 | """Schwefel n-dimensional function 127 | 128 | Params: 129 | x = numpy array or list containing the independent variables 130 | returns y = objective function value 131 | 132 | Best solution: 133 | f(x_i*) = y = -418.983 (i dimensions) 134 | x_i* = 420.968746 135 | 136 | -500 <= x_i <= 500 137 | """ 138 | 139 | x = np.array(x) # converts list to numpy array 140 | n = x.size # n-dimensions of the vector 141 | 142 | y = -1/n*np.sum(x*np.sin(np.sqrt(np.abs(x)))) 143 | 144 | return y 145 | 146 | def rana(x): 147 | """Rana n-dimensional function 148 | 149 | Params: 150 | x = numpy array or list containing the independent variables 151 | returns y = objective function value 152 | 153 | Best solution: 154 | f(x_i*) = y = -511.708 (i dimensions) 155 | x_i* = -512 156 | 157 | -512 <= x_i <= 512 158 | """ 159 | 160 | x = np.array(x) # converts list to numpy array 161 | n = x.size # n-dimensions of the vector 162 | assert n>=2, "Error: Rana function requires at least 2D" 163 | 164 | #import pdb; pdb.set_trace() 165 | 166 | x_j = x[:-1] 167 | x_j1 = x[1:] 168 | alpha = np.sqrt(np.abs(x_j1+1-x_j)) 169 | beta = np.sqrt(np.abs(x_j1+1+x_j)) 170 | 171 | fo = np.sum(x_j*np.sin(alpha)*np.cos(beta)+x_j1*np.cos(alpha)*np.sin(beta)) 172 | 173 | return fo 174 | 175 | -------------------------------------------------------------------------------- /PSO/nD/plotPSO.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from mpl_toolkits.mplot3d import Axes3D 4 | 5 | plt.style.use('bmh') 6 | 7 | 8 | def plotPSO_2D(function, limits=([-5,5],[-5,5]), 9 | particles_xy=([],[]), particles_uv=([],[]), 10 | n_points=100, *arg): 11 | """Creates a figure of 1x2 with a 3D projection representation of a 2D function and a its projection 12 | 13 | Params: 14 | function: a 2D or nD objective function 15 | limits: define the bounds of the function 16 | particles_xy a tuple contatining 2 lists with the x and y coordinate of the particles 17 | particles_xy a tuple contatining 2 lists with the u and v velocities of the particles 18 | n_points: number of points where the function is evaluated to be plotted, the bigger the finner""" 19 | 20 | 21 | # Grid points 22 | x_lo = limits[0][0] 23 | x_up = limits[0][1] 24 | y_lo = limits[1][0] 25 | y_up = limits[1][1] 26 | 27 | assert x_lo=1: 75 | z_particles = np.zeros(n_particles) 76 | 77 | for i in range(n_particles): 78 | z_particles[i] = function((x_particles[i],y_particles[i])) 79 | 80 | # Plot particles over the function 81 | ax1.scatter(x_particles, y_particles, z_particles, 82 | s=50, c='magenta', 83 | depthshade=False, zorder=1000) 84 | 85 | z_particles_projection = z_cut_plane*np.ones(n_particles) 86 | 87 | # Plot particles below the function (projection) 88 | ax1.scatter(x_particles, y_particles, z_particles_projection, 89 | s=50, c='red', 90 | depthshade=False, zorder=1000) 91 | 92 | 93 | # 2D projection (right figure) 94 | ax2 = fig.add_subplot(1, 2, 2) 95 | 96 | # Projection of function 97 | cf2d = ax2.contourf(XX,YY,ZZ, 98 | zdir='z', offset=z_cut_plane, 99 | cmap=plt.cm.viridis, zorder=1) 100 | 101 | # Particles (2D) 102 | if n_particles>=1: 103 | ax2.scatter(x_particles, y_particles, 104 | s=50, c='red', zorder=2) 105 | 106 | if n_velocities>=1: 107 | ax2.quiver(x_particles,y_particles,u_particles,v_particles, 108 | angles='xy', scale_units='xy', scale=1) 109 | 110 | tag_particles = range(n_particles) 111 | 112 | for j, txt in enumerate(tag_particles): 113 | ax2.annotate(txt, (x_particles[j],y_particles[j]), zorder=3) 114 | 115 | 116 | ax2.set_title('xy plane') 117 | fig.colorbar(cf2d, shrink=1) 118 | 119 | #plt.savefig(function.__name__+'_2D', bbox_inches='tight') 120 | plt.show() 121 | 122 | 123 | 124 | return fig, (ax1, ax2) 125 | 126 | def plotPSO_1D(function, limits=([-5,5]), particles_coordinates=([]), particles_velocities=([]), n_points=100, *arg): 127 | """Returns and shows a figure of a 2D representation of a 1D function 128 | 129 | Params: 130 | function: a 2D or nD objective function 131 | limits: define the bounds of the function 132 | particles_coordinates: a tuple contatining 2 lists with the x and y coordinate of the particles 133 | particles_velocities: a tuple contatining 2 lists with the u and v velocities of the particles 134 | n_points: number of points where the function is evaluated to be plotted, the bigger the finner""" 135 | 136 | # Grid points 137 | x_lo = limits[0] 138 | x_up = limits[1] 139 | 140 | x = np.linspace(x_lo, x_up, n_points) # x coordinates of the grid 141 | z = np.zeros(n_points) 142 | 143 | for i in range(n_points): 144 | z[i] = function(x[i]) 145 | 146 | fig = plt.figure() 147 | ax = fig.add_subplot(111) # 111 stands for subplot(nrows, ncols, plot_number) 148 | ax.plot(x,z, zorder=1) 149 | 150 | particles_coordinates = np.array(particles_coordinates) 151 | particles_velocities = np.array(particles_velocities) 152 | 153 | assert particles_coordinates.ndim <=1, \ 154 | "Arrays containing particle coordinates have more than 1 dimmension" 155 | 156 | if particles_coordinates.shape[0] is not 0: 157 | x_particles = particles_coordinates 158 | n_particles = x_particles.shape[0] 159 | 160 | z_particles = np.zeros(n_particles) 161 | 162 | 163 | for i in range(n_particles): 164 | z_particles[i] = function(x_particles[i]) 165 | 166 | # Plot particles over the function 167 | ax.scatter(x_particles, z_particles, 168 | s=50, c='red', zorder=2) 169 | 170 | if particles_velocities.shape[0] is not 0: 171 | u_particles = particles_velocities 172 | 173 | n_velocities = u_particles.shape[0] 174 | 175 | v_particles = np.zeros(n_particles) 176 | 177 | ax1.quiver(x_particles,z_particles,u_particles,v_particles, 178 | angles='xy', scale_units='xy', scale=1) 179 | 180 | tag_particles = range(n_particles) 181 | 182 | for j, txt in enumerate(tag_particles): 183 | ax1.annotate(txt, (x_particles[j,i],z_particles[j,i])) 184 | 185 | 186 | 187 | ax.set_xlabel('$x$') 188 | ax.set_ylabel('$y$') 189 | 190 | ax.set_title(function.__name__) 191 | 192 | #plt.savefig(function.__name__+'_1D', bbox_inches='tight') 193 | plt.show() 194 | 195 | return fig, ax -------------------------------------------------------------------------------- /PSO/nD/print_pso.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def print_results(iter, FO_evaluations, gbest, pworst, 4 | error_fnc, error_x, swarm_size, n_variables, 5 | intVar, print_freq): 6 | """ 7 | Auxiliary function to print PSO results 8 | 9 | :param iter: numer of iteration 10 | :param FO_evaluations: 11 | :param gbest: global best particle 12 | :param pworst: worst particle 13 | :param error_fnc: normalized error of the obj function ||pworst_fitness - gbest_fitness|| 14 | :param error_x: normalized error of the obj function ||pworst_position - gbest_position|| 15 | :param swarm_size: number of particles 16 | :param n_variables: number of dimmesions 17 | :param intVar: array or list containing the indexes for the variables that must be integers 18 | :param print_freq: frequency with the number of iterations that prints 19 | :return: 20 | """ 21 | intVar = np.array(intVar) 22 | 23 | if iter == 1: 24 | print(' \n') 25 | print('# STANDARD PARTICLE SWARM OPTIMIZATION ALGORITHM - gbest version ### \n') 26 | print(' * Swarm size ................. {}\n'.format(swarm_size)) 27 | print(' * # continuous variables ..... {}\n'.format(n_variables - intVar.size)) 28 | print(' * # integer variables ....... {}\n'.format(intVar.size)) 29 | print(' \n') 30 | 31 | 32 | if (iter == 1) or (iter/(print_freq) == round(iter/print_freq)): 33 | if (iter == 1) or (iter/(print_freq*20) == round(iter/(print_freq))): 34 | print(' --------------------------------------------------------------------------------------------\n') 35 | print(' Iteration \t FO_evals \t gBest Fitness \t pWorst Fitness\t error_FO \t error_x\n') 36 | print(' --------------------------------------------------------------------------------------------\n') 37 | 38 | 39 | print('{:8.0f} \t {:5.0f} \t {:15.3e} \t {:11.3e} \t {:11.3e} \t {:6.3e} \n'.format( 40 | iter, FO_evaluations, gbest, pworst, error_fnc, error_x)) 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /PSO/nD/pso.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import numpy as np 4 | import sys 5 | import time 6 | # from optitestfuns import ackley 7 | # from tictoc import tic, toc 8 | from print_pso import print_results 9 | 10 | def pso(objfnc, lb, ub, intVar, *varargin): 11 | """ 12 | Standard PSO algorithm (gbest) to minimize a function 13 | 14 | v = 0.1 - Sept 2016 15 | Authors: J.Javaloyes, FJ.Navarro (CAChemE.org) 16 | License: BSD-Clause 3 17 | 18 | Parameters 19 | ---------- 20 | objfnc: argument containing the objective function 21 | lb: lower bound (array or list with len()=n_dimensions) 22 | ub: upper bound (array or list with len()=n_dimensions) 23 | intVar: list containing the indexes for the variables that must be integers 24 | varargin: unused input variables 25 | 26 | Returns: structure containing the results 27 | ------- 28 | 29 | """ 30 | 31 | 32 | # ----------------- PSO OPTIONS (user inputs) ----------------------------------------- 33 | 34 | # * Population size 35 | swarm_size = 20 # number of the swarm particles 36 | 37 | # * Termination Conditions 38 | maxIter = 1000 # maximum number of iterations 39 | maxFO = sys.float_info.max # maximum number of function after i evaluations 40 | 41 | maxIterNoImprov = sys.maxsize # maximum number of iterations without improving the objective function 42 | maxTime = sys.float_info.max # time limit in seconds [s] 43 | 44 | tol_x = 1e-5 # tolerance in x (norm 2) 45 | tol_fnc = 1e-5 # tolerance in objective function 46 | 47 | # * PSO parameters 48 | inertia_w = 0.72 # Inertia weight 49 | acceleration_c1 = 1.49 # Acceleration coefficient (cognitive) 50 | acceleration_c2 = 1.49 # Acceleration coefficient (social) 51 | v_max = 0.07 # maximum velocity in absolute value 52 | break_coeff = 0.05 # break # stops while loop factor for the worst particle 53 | Red_acceleration_c1 = 2 # Reduction factor of acceleration c1 coefficient for the worst particle 54 | 55 | 56 | # * Algorithm options 57 | print_freq = 10 58 | plotPSO = False 59 | # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> inputs 60 | 61 | 62 | # ????????? PARTICLE SWARM OPTIMIZATION ALGORITHM CODE ???????????????????? 63 | 64 | # # Pre-processing Operations ############################################## 65 | n_variables = np.size(lb) # number variables 66 | 67 | lb = np.array(lb) 68 | lb_original = lb # Lower and upper bounds must be column vectors. 69 | 70 | ub = np.array(ub) 71 | ub_original = ub 72 | 73 | 74 | # # Initialization ####################################################### 75 | 76 | # 01. Set new bounds on the integer variables ----------------------------- 77 | # NOTE1: Bounds on integer variables must be integer numbers 78 | # NOTE2: New bounds are established in order to give the same probability 79 | # to the variable bounds when round MATLAB function is used. 80 | assert isinstance(intVar, list), "intVar must be a list" 81 | 82 | if intVar: # if intVar has elements (not empty) 83 | assert max(intVar) <= (n_variables-1), "intVar indexes out of range (Python indexing starts at 0)" 84 | for i in intVar: assert i >= 0, "Indexes containing int variables must be positive" 85 | 86 | lb[intVar] = lb[intVar] - 0.49 87 | ub[intVar] = ub[intVar] + 0.49 88 | 89 | # 02. Set the initial position of the particles --------------------------- 90 | aux1 = (ub - lb) 91 | x = np.outer(lb, np.ones(swarm_size)) + \ 92 | np.outer(aux1, np.ones(swarm_size))*np.random.rand(n_variables, swarm_size) 93 | 94 | # x = np.array([[-4.067602406241254, 1.411475292329600, 2.311848990285760]]) 95 | x[intVar, :] = np.round(x[intVar, :]) 96 | 97 | 98 | # 03. Set initial velocity for particles ---------------------------------- 99 | v = np.zeros([n_variables, swarm_size]) 100 | 101 | # 04. Evaluation of each particle ----------------------------------------- 102 | # NOTE3: It is not possible to perform a vectorized version since our 103 | # objective function can be a black box (e.g. process simulator) 104 | 105 | tic = time.time() 106 | fval = np.zeros(swarm_size) 107 | for iParticle in range(swarm_size): 108 | fval[iParticle] = objfnc(x[:, iParticle]) 109 | 110 | 111 | # 05. Best particle position and global best particle position and fitness- 112 | pbest_position = np.copy(x) 113 | pbest_fitness = np.copy(fval) 114 | 115 | gbest_fitness = np.nanmin(fval) 116 | gbest_ind = np.nanargmin(fval) 117 | 118 | gbest_position = np.copy(x[:, gbest_ind]) 119 | 120 | iter1_time = round((time.time()-tic), 2) 121 | 122 | # 06. Print Results ------------------------------------------------------- 123 | 124 | # * Worst particle in each iteration 125 | pworst_fitness = np.nanmax(pbest_fitness) 126 | pworst_ind = np.nanargmax(pbest_fitness) 127 | pworst_position = pbest_position[:, pworst_ind] 128 | 129 | error_x = np.linalg.norm(pworst_position - gbest_position, 2) 130 | error_fnc = np.abs(pworst_fitness - gbest_fitness) 131 | 132 | print_results(1, swarm_size, gbest_fitness, pworst_fitness, 133 | error_fnc, error_x, swarm_size, n_variables, intVar, 134 | print_freq) 135 | 136 | 137 | # 07. Plot Particles and Objective Function ------------------------------- 138 | 139 | if plotPSO: 140 | if n_variables == 2: 141 | # plot_3D(objfnc, lb_original, ub_original, x, fval, 1) # Aux Fnc # 02 ### 142 | pass 143 | elif n_variables == 1: 144 | pass 145 | else: 146 | raise Warning(" Only 2D and 3D plots are possible !!! ") 147 | 148 | 149 | 150 | 151 | # ######################################################################### 152 | # ####### Main Body of the Algorithm ### ################################## 153 | # ######################################################################### 154 | 155 | # * Control parameters & Preallocation arrays 156 | iter = 1 157 | timeLimit = iter1_time 158 | FO_evaluations = swarm_size 159 | iter_fitness_improvement = 0 160 | 161 | v_new = np.copy(v) 162 | x_new = np.copy(x) 163 | 164 | tic = time.time() 165 | 166 | pso_flag = True 167 | 168 | 169 | while True: 170 | 171 | for iP in range(swarm_size): 172 | 173 | # 08. Update velocity for all particles ----------------------------------- 174 | 175 | if iter > 1 and iP == pworst_ind: 176 | 177 | v_new[:, iP] = break_coeff * inertia_w * v[:, iP] +\ 178 | acceleration_c1 * np.random.rand(n_variables) * (pbest_position[:, iP] - x[:, iP])/Red_acceleration_c1 + \ 179 | acceleration_c2 * np.random.rand(n_variables) * (gbest_position - x[:, iP]) 180 | else: 181 | v_new[:, iP] = inertia_w * v[:, iP] + \ 182 | acceleration_c1 * np.random.rand(n_variables) * (pbest_position[:, iP] - x[:, iP]) + \ 183 | acceleration_c2 * np.random.rand(n_variables) * (gbest_position - x[:, iP]) 184 | 185 | 186 | # 09. Velocity control ---------------------------------------------------- 187 | v_new[v_new > v_max] = v_max 188 | v_new[v_new < -v_max] = -v_max 189 | 190 | # 10. Update position for all particles pbest ------------------------------- 191 | x_new[:, iP] = x[:, iP] + v_new[:, iP] 192 | 193 | # 11. Position control ---------------------------------------------------- 194 | 195 | # * Lower bound 196 | x_new[:, iP] = (x_new[:, iP] < lb)*lb + (x_new[:, iP] >= lb)*x_new[:, iP] 197 | 198 | # * Upper bound 199 | x_new[:, iP] = (x_new[:, iP] > ub)*ub + (x_new[:, iP] <= ub)*x_new[:, iP] 200 | 201 | 202 | # 12. Round integer variables to the nearest integer ---------------------- 203 | # NOTE4: we need an aux var for the position in order to round the integer 204 | # variables keeping unalterd x_new for next iterations 205 | x_iP = x_new[:, iP] 206 | x_iP[intVar] = np.round(x_iP[intVar]) 207 | 208 | 209 | # 13. Function evaluation & update personal best particle (pbest) so far -- 210 | fval[iP] = objfnc(x_iP) 211 | 212 | if fval[iP] < pbest_fitness[iP]: 213 | pbest_fitness[iP] = fval[iP] 214 | pbest_position[:, iP] = x_iP 215 | 216 | 217 | # 14. Update global best particle (gbest) --------------------------------- 218 | if pbest_fitness[iP] < gbest_fitness: 219 | gbest_fitness = pbest_fitness[iP] 220 | gbest_position = x_iP 221 | iter_fitness_improvement = 0 222 | else: 223 | iter_fitness_improvement = iter_fitness_improvement + 1 224 | 225 | # for loop in range 1:size_swarm ################################## 226 | # ################################################################# 227 | 228 | iter_time = tic - time.time() 229 | 230 | # 15. Print Results ------------------------------------------------------- 231 | iter = iter + 1 232 | FO_evaluations = FO_evaluations + swarm_size 233 | 234 | timeLimit = timeLimit + iter_time 235 | 236 | # * Worst particle in each iteration 237 | pworst_fitness = np.nanmax(pbest_fitness) 238 | pworst_ind = np.nanargmax(pbest_fitness) 239 | pworst_position = pbest_position[:, pworst_ind] 240 | 241 | error_x = np.linalg.norm(pworst_position - gbest_position, 2) 242 | error_fnc = np.abs(pworst_fitness - gbest_fitness) 243 | 244 | print_results(iter, FO_evaluations, gbest_fitness, pworst_fitness, 245 | error_fnc, error_x, swarm_size, n_variables, intVar, 246 | print_freq ) 247 | 248 | # print('x:{}'.format(gbest_position)) 249 | # import pdb; pdb.set_trace() 250 | 251 | # 16. Plot Particles and Objective Function ------------------------------- 252 | 253 | if plotPSO: 254 | if n_variables == 2: 255 | # plot_3D(objfnc, lb_original, ub_original, x, fval, 1) # Aux Fnc # 02 ### 256 | pass 257 | elif n_variables == 1: 258 | pass 259 | else: 260 | raise Warning(" Only 2D and 3D plots are possible !!! ") 261 | 262 | 263 | # 17. Check Termination criteria ----------------------------------------- 264 | 265 | if iter >= maxIter: 266 | termination = 'Stop due to maximum number of major iterations.' 267 | break # stops while loop 268 | 269 | elif FO_evaluations >= maxFO: 270 | termination = 'Stop due to maximum number of function evaluations.' 271 | break # stops while loop 272 | elif iter_fitness_improvement >= maxIterNoImprov: 273 | termination = 'Number of generations without fitness improvement Reached. The objective function is under specified tolerance' 274 | break # stops while loop 275 | elif timeLimit >= maxTime: 276 | termination = 'The solver was interrupted because it reached the time limit.' 277 | break # stops while loop 278 | 279 | elif error_fnc <= tol_fnc: 280 | termination = ' The objective function is under specified tolerance ' 281 | break # stops while loop 282 | elif error_x <= tol_x: 283 | termination = ' The tolerance between best and worse particles is under specification' 284 | break 285 | else: 286 | termination = 'Continue: # {0} iteration'.format(iter) 287 | 288 | # * Position and velocity for next iteration 289 | x = np.copy(x_new) 290 | v = np.copy(v_new) 291 | 292 | class Result: 293 | pass 294 | 295 | Result.xopt = gbest_position 296 | Result.FO = gbest_fitness 297 | Result.exit = termination 298 | return Result 299 | -------------------------------------------------------------------------------- /PSO/nD/test_pso.py: -------------------------------------------------------------------------------- 1 | from pso import pso 2 | from optitestfuns import ackley 3 | import unittest 4 | from numpy import isclose, array 5 | 6 | '''Tests for the nD PSO implementation. 7 | To run it please execute the following command in your terminal or cmd 8 | python -m unittest test_pso.py 9 | ''' 10 | 11 | class PSOfunctionMethodTests(unittest.TestCase): 12 | 13 | def test_pso1D(self): 14 | intVar = [] 15 | result = pso(ackley, [-5], [5], intVar) 16 | 17 | theo_min = array([0]) 18 | 19 | print(result.exit) 20 | print('x_opt: {}'.format(result.xopt)) 21 | print('FO: {:2e}'.format(result.FO)) 22 | 23 | assert isclose(result.xopt[0], theo_min, atol=1e-3), "ERROR: variable didn't converged to 0" 24 | 25 | def test_pso1Dinteger(self): 26 | intVar = [0] 27 | result = pso(ackley, [-5], [5], intVar) 28 | 29 | theo_min = array([0]) 30 | 31 | print(result.exit) 32 | print('x_opt: {}'.format(result.xopt)) 33 | print('FO: {:2e}'.format(result.FO)) 34 | 35 | assert isclose(result.xopt[0], theo_min, atol=1e-3), "ERROR: variable didn't converged to 0" 36 | assert float(result.xopt[0]).is_integer(), "ERROR: variable obtained wasn't an integer" 37 | 38 | 39 | def test_pso2D(self): 40 | intVar = [] 41 | result = pso(ackley, [-5,-5], [5,5], intVar) 42 | 43 | theo_min = array([0]) 44 | 45 | print(result.exit) 46 | print('x_opt: {}'.format(result.xopt)) 47 | print('FO: {:2e}'.format(result.FO)) 48 | 49 | assert isclose(result.xopt[0], theo_min, atol=1e-3), "ERROR: first variable didn't converged to 0" 50 | assert isclose(result.xopt[1], theo_min, atol=1e-3), "ERROR: second variable didn't converged to 0" 51 | 52 | 53 | # def test_pso2Dinteger(self): 54 | # intVar = [0,1] 55 | # result = pso(ackley, [-5, -5], [5, 5], intVar) 56 | # 57 | # print(result.exit) 58 | # print('x_opt: {}'.format(result.xopt)) 59 | # print('FO: {:2e}'.format(result.FO)) 60 | # 61 | # assert math.isclose(result.xopt[0], 0, abs_tol=1e-3), "ERROR: first variable didn't converged to 0" 62 | # assert math.isclose(result.xopt[1], 0, abs_tol=1e-3), "ERROR: second variable didn't converged to 0" 63 | # assert float(result.xopt[0]).is_integer(), "ERROR: first variable obtained wasn't an integer" 64 | # assert float(result.xopt[1]).is_integer(), "ERROR: second variable obtained wasn't an integer" 65 | 66 | if __name__ == '__main__': 67 | unittest.main() -------------------------------------------------------------------------------- /PSO/nD/tictoc.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | """ 4 | Analog of the Matlab tic and toc functions: 5 | 6 | tic() 7 | 8 | time.sleep(5) 9 | 10 | toc() # returns "Elapsed time: 5.00 seconds." 11 | 12 | More info: 13 | http://stackoverflow.com/a/26695514/984077 14 | """ 15 | 16 | def TicTocGenerator(): 17 | # Generator that returns time differences 18 | ti = 0 # initial time 19 | tf = time.time() # final time 20 | while True: 21 | ti = tf 22 | tf = time.time() 23 | yield tf-ti # returns the time difference 24 | 25 | TicToc = TicTocGenerator() # create an instance of the TicTocGen generator 26 | 27 | # This will be the main function through which we define both tic() and toc() 28 | def toc(tempBool=True): 29 | # Prints the time difference yielded by generator instance TicToc 30 | tempTimeInterval = next(TicToc) 31 | if tempBool: 32 | print( "Elapsed time: %f seconds.\n" %tempTimeInterval ) 33 | 34 | def tic(): 35 | # Records a time in TicToc, marks the beginning of a time interval 36 | toc(False) -------------------------------------------------------------------------------- /PSO/talk-structure: -------------------------------------------------------------------------------- 1 | * Cool demo 2 | 3 | * Why do we need derivate free algorithms? 4 | * Types of them (map) 5 | 6 | * PSO 7 | - Motivation 8 | - Algorithm 9 | - Tuning parameters and variations 10 | - Benchmark 11 | 12 | * Application of PSO to ChemEng 13 | - What can we do as Chemical Engineers? 14 | - Optimization problem 15 | - Results 16 | 17 | * Conclusions 18 | - Differences against GA 19 | -------------------------------------------------------------------------------- /PyConES-2016.md: -------------------------------------------------------------------------------- 1 | # Aprendiendo magia negra con Python, optimización estocástica y simuladores 2 | 3 | ## Breve descripción 4 | 5 | La optimización mediante algoritmos estocásticos —ej. algoritmos genéticos o por enjambre de partículas— presenta una serie de ventajas frente a los algoritmos _«clásicos»_ deterministas al no requerir el cálculo de las derivadas del sistema por lo que su implementación en simuladores es casi inmediata. En esta charla se explicará mediante código las ventajas del algoritmo PSO (_Particle Swarm Optimization_) y se mostrarán ejemplos no triviales haciendo uso de simuladores de procesos químicos. 6 | 7 | ## Resumen detallado 8 | 9 | La simulación y optimización de procesos han experimentado un crecimiento considerable durante los últimos años. Con el avance, abaratamiento de arquitecturas y mejora de software para procesamiento en paralelo, muchas industrias apuestan por algoritmos estocásticos para mejorar la producción, reducir los costes o disminuir el impacto medioambiental. 10 | 11 | 12 | Debido a la complejidad de la multitud de procesos industriales, es habitual hacer uso de simuladores donde existe un flujo de datos con los que se opera en módulos o bloques de forma secuencial. Sin embargo, con respecto a la optimización, los simuladores no han alcanzado un grado de desarrollo o robustez deseada —no existe aún un botón mágico en los simuladores que “optimice”, por ejemplo, el número de equipos y/o las condiciones de operación—. 13 | 14 | 15 | En esta charla, sin embargo, mostraremos con código Python como algoritmos del tipo PSO ([_Particle Swarm Optimization_](https://es.wikipedia.org/wiki/Optimizaci%C3%B3n_por_enjambre_de_part%C3%ADculas)) pueden ser acoplados fácilmente con simuladores de procesos para resolver problemas de optimización. Recientemente en Python han aparecido librerías especializadas en algoritmos [_libres de derivadas_](https://en.wikipedia.org/wiki/Derivative-free_optimization) ([OpenMDAO](https://en.wikipedia.org/wiki/OpenMDAO)-NASA, [PyGMO](http://esa.github.io/pygmo/)-ESA o [PySwarm](http://pythonhosted.org/pyswarm/), entre otras). Éstas, junto al uso de simuladores (propietarios o libres) pueden ser muy interesantes en un gran número de aplicaciones como herramientas de optimización de _~~magia~~ caja negra_. 16 | 17 | Por ejemplo, en el ámbito de la ingeniería de procesos químicos, los [simuladores secuenciales modulares](https://en.wikipedia.org/wiki/List_of_chemical_process_simulators) (como Aspen Hysys, Aspen Plus, Pro/II, ChemCAD…) son ampliamente utilizados para el diseño refinerías, plantas químicas y/o tratamiento de aguas. Estos paquetes de software incluyen bibliotecas termodinámicas y modelos numéricos que conducen a predicciones precisas de los procesos implementados. Por ello y a modo de aplicación real, combinaremos finalmente estos simuladores con Python, lo que nos permitirá obtener un ahorro económico significativo en el diseño final de una planta de procesos químicos. 18 | 19 | Esta charla será impartida por investigadores de ingeniería química de la Universidad de Alicante miembros de [CAChemE](http://cacheme.org/) y su estructura será la siguiente: 20 | * Introducción a la problemática en la optimización matemática (5 min). Se realizará una introducción visual a conceptos de optimización determinista, así como a las ventajas e inconvenientes que presentan los algoritmos estocásticos. 21 | * Implementación del algoritmo PSO (15 min). Se verán ejemplos sencillos de optimización con Python y se explicará de manera breve cómo acelerar su tiempo de ejecución. 22 | * Serie de ejemplos de problemas de optimización en ingeniería (10 min), con especial hincapié en ejemplos reales en la industria e ingeniería química. 23 | 24 | ## Por qué no deberías perderte esta charla 25 | La charla podrá ser seguida tanto como por principiantes en el mundo de la ciencia e ingeniería así como por desarrolladores/as profesionales. Creemos que con esta charla captaremos la atención de estos dos espectros ya que: 26 | 27 | 1. Python es sencillo de leer y la implementación de estos algoritmos estocásticos puede ser entendida por gente sin experiencia en programación pero que hace uso de simuladores. 28 | 2. Los desarrolladores/as podrán ver cómo sus conocimientos en procesamiento en paralelo y/o optimización de código con Python pueden darles nuevas aplicaciones en nichos de mercado quizás no tan conocidos. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chemical process design and optimization via derivative-free algorithms (written in Python!) 2 | 3 | A set of examples to optimize process simulators with Python and derivative-free algorithms such as GA or PSO. 4 | ![PSO-2D](https://github.com/CAChemE/stochastic-optimization/blob/master/PSO/2D/img/PSO_Example1.gif) 5 | 6 | 7 | [Slides](https://github.com/CAChemE/stochastic-optimization/raw/master/Slides%20-%20PyconES%202016%20-%20Simulation-Based%20Optimization%20Using%20PSO.pdf) and interactive [jupyter notebooks](http://mybinder.org:/repo/cacheme/stochastic-optimization) from your browser, powered by [![Binder](http://mybinder.org/badge.svg)](http://mybinder.org:/repo/cacheme/stochastic-optimization) 8 | 9 | [![Talk (Spanish)](https://github.com/CAChemE/stochastic-optimization/raw/master/optimizacion-estocastica-python.png)](https://www.youtube.com/watch?v=FByXobXC64U) 10 | 11 | This was a talk submitted to the _great_ Python Conference in Spain (PyConES 2016) 12 | 13 | References: 14 | [Rigorous Design of Complex Distillation Columns Using Process Simulators and the Particle Swarm Optimization Algrithm](http://pubs.acs.org/doi/abs/10.1021/ie400918x?journalCode=iecred)(paper) 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Slides - PyconES 2016 - Simulation-Based Optimization Using PSO.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/Slides - PyconES 2016 - Simulation-Based Optimization Using PSO.pdf -------------------------------------------------------------------------------- /optimizacion-estocastica-python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CAChemE/stochastic-optimization/90dcfef2469e270a1f74458797c03cc90ff4a0dd/optimizacion-estocastica-python.png --------------------------------------------------------------------------------