Advertisement
JackOUT

Untitled

Jan 19th, 2024
992
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 19.90 KB | None | 0 0
  1. package com.bcs2024.knapsack.algorithm;
  2.  
  3. import com.bcs2024.knapsack.model.CargoSpace;
  4. import com.bcs2024.knapsack.renderer.UI;
  5. import com.bcs2024.knapsack.util.ShapesAndRotations;
  6.  
  7. import java.util.ArrayList;
  8. import java.util.Arrays;
  9. import java.util.List;
  10. import java.util.Random;
  11.  
  12. public class GeneticKnapsackSolverDynamic {
  13.  
  14.     private final double MUTATION_RATE = 0.3;
  15.     //private double dynamicMutationRate = MUTATION_RATE;
  16.     private final double CROSSOVER_RATE = 0.8;
  17.     private final int MAX_GENERATIONS = 10;
  18.     private final int GENE_LENGTH = 54;
  19.     private final Random random = new Random();
  20.     private final int POPULATION_SIZE = 100;
  21.     private List<Chromosome> population;
  22.     private int[] bestSolutionRotation;
  23.     private String[] bestSolutionGene;
  24.  
  25.     private Chromosome bestChromosome;
  26.  
  27.     private CargoSpace cargoSpace = UI.cargoSpace;
  28.  
  29.     public static void main(final String[] args) {
  30.         /*final List<Parcel> parcels = new ArrayList<>();
  31.         parcels.add(new Parcel("A"));
  32.         parcels.add(new Parcel("B"));
  33.         parcels.add(new Parcel("C"));*/
  34.  
  35.         final GeneticKnapsackSolverDynamic solver = new GeneticKnapsackSolverDynamic();
  36.         solver.solve();
  37.     }
  38.  
  39.     public void solve() {
  40.         bestSolutionGene = new String[GENE_LENGTH];
  41.         bestSolutionRotation = new int[GENE_LENGTH];
  42.  
  43.         initializePopulation();
  44.  
  45.         for (int i = 0; i < MAX_GENERATIONS; i++) {
  46.             evaluateFitness(population);
  47.             crossover();
  48.             mutation();
  49.             //final double currentDiversity = calculateDiversity(population);
  50.             //System.out.println("Diversity after generation " + i + ": " + currentDiversity);
  51.             System.out.println("Generation: " + i + " done. -------------------------------------------------------------------------------" + "\n");
  52.         }
  53.  
  54.         System.out.println("Rotation: " + Arrays.toString(bestSolutionRotation));
  55.         System.out.println("Genes: " + Arrays.toString(bestSolutionGene));
  56.         applyBestSolution();
  57.     }
  58.  
  59.     private void initializePopulation() {
  60.         population = new ArrayList<>(POPULATION_SIZE);
  61.         final String[] parcelTypes = {"A", "B", "C"}; // Define available parcel types
  62.         final ShapesAndRotations shapesAndRotations = new ShapesAndRotations(); // To get the number of rotations
  63.  
  64.         for (int i = 0; i < POPULATION_SIZE; i++) {
  65.             final Chromosome chromosome = new Chromosome(GENE_LENGTH);
  66.             final String[] genes = chromosome.getGenes();
  67.             final int[] rotations = chromosome.getRotations();
  68.  
  69.             for (int j = 0; j < GENE_LENGTH; j++) {
  70.                 // Randomly assign a parcel type
  71.                 final String parcelType = parcelTypes[random.nextInt(parcelTypes.length)];
  72.                 genes[j] = parcelType;
  73.  
  74.                 // Randomly assign a rotation
  75.                 final int maxRotations = shapesAndRotations.rotationNum(parcelType);
  76.                 final int rotation = random.nextInt(maxRotations);
  77.                 rotations[j] = rotation;
  78.             }
  79.  
  80.             chromosome.setGenes(genes);
  81.             chromosome.setRotations(rotations);
  82.             population.add(chromosome);
  83.         }
  84.     }
  85.  
  86.     private void evaluateFitness(final List<Chromosome> population) {
  87.         final ShapesAndRotations shapes = new ShapesAndRotations();
  88.  
  89.         for (final Chromosome chromo : population) {
  90.             int totalValue = 0;
  91.             int countA = 0;
  92.             int countB = 0;
  93.             int countC = 0;
  94.             final CargoSpace localCargoSpace = new CargoSpace();
  95.             final int[][][] occupied = localCargoSpace.getOccupied();
  96.             final boolean[] parcelUsed = new boolean[GENE_LENGTH]; // To track which parcels are used
  97.  
  98.             for (int x = 0; x < occupied.length; x++) {
  99.                 for (int y = 0; y < occupied[0].length; y++) {
  100.                     for (int z = 0; z < occupied[0][0].length; z++) {
  101.                         for (int i = 0; i < chromo.getGenes().length; i++) {
  102.                             final String gene = chromo.getGenes()[i];
  103.                             final int rotation = chromo.getRotationFromGene(i);
  104.                             final int[][][] shape = shapes.getShape(gene, rotation);
  105.  
  106.                             //final Parcel parcel = new Parcel(gene, shape);
  107.                             //final ParcelPlacement placement = new ParcelPlacement(parcel, x, y, z);
  108.  
  109.                             if (localCargoSpace.canPlace(shape, x, y, z)) {
  110.                                 localCargoSpace.placeParcel(shape, x, y, z, occupied);
  111.                                 parcelUsed[i] = true; // Mark this parcel as used
  112.  
  113.                                 switch (gene) {
  114.                                     case "A" -> {
  115.                                         totalValue += 3;
  116.                                         countA++;
  117.                                     }
  118.                                     case "B" -> {
  119.                                         totalValue += 4;
  120.                                         countB++;
  121.                                     }
  122.                                     case "C" -> {
  123.                                         totalValue += 5;
  124.                                         countC++;
  125.                                     }
  126.                                 }
  127.                             }
  128.                         }
  129.                     }
  130.                 }
  131.             }
  132.  
  133.             final int fitness = getFitness(occupied, totalValue);
  134.             chromo.setFitness(fitness);
  135.  
  136.             // Store the best solution
  137.             if (bestChromosome == null || chromo.getFitness() > bestChromosome.getFitness()) {
  138.                 bestChromosome = chromo;
  139.                 bestSolutionRotation = chromo.getRotations();
  140.                 bestSolutionGene = chromo.getGenes();
  141.             }
  142.  
  143.             System.out.println("Chromosome Fitness: " + chromo.getFitness());
  144.             System.out.println(Arrays.toString(chromo.getRotations()));
  145.             System.out.println(Arrays.toString(chromo.getGenes()));
  146.             System.out.println("A: " + countA + " B: " + countB + " C: " + countC);
  147.         }
  148.     }
  149.  
  150.     private int getFitness(final int[][][] occupied, final int totalValue) {
  151.         int emptySlots = 0;
  152.         for (final int[][] slice : occupied) {
  153.             for (final int[] row : slice) {
  154.                 for (final int cell : row) {
  155.                     if (cell == -1) {
  156.                         emptySlots++;
  157.                     }
  158.                 }
  159.             }
  160.         }
  161.  
  162.         // Parameters for weighing the importance of space utilization
  163.         final double spaceUtilizationWeight = 0.5; // Can be adjusted
  164.         final double valueWeight = 1.0 - spaceUtilizationWeight;
  165.  
  166.         return (int) (valueWeight * totalValue - spaceUtilizationWeight * emptySlots);
  167.     }
  168.  
  169.     private Chromosome tournamentSelection(final int tournamentSize) {
  170.         final List<Chromosome> tournamentParticipants = new ArrayList<>();
  171.  
  172.         if (tournamentSize > population.size() || tournamentSize < 1) {
  173.             throw new IllegalArgumentException("Tournament size should be between 1 and population size.");
  174.         }
  175.  
  176.         for (int i = 0; i < tournamentSize; i++) {
  177.             tournamentParticipants.add(population.get(random.nextInt(population.size())));
  178.         }
  179.  
  180.         Chromosome winner = tournamentParticipants.get(0);
  181.         for (final Chromosome participant : tournamentParticipants) {
  182.             if (participant.getFitness() > winner.getFitness()) {
  183.                 winner = participant;
  184.             }
  185.         }
  186.  
  187.         return winner;
  188.     }
  189.  
  190.     private void crossover() {
  191.         final List<Chromosome> newPopulation = new ArrayList<>();
  192.         //final double preCrossoverDiversity = calculateDiversity(population);
  193.  
  194.         // Loop to create offspring in pairs
  195.         for (int i = 0; i < POPULATION_SIZE; i += 2) {
  196.             final Chromosome parent1 = tournamentSelection(2);
  197.             final Chromosome parent2 = tournamentSelection(2);
  198.  
  199.             final Chromosome offspring1 = new Chromosome(GENE_LENGTH);
  200.             final Chromosome offspring2 = new Chromosome(GENE_LENGTH);
  201.  
  202.             int crossoverPoint1 = random.nextInt(GENE_LENGTH);
  203.             int crossoverPoint2 = random.nextInt(GENE_LENGTH);
  204.  
  205.             // Ensure crossoverPoint1 is less than crossoverPoint2
  206.             if (crossoverPoint1 > crossoverPoint2) {
  207.                 final int temp = crossoverPoint1;
  208.                 crossoverPoint1 = crossoverPoint2;
  209.                 crossoverPoint2 = temp;
  210.             }
  211.  
  212.             if (random.nextDouble() <= CROSSOVER_RATE) {
  213.                 for (int j = 0; j < GENE_LENGTH; j++) {
  214.                     if (j < crossoverPoint1 || j > crossoverPoint2) {
  215.                         offspring1.getGenes()[j] = parent1.getGenes()[j];
  216.                         offspring1.getRotations()[j] = parent1.getRotations()[j];
  217.  
  218.                         offspring2.getGenes()[j] = parent2.getGenes()[j];
  219.                         offspring2.getRotations()[j] = parent2.getRotations()[j];
  220.                     } else {
  221.                         offspring1.getGenes()[j] = parent2.getGenes()[j];
  222.                         offspring1.getRotations()[j] = parent2.getRotations()[j];
  223.  
  224.                         offspring2.getGenes()[j] = parent1.getGenes()[j];
  225.                         offspring2.getRotations()[j] = parent1.getRotations()[j];
  226.                     }
  227.                 }
  228.             } else {
  229.                 offspring1.setGenes(parent1.getGenes().clone());
  230.                 offspring1.setRotations(parent1.getRotations().clone());
  231.  
  232.                 offspring2.setGenes(parent2.getGenes().clone());
  233.                 offspring2.setRotations(parent2.getRotations().clone());
  234.             }
  235.  
  236.             if (isValid(offspring1)) {
  237.                 newPopulation.add(offspring1);
  238.             } else {
  239.                 final Chromosome offspringRepaired = new Chromosome(GENE_LENGTH);
  240.                 newPopulation.add(offspringRepaired);
  241.             }
  242.  
  243.             if (isValid(offspring2)) {
  244.                 newPopulation.add(offspring2);
  245.             } else {
  246.                 final Chromosome offspringRepaired2 = new Chromosome(GENE_LENGTH);
  247.                 newPopulation.add(offspringRepaired2);
  248.             }
  249.         }
  250.  
  251.         population = newPopulation;
  252.         //final double postCrossoverDiversity = calculateDiversity(population);
  253.         //  System.out.println("Diversity change after crossover: " + (postCrossoverDiversity - preCrossoverDiversity));
  254.  
  255.         // Adapt mutation rate based on diversity change
  256.         //adaptMutationRate(preCrossoverDiversity, postCrossoverDiversity);
  257.     }
  258.  
  259.     private void mutation() {
  260.         // final double preMutationDiversity = calculateDiversity(population);
  261.  
  262.         for (final Chromosome chromo : population) {
  263.             if (random.nextDouble() < MUTATION_RATE) { // Use dynamicMutationRate
  264.                 final int index = random.nextInt(GENE_LENGTH);
  265.                 final String[] types = {"A", "B", "C"};
  266.                 final String newType = types[random.nextInt(types.length)];
  267.  
  268.                 chromo.getGenes()[index] = newType;
  269.  
  270.                 final ShapesAndRotations shapesAndRotations = new ShapesAndRotations();
  271.                 final int newRotation = random.nextInt(shapesAndRotations.rotationNum(newType));
  272.                 chromo.getRotations()[index] = newRotation;
  273.             }
  274.         }
  275.         // final double postMutationDiversity = calculateDiversity(population);
  276.         //System.out.println("Diversity change after mutation: " + (postMutationDiversity - preMutationDiversity));
  277.  
  278.         // Adapt mutation rate based on diversity change
  279.         //adaptMutationRate(preMutationDiversity, postMutationDiversity);
  280.     }
  281.  
  282.     /*private void adaptMutationRate(final double preDiversity, final double postDiversity) {
  283.         if (postDiversity < preDiversity) {
  284.             // If diversity has decreased, increase the mutation rate to introduce more diversity
  285.             dynamicMutationRate = Math.min(dynamicMutationRate + 0.1, 1.0);
  286.         } else {
  287.             // If diversity has increased or stayed the same, decrease the mutation rate to allow the population to stabilize
  288.             dynamicMutationRate = Math.max(dynamicMutationRate - 0.05, 0.1);
  289.         }
  290.         System.out.println("Adapted Mutation Rate: " + dynamicMutationRate);
  291.     }
  292.  
  293.     private double calculateShapeDiversity(final List<CargoSpace> population) {
  294.         final Set<int[][][]> uniqueShapes = new HashSet<>();
  295.         for (final CargoSpace cargoSpace : population) {
  296.             for (final ParcelPlacement placement : cargoSpace.getPlacements()) {
  297.                 final int[][][] shapeSignature = getShapeSignature(placement);
  298.                 uniqueShapes.add(shapeSignature);
  299.             }
  300.         }
  301.  
  302.         return uniqueShapes.size();
  303.     }
  304.  
  305.     private int[][][] getShapeSignature(final ParcelPlacement placement) {
  306.         return placement.getShape();
  307.     }
  308.  
  309.     private double calculatePositionalDiversity(final List<CargoSpace> population) {
  310.         double totalDistance = 0.0;
  311.         int comparisons = 0;
  312.  
  313.         for (int i = 0; i < population.size() - 1; i++) {
  314.             for (int j = i + 1; j < population.size(); j++) {
  315.                 final CargoSpace space1 = population.get(i);
  316.                 final CargoSpace space2 = population.get(j);
  317.                 // Compare placements in space1 and space2
  318.                 for (final ParcelPlacement placement1 : space1.getPlacements()) {
  319.                     for (final ParcelPlacement placement2 : space2.getPlacements()) {
  320.                         if (Arrays.deepEquals(getShapeSignature(placement1), getShapeSignature(placement2))) {
  321.                             totalDistance += calculateDistance(placement1, placement2);
  322.                             comparisons++;
  323.                         }
  324.                     }
  325.                 }
  326.             }
  327.         }
  328.  
  329.         return comparisons > 0 ? totalDistance / comparisons : 0;
  330.     }
  331.  
  332.     private double calculateDistance(final ParcelPlacement placement1, final ParcelPlacement placement2) {
  333.         // Euclidean distance between two parcel placements
  334.         return Math.sqrt(Math.pow(placement1.getX() - placement2.getX(), 2) +
  335.                 Math.pow(placement1.getY() - placement2.getY(), 2) +
  336.                 Math.pow(placement1.getZ() - placement2.getZ(), 2));
  337.     }
  338.  
  339.     private double calculateDiversity(final List<Chromosome> chromosomePopulation) {
  340.         // Convert each chromosome to a corresponding CargoSpace
  341.         final List<CargoSpace> cargoSpacePopulation = new ArrayList<>();
  342.         for (final Chromosome chromosome : chromosomePopulation) {
  343.             cargoSpacePopulation.add(chromosomeToCargoSpace(chromosome));
  344.         }
  345.  
  346.         // Now calculate diversity based on the CargoSpace objects
  347.         final double shapeDiversityScore = calculateShapeDiversity(cargoSpacePopulation);
  348.         final double positionalDiversityScore = calculatePositionalDiversity(cargoSpacePopulation);
  349.  
  350.         // Combine the scores. Adjust the weights if necessary.
  351.         return shapeDiversityScore * 0.5 + positionalDiversityScore * 0.5;
  352.     }
  353.  
  354.     private CargoSpace chromosomeToCargoSpace(final Chromosome chromosome) {
  355.         final CargoSpace cargoSpace = new CargoSpace();
  356.         final ShapesAndRotations shapes = new ShapesAndRotations();
  357.  
  358.         for (int i = 0; i < chromosome.getGenes().length; i++) {
  359.             final String gene = chromosome.getGenes()[i];
  360.             final int rotation = chromosome.getRotationFromGene(i);
  361.             final int[][][] shape = shapes.getShape(gene, rotation);
  362.  
  363.             // Find a place to put the parcel. This is a simplified placement logic.
  364.             // You might have a more complex placement strategy.
  365.             for (int x = 0; x < cargoSpace.getOccupied().length; x++) {
  366.                 for (int y = 0; y < cargoSpace.getOccupied()[0].length; y++) {
  367.                     for (int z = 0; z < cargoSpace.getOccupied()[0][0].length; z++) {
  368.                         final Parcel parcel = new Parcel(gene, shape);
  369.                         final ParcelPlacement placement = new ParcelPlacement(parcel, x, y, z);
  370.                         if (cargoSpace.canPlace(placement)) {
  371.                             cargoSpace.placeParcel(placement);
  372.                             // Break the loops after placing the parcel
  373.                             x = cargoSpace.getOccupied().length;
  374.                             y = cargoSpace.getOccupied()[0].length;
  375.                             z = cargoSpace.getOccupied()[0][0].length;
  376.                         }
  377.                     }
  378.                 }
  379.             }
  380.         }
  381.  
  382.         return cargoSpace;
  383.     }*/
  384.  
  385.     private boolean isValid(final Chromosome chromo) {
  386.         final ShapesAndRotations shapes = new ShapesAndRotations();
  387.         int totalValue = 0;
  388.         final CargoSpace cargoSpace = new CargoSpace();
  389.         final int[][][] occupied = cargoSpace.getOccupied();
  390.  
  391.         for (int x = 0; x < occupied.length; x++) {
  392.             for (int y = 0; y < occupied[0].length; y++) {
  393.                 for (int z = 0; z < occupied[0][0].length; z++) {
  394.                     for (int i = 0; i < chromo.getGenes().length; i++) {
  395.                         final String gene = chromo.getGenes()[i];
  396.                         final int rotation = chromo.getRotationFromGene(i);
  397.                         final int[][][] shape = shapes.getShape(gene, rotation);
  398.                         if (cargoSpace.canPlace(shape, x, y, z)) {
  399.                             if ("A".equals(gene)) {
  400.                                 totalValue += 3;
  401.                             } else if ("B".equals(gene)) {
  402.                                 totalValue += 4;
  403.                             } else if ("C".equals(gene)) {
  404.                                 totalValue += 5;
  405.                             }
  406.                         }
  407.                     }
  408.                 }
  409.             }
  410.         }
  411.  
  412.         return totalValue > 0;
  413.     }
  414.  
  415.     private void applyBestSolution() {
  416.         if (bestChromosome == null) {
  417.             System.out.println("No optimal solution found.");
  418.             return;
  419.         }
  420.         final CargoSpace bestCargoSpace = new CargoSpace();
  421.         final ShapesAndRotations shapes = new ShapesAndRotations();
  422.         final int[][][] occupied = bestCargoSpace.getOccupied();
  423.  
  424.         // Use the best chromosome to set the cargo space fields
  425.         for (int i = 0; i < bestChromosome.getGenes().length; i++) {
  426.             final String gene = bestChromosome.getGenes()[i];
  427.             final int rotation = bestChromosome.getRotationFromGene(i);
  428.             final int[][][] shape = shapes.getShape(gene, rotation);
  429.  
  430.             boolean placed = false;
  431.             for (int x = 0; x < occupied.length && !placed; x++) {
  432.                 for (int y = 0; y < occupied[0].length && !placed; y++) {
  433.                     for (int z = 0; z < occupied[0][0].length && !placed; z++) {
  434.  
  435.                         /*final Parcel parcel = new Parcel(gene);
  436.                         parcel.setShape(shape);
  437.                         final ParcelPlacement placement = new ParcelPlacement(parcel, x, y, z);*/
  438.  
  439.                         if (bestCargoSpace.canPlace(shape, x, y, z)) {
  440.                             bestCargoSpace.placeParcel(shape, x, y, z, occupied);
  441.                             placed = true; // Parcel placed, move to next parcel
  442.                         }
  443.                     }
  444.                 }
  445.             }
  446.  
  447.             if (!placed) {
  448.                 System.out.println("Could not place parcel: " + gene);
  449.             }
  450.         }
  451.  
  452.         System.out.println("Best solution: " + bestChromosome.getFitness());
  453.         cargoSpace.setOccupied(occupied); // Reflect the best solution in the CargoSpace
  454.         System.out.println(Arrays.deepToString(cargoSpace.getOccupied()));
  455.     }
  456.  
  457. }
  458.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement