Repository where I mostly put random python scripts.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

486 lines
15 KiB

  1. <html>
  2. <head>
  3. <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
  4. <script
  5. src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
  6. integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E="
  7. crossorigin="anonymous">
  8. </script>
  9. <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  10. <script>
  11. class Gene
  12. {
  13. constructor(min, max, value)
  14. {
  15. this.min = min;
  16. this.max = max;
  17. this.value = value;
  18. }
  19. getRealValue()
  20. {
  21. return (this.max - this.min) * this.value + this.min;
  22. }
  23. getValue()
  24. {
  25. return this.value;
  26. }
  27. setValue(val)
  28. {
  29. this.value = val;
  30. }
  31. makeClone()
  32. {
  33. return new Gene(this.min, this.max, this.value);
  34. }
  35. makeRandomGene()
  36. {
  37. return new Gene(this.min, this.max, Math.random());
  38. }
  39. }
  40. class Chromosome
  41. {
  42. constructor(geneArray)
  43. {
  44. this.genes = [];
  45. for(let i = 0; i < geneArray.length; i++)
  46. {
  47. this.genes.push(geneArray[i].makeClone());
  48. }
  49. }
  50. getGenes()
  51. {
  52. return this.genes;
  53. }
  54. mutate()
  55. {
  56. this.genes[Math.round(Math.random() * (this.genes.length-1))].setValue(Math.random());
  57. }
  58. createRandomChromosome()
  59. {
  60. let geneAr = [];
  61. for(let i = 0; i < this.genes.length; i++)
  62. {
  63. geneAr.push(this.genes[i].makeRandomGene());
  64. }
  65. return new Chromosome(geneAr);
  66. }
  67. }
  68. const breed = function(father, mother)
  69. {
  70. let son = new Chromosome(father.getGenes());
  71. let daughter = new Chromosome(mother.getGenes());
  72. for(let i = 0;i < son.getGenes().length; i++)
  73. {
  74. let blendCoef = Math.random();
  75. blendGene(son.getGenes()[i], daughter.getGenes()[i], blendCoef);
  76. }
  77. return [son, daughter];
  78. };
  79. function predicateBy(prop)
  80. {
  81. return function(a,b)
  82. {
  83. var result;
  84. if(a[prop] > b[prop])
  85. {
  86. result = 1;
  87. }
  88. else if(a[prop] < b[prop])
  89. {
  90. result = -1;
  91. }
  92. return result;
  93. }
  94. }
  95. const naturalSelection = function(population, keepNumber, fitnessFunction)
  96. {
  97. let fitnessArray = [];
  98. let total = 0;
  99. for(let i = 0; i < population.length; i++)
  100. {
  101. const fitness = fitnessFunction(population[i]);
  102. console.log(fitness);
  103. fitnessArray.push({fit:fitness, chrom: population[i]});
  104. total+= fitness;
  105. }
  106. fitnessArray.sort(predicateBy("fit"));
  107. let survivors = [];
  108. let bestFitness = fitnessArray[0].fit;
  109. let bestChromosome = fitnessArray[0].chrom;
  110. for(let i = 0; i < keepNumber; i++)
  111. {
  112. survivors.push(fitnessArray[i].chrom);
  113. }
  114. return {average: total/population.length, survivors: survivors, bestFit: bestFitness, bestChrom: bestChromosome};
  115. };
  116. const blendGene = function(gene1, gene2, blendCoef)
  117. {
  118. let value1 = (blendCoef * gene1.getValue()) +
  119. (gene2.getValue() * (1- blendCoef));
  120. let value2 = ((1-blendCoef) * gene1.getValue()) +
  121. (gene2.getValue() * blendCoef);
  122. gene1.setValue(value1);
  123. gene2.setValue(value2);
  124. };
  125. const matePopulation = function(population, desiredPopulationSize)
  126. {
  127. let pairsNeeded = (desiredPopulationSize - population.length)/2;
  128. const originalLength = population.length;
  129. for(let i = 0; i < pairsNeeded; i++)
  130. {
  131. let index1 = Math.round(Math.random() * (originalLength-1));
  132. let index2 = Math.round(Math.random() * (originalLength-1));
  133. if(index1 !== index2)
  134. {
  135. const babies = breed(population[index1], population[index2]);
  136. population.push(babies[0]);
  137. population.push(babies[1]);
  138. }
  139. }
  140. };
  141. const mutatePopulation = function(population, mutatePercentage)
  142. {
  143. if(population.length >= 2)
  144. {
  145. let mutations = mutatePercentage *
  146. population.length *
  147. population[0].getGenes().length;
  148. for(let i = 0; i < mutations; i++)
  149. {
  150. population[i].mutate();
  151. }
  152. }
  153. else
  154. {
  155. console.log("Error, population too small to mutate");
  156. }
  157. };
  158. const newBlood = function(population, immigrationSize)
  159. {
  160. for(let i = 0; i < immigrationSize; i++)
  161. {
  162. let geneticChromosome = population[0];
  163. population.push(geneticChromosome.createRandomChromosome());
  164. }
  165. };
  166. const basicCostFunction = function(chromosome)
  167. {
  168. console.log(chromosome);
  169. console.log((chromosome.getGenes()[0].getRealValue()));
  170. return Math.abs(chromosome.getGenes()[0].getRealValue() - 6) +
  171. Math.abs(chromosome.getGenes()[1].getRealValue() - 2);
  172. };
  173. const createRandomPopulation = function(geneticChromosome, populationSize)
  174. {
  175. let population = [];
  176. for(let i = 0; i < populationSize; i++)
  177. {
  178. population.push(geneticChromosome.createRandomChromosome());
  179. }
  180. return population;
  181. };
  182. const runGeneticOptimization = function(geneticChromosome, costFunction,
  183. populationSize, maxGenerations,
  184. desiredCost, mutationRate, keepNumber,
  185. newBloodNumber)
  186. {
  187. let population = createRandomPopulation(geneticChromosome, populationSize);
  188. let generation = 0;
  189. let bestCost = Number.MAX_VALUE;
  190. let bestChromosome = geneticChromosome;
  191. do
  192. {
  193. matePopulation(population, populationSize);
  194. newBlood(population, newBloodNumber);
  195. mutatePopulation(population, mutationRate);
  196. let generationResult = naturalSelection(population, keepNumber, costFunction);
  197. if(bestCost > generationResult.bestFit)
  198. {
  199. bestChromosome = generationResult.bestChrom;
  200. bestCost = generationResult.bestFit;
  201. }
  202. population = generationResult.survivors;
  203. generation++;
  204. console.log("Generation " + generation + " Best Cost: " + bestCost);
  205. console.log(generationResult);
  206. }while(generation < maxGenerations && bestCost > desiredCost);
  207. return bestChromosome;
  208. };
  209. let genericChromosomeG, costFunctionG,
  210. populationSizeG, maxGenerationsG,
  211. desiredCostG, mutationRateG, keepNumberG,
  212. newBloodNumberG, populationG, generationG,
  213. bestCostG = Number.MAX_VALUE, bestChromosomeG = genericChromosomeG;
  214. const runGeneticOptimizationforGraph = function()
  215. {
  216. let generationResult = naturalSelection(populationG, keepNumberG, costFunctionG);
  217. stats.push([generationG, generationResult.bestFit, generationResult.average]);
  218. if(bestCostG > generationResult.bestFit)
  219. {
  220. bestChromosomeG = generationResult.bestChrom;
  221. bestCostG = generationResult.bestFit;
  222. }
  223. populationG = generationResult.survivors;
  224. generationG++;
  225. console.log("Generation " + generationG + " Best Cost: " + bestCostG);
  226. console.log(generationResult);
  227. matePopulation(populationG, populationSizeG);
  228. newBlood(populationG, newBloodNumberG);
  229. mutatePopulation(populationG, mutationRateG);
  230. createGraph();
  231. };
  232. let stats = [];
  233. const createGraph = function()
  234. {
  235. var dataPoints = [];
  236. console.log(dataPoints);
  237. var data = new google.visualization.DataTable();
  238. data.addColumn('number', 'Gene 1');
  239. data.addColumn('number', 'Gene 2');
  240. for(let i = 0; i < populationG.length; i++)
  241. {
  242. data.addRow([populationG[i].getGenes()[0].getRealValue(),
  243. populationG[i].getGenes()[1].getRealValue()]);
  244. }
  245. var options = {
  246. title: 'Genetic Evolution On Two Genes Generation: ' + generationG,
  247. hAxis: {title: 'Gene 1', minValue: 0, maxValue: 10},
  248. vAxis: {title: 'Gene 2', minValue: 0, maxValue: 10},
  249. };
  250. var chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
  251. chart.draw(data, options);
  252. //line chart stuff
  253. var line_data = new google.visualization.DataTable();
  254. line_data.addColumn('number', 'Generation');
  255. line_data.addColumn('number', 'Best');
  256. line_data.addColumn('number', 'Average');
  257. line_data.addRows(stats);
  258. console.log(stats);
  259. var lineChartOptions = {
  260. hAxis: {
  261. title: 'Generation'
  262. },
  263. vAxis: {
  264. title: 'Cost'
  265. },
  266. colors: ['#AB0D06', '#007329']
  267. };
  268. var chart = new google.visualization.LineChart(document.getElementById('line_chart'));
  269. chart.draw(line_data, lineChartOptions);
  270. };
  271. let gene1 = new Gene(1,10,10);
  272. let gene2 = new Gene(1,10,0.4);
  273. let geneList = [gene1, gene2];
  274. let exampleOrganism = new Chromosome(geneList);
  275. genericChromosomeG = exampleOrganism;
  276. costFunctionG = basicCostFunction;
  277. populationSizeG = 100;
  278. maxGenerationsG = 30;
  279. desiredCostG = 0.00001;
  280. mutationRateG = 0.3;
  281. keepNumberG = 30;
  282. newBloodNumberG = 10;
  283. generationG = 0;
  284. function verifyForm()
  285. {
  286. if(Number($("#populationSize").val()) <= 1)
  287. {
  288. alert("Population size must be greater than one.");
  289. return false;
  290. }
  291. if(Number($("#mutationRate").val()) > 1 ||
  292. Number($("#mutationRate").val()) < 0)
  293. {
  294. alert("Mutation rate must be between zero and one.");
  295. return false;
  296. }
  297. if(Number($("#survivalSize").val()) < 0)
  298. {
  299. alert("Survival size can't be less than one.");
  300. return false;
  301. }
  302. if(Number($("#newBlood").val()) < 0)
  303. {
  304. alert("New organisms can't be a negative number.");
  305. return false;
  306. }
  307. return true;
  308. }
  309. function resetPopulation()
  310. {
  311. if(verifyForm())
  312. {
  313. stats = [];
  314. autoRunning = false;
  315. $("#runAutoOptimizer").val("Auto Run");
  316. populationSizeG = $("#populationSize").val();
  317. mutationRateG = $("#mutationRate").val();
  318. keepNumberG = $("#survivalSize").val();
  319. newBloodNumberG = $("#newBlood").val();
  320. generationG = 0;
  321. populationG = createRandomPopulation(genericChromosomeG, populationSizeG);
  322. createGraph();
  323. }
  324. }
  325. populationG = createRandomPopulation(genericChromosomeG, populationSizeG);
  326. window.onload = function (){
  327. google.charts.load('current', {packages: ['corechart', 'line']});
  328. google.charts.load('current', {'packages':['corechart']}).then(function()
  329. {
  330. createGraph();
  331. })
  332. };
  333. let autoRunning = false;
  334. function runAutoOptimizer()
  335. {
  336. if(autoRunning === true)
  337. {
  338. runGeneticOptimizationforGraph();
  339. setTimeout(runAutoOptimizer, 1000);
  340. }
  341. }
  342. function startStopAutoRun()
  343. {
  344. autoRunning = !autoRunning;
  345. if(autoRunning)
  346. {
  347. $("#runAutoOptimizer").val("Stop Auto Run");
  348. }
  349. else
  350. {
  351. $("#runAutoOptimizer").val("Resume Auto Run");
  352. }
  353. runAutoOptimizer();
  354. }
  355. //runGeneticOptimization(exampleOrganism, basicCostFunction, 100, 50, 0.01, 0.3, 20, 10);
  356. </script>
  357. </head>
  358. <body>
  359. <div id="chart_div" style="width: 900px; height: 500px;"></div>
  360. <div id="line_chart"></div>
  361. <input class='btn btn-primary' id="runOptimizer" onclick='runGeneticOptimizationforGraph()' type="button" value="Next Generation">
  362. <input class='btn btn-primary' id="runAutoOptimizer" onclick='startStopAutoRun()' type="button" value="Auto Run">
  363. <div class="card">
  364. <div class="card-header">
  365. <h2>Population Variables</h2>
  366. </div>
  367. <form class="card-body">
  368. <div class="row p-2">
  369. <div class="col">
  370. <label for="populationSize">Population Size</label>
  371. <input type="text" class="form-control" value="100" id="populationSize" placeholder="Population Size" required>
  372. </div>
  373. <div class="col">
  374. <label for="populationSize">Survival Size</label>
  375. <input type="text" class="form-control" value="20" id="survivalSize" placeholder="Survival Size" required>
  376. </div>
  377. </div>
  378. <div class="row p-2">
  379. <div class="col">
  380. <label for="populationSize">Mutation Rate</label>
  381. <input type="text" class="form-control" value="0.03" id="mutationRate" placeholder="Mutation Rate" required>
  382. </div>
  383. <div class="col">
  384. <label for="populationSize">New Organisms Per Generation</label>
  385. <input type="text" class="form-control" value="5" id="newBlood" placeholder="New Organisms" required>
  386. </div>
  387. </div>
  388. <br>
  389. <input class='btn btn-primary' id="reset" onclick='resetPopulation()' type="button" value="Reset Population">
  390. </form>
  391. </div>
  392. </body>
  393. </html>