单词查找遗传算法中偶尔出现错误



我(几乎)成功地创建了一个遗传算法来查找给定的字符串,但由于某种原因,我在运行程序时半频繁地出现错误,否则它可以完美运行。

Cannot read property 'dna' of undefined at Population.populate

我似乎只能几次弄清楚导致此问题的原因。

<!DOCTYPE html>
<html>
<head>
	<title>Word Search</title>
	<link href='https://fonts.googleapis.com/css?family=Ubuntu' rel='stylesheet'>
</head>
<body style ='font-family: Ubuntu, sans-serif'>
	Target: <input type='text' value='Hello World!'  id='target'> <br>
	Population Size: <input type='number' id='size' min='0' max='100' step='1' value='10'><br>
	Mutation Rate: <input type='number' id='rate' min='0' max='100' step='1' value='10'>%<br>
	<input type='submit' id='submit' onclick='evolution()'>
	<div  style='border-width: 2px; border-style: dashed; width: 250px'>
		<div style='text-align: center;' id='value'>
			<p id='generation';>Generation | 0</p>
			<div id='pop'>
			</div>
		</div>
	</div>
<script type="text/javascript">
window.onload = function() {
	evolution();
}
function evolution() {
	var population = new Population(
		document.getElementById('target').value, 
		document.getElementById('rate').value/100, 
		document.getElementById('size').value);
	var running = setInterval(function() {
		document.getElementById('submit').disabled = true;
		population.natSelection();
		population.populate();
		population.evaluate();
		population.display();
		if(population.completed) {
			clearInterval(running);
			document.getElementById('submit').disabled = false;
		}
	}, 50);
}
function Population(target, mutationRate, size) {
	this.target = target;
	this.mutationRate = mutationRate;
	this.size = size;
	this.members = [];
	this.genePool = [];
	this.completed = false;
	this.generation = 0;
	for(var i = 0; i < this.size; i++)
		this.members.push(new Genome(this.target, this.mutationRate));
	this.natSelection = function() {
		for(var i = 0; i < this.members.length; i++)
			this.members[i].calcFitness();
		
		this.genePool = [];
		for(var i = 0; i < this.members.length; i++)
			for(var j = 0; j < this.members[i].fitness*10; j++)
				this.genePool.push(this.members[i]);
	}
	this.populate = function() {
		this.generation++;
		this.members = [];
		for(var i = 0; i < this.size; i++) {
			var a = this.genePool[Math.floor(Math.random()*this.genePool.length)].dna;
			var b = this.genePool[Math.floor(Math.random()*this.genePool.length)].dna;
			this.members.push(new Genome(this.target, this.mutationRate, a, b));
		}
	}
	this.evaluate = function() {
		for(var i = 0; i < this.members.length; i++) {
			if(this.members[i].dna === this.target)
				this.completed = true;
		}
	}
	this.calcMaxFitness = function() {
		var fittest = this.memebers[0].fitness; 
		for(var i = 1; i < this.members.length; i++)
			if(this.memebers[i].fitness > fittest)
				fittest = this.memebers[i].fitness;
		return fittest;
	}
	this.display = function() {
		document.getElementById('generation').innerHTML = 'Generation | '+this.generation;
		var div = document.getElementById('pop');
		div.innerHTML = '';
		for(var i = 0; i < this.members.length; i++) {
			div.innerHTML += this.members[i].dna+'<br>'
		}
	}
}
function Genome(target, mutationRate, parentA, parentB) {
	this.dna = '';
	this.fitness = 0;
	this.target = target;
	this.mutationRate = mutationRate;
	this.mutate = function() {
		for(var i = 0; i < this.target.length; i++) {
			if(this.dna.charCodeAt(i) != this.target.charCodeAt(i))
				if(Math.random() > this.mutationRate)
					this.dna = this.dna.replaceAt(i, String.fromCharCode(Math.floor(Math.random()*94+32)));
		}
	}
	if(!parentA && !parentB) {
		for(var i = 0; i < this.target.length; i++)
			this.dna += String.fromCharCode(Math.floor(Math.random()*94+32));
	} else {
		var mid = Math.floor(Math.random()*this.target.length); 
		this.dna = parentA.substr(0, mid) + parentB.substr(mid, parentB.length);
		this.mutate();
	}
	
	this.calcFitness = function() {
		this.fitness = 0;
		for(var i = 0; i < this.target.length; i++) {
			if(this.dna.charCodeAt(i) === this.target.charCodeAt(i))
				this.fitness++;
		}
	}
}
Number.prototype.map = function (in_min, in_max, out_min, out_max) {
return (this - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
String.prototype.replaceAt=function(index, replacement) {
return this.substr(0, index) + replacement+ this.substr(index + replacement.length);
}
</script>
</body>
</html>

当所有成员的适应度为零时,就会发生此错误,然后natSelection函数中的循环将循环直到j < this.members[i].fitness*10为零,因此没有循环,也没有向genePool添加任何内容。

现在,当发生这种情况时,显然this.genePool[Math.floor(Math.random()*this.genePool.length)]将是未定义的,当您尝试访问属性dna时,您会得到错误。

要解决此问题,您必须添加一些验证,以便当所有成员的适应度为零时,您可以对其进行处理。或者,在natSelection函数结束时,检查genePool.length,如果它仍然为零,则至少添加一个项目。

首先,让我们确保我们完全理解错误。

您正在尝试读取populate方法中未定义的属性dna

换一种说法:

// Your populate method
this.populate = function() {
this.generation++;
this.members = [];
for(var i = 0; i < this.size; i++) {
var a = this.genePool[Math.floor(Math.random()*this.genePool.length)].dna;
var b = this.genePool[Math.floor(Math.random()*this.genePool.length)].dna;
this.members.push(new Genome(this.target, this.mutationRate, a, b));
}
}

JavasScript 正在看到

this.genePool[Math.floor(Math.random()*this.genePool.length)]

作为undefined

然后,你要求JavaScript读取undefineddna属性。

undefined.dna

现在,让我们弄清楚如何调试错误。

就个人而言,我会记录以下内容:

// Your populate method
this.populate = function() {
this.generation++;
this.members = [];
console.log('SIZE', this.size);
for(var i = 0; i < this.size; i++) {
console.log('I', i);
console.log('this.genePool', this.genePool);
console.log('this.genePool.length', this.genePool.length);
var a = this.genePool[Math.floor(Math.random()*this.genePool.length)].dna;
var b = this.genePool[Math.floor(Math.random()*this.genePool.length)].dna;
this.members.push(new Genome(this.target, this.mutationRate, a, b));
}
}

接下来,让我们分析日志。

也许我们在应该使用i < this.size时使用了i < this.size - 1,或者在其他地方类似的东西(又名逐个错误)。

也许this.genePool有时是不确定的。

如果仍有问题,请使用一些日志输出更新您的问题。

相关内容

  • 没有找到相关文章

最新更新