[PYTHON] Suche nach einer Lösung für das N-Queen-Problem mit einem genetischen Algorithmus (1)

Ich beschloss, das N-Queen-Problem zu lösen (eine der Lösungen zu finden), um genetische Algorithmen zu untersuchen. Jede Programmiersprache war in Ordnung, aber ich habe mich für Python entschieden, weil es einfach zu schreiben ist.

N-Queen Problem

Das Problem, ein Muster zu finden, das N Schachköniginnen auf das NxN-Brett legt, damit sie nicht miteinander in Konflikt stehen. Queen kann sich ohne Einschränkungen vertikal, horizontal und naname bewegen. Ich wünschte wirklich, ich könnte alle Lösungen finden, aber dieses Mal werde ich versuchen, eine davon mithilfe eines genetischen Algorithmus zu finden. Um das Problem zu vereinfachen, betrachten Sie zuerst den Fall von N = 8 und versuchen Sie dann, ein beliebiges N aufzunehmen.

Anwendung genetischer Algorithmen

Definition von Genen

Zunächst einmal, wie man ein Gen darstellt. Es muss in der Lage sein, die endgültige Lösung auszudrücken. Daher wird ein Vektor erster Ordnung, der die Position der Königin auf dem Brett darstellt, als Gen angenommen. Die Queen-Position in jeder Spalte wird durch 0-7 dargestellt. Zum Beispiel. [0, 2, 3, 1, 4, 3, 6, 7] queen_example.jpg Bereiten Sie darauf basierend das ursprüngliche Gen vor. Dieses Mal werden wir vier verwenden. Jedes Element des Vektors wählt zufällig 0-7 aus.

python


def makeIniGene():
	ini_gene = []
	for cnt in range(0, 4):
		line = []
		for i in range(0, 8):
			val = random.randint(0, 7)
			line.append(val)

		ini_gene.append(line)

	return ini_gene

Anpassungsfähigkeit

Anpassungsfähigkeit ist ein Indikator dafür, wie nahe ein Gen an einem Ziel ist. Dieses Mal wird bei der Anordnung eines bestimmten Gens = Königin auf dem Brett die Anzahl der miteinander konkurrierenden Königinnen als Grad der Anpassungsfähigkeit genommen. Daher kann die endgültige Lösung gefunden werden, wenn die Anpassungsfähigkeit = 0 ist. Die Anpassungsfähigkeit wird berechnet, indem ein Quadrat in acht Richtungen von der Position einer Königin aus gesucht wird. Wenn eine andere Königin gefunden wird, wird die Anpassungsfähigkeit um +1 erhöht.

python


gVec = [(-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)]
def calcFitness(gene):
	fitness = 0
	board = []
	line = []
	for i in range(0, 8):
		line = []
		for j in range(0, 8):
			if j == gene[i]:
				line.append(1)
			else:
				line.append(0)
		board.append(line)

	for i in range(0, 8):
		for j in range(0, 8):
			val = getCell(board, (i,j), (0,0))
			if val == 1:
				for vec in gVec:
					for k in range(1, 8):
						valofst = getCell(board, (i,j), (vec[0]*k, vec[1]*k))
						if valofst == 1:
							fitness += 1
						elif valofst == -1:
							break

	return fitness

def getCell(board, pos, ofst):
	posx = pos[0] + ofst[0]
	posy = pos[1] + ofst[1]
	if posx >= 0 and posy >= 0 and posx < 8 and posy < 8:
		val = board[posx][posy]
	else:
		val = -1
	
	return val

Ein Beispiel für das Berechnungsergebnis ist unten dargestellt. [0, 1, 2, 3, 4, 5, 6, 7] => fitness = 56

Genetik

Beispielsweise werden die folgenden vier Gene als Eltern verwendet, um Kindergene zu erzeugen. G0 = [0, 1, 2, 3, 4, 5, 6, 7] => fitness = 56 G1 = [0, 0, 1, 1, 2, 2, 3, 3] => fitness = 14 G2 = [0, 2, 4, 6, 7, 5, 3, 1] => fitness = 6 G3 = [1, 3, 5, 7, 0, 1, 2, 3] => fitness = 20

In aufsteigender Reihenfolge der Anpassungsfähigkeit anordnen. Der Rang ist Rang = 0 bis 3. G2 = [0, 2, 4, 6, 7, 5, 3, 1] => rank = 0 G1 = [0, 0, 1, 1, 2, 2, 3, 3] => rank = 1 G3 = [1, 3, 5, 7, 0, 1, 2, 3] => rank = 2 G0 = [0, 1, 2, 3, 4, 5, 6, 7] => rank = 3

Lassen Sie zuerst die ausgezeichneten Gene. Ersetzt das Gen mit der höchsten Anpassungsfähigkeit durch das Gen mit der niedrigsten Anpassungsfähigkeit. In diesem Fall überschreiben Sie den Wert von G0 mit dem Wert von G2. G2 = [0, 2, 4, 6, 7, 5, 3, 1] G1 = [0, 0, 1, 1, 2, 2, 3, 3] G3 = [1, 3, 5, 7, 0, 1, 2, 3] G0' = [0, 2, 4, 6, 7, 5, 3, 1]

Als nächstes überqueren. Crossover ist ein Verfahren zum Erzeugen eines Kindergens aus einem Elterngen. Dieses Mal werden wir eine einfache Frequenzweiche betrachten. Ersetzen Sie zunächst das k-te und die nachfolgenden Elemente des Gens rank = 0 und des Gens rank = 1. Dieses Mal werde ich die Elemente nach k = 5 ersetzen. G2' = [0, 2, 4, 6, 2, 2, 3, 3] G1' = [0, 0, 1, 1, 7, 5, 3, 1] Ersetzen Sie als nächstes das m-te und die nachfolgenden Elemente des Gens rank = 2 und des Gens rank = 3. Dieses Mal werde ich die Elemente nach m = 7 ersetzen. G3' = [1, 3, 5, 7, 0, 1, 3, 1] G0'' = [0, 2, 4, 6, 7, 5, 2, 3]

Aus dem Obigen haben die Nachkommen die folgenden vier Gene. G2' = [0, 2, 4, 6, 2, 2, 3, 3] G1' = [0, 0, 1, 1, 7, 5, 3, 1] G3' = [1, 3, 5, 7, 0, 1, 3, 1] G0'' = [0, 2, 4, 6, 7, 5, 2, 3]

Der Quellcode des genetischen Teils lautet wie folgt. gene_list ist eine Liste der elterlichen Gene. rank_list speichert den Index von gene_list in seinem Element mit seinem Index als Rang. Mit anderen Worten, im Fall dieses Beispiels ist das Bild rank_list = [2, 1, 3, 0].

python


gGaIdx = [4, 6]
def simpleGa(gene_list, rank_list):
	new_gene_list = []
	for i in range(0, gGeneCnt):
		if i == rank_list[3]:
			new_gene_list.append(gene_list[rank_list[0]])
		else:
			new_gene_list.append(gene_list[i])

	updated_gene_list = []
	line1 = []
	line2 = []
	for i in range(0, 8):
		if i < gGaIdx[0]:
			line1.append(new_gene_list[rank_list[0]][i])
			line2.append(new_gene_list[rank_list[1]][i])
		else:
			line1.append(new_gene_list[rank_list[1]][i])
			line2.append(new_gene_list[rank_list[0]][i])
	updated_gene_list.append(line1)
	updated_gene_list.append(line2)
	
	line1 = []
	line2 = []
	for i in range(0, 8):
		if i < gGaIdx[1]:
			line1.append(new_gene_list[rank_list[2]][i])
			line2.append(new_gene_list[rank_list[3]][i])
		else:
			line1.append(new_gene_list[rank_list[3]][i])
			line2.append(new_gene_list[rank_list[2]][i])
	updated_gene_list.append(line1)
	updated_gene_list.append(line2)
	
	return updated_gene_list

Mutation

Durch Wiederholen des genetischen Verfahrens (Crossover) werden wir versuchen, hervorragende Gene zu hinterlassen. Wiederholte Überkreuzungen können jedoch zu lokalen Lösungen führen. Um ein Beispiel für eine lokale Lösung des 8-Queen-Problems zu geben, Anpassungsfähigkeit = 2, dh das verbleibende Queens-Paar kann in einem Zustand des Wettbewerbs miteinander stecken bleiben. Um diesen Zustand zu überwinden, ist eine Mutation erforderlich. Dieses Mal werde ich einfach alle vier genetischen Verfahren ein Element eines Gens durch einen Zufallswert von 0 bis 7 ersetzen.

python


# mutation
if loop % 4 == 0:
	geneidx = random.randint(0, 3)
	posidx = random.randint(0,  7)
	valrand = random.randint(0,  7)
	gene_list[geneidx][posidx] = valrand

Zusammenfassung

Fügen Sie das Obige im Quellcode zusammen.

8-queen.py


#! /usr/bin/env python
# encoding=utf-8

# 8 Queens Problem

import sys
import random

gGeneCnt = 4
gMutationSpan = 4
gRange = 0
gVec = [(-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)]
gGaIdx = [4, 6]

def makeIniGene():
	ini_gene = []
	for cnt in range(0,gGeneCnt):
		line = []
		for i in range(0, 8):
			val = random.randint(0, 7)
			line.append(val)

		ini_gene.append(line)

	return ini_gene

def calcFitness(gene):
	fitness = 0
	board = []
	line = []
	for i in range(0, 8):
		line = []
		for j in range(0, 8):
			if j == gene[i]:
				line.append(1)
			else:
				line.append(0)
		board.append(line)

	for i in range(0, 8):
		for j in range(0, 8):
			val = getCell(board, (i,j), (0,0))
			if val == 1:
				for vec in gVec:
					for k in range(1, 8):
						valofst = getCell(board, (i,j), (vec[0]*k, vec[1]*k))
						if valofst == 1:
							fitness += 1
						elif valofst == -1:
							break

	return fitness

def getCell(board, pos, ofst):
	posx = pos[0] + ofst[0]
	posy = pos[1] + ofst[1]
	if posx >= 0 and posy >= 0 and posx < 8 and posy < 8:
		val = board[posx][posy]
	else:
		val = -1
	
	return val

def simpleGa(gene_list, rank_list):
	new_gene_list = []
	for i in range(0, gGeneCnt):
		if i == rank_list[3]:
			new_gene_list.append(gene_list[rank_list[0]])
		else:
			new_gene_list.append(gene_list[i])

	updated_gene_list = []
	line1 = []
	line2 = []
	for i in range(0, 8):
		if i < gGaIdx[0]:
			line1.append(new_gene_list[rank_list[0]][i])
			line2.append(new_gene_list[rank_list[1]][i])
		else:
			line1.append(new_gene_list[rank_list[1]][i])
			line2.append(new_gene_list[rank_list[0]][i])
	updated_gene_list.append(line1)
	updated_gene_list.append(line2)
	
	line1 = []
	line2 = []
	for i in range(0, 8):
		if i < gGaIdx[1]:
			line1.append(new_gene_list[rank_list[2]][i])
			line2.append(new_gene_list[rank_list[3]][i])
		else:
			line1.append(new_gene_list[rank_list[3]][i])
			line2.append(new_gene_list[rank_list[2]][i])
	updated_gene_list.append(line1)
	updated_gene_list.append(line2)
	
	return updated_gene_list

def printBoard(gene):
	for i in range(0, len(gene)):
		line = []
		for j in range(0, len(gene)):
			if j == gene[i]:
				line.append(1)
			else:
				line.append(0)

		print line

def main(argv):
	gene_list = makeIniGene()
	print "Initial gene = " + str(gene_list)

	fitness = []
	for i in range(0, gGeneCnt):
		fitness.append(0)

	loop = 0
	while True :
		loop += 1
		idx = 0
		max_fitness_idx = []
		min_fitness_idx = []

		# mutation
		if loop % gMutationSpan == 0:
			geneidx = random.randint(0, gGeneCnt-1)
			posidx = random.randint(0,  7)
			valrand = random.randint(0,  7)
			gene_list[geneidx][posidx] = valrand

		# compare fitness
		for gene in gene_list:
			fitness[idx] = calcFitness(gene)
			if idx == 0:
				max_fitness_idx = (fitness[0], 0)
				min_fitness_idx = (fitness[0], 0)

			if max_fitness_idx[0] < fitness[idx]:
				max_fitness_idx = (fitness[idx], idx)

			if min_fitness_idx[0] > fitness[idx]:
				min_fitness_idx = (fitness[idx], idx)

			print fitness[idx]
			idx += 1

		min_fitness = min(fitness)
		if min_fitness <= gRange:
			print "Loop end = " + str(loop) + ", Fitness = " +  str(min_fitness)
			printBoard(gene_list[min_fitness_idx[1]])
			break

		ranktemp = []
		for i in range(0, gGeneCnt):
			if i !=  max_fitness_idx[1] and i != min_fitness_idx[1]:
				ranktemp.append(i)

		if fitness[ranktemp[0]] > fitness[ranktemp[1]]:
			rank_list = [ min_fitness_idx[1], ranktemp[1], ranktemp[0], max_fitness_idx[1] ]
		else:
			rank_list = [ min_fitness_idx[1], ranktemp[0], ranktemp[1], max_fitness_idx[1] ]

		updated_gene_list = []
		updated_gene_list = simpleGa(gene_list, rank_list)
		gene_list = updated_gene_list


if __name__ == "__main__":
        main(sys.argv)

Bei der Ausführung wird die Anpassungsfähigkeit angezeigt, und wenn eine Lösung gefunden wird (Anpassungsfähigkeit = 0), werden die Anzahl der Schleifen und die Position der Königin auf dem Brett angezeigt.

$ ./8-queen.py
...
...
2
2
2
2
2
2
0
2
Loop end = 12964, Fitness = 0
[0, 0, 0, 1, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 1, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 0]
[0, 1, 0, 0, 0, 0, 0, 0]

Nächstes Mal wird versuchen, sich von N = 8 auf ein beliebiges N zu erstrecken.

Recommended Posts

Suche nach einer Lösung für das N-Queen-Problem mit einem genetischen Algorithmus (2)
Suche nach einer Lösung für das N-Queen-Problem mit einem genetischen Algorithmus (1)
Versuchen Sie, das Problem des Handlungsreisenden mit einem genetischen Algorithmus zu lösen (Theorie)
Versuchen Sie, das Problem des Handlungsreisenden mit einem genetischen Algorithmus (Python-Code) zu lösen.
Versuchen Sie, das Problem des Handlungsreisenden mit einem genetischen Algorithmus zu lösen (Ausführungsergebnis)
Wie man die anfängliche Population mit einem genetischen Algorithmus unter Verwendung von DEAP fixiert
Eine Geschichte über den Umgang mit dem CORS-Problem
Ich wollte das ABC164 A ~ D-Problem mit Python lösen
Finden Sie den optimalen Wert der Funktion mit einem genetischen Algorithmus (Teil 1)
Durchsuche das Labyrinth mit dem Python A * -Algorithmus
Ich habe versucht, "einen genetischen Algorithmus (GA) in Python zu implementieren, um das Problem des Handlungsreisenden (TSP) zu lösen".
Versuchen Sie, das Fizzbuzz-Problem mit Keras zu lösen
So testen Sie den Friends-of-Friends-Algorithmus mit pyfof
Speichern Sie das Objekt in einer Datei mit pickle
Beachten Sie die Lösung, da Django nicht mit pip installiert werden konnte
[Python] Lösung für das Problem, dass Elemente beim Kopieren einer Liste verknüpft werden
Berechnen Sie mit scipy.optimize die optimale Lösung, um einen Weltrekord für zehn Arten von Wettbewerb aufzustellen
Versuchen Sie, das Problem der Zuweisung von Schulungsärzten mit Python zu lösen
Übergang zum Update-Bildschirm mit dem Django-Tag
Ich habe versucht, das Problem mit Python Vol.1 zu lösen
Eine Lösung für das Problem, dass Dateien mit [und] nicht in glob.glob () aufgeführt sind
So lösen Sie das Problem, dass beim Ausführen des PyQt-Systems mit Jupyter oder Spyder IDE häufig ein Neustart des Kernels auftritt
Eine Python-Probe zum Lernen von XOR mit einem genetischen Algorithmus in einem neuronalen Netz
Wahrscheinlich der einfachste Weg, um mit Python 3 ein PDF zu erstellen
[Python] Versuchen Sie, die FX-Systolenparameter mit einem genetischen Algorithmus zu optimieren
Der erste Schritt beim Erstellen einer serverlosen Anwendung mit Zappa
Ich habe versucht, das Problem der Kombinationsoptimierung mit Qiskit zu lösen
Die übliche Art, einen Kernel mit Jupyter Notebook hinzuzufügen
Ein Memo, das das Rucksackproblem mit der gierigen Methode löste
Versuchen Sie, eine multimodale Verteilung mithilfe des EM-Algorithmus zu modellieren
Eine Person, die das D-Problem mit ABC von AtCoder lösen möchte, hat versucht, zu kratzen
Eine Geschichte, in der der Algorithmus zu einem lächerlichen Ergebnis kam, als er versuchte, das Problem der reisenden Verkäufer richtig zu lösen
Schreiben Sie ein Programm, um den 4x4x4 Rubik Cube zu lösen! 2. Algorithmus
[Einführung in Python] So teilen Sie eine Zeichenfolge mit der Funktion split
[Einführung in StyleGAN] Ich habe mit "The Life of a Man" ♬ gespielt
Versuchen Sie, das N Queen-Problem mit SA von PyQUBO zu lösen
Lösen des Labyrinths mit Python-Ergänzung zu Kapitel 6 der Algorithmus-Kurzreferenz-
Fehler mit pip: Beim Bestätigen des SSL-Zertifikats ist ein Problem aufgetreten
Schreiben Sie ein Skript, um die Entfernung mit dem Elasticsearch 5-System schmerzfrei zu berechnen
Lösen Sie das Python-Rucksackproblem mit der Branch-and-Bound-Methode
Lösen Sie Teilsummenprobleme mit der vollständigen Suche in Python
So senden Sie eine Anfrage mit Python an die DMM (FANZA) -API
Erstellen Sie eine REST-API, um dynamodb mit dem Django REST Framework zu betreiben
PhytoMine-I hat versucht, mit Python die genetischen Informationen der Pflanze zu erhalten
Mit OpenCV die einfachsten Fehler finden
(Maschinelles Lernen) Ich habe versucht, den EM-Algorithmus in der gemischten Gaußschen Verteilung sorgfältig mit der Implementierung zu verstehen.
Ich möchte das Problem des Speicherverlusts bei der Ausgabe einer großen Anzahl von Bildern mit Matplotlib lösen
Das 16. Offline-Echtzeit-Schreibproblem wurde mit Python gelöst
Ein Memo zur einfachen Verwendung des Beleuchtungsstärkesensors TSL2561 mit Raspberry Pi 2
Berechnen Sie die kürzeste Route eines Diagramms mit der Dyxtra-Methode und Python
Überlegen Sie, wie Sie einen Filter mit den Shotgun API-Contact-Versionen schreiben
[Python] Erklärt anhand eines konkreten Beispiels, wie die Bereichsfunktion verwendet wird
Ich versuchte, Trauer und Freude über das Problem der stabilen Ehe auszudrücken.
Das 16. Offline-Echtzeit-Schreiben eines Referenzproblems zur Lösung mit Python
[Django] Erstellt ein Feld zur Eingabe von Daten mit 4-stelligen Zahlen
[Einführung in Python] So sortieren Sie den Inhalt einer Liste effizient mit Listensortierung
[Einführung in Python] So schreiben Sie eine Zeichenfolge mit der Formatierungsfunktion
Das 15. Offline-Problem beim Schreiben in Echtzeit wurde mit Python gelöst