[BAEL-9551] - Splitted algorithms into 4 modules

This commit is contained in:
amit2103
2018-10-28 23:29:09 +05:30
parent c10101a9ac
commit 539ce3e787
164 changed files with 1735 additions and 1241 deletions

4
algorithms-genetic/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
/target/
.settings/
.classpath
.project

View File

@@ -0,0 +1,4 @@
## Relevant articles:
- [Introduction to Jenetics Library](http://www.baeldung.com/jenetics)
- [Ant Colony Optimization](http://www.baeldung.com/java-ant-colony-optimization)

View File

@@ -0,0 +1,96 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>algorithms-genetic</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>${commons-math3.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.jenetics</groupId>
<artifactId>jenetics</artifactId>
<version>${io.jenetics.version}</version>
</dependency>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-core</artifactId>
<version>${org.jgrapht.core.version}</version>
</dependency>
<dependency>
<groupId>pl.allegro.finance</groupId>
<artifactId>tradukisto</artifactId>
<version>${tradukisto.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${org.assertj.core.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec-maven-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.7</version>
<configuration>
<instrumentation>
<ignores>
<ignore>com/baeldung/algorithms/dijkstra/*</ignore>
</ignores>
<excludes>
<exclude>com/baeldung/algorithms/dijkstra/*</exclude>
</excludes>
</instrumentation>
</configuration>
</plugin>
</plugins>
</reporting>
<properties>
<lombok.version>1.16.12</lombok.version>
<commons-math3.version>3.6.1</commons-math3.version>
<tradukisto.version>1.0.1</tradukisto.version>
<io.jenetics.version>3.7.0</io.jenetics.version>
<org.jgrapht.core.version>1.0.1</org.jgrapht.core.version>
<org.assertj.core.version>3.9.0</org.assertj.core.version>
<commons-codec.version>1.11</commons-codec.version>
</properties>
</project>

View File

@@ -0,0 +1 @@
/bin/

View File

@@ -0,0 +1,20 @@
package com.java.src;
import java.util.Scanner;
public class RoundUpToHundred {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double input = scanner.nextDouble();
scanner.close();
RoundUpToHundred.round(input);
}
static long round(double input) {
long i = (long) Math.ceil(input);
return ((i + 99) / 100) * 100;
};
}

View File

@@ -0,0 +1,14 @@
package com.java.src;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class RoundUpToHundredTest {
@Test
public void givenInput_whenRound_thenRoundUpToTheNearestHundred() {
assertEquals("Rounded up to hundred", 100, RoundUpToHundred.round(99));
assertEquals("Rounded up to three hundred ", 300, RoundUpToHundred.round(200.2));
assertEquals("Returns same rounded value", 400, RoundUpToHundred.round(400));
}
}

View File

@@ -0,0 +1,48 @@
package com.baeldung.algorithms;
import java.util.Scanner;
import com.baeldung.algorithms.ga.annealing.SimulatedAnnealing;
import com.baeldung.algorithms.ga.ant_colony.AntColonyOptimization;
import com.baeldung.algorithms.ga.binary.SimpleGeneticAlgorithm;
import com.baeldung.algorithms.slope_one.SlopeOne;
public class RunAlgorithm {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Scanner in = new Scanner(System.in);
System.out.println("Run algorithm:");
System.out.println("1 - Simulated Annealing");
System.out.println("2 - Slope One");
System.out.println("3 - Simple Genetic Algorithm");
System.out.println("4 - Ant Colony");
System.out.println("5 - Dijkstra");
System.out.println("6 - All pairs in an array that add up to a given sum");
int decision = in.nextInt();
switch (decision) {
case 1:
System.out.println(
"Optimized distance for travel: " + SimulatedAnnealing.simulateAnnealing(10, 10000, 0.9995));
break;
case 2:
SlopeOne.slopeOne(3);
break;
case 3:
SimpleGeneticAlgorithm ga = new SimpleGeneticAlgorithm();
ga.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111");
break;
case 4:
AntColonyOptimization antColony = new AntColonyOptimization(21);
antColony.startAntOptimization();
break;
case 5:
System.out.println("Please run the DijkstraAlgorithmTest.");
break;
default:
System.out.println("Unknown option");
break;
}
in.close();
}
}

View File

@@ -0,0 +1,22 @@
package com.baeldung.algorithms.ga.annealing;
import lombok.Data;
@Data
public class City {
private int x;
private int y;
public City() {
this.x = (int) (Math.random() * 500);
this.y = (int) (Math.random() * 500);
}
public double distanceToCity(City city) {
int x = Math.abs(getX() - city.getX());
int y = Math.abs(getY() - city.getY());
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
}
}

View File

@@ -0,0 +1,36 @@
package com.baeldung.algorithms.ga.annealing;
public class SimulatedAnnealing {
private static Travel travel = new Travel(10);
public static double simulateAnnealing(double startingTemperature, int numberOfIterations, double coolingRate) {
System.out.println("Starting SA with temperature: " + startingTemperature + ", # of iterations: " + numberOfIterations + " and colling rate: " + coolingRate);
double t = startingTemperature;
travel.generateInitialTravel();
double bestDistance = travel.getDistance();
System.out.println("Initial distance of travel: " + bestDistance);
Travel bestSolution = travel;
Travel currentSolution = bestSolution;
for (int i = 0; i < numberOfIterations; i++) {
if (t > 0.1) {
currentSolution.swapCities();
double currentDistance = currentSolution.getDistance();
if (currentDistance < bestDistance) {
bestDistance = currentDistance;
} else if (Math.exp((bestDistance - currentDistance) / t) < Math.random()) {
currentSolution.revertSwap();
}
t *= coolingRate;
} else {
continue;
}
if (i % 100 == 0) {
System.out.println("Iteration #" + i);
}
}
return bestDistance;
}
}

View File

@@ -0,0 +1,63 @@
package com.baeldung.algorithms.ga.annealing;
import java.util.ArrayList;
import java.util.Collections;
import lombok.Data;
@Data
public class Travel {
private ArrayList<City> travel = new ArrayList<>();
private ArrayList<City> previousTravel = new ArrayList<>();
public Travel(int numberOfCities) {
for (int i = 0; i < numberOfCities; i++) {
travel.add(new City());
}
}
public void generateInitialTravel() {
if (travel.isEmpty())
new Travel(10);
Collections.shuffle(travel);
}
public void swapCities() {
int a = generateRandomIndex();
int b = generateRandomIndex();
previousTravel = travel;
City x = travel.get(a);
City y = travel.get(b);
travel.set(a, y);
travel.set(b, x);
}
public void revertSwap() {
travel = previousTravel;
}
private int generateRandomIndex() {
return (int) (Math.random() * travel.size());
}
public City getCity(int index) {
return travel.get(index);
}
public int getDistance() {
int distance = 0;
for (int index = 0; index < travel.size(); index++) {
City starting = getCity(index);
City destination;
if (index + 1 < travel.size()) {
destination = getCity(index + 1);
} else {
destination = getCity(0);
}
distance += starting.distanceToCity(destination);
}
return distance;
}
}

View File

@@ -0,0 +1,37 @@
package com.baeldung.algorithms.ga.ant_colony;
public class Ant {
protected int trailSize;
protected int trail[];
protected boolean visited[];
public Ant(int tourSize) {
this.trailSize = tourSize;
this.trail = new int[tourSize];
this.visited = new boolean[tourSize];
}
protected void visitCity(int currentIndex, int city) {
trail[currentIndex + 1] = city;
visited[city] = true;
}
protected boolean visited(int i) {
return visited[i];
}
protected double trailLength(double graph[][]) {
double length = graph[trail[trailSize - 1]][trail[0]];
for (int i = 0; i < trailSize - 1; i++) {
length += graph[trail[i]][trail[i + 1]];
}
return length;
}
protected void clear() {
for (int i = 0; i < trailSize; i++)
visited[i] = false;
}
}

View File

@@ -0,0 +1,203 @@
package com.baeldung.algorithms.ga.ant_colony;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.OptionalInt;
import java.util.Random;
import java.util.stream.IntStream;
public class AntColonyOptimization {
private double c = 1.0;
private double alpha = 1;
private double beta = 5;
private double evaporation = 0.5;
private double Q = 500;
private double antFactor = 0.8;
private double randomFactor = 0.01;
private int maxIterations = 1000;
private int numberOfCities;
private int numberOfAnts;
private double graph[][];
private double trails[][];
private List<Ant> ants = new ArrayList<>();
private Random random = new Random();
private double probabilities[];
private int currentIndex;
private int[] bestTourOrder;
private double bestTourLength;
public AntColonyOptimization(int noOfCities) {
graph = generateRandomMatrix(noOfCities);
numberOfCities = graph.length;
numberOfAnts = (int) (numberOfCities * antFactor);
trails = new double[numberOfCities][numberOfCities];
probabilities = new double[numberOfCities];
IntStream.range(0, numberOfAnts)
.forEach(i -> ants.add(new Ant(numberOfCities)));
}
/**
* Generate initial solution
*/
public double[][] generateRandomMatrix(int n) {
double[][] randomMatrix = new double[n][n];
IntStream.range(0, n)
.forEach(i -> IntStream.range(0, n)
.forEach(j -> randomMatrix[i][j] = Math.abs(random.nextInt(100) + 1)));
return randomMatrix;
}
/**
* Perform ant optimization
*/
public void startAntOptimization() {
IntStream.rangeClosed(1, 3)
.forEach(i -> {
System.out.println("Attempt #" + i);
solve();
});
}
/**
* Use this method to run the main logic
*/
public int[] solve() {
setupAnts();
clearTrails();
IntStream.range(0, maxIterations)
.forEach(i -> {
moveAnts();
updateTrails();
updateBest();
});
System.out.println("Best tour length: " + (bestTourLength - numberOfCities));
System.out.println("Best tour order: " + Arrays.toString(bestTourOrder));
return bestTourOrder.clone();
}
/**
* Prepare ants for the simulation
*/
private void setupAnts() {
IntStream.range(0, numberOfAnts)
.forEach(i -> {
ants.forEach(ant -> {
ant.clear();
ant.visitCity(-1, random.nextInt(numberOfCities));
});
});
currentIndex = 0;
}
/**
* At each iteration, move ants
*/
private void moveAnts() {
IntStream.range(currentIndex, numberOfCities - 1)
.forEach(i -> {
ants.forEach(ant -> ant.visitCity(currentIndex, selectNextCity(ant)));
currentIndex++;
});
}
/**
* Select next city for each ant
*/
private int selectNextCity(Ant ant) {
int t = random.nextInt(numberOfCities - currentIndex);
if (random.nextDouble() < randomFactor) {
OptionalInt cityIndex = IntStream.range(0, numberOfCities)
.filter(i -> i == t && !ant.visited(i))
.findFirst();
if (cityIndex.isPresent()) {
return cityIndex.getAsInt();
}
}
calculateProbabilities(ant);
double r = random.nextDouble();
double total = 0;
for (int i = 0; i < numberOfCities; i++) {
total += probabilities[i];
if (total >= r) {
return i;
}
}
throw new RuntimeException("There are no other cities");
}
/**
* Calculate the next city picks probabilites
*/
public void calculateProbabilities(Ant ant) {
int i = ant.trail[currentIndex];
double pheromone = 0.0;
for (int l = 0; l < numberOfCities; l++) {
if (!ant.visited(l)) {
pheromone += Math.pow(trails[i][l], alpha) * Math.pow(1.0 / graph[i][l], beta);
}
}
for (int j = 0; j < numberOfCities; j++) {
if (ant.visited(j)) {
probabilities[j] = 0.0;
} else {
double numerator = Math.pow(trails[i][j], alpha) * Math.pow(1.0 / graph[i][j], beta);
probabilities[j] = numerator / pheromone;
}
}
}
/**
* Update trails that ants used
*/
private void updateTrails() {
for (int i = 0; i < numberOfCities; i++) {
for (int j = 0; j < numberOfCities; j++) {
trails[i][j] *= evaporation;
}
}
for (Ant a : ants) {
double contribution = Q / a.trailLength(graph);
for (int i = 0; i < numberOfCities - 1; i++) {
trails[a.trail[i]][a.trail[i + 1]] += contribution;
}
trails[a.trail[numberOfCities - 1]][a.trail[0]] += contribution;
}
}
/**
* Update the best solution
*/
private void updateBest() {
if (bestTourOrder == null) {
bestTourOrder = ants.get(0).trail;
bestTourLength = ants.get(0)
.trailLength(graph);
}
for (Ant a : ants) {
if (a.trailLength(graph) < bestTourLength) {
bestTourLength = a.trailLength(graph);
bestTourOrder = a.trail.clone();
}
}
}
/**
* Clear trails after simulation
*/
private void clearTrails() {
IntStream.range(0, numberOfCities)
.forEach(i -> {
IntStream.range(0, numberOfCities)
.forEach(j -> trails[i][j] = c);
});
}
}

View File

@@ -0,0 +1,44 @@
package com.baeldung.algorithms.ga.binary;
import lombok.Data;
@Data
public class Individual {
protected int defaultGeneLength = 64;
private byte[] genes = new byte[defaultGeneLength];
private int fitness = 0;
public Individual() {
for (int i = 0; i < genes.length; i++) {
byte gene = (byte) Math.round(Math.random());
genes[i] = gene;
}
}
protected byte getSingleGene(int index) {
return genes[index];
}
protected void setSingleGene(int index, byte value) {
genes[index] = value;
fitness = 0;
}
public int getFitness() {
if (fitness == 0) {
fitness = SimpleGeneticAlgorithm.getFitness(this);
}
return fitness;
}
@Override
public String toString() {
String geneString = "";
for (int i = 0; i < genes.length; i++) {
geneString += getSingleGene(i);
}
return geneString;
}
}

View File

@@ -0,0 +1,40 @@
package com.baeldung.algorithms.ga.binary;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
@Data
public class Population {
private List<Individual> individuals;
public Population(int size, boolean createNew) {
individuals = new ArrayList<>();
if (createNew) {
createNewPopulation(size);
}
}
protected Individual getIndividual(int index) {
return individuals.get(index);
}
protected Individual getFittest() {
Individual fittest = individuals.get(0);
for (int i = 0; i < individuals.size(); i++) {
if (fittest.getFitness() <= getIndividual(i).getFitness()) {
fittest = getIndividual(i);
}
}
return fittest;
}
private void createNewPopulation(int size) {
for (int i = 0; i < size; i++) {
Individual newIndividual = new Individual();
individuals.add(i, newIndividual);
}
}
}

View File

@@ -0,0 +1,117 @@
package com.baeldung.algorithms.ga.binary;
import lombok.Data;
@Data
public class SimpleGeneticAlgorithm {
private static final double uniformRate = 0.5;
private static final double mutationRate = 0.025;
private static final int tournamentSize = 5;
private static final boolean elitism = true;
private static byte[] solution = new byte[64];
public boolean runAlgorithm(int populationSize, String solution) {
if (solution.length() != SimpleGeneticAlgorithm.solution.length) {
throw new RuntimeException("The solution needs to have " + SimpleGeneticAlgorithm.solution.length + " bytes");
}
setSolution(solution);
Population myPop = new Population(populationSize, true);
int generationCount = 1;
while (myPop.getFittest().getFitness() < getMaxFitness()) {
System.out.println("Generation: " + generationCount + " Correct genes found: " + myPop.getFittest().getFitness());
myPop = evolvePopulation(myPop);
generationCount++;
}
System.out.println("Solution found!");
System.out.println("Generation: " + generationCount);
System.out.println("Genes: ");
System.out.println(myPop.getFittest());
return true;
}
public Population evolvePopulation(Population pop) {
int elitismOffset;
Population newPopulation = new Population(pop.getIndividuals().size(), false);
if (elitism) {
newPopulation.getIndividuals().add(0, pop.getFittest());
elitismOffset = 1;
} else {
elitismOffset = 0;
}
for (int i = elitismOffset; i < pop.getIndividuals().size(); i++) {
Individual indiv1 = tournamentSelection(pop);
Individual indiv2 = tournamentSelection(pop);
Individual newIndiv = crossover(indiv1, indiv2);
newPopulation.getIndividuals().add(i, newIndiv);
}
for (int i = elitismOffset; i < newPopulation.getIndividuals().size(); i++) {
mutate(newPopulation.getIndividual(i));
}
return newPopulation;
}
private Individual crossover(Individual indiv1, Individual indiv2) {
Individual newSol = new Individual();
for (int i = 0; i < newSol.getDefaultGeneLength(); i++) {
if (Math.random() <= uniformRate) {
newSol.setSingleGene(i, indiv1.getSingleGene(i));
} else {
newSol.setSingleGene(i, indiv2.getSingleGene(i));
}
}
return newSol;
}
private void mutate(Individual indiv) {
for (int i = 0; i < indiv.getDefaultGeneLength(); i++) {
if (Math.random() <= mutationRate) {
byte gene = (byte) Math.round(Math.random());
indiv.setSingleGene(i, gene);
}
}
}
private Individual tournamentSelection(Population pop) {
Population tournament = new Population(tournamentSize, false);
for (int i = 0; i < tournamentSize; i++) {
int randomId = (int) (Math.random() * pop.getIndividuals().size());
tournament.getIndividuals().add(i, pop.getIndividual(randomId));
}
Individual fittest = tournament.getFittest();
return fittest;
}
protected static int getFitness(Individual individual) {
int fitness = 0;
for (int i = 0; i < individual.getDefaultGeneLength() && i < solution.length; i++) {
if (individual.getSingleGene(i) == solution[i]) {
fitness++;
}
}
return fitness;
}
protected int getMaxFitness() {
int maxFitness = solution.length;
return maxFitness;
}
protected void setSolution(String newSolution) {
solution = new byte[newSolution.length()];
for (int i = 0; i < newSolution.length(); i++) {
String character = newSolution.substring(i, i + 1);
if (character.contains("0") || character.contains("1")) {
solution[i] = Byte.parseByte(character);
} else {
solution[i] = 0;
}
}
}
}

View File

@@ -0,0 +1,57 @@
package com.baeldung.algorithms.ga.dijkstra;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Set;
public class Dijkstra {
public static Graph calculateShortestPathFromSource(Graph graph, Node source) {
source.setDistance(0);
Set<Node> settledNodes = new HashSet<>();
Set<Node> unsettledNodes = new HashSet<>();
unsettledNodes.add(source);
while (unsettledNodes.size() != 0) {
Node currentNode = getLowestDistanceNode(unsettledNodes);
unsettledNodes.remove(currentNode);
for (Entry<Node, Integer> adjacencyPair : currentNode.getAdjacentNodes().entrySet()) {
Node adjacentNode = adjacencyPair.getKey();
Integer edgeWeigh = adjacencyPair.getValue();
if (!settledNodes.contains(adjacentNode)) {
CalculateMinimumDistance(adjacentNode, edgeWeigh, currentNode);
unsettledNodes.add(adjacentNode);
}
}
settledNodes.add(currentNode);
}
return graph;
}
private static void CalculateMinimumDistance(Node evaluationNode, Integer edgeWeigh, Node sourceNode) {
Integer sourceDistance = sourceNode.getDistance();
if (sourceDistance + edgeWeigh < evaluationNode.getDistance()) {
evaluationNode.setDistance(sourceDistance + edgeWeigh);
LinkedList<Node> shortestPath = new LinkedList<>(sourceNode.getShortestPath());
shortestPath.add(sourceNode);
evaluationNode.setShortestPath(shortestPath);
}
}
private static Node getLowestDistanceNode(Set<Node> unsettledNodes) {
Node lowestDistanceNode = null;
int lowestDistance = Integer.MAX_VALUE;
for (Node node : unsettledNodes) {
int nodeDistance = node.getDistance();
if (nodeDistance < lowestDistance) {
lowestDistance = nodeDistance;
lowestDistanceNode = node;
}
}
return lowestDistanceNode;
}
}

View File

@@ -0,0 +1,21 @@
package com.baeldung.algorithms.ga.dijkstra;
import java.util.HashSet;
import java.util.Set;
public class Graph {
private Set<Node> nodes = new HashSet<>();
public void addNode(Node nodeA) {
nodes.add(nodeA);
}
public Set<Node> getNodes() {
return nodes;
}
public void setNodes(Set<Node> nodes) {
this.nodes = nodes;
}
}

View File

@@ -0,0 +1,58 @@
package com.baeldung.algorithms.ga.dijkstra;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class Node {
private String name;
private LinkedList<Node> shortestPath = new LinkedList<>();
private Integer distance = Integer.MAX_VALUE;
private Map<Node, Integer> adjacentNodes = new HashMap<>();
public Node(String name) {
this.name = name;
}
public void addDestination(Node destination, int distance) {
adjacentNodes.put(destination, distance);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<Node, Integer> getAdjacentNodes() {
return adjacentNodes;
}
public void setAdjacentNodes(Map<Node, Integer> adjacentNodes) {
this.adjacentNodes = adjacentNodes;
}
public Integer getDistance() {
return distance;
}
public void setDistance(Integer distance) {
this.distance = distance;
}
public List<Node> getShortestPath() {
return shortestPath;
}
public void setShortestPath(LinkedList<Node> shortestPath) {
this.shortestPath = shortestPath;
}
}

View File

@@ -0,0 +1,47 @@
package com.baeldung.algorithms.ga.jenetics;
import static org.jenetics.engine.EvolutionResult.toBestPhenotype;
import static org.jenetics.engine.limit.bySteadyFitness;
import java.util.stream.Stream;
import org.jenetics.BitChromosome;
import org.jenetics.BitGene;
import org.jenetics.Mutator;
import org.jenetics.Phenotype;
import org.jenetics.RouletteWheelSelector;
import org.jenetics.SinglePointCrossover;
import org.jenetics.TournamentSelector;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionStatistics;
//The main class.
public class Knapsack {
public static void main(String[] args) {
int nItems = 15;
double ksSize = nItems * 100.0 / 3.0;
KnapsackFF ff = new KnapsackFF(Stream.generate(KnapsackItem::random)
.limit(nItems)
.toArray(KnapsackItem[]::new), ksSize);
Engine<BitGene, Double> engine = Engine.builder(ff, BitChromosome.of(nItems, 0.5))
.populationSize(500)
.survivorsSelector(new TournamentSelector<>(5))
.offspringSelector(new RouletteWheelSelector<>())
.alterers(new Mutator<>(0.115), new SinglePointCrossover<>(0.16))
.build();
EvolutionStatistics<Double, ?> statistics = EvolutionStatistics.ofNumber();
Phenotype<BitGene, Double> best = engine.stream()
.limit(bySteadyFitness(7))
.limit(100)
.peek(statistics)
.collect(toBestPhenotype());
System.out.println(statistics);
System.out.println(best);
}
}

View File

@@ -0,0 +1,25 @@
package com.baeldung.algorithms.ga.jenetics;
import java.util.function.Function;
import org.jenetics.BitChromosome;
import org.jenetics.BitGene;
import org.jenetics.Genotype;
public class KnapsackFF implements Function<Genotype<BitGene>, Double> {
private KnapsackItem[] items;
private double size;
public KnapsackFF(KnapsackItem[] items, double size) {
this.items = items;
this.size = size;
}
@Override
public Double apply(Genotype<BitGene> gt) {
KnapsackItem sum = ((BitChromosome) gt.getChromosome()).ones()
.mapToObj(i -> items[i])
.collect(KnapsackItem.toSum());
return sum.size <= this.size ? sum.value : 0;
}
}

View File

@@ -0,0 +1,34 @@
package com.baeldung.algorithms.ga.jenetics;
import java.util.Random;
import java.util.stream.Collector;
import org.jenetics.util.RandomRegistry;
public class KnapsackItem {
public double size;
public double value;
public KnapsackItem(double size, double value) {
this.size = size;
this.value = value;
}
protected static KnapsackItem random() {
Random r = RandomRegistry.getRandom();
return new KnapsackItem(r.nextDouble() * 100, r.nextDouble() * 100);
}
protected static Collector<KnapsackItem, ?, KnapsackItem> toSum() {
return Collector.of(() -> new double[2], (a, b) -> {
a[0] += b.size;
a[1] += b.value;
} , (a, b) -> {
a[0] += b[0];
a[1] += b[1];
return a;
} , r -> new KnapsackItem(r[0], r[1]));
}
}

View File

@@ -0,0 +1,33 @@
package com.baeldung.algorithms.ga.jenetics;
import org.jenetics.BitChromosome;
import org.jenetics.BitGene;
import org.jenetics.Genotype;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionResult;
import org.jenetics.util.Factory;
public class SimpleGeneticAlgorithm {
private static Integer eval(Genotype<BitGene> gt) {
return gt.getChromosome()
.as(BitChromosome.class)
.bitCount();
}
public static void main(String[] args) {
Factory<Genotype<BitGene>> gtf = Genotype.of(BitChromosome.of(10, 0.5));
System.out.println("Before the evolution:\n" + gtf);
Engine<BitGene, Integer> engine = Engine.builder(SimpleGeneticAlgorithm::eval, gtf)
.build();
Genotype<BitGene> result = engine.stream()
.limit(500)
.collect(EvolutionResult.toBestGenotype());
System.out.println("After the evolution:\n" + result);
}
}

View File

@@ -0,0 +1,86 @@
package com.baeldung.algorithms.ga.jenetics;
import static java.util.Objects.requireNonNull;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.jenetics.BitGene;
import org.jenetics.engine.Codec;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionResult;
import org.jenetics.engine.Problem;
import org.jenetics.engine.codecs;
import org.jenetics.util.ISeq;
public class SpringsteenProblem implements Problem<ISeq<SpringsteenRecord>, BitGene, Double> {
private ISeq<SpringsteenRecord> records;
private double maxPricePerUniqueSong;
public SpringsteenProblem(ISeq<SpringsteenRecord> records, double maxPricePerUniqueSong) {
this.records = requireNonNull(records);
this.maxPricePerUniqueSong = maxPricePerUniqueSong;
}
@Override
public Function<ISeq<SpringsteenRecord>, Double> fitness() {
return SpringsteenRecords -> {
double cost = SpringsteenRecords.stream()
.mapToDouble(r -> r.price)
.sum();
int uniqueSongCount = SpringsteenRecords.stream()
.flatMap(r -> r.songs.stream())
.collect(Collectors.toSet())
.size();
double pricePerUniqueSong = cost / uniqueSongCount;
return pricePerUniqueSong <= maxPricePerUniqueSong ? uniqueSongCount : 0.0;
};
}
@Override
public Codec<ISeq<SpringsteenRecord>, BitGene> codec() {
return codecs.ofSubSet(records);
}
public static void main(String[] args) {
double maxPricePerUniqueSong = 2.5;
SpringsteenProblem springsteen = new SpringsteenProblem(
ISeq.of(new SpringsteenRecord("SpringsteenRecord1", 25, ISeq.of("Song1", "Song2", "Song3", "Song4", "Song5", "Song6")), new SpringsteenRecord("SpringsteenRecord2", 15, ISeq.of("Song2", "Song3", "Song4", "Song5", "Song6", "Song7")),
new SpringsteenRecord("SpringsteenRecord3", 35, ISeq.of("Song5", "Song6", "Song7", "Song8", "Song9", "Song10")), new SpringsteenRecord("SpringsteenRecord4", 17, ISeq.of("Song9", "Song10", "Song12", "Song4", "Song13", "Song14")),
new SpringsteenRecord("SpringsteenRecord5", 29, ISeq.of("Song1", "Song2", "Song13", "Song14", "Song15", "Song16")), new SpringsteenRecord("SpringsteenRecord6", 5, ISeq.of("Song18", "Song20", "Song30", "Song40"))),
maxPricePerUniqueSong);
Engine<BitGene, Double> engine = Engine.builder(springsteen)
.build();
ISeq<SpringsteenRecord> result = springsteen.codec()
.decoder()
.apply(engine.stream()
.limit(10)
.collect(EvolutionResult.toBestGenotype()));
double cost = result.stream()
.mapToDouble(r -> r.price)
.sum();
int uniqueSongCount = result.stream()
.flatMap(r -> r.songs.stream())
.collect(Collectors.toSet())
.size();
double pricePerUniqueSong = cost / uniqueSongCount;
System.out.println("Overall cost: " + cost);
System.out.println("Unique songs: " + uniqueSongCount);
System.out.println("Cost per song: " + pricePerUniqueSong);
System.out.println("Records: " + result.map(r -> r.name)
.toString(", "));
}
}

View File

@@ -0,0 +1,24 @@
package com.baeldung.algorithms.ga.jenetics;
import static java.util.Objects.requireNonNull;
import org.jenetics.util.ISeq;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class SpringsteenRecord {
String name;
double price;
ISeq<String> songs;
public SpringsteenRecord(String name, double price, ISeq<String> songs) {
this.name = requireNonNull(name);
this.price = price;
this.songs = requireNonNull(songs);
}
}

View File

@@ -0,0 +1,66 @@
package com.baeldung.algorithms.ga.jenetics;
import static java.util.Objects.requireNonNull;
import java.util.Random;
import java.util.function.Function;
import org.jenetics.EnumGene;
import org.jenetics.Mutator;
import org.jenetics.PartiallyMatchedCrossover;
import org.jenetics.Phenotype;
import org.jenetics.engine.Codec;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionResult;
import org.jenetics.engine.Problem;
import org.jenetics.engine.codecs;
import org.jenetics.engine.limit;
import org.jenetics.util.ISeq;
import org.jenetics.util.LCG64ShiftRandom;
public class SubsetSum implements Problem<ISeq<Integer>, EnumGene<Integer>, Integer> {
private ISeq<Integer> basicSet;
private int size;
public SubsetSum(ISeq<Integer> basicSet, int size) {
this.basicSet = requireNonNull(basicSet);
this.size = size;
}
@Override
public Function<ISeq<Integer>, Integer> fitness() {
return subset -> Math.abs(subset.stream()
.mapToInt(Integer::intValue)
.sum());
}
@Override
public Codec<ISeq<Integer>, EnumGene<Integer>> codec() {
return codecs.ofSubSet(basicSet, size);
}
public static SubsetSum of(int n, int k, Random random) {
return new SubsetSum(random.doubles()
.limit(n)
.mapToObj(d -> (int) ((d - 0.5) * n))
.collect(ISeq.toISeq()), k);
}
public static void main(String[] args) {
SubsetSum problem = of(500, 15, new LCG64ShiftRandom(101010));
Engine<EnumGene<Integer>, Integer> engine = Engine.builder(problem)
.minimizing()
.maximalPhenotypeAge(5)
.alterers(new PartiallyMatchedCrossover<>(0.4), new Mutator<>(0.3))
.build();
Phenotype<EnumGene<Integer>, Integer> result = engine.stream()
.limit(limit.bySteadyFitness(55))
.collect(EvolutionResult.toBestPhenotype());
System.out.print(result);
}
}

View File

@@ -0,0 +1,67 @@
package com.baeldung.algorithms.ga.jenetics;
import static java.lang.Math.PI;
import static java.lang.Math.abs;
import static java.lang.Math.sin;
import static org.jenetics.engine.EvolutionResult.toBestPhenotype;
import static org.jenetics.engine.limit.bySteadyFitness;
import java.util.stream.IntStream;
import org.jenetics.EnumGene;
import org.jenetics.Optimize;
import org.jenetics.PartiallyMatchedCrossover;
import org.jenetics.Phenotype;
import org.jenetics.SwapMutator;
import org.jenetics.engine.Engine;
import org.jenetics.engine.EvolutionStatistics;
import org.jenetics.engine.codecs;
public class TravelingSalesman {
private static final int STOPS = 50;
private static final double[][] ADJACENCE = matrix(STOPS);
private static double[][] matrix(int stops) {
final double radius = 100.0;
double[][] matrix = new double[stops][stops];
for (int i = 0; i < stops; ++i) {
for (int j = 0; j < stops; ++j) {
matrix[i][j] = chord(stops, abs(i - j), radius);
}
}
return matrix;
}
private static double chord(int stops, int i, double r) {
return 2.0 * r * abs(sin(PI * i / stops));
}
private static double dist(final int[] path) {
return IntStream.range(0, STOPS)
.mapToDouble(i -> ADJACENCE[path[i]][path[(i + 1) % STOPS]])
.sum();
}
public static void main(String[] args) {
final Engine<EnumGene<Integer>, Double> engine = Engine.builder(TravelingSalesman::dist, codecs.ofPermutation(STOPS))
.optimize(Optimize.MINIMUM)
.maximalPhenotypeAge(11)
.populationSize(500)
.alterers(new SwapMutator<>(0.2), new PartiallyMatchedCrossover<>(0.35))
.build();
final EvolutionStatistics<Double, ?> statistics = EvolutionStatistics.ofNumber();
final Phenotype<EnumGene<Integer>, Double> best = engine.stream()
.limit(bySteadyFitness(15))
.limit(250)
.peek(statistics)
.collect(toBestPhenotype());
System.out.println(statistics);
System.out.println(best);
}
}

View File

@@ -0,0 +1,35 @@
package com.baeldung.algorithms.slope_one;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.Data;
@Data
public class InputData {
protected static List<Item> items = Arrays.asList(new Item("Candy"), new Item("Drink"), new Item("Soda"), new Item("Popcorn"), new Item("Snacks"));
public static Map<User, HashMap<Item, Double>> initializeData(int numberOfUsers) {
Map<User, HashMap<Item, Double>> data = new HashMap<>();
HashMap<Item, Double> newUser;
Set<Item> newRecommendationSet;
for (int i = 0; i < numberOfUsers; i++) {
newUser = new HashMap<Item, Double>();
newRecommendationSet = new HashSet<>();
for (int j = 0; j < 3; j++) {
newRecommendationSet.add(items.get((int) (Math.random() * 5)));
}
for (Item item : newRecommendationSet) {
newUser.put(item, Math.random());
}
data.put(new User("User " + i), newUser);
}
return data;
}
}

View File

@@ -0,0 +1,13 @@
package com.baeldung.algorithms.slope_one;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Item {
private String itemName;
}

View File

@@ -0,0 +1,124 @@
package com.baeldung.algorithms.slope_one;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* Slope One algorithm implementation
*/
public class SlopeOne {
private static Map<Item, Map<Item, Double>> diff = new HashMap<>();
private static Map<Item, Map<Item, Integer>> freq = new HashMap<>();
private static Map<User, HashMap<Item, Double>> inputData;
private static Map<User, HashMap<Item, Double>> outputData = new HashMap<>();
public static void slopeOne(int numberOfUsers) {
inputData = InputData.initializeData(numberOfUsers);
System.out.println("Slope One - Before the Prediction\n");
buildDifferencesMatrix(inputData);
System.out.println("\nSlope One - With Predictions\n");
predict(inputData);
}
/**
* Based on the available data, calculate the relationships between the
* items and number of occurences
*
* @param data
* existing user data and their items' ratings
*/
private static void buildDifferencesMatrix(Map<User, HashMap<Item, Double>> data) {
for (HashMap<Item, Double> user : data.values()) {
for (Entry<Item, Double> e : user.entrySet()) {
if (!diff.containsKey(e.getKey())) {
diff.put(e.getKey(), new HashMap<Item, Double>());
freq.put(e.getKey(), new HashMap<Item, Integer>());
}
for (Entry<Item, Double> e2 : user.entrySet()) {
int oldCount = 0;
if (freq.get(e.getKey()).containsKey(e2.getKey())) {
oldCount = freq.get(e.getKey()).get(e2.getKey()).intValue();
}
double oldDiff = 0.0;
if (diff.get(e.getKey()).containsKey(e2.getKey())) {
oldDiff = diff.get(e.getKey()).get(e2.getKey()).doubleValue();
}
double observedDiff = e.getValue() - e2.getValue();
freq.get(e.getKey()).put(e2.getKey(), oldCount + 1);
diff.get(e.getKey()).put(e2.getKey(), oldDiff + observedDiff);
}
}
}
for (Item j : diff.keySet()) {
for (Item i : diff.get(j).keySet()) {
double oldValue = diff.get(j).get(i).doubleValue();
int count = freq.get(j).get(i).intValue();
diff.get(j).put(i, oldValue / count);
}
}
printData(data);
}
/**
* Based on existing data predict all missing ratings. If prediction is not
* possible, the value will be equal to -1
*
* @param data
* existing user data and their items' ratings
*/
private static void predict(Map<User, HashMap<Item, Double>> data) {
HashMap<Item, Double> uPred = new HashMap<Item, Double>();
HashMap<Item, Integer> uFreq = new HashMap<Item, Integer>();
for (Item j : diff.keySet()) {
uFreq.put(j, 0);
uPred.put(j, 0.0);
}
for (Entry<User, HashMap<Item, Double>> e : data.entrySet()) {
for (Item j : e.getValue().keySet()) {
for (Item k : diff.keySet()) {
try {
double predictedValue = diff.get(k).get(j).doubleValue() + e.getValue().get(j).doubleValue();
double finalValue = predictedValue * freq.get(k).get(j).intValue();
uPred.put(k, uPred.get(k) + finalValue);
uFreq.put(k, uFreq.get(k) + freq.get(k).get(j).intValue());
} catch (NullPointerException e1) {
}
}
}
HashMap<Item, Double> clean = new HashMap<Item, Double>();
for (Item j : uPred.keySet()) {
if (uFreq.get(j) > 0) {
clean.put(j, uPred.get(j).doubleValue() / uFreq.get(j).intValue());
}
}
for (Item j : InputData.items) {
if (e.getValue().containsKey(j)) {
clean.put(j, e.getValue().get(j));
} else {
clean.put(j, -1.0);
}
}
outputData.put(e.getKey(), clean);
}
printData(outputData);
}
private static void printData(Map<User, HashMap<Item, Double>> data) {
for (User user : data.keySet()) {
System.out.println(user.getUsername() + ":");
print(data.get(user));
}
}
private static void print(HashMap<Item, Double> hashMap) {
NumberFormat formatter = new DecimalFormat("#0.000");
for (Item j : hashMap.keySet()) {
System.out.println(" " + j.getItemName() + " --> " + formatter.format(hashMap.get(j).doubleValue()));
}
}
}

View File

@@ -0,0 +1,14 @@
package com.baeldung.algorithms.slope_one;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String username;
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@@ -0,0 +1,22 @@
package com.baeldung.algorithms;
import org.junit.Assert;
import org.junit.Test;
import com.baeldung.algorithms.ga.ant_colony.AntColonyOptimization;
public class AntColonyOptimizationLongRunningUnitTest {
@Test
public void testGenerateRandomMatrix() {
AntColonyOptimization antTSP = new AntColonyOptimization(5);
Assert.assertNotNull(antTSP.generateRandomMatrix(5));
}
@Test
public void testStartAntOptimization() {
AntColonyOptimization antTSP = new AntColonyOptimization(5);
Assert.assertNotNull(antTSP.solve());
}
}

View File

@@ -0,0 +1,16 @@
package com.baeldung.algorithms;
import org.junit.Assert;
import org.junit.Test;
import com.baeldung.algorithms.ga.binary.SimpleGeneticAlgorithm;
public class BinaryGeneticAlgorithmLongRunningUnitTest {
@Test
public void testGA() {
SimpleGeneticAlgorithm ga = new SimpleGeneticAlgorithm();
Assert.assertTrue(ga.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111"));
}
}

View File

@@ -0,0 +1,86 @@
package com.baeldung.algorithms;
import org.junit.Test;
import com.baeldung.algorithms.ga.dijkstra.Dijkstra;
import com.baeldung.algorithms.ga.dijkstra.Graph;
import com.baeldung.algorithms.ga.dijkstra.Node;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertTrue;
public class DijkstraAlgorithmLongRunningUnitTest {
@Test
public void whenSPPSolved_thenCorrect() {
Node nodeA = new Node("A");
Node nodeB = new Node("B");
Node nodeC = new Node("C");
Node nodeD = new Node("D");
Node nodeE = new Node("E");
Node nodeF = new Node("F");
nodeA.addDestination(nodeB, 10);
nodeA.addDestination(nodeC, 15);
nodeB.addDestination(nodeD, 12);
nodeB.addDestination(nodeF, 15);
nodeC.addDestination(nodeE, 10);
nodeD.addDestination(nodeE, 2);
nodeD.addDestination(nodeF, 1);
nodeF.addDestination(nodeE, 5);
Graph graph = new Graph();
graph.addNode(nodeA);
graph.addNode(nodeB);
graph.addNode(nodeC);
graph.addNode(nodeD);
graph.addNode(nodeE);
graph.addNode(nodeF);
graph = Dijkstra.calculateShortestPathFromSource(graph, nodeA);
List<Node> shortestPathForNodeB = Arrays.asList(nodeA);
List<Node> shortestPathForNodeC = Arrays.asList(nodeA);
List<Node> shortestPathForNodeD = Arrays.asList(nodeA, nodeB);
List<Node> shortestPathForNodeE = Arrays.asList(nodeA, nodeB, nodeD);
List<Node> shortestPathForNodeF = Arrays.asList(nodeA, nodeB, nodeD);
for (Node node : graph.getNodes()) {
switch (node.getName()) {
case "B":
assertTrue(node
.getShortestPath()
.equals(shortestPathForNodeB));
break;
case "C":
assertTrue(node
.getShortestPath()
.equals(shortestPathForNodeC));
break;
case "D":
assertTrue(node
.getShortestPath()
.equals(shortestPathForNodeD));
break;
case "E":
assertTrue(node
.getShortestPath()
.equals(shortestPathForNodeE));
break;
case "F":
assertTrue(node
.getShortestPath()
.equals(shortestPathForNodeF));
break;
}
}
}
}

View File

@@ -0,0 +1,15 @@
package com.baeldung.algorithms;
import org.junit.Assert;
import org.junit.Test;
import com.baeldung.algorithms.ga.annealing.SimulatedAnnealing;
public class SimulatedAnnealingLongRunningUnitTest {
@Test
public void testSimulateAnnealing() {
Assert.assertTrue(SimulatedAnnealing.simulateAnnealing(10, 1000, 0.9) > 0);
}
}