package aima.gui.fx.applications.search; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Random; import aima.core.agent.Action; import aima.core.environment.nqueens.AttackingPairsHeuristic; import aima.core.environment.nqueens.NQueensBoard; import aima.core.environment.nqueens.NQueensBoard.Config; import aima.core.environment.nqueens.NQueensFunctionFactory; import aima.core.environment.nqueens.NQueensGenAlgoUtil; import aima.core.environment.nqueens.NQueensGoalTest; import aima.core.search.framework.Metrics; import aima.core.search.framework.SearchForActions; import aima.core.search.framework.problem.Problem; import aima.core.search.framework.qsearch.TreeSearch; import aima.core.search.local.FitnessFunction; import aima.core.search.local.GeneticAlgorithm; import aima.core.search.local.HillClimbingSearch; import aima.core.search.local.Individual; import aima.core.search.local.Scheduler; import aima.core.search.local.SimulatedAnnealingSearch; import aima.core.search.uninformed.DepthFirstSearch; /** * Command line demo which demonstrates how different search algorithms * solve the n-queens problem. * * @author Ruediger Lunde */ public class NQueensSearchDemo { private int boardSize = 8; private int populationSize = 10; private double mutationProbability = 0.2; public int k = 30; private double lambda = 2.0 / 100; private int maxIterations = 500; private static Random random = new Random(); private GeneticAlgorithm<Integer> genAlgo; private SearchForActions search; private NQueensBoard board; private List<ProgressTracer> progressTracers = new ArrayList<>(); public static void main(String[] args) { NQueensSearchDemo demo = new NQueensSearchDemo(); // prog.setBoardSize(32); demo.addProgressTracer(demo::printProgress); System.out.println("NQueens depth-first search experiment (boardSize=" + demo.boardSize + ") -->"); demo.initExperiment(Config.EMPTY); demo.startExperiment(new DepthFirstSearch(new TreeSearch())); demo.printResult(); System.out.println("NQueens hill climbing search experiment (boardSize=" + demo.boardSize + ") -->"); demo.initExperiment(Config.QUEENS_IN_FIRST_ROW); demo.startHillClimbingExperiment(); demo.printResult(); System.out.println("NQueens simulated annealing experiment (boardSize=" + demo.boardSize + ", maxIterations=" + demo.maxIterations + ") -->"); demo.initExperiment(Config.QUEENS_IN_FIRST_ROW); demo.startSimulatedAnnealingExperiment(); demo.printResult(); System.out.println("NQueens genetic algorithm experiment (boardSize=" + demo.boardSize + ", popSize=" + demo.populationSize + ", mutProb=" + demo.mutationProbability + ") -->"); demo.initExperiment(Config.EMPTY); demo.startGenAlgoExperiment(false); demo.printResult(); } public void setBoardSize(int size) { boardSize = size; board = new NQueensBoard(boardSize); } public void addProgressTracer(ProgressTracer tracer) { progressTracers.add(tracer); } public void initExperiment(Config config) { board = new NQueensBoard(boardSize, config); genAlgo = null; search = null; } public void startExperiment(SearchForActions search) { search.getNodeExpander() .addNodeListener(n -> notifyProgressTracers((NQueensBoard) n.getState(), search.getMetrics())); Problem problem = null; if (board.getNumberOfQueensOnBoard() == 0) problem = new Problem(board, NQueensFunctionFactory.getIActionsFunction(), NQueensFunctionFactory.getResultFunction(), new NQueensGoalTest()); else problem = new Problem(board, NQueensFunctionFactory.getCActionsFunction(), NQueensFunctionFactory.getResultFunction(), new NQueensGoalTest()); List<Action> actions = search.findActions(problem); for (Action action : actions) board = (NQueensBoard) NQueensFunctionFactory.getResultFunction().result(board, action); notifyProgressTracers(board, search.getMetrics()); } public void startHillClimbingExperiment() { // board = new NQueensBoard(boardSize, Config.QUEEN_IN_EVERY_COL); Problem problem = new Problem(board, NQueensFunctionFactory.getCActionsFunction(), NQueensFunctionFactory.getResultFunction(), new NQueensGoalTest()); search = new HillClimbingSearch(new AttackingPairsHeuristic()); search.getNodeExpander() .addNodeListener(n -> notifyProgressTracers((NQueensBoard) n.getState(), search.getMetrics())); search.findActions(problem); board = (NQueensBoard) ((HillClimbingSearch) search).getLastSearchState(); notifyProgressTracers(board, search.getMetrics()); } public void startSimulatedAnnealingExperiment() { Problem problem = new Problem(board, NQueensFunctionFactory.getCActionsFunction(), NQueensFunctionFactory.getResultFunction(), new NQueensGoalTest()); Scheduler scheduler = new Scheduler(k, lambda, maxIterations); search = new SimulatedAnnealingSearch(new AttackingPairsHeuristic(), scheduler); search.getNodeExpander() .addNodeListener(n -> notifyProgressTracers((NQueensBoard) n.getState(), search.getMetrics())); search.findActions(problem); board = (NQueensBoard) ((SimulatedAnnealingSearch) search).getLastSearchState(); notifyProgressTracers(board, search.getMetrics()); } public void startGenAlgoExperiment(boolean randomConfig) { Collection<Integer> alphabet = NQueensGenAlgoUtil.getFiniteAlphabetForBoardOfSize(boardSize); FitnessFunction<Integer> fitnessFn = NQueensGenAlgoUtil.getFitnessFunction(); genAlgo = new GeneticAlgorithm<Integer>(boardSize, alphabet, mutationProbability, random) { protected void updateMetrics(Collection<Individual<Integer>> pop, int itCount, long time) { super.updateMetrics(pop, itCount, time); double avg = 0.0; double max = Double.NEGATIVE_INFINITY; for (Individual<Integer> ind : pop) { double fval = fitnessFn.apply(ind); avg += fval; max = Math.max(max, fval); } avg /= pop.size(); metrics.set("fitMax", max); metrics.set("fitAvg", avg); } }; genAlgo.addProgressTracer((it, pop) -> notifyProgressTracers(pop, fitnessFn)); List<Individual<Integer>> population = new ArrayList<>(); List<Integer> rep = new ArrayList<Integer>(); for (int i = 0; i < boardSize; i++) rep.add(0); for (int i = 0; i < populationSize; i++) if (randomConfig) population.add(NQueensGenAlgoUtil.generateRandomIndividual(boardSize)); else population.add(new Individual<Integer>(rep)); Individual<Integer> result = genAlgo.geneticAlgorithm(population, fitnessFn, maxIterations); board = NQueensGenAlgoUtil.getBoardForIndividual(result); } public NQueensBoard getBoard() { return board; } private void printProgress(NQueensBoard board, Metrics metrics) { System.out.println(board.getNumberOfAttackingPairs() + " attacking pairs " + metrics); } private void printResult() { if (board != null) { System.out.println("Final State:\n" + board); System.out.println("Attacking pairs: " + board.getNumberOfAttackingPairs()); } if (genAlgo != null) System.out.println("Metrics: " + genAlgo.getMetrics()); if (search != null) System.out.println("Metrics: " + search.getMetrics()); System.out.println("Experiment finished.\n"); } private void notifyProgressTracers(Collection<Individual<Integer>> population, FitnessFunction<Integer> fitnessFn) { Individual<Integer> best = genAlgo.retrieveBestIndividual(population, fitnessFn); notifyProgressTracers(NQueensGenAlgoUtil.getBoardForIndividual(best), genAlgo.getMetrics()); } private void notifyProgressTracers(NQueensBoard board, Metrics metrics) { for (ProgressTracer tracer : progressTracers) tracer.traceProgress(board, metrics); } public interface ProgressTracer { void traceProgress(NQueensBoard board, Metrics metrics); } }