public NondetMooreAutomaton run() {
		fitnessCalls = 0;
		bestSolution = new int[automaton.stateCount()];
		for (int i = 0; i < bestSolution.length; i++) {
			bestSolution[i] = i; // initial solution
		}
		bestFitness = fitness(bestSolution);
		System.out.println(">>> " + bestFitness);
		
		final long time = System.currentTimeMillis();
		int lastSuccessfulCallsNum = 0;

		while (fitnessCalls < MAX_FITNESS_CALLS) {
			int pos1 = RND.nextInt(bestSolution.length);
			int pos2;
			do {
				pos2 = RND.nextInt(bestSolution.length);
			} while (pos2 == pos1);
			swap(bestSolution, pos1, pos2);
			int candidateFitness = fitness(bestSolution);
			if (candidateFitness <= bestFitness) {
				if (candidateFitness < bestFitness) {
					lastSuccessfulCallsNum = fitnessCalls;
					System.out.println(">>> " + candidateFitness);
				}
				bestFitness = candidateFitness;
			} else {
				swap(bestSolution, pos1, pos2); // revert
			}
			if (fitnessCalls % 1000 == 0) {
				System.out.println(fitnessCalls + " computed");
			}
			if (fitnessCalls - lastSuccessfulCallsNum > STAG_CALLS) {
				System.out.println(">>> Stagnation");
				break;
			}
		}

		System.out.println(">>> Best fitness: " + bestFitness + "\n");
		System.out.println(">>> Method execution time: " + (System.currentTimeMillis() - time) / 1000.0);
		System.out.println(Arrays.toString(bestSolution));
		return automaton.swapStates(bestSolution);
	}