170 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * Created by joonkukang on 2014. 1. 16..
 | |
|  */
 | |
| var math = require('./utils').math;
 | |
| let optimize = module.exports;
 | |
| 
 | |
| optimize.hillclimb = function(options){
 | |
|     var domain = options['domain'];
 | |
|     var costf = options['costf'];
 | |
| 
 | |
|     var i;
 | |
|     var vec = [];
 | |
|     for(i=0 ; i<domain.length ; i++)
 | |
|         vec.push(math.randInt(domain[i][0],domain[i][1]));
 | |
| 
 | |
|     var current, best;
 | |
| 
 | |
|     while(true) {
 | |
|         var neighbors = [];
 | |
|         var i,j;
 | |
| 
 | |
|         for(i=0 ; i<domain.length ; i++) {
 | |
|             if(vec[i] > domain[i][0]) {
 | |
|                 var newVec = [];
 | |
|                 for(j=0 ; j<domain.length ; j++)
 | |
|                     newVec.push(vec[j]);
 | |
|                 newVec[i]-=1;
 | |
|                 neighbors.push(newVec);
 | |
|             } else if (vec[i] < domain[i][1]) {
 | |
|                 var newVec = [];
 | |
|                 for(j=0 ; j<domain.length ; j++)
 | |
|                     newVec.push(vec[j]);
 | |
|                 newVec[i]+=1;
 | |
|                 neighbors.push(newVec);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         current = costf(vec);
 | |
|         best = current;
 | |
|         for(i=0 ; i<neighbors.length ; i++) {
 | |
|             var cost = costf(neighbors[i]);
 | |
|             if(cost < best) {
 | |
|                 best = cost;
 | |
|                 vec = neighbors[i];
 | |
|             }
 | |
|         }
 | |
|         if(best === current)
 | |
|             break;
 | |
|     }
 | |
|     return vec;
 | |
| }
 | |
| 
 | |
| optimize.anneal = function(options){
 | |
|     var domain = options['domain'];
 | |
|     var costf = options['costf'];
 | |
|     var temperature = options['temperature'];
 | |
|     var cool = options['cool'];
 | |
|     var step = options['step'];
 | |
|     var callback
 | |
| 
 | |
|     var i;
 | |
|     var vec = [];
 | |
|     for(i=0 ; i<domain.length ; i++)
 | |
|         vec.push(math.randInt(domain[i][0],domain[i][1]));
 | |
| 
 | |
|     while(temperature > 0.1) {
 | |
|         var idx = math.randInt(0,domain.length - 1);
 | |
|         var dir = math.randInt(-step,step);
 | |
|         var newVec = [];
 | |
|         for(i=0; i<vec.length ; i++)
 | |
|             newVec.push(vec[i]);
 | |
|         newVec[idx]+=dir;
 | |
|         if(newVec[idx] < domain[idx][0]) newVec[idx] = domain[idx][0];
 | |
|         if(newVec[idx] > domain[idx][1]) newVec[idx] = domain[idx][1];
 | |
| 
 | |
|         var ea = costf(vec);
 | |
|         var eb = costf(newVec);
 | |
|         var p = Math.exp(-1.*(eb-ea)/temperature);
 | |
|         if(eb < ea || Math.random() < p)
 | |
|             vec = newVec;
 | |
| 
 | |
|         temperature *= cool;
 | |
|     }
 | |
| 
 | |
|     return vec;
 | |
| }
 | |
| 
 | |
| optimize.genetic = function(options){
 | |
|     var domain = options['domain'];
 | |
|     var costf = options['costf'];
 | |
|     var population = options['population'];
 | |
|     var q = options['q'] || 0.3;
 | |
|     var elite = options['elite'] || population * 0.04;
 | |
|     var epochs = options['epochs'] || 100;
 | |
| 
 | |
|     var i,j;
 | |
|     // Initialize population array
 | |
|     var pop =[];
 | |
|     for(i=0; i<population; i++) {
 | |
|         var vec = [];
 | |
|         for(j=0; j<domain.length; j++)
 | |
|             vec.push(math.randInt(domain[j][0],domain[j][1]));
 | |
|         pop.push(vec);
 | |
|     }
 | |
|     pop.sort(function(a,b){return costf(a) - costf(b);});
 | |
| 
 | |
|     for(i=0 ; i<epochs ; i++) {
 | |
|         // elitism
 | |
|         var newPop = [];
 | |
|         for(j=0;j<elite;j++)
 | |
|             newPop.push(pop[j]);
 | |
| 
 | |
|         // compute fitnesses
 | |
|         var fitnesses = [];
 | |
|         for(j=0; j<pop.length; j++)
 | |
|             fitnesses[j] = q * Math.pow(1-q,j);
 | |
|         fitnesses = math.normalizeVec(fitnesses);
 | |
| 
 | |
|         // crossover, mutate
 | |
|         for(j=0; j<pop.length - elite;j++) {
 | |
|             var idx1 = rouletteWheel(fitnesses);
 | |
|             var idx2 = rouletteWheel(fitnesses);
 | |
|             var crossovered = crossover(pop[idx1],pop[idx2]);
 | |
|             var mutated = mutate(crossovered);
 | |
|             newPop.push(mutated);
 | |
|         }
 | |
| 
 | |
|         // replacement
 | |
|         pop = newPop;
 | |
|         pop.sort(function(a,b){return costf(a) - costf(b);});
 | |
|        //console.log("Current Cost : ",costf(pop[0]));
 | |
|     }
 | |
|     return pop[0];
 | |
| 
 | |
|     function mutate(vec) {
 | |
|         var idx = math.randInt(0,domain.length - 1);
 | |
|         var newVec = [];
 | |
|         var i;
 | |
|         for(i=0; i<domain.length ; i++)
 | |
|             newVec.push(vec[i]);
 | |
|         newVec[idx] += (Math.random() < 0.5) ? 1 : -1;
 | |
|         if(newVec[idx] < domain[idx][0]) newVec[idx] = domain[idx][0];
 | |
|         if(newVec[idx] > domain[idx][1]) newVec[idx] = domain[idx][1];
 | |
|         return newVec;
 | |
|     }
 | |
|     function crossover(vec1,vec2) {
 | |
|         var idx = math.randInt(0,domain.length - 2);
 | |
|         var newVec = [];
 | |
|         var i;
 | |
|         for(i=0; i<idx ; i++)
 | |
|             newVec.push(vec1[i]);
 | |
|         for(i=idx; i<domain.length; i++)
 | |
|             newVec.push(vec2[i]);
 | |
|         return newVec;
 | |
|     }
 | |
|     function rouletteWheel(vec) {
 | |
|         var a = [0.0];
 | |
|         var i;
 | |
|         for(i=0;i<vec.length;i++) {
 | |
|             a.push(a[i] + vec[i]);
 | |
|         }
 | |
|         var rand = Math.random();
 | |
|         for(i=0;i< a.length;i++) {
 | |
|             if(rand > a[i] && rand <= a[i+1])
 | |
|                 return i;
 | |
|         }
 | |
|         return -1;
 | |
|     }
 | |
| };
 |