Merge remote-tracking branch 'Baeldung/master' into active_mq
# Conflicts: # .gitignore # LICENSE # README.md # core-java-modules/README.md # core-java-modules/core-java-11/README.md # core-java-modules/core-java-11/pom.xml # core-java-modules/core-java-8/README.md # core-java-modules/core-java-8/pom.xml # core-java-modules/core-java-8/src/main/resources/logback.xml # core-java-modules/core-java-annotations/README.md # core-java-modules/core-java-annotations/pom.xml # core-java-modules/core-java-collections-2/README.md # core-java-modules/core-java-collections-2/pom.xml # core-java-modules/core-java-collections-3/README.md # core-java-modules/core-java-collections-3/pom.xml # core-java-modules/core-java-collections-conversions-2/README.md # core-java-modules/core-java-collections-conversions-2/pom.xml # core-java-modules/core-java-collections-conversions/README.md # core-java-modules/core-java-collections-conversions/pom.xml # core-java-modules/core-java-collections-list/README.md # core-java-modules/core-java-collections-list/pom.xml # core-java-modules/core-java-collections/pom.xml # core-java-modules/core-java-datetime-conversion/README.md # core-java-modules/core-java-datetime-conversion/pom.xml # core-java-modules/core-java-datetime-conversion/src/test/java/com/baeldung/datetime/ConvertInstantToTimestampUnitTest.java # core-java-modules/core-java-io-2/pom.xml # core-java-modules/core-java-io/README.md # core-java-modules/core-java-io/pom.xml # core-java-modules/core-java-io/src/test/resources/fileTest.txt # core-java-modules/core-java-io/src/test/resources/sampleTextFile.txt # core-java-modules/core-java-lambdas/README.md # core-java-modules/core-java-lambdas/pom.xml # core-java-modules/core-java-serialization/pom.xml # core-java-modules/core-java-streams/README.md # core-java-modules/core-java-streams/pom.xml # core-java-modules/core-java-strings/README.md # core-java-modules/core-java-strings/pom.xml # core-java-modules/core-java-strings/src/test/resources/stringtoolong.txt # core-java-modules/core-java-uuid/README.md # core-java-modules/core-java-uuid/pom.xml # core-java-modules/pom.xml # image-processing/README.md # image-processing/pom.xml # image-processing/src/main/java/com/baeldung/imageprocessing/addingtext/AddText.java # image-processing/src/main/java/com/baeldung/imageprocessing/opencv/CameraStream.java # jackson-modules/jackson-annotations/README.md # jackson-modules/jackson-annotations/pom.xml # jackson-modules/jackson-conversions-2/README.md # jackson-modules/jackson-conversions-2/pom.xml # jackson-modules/jackson-conversions/README.md # jackson-modules/jackson-conversions/pom.xml # jackson-modules/jackson-custom-conversions/README.md # jackson-modules/jackson-custom-conversions/pom.xml # jackson-modules/jackson-custom-conversions/src/test/java/com/baeldung/defaultserializercustomserializer/CallingDefaultSerializerUnitTest.java # jackson-modules/jackson-custom-conversions/src/test/java/com/baeldung/deserialization/CustomDeserializationUnitTest.java # jackson-modules/jackson-exceptions/README.md # jackson-modules/jackson-exceptions/pom.xml # jackson-modules/jackson-exceptions/src/test/java/com/baeldung/exceptions/JacksonExceptionsUnitTest.java # jackson-modules/jackson-exceptions/src/test/java/com/baeldung/mappingexception/JacksonMappingExceptionUnitTest.java # jackson-modules/pom.xml # parent-boot-1/pom.xml # parent-boot-2/pom.xml # parent-boot-3/pom.xml # patterns-modules/design-patterns-architectural/pom.xml # patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/repositoryvsdaopattern/UserDaoImpl.java # patterns-modules/design-patterns-behavioral-2/README.md # patterns-modules/design-patterns-behavioral-2/pom.xml # patterns-modules/design-patterns-creational-2/README.md # patterns-modules/design-patterns-creational-2/pom.xml # patterns-modules/design-patterns-singleton/README.md # patterns-modules/design-patterns-structural/src/main/resources/log4jstructuraldp.properties # patterns-modules/enterprise-patterns/pom.xml # patterns-modules/intercepting-filter/pom.xml # patterns-modules/pom.xml # persistence-modules/activejdbc/pom.xml # persistence-modules/hibernate5/README.md # persistence-modules/hibernate5/pom.xml # persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/interceptors/CustomInterceptor.java # persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/interceptors/entity/User.java # persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/namingstrategy/CustomPhysicalNamingStrategy.java # persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/persistjson/Customer.java # persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/persistjson/HashMapConverter.java # persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/OrderEntryIdClass.java # persistence-modules/hibernate5/src/main/java/com/baeldung/hibernate/pojo/OrderEntryPK.java # persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/IdentifiersIntegrationTest.java # persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/bootstrap/BootstrapAPIIntegrationTest.java # persistence-modules/hibernate5/src/test/java/com/baeldung/hibernate/proxy/HibernateProxyUnitTest.java # persistence-modules/hibernate5/src/test/resources/hibernate-interceptors.properties # persistence-modules/hibernate5/src/test/resources/hibernate-lifecycle.properties # persistence-modules/hibernate5/src/test/resources/hibernate-namingstrategy.properties # persistence-modules/hibernate5/src/test/resources/hibernate-persistjson.properties # persistence-modules/hibernate5/src/test/resources/hibernate.properties # persistence-modules/pom.xml # persistence-modules/spring-data-jpa-crud/pom.xml # persistence-modules/spring-data-jpa-crud/src/main/java/com/baeldung/repository/FruitRepository.java # persistence-modules/spring-data-jpa-repo-2/README.md # persistence-modules/spring-data-jpa-repo-2/pom.xml # persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/model/User.java # persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/customrepository/repository/CustomUserRepositoryImpl.java # persistence-modules/spring-data-jpa-repo-2/src/main/java/com/baeldung/spring/data/persistence/saveperformance/Book.java # persistence-modules/spring-data-jpa-repo-2/src/main/resources/application.properties # persistence-modules/spring-data-mongodb-reactive/pom.xml # persistence-modules/spring-data-redis/README.md # persistence-modules/spring-data-redis/pom.xml # persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/reactive/redis/config/RedisConfig.java # persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java # persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java # persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/queue/RedisMessageSubscriber.java # persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisKeyCommandsManualTest.java # persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisTemplateListOpsManualTest.java # persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/reactive/redis/template/RedisTemplateValueOpsManualTest.java # persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryManualTest.java # pom.xml # testing-modules/assertion-libraries/README.md # testing-modules/assertion-libraries/pom.xml # testing-modules/junit-5-basics/README.md # testing-modules/junit-5-basics/pom.xml # testing-modules/mockito-2/src/main/java/com/baeldung/nullmatcher/Helper.java # testing-modules/mockito-2/src/main/java/com/baeldung/nullmatcher/Main.java # testing-modules/mockito-2/src/main/java/com/baeldung/wantedbutnotinvocked/Helper.java # testing-modules/mockito-2/src/main/java/com/baeldung/wantedbutnotinvocked/Main.java # testing-modules/mockito-2/src/test/java/com/baeldung/nullmatcher/MainUnitTest.java # testing-modules/mockito-2/src/test/java/com/baeldung/wantedbutnotinvocked/MainUnitTest.java # testing-modules/pom.xml # testing-modules/spring-mockito/pom.xml # web-modules/dropwizard/pom.xml # web-modules/jakarta-ee/README.md # web-modules/jakarta-ee/pom.xml # web-modules/jakarta-ee/src/test/java/com/baeldung/eclipse/krazo/UserControllerUnitTest.java # web-modules/java-lite/pom.xml # web-modules/javax-servlets-2/README.md # web-modules/javax-servlets-2/pom.xml # web-modules/javax-servlets/pom.xml # web-modules/jee-7/pom.xml # web-modules/jooby/pom.xml # web-modules/ninja/pom.xml # web-modules/pom.xml # web-modules/ratpack/pom.xml # web-modules/resteasy/pom.xml # web-modules/restx/pom.xml # web-modules/spark-java/pom.xml # web-modules/vraptor/pom.xml # xml/README.md # xml/pom.xml # xml/src/main/resources/customer-binding.xml # xml/src/main/resources/sax/baeldung.xml # xml/src/test/resources/example_default_parser.xml # xml/src/test/resources/example_dom4j.xml # xml/src/test/resources/example_jaxb.xml # xml/src/test/resources/example_jaxen.xml # xml/src/test/resources/example_jdom.xml # xml/src/test/resources/example_stax.xml # xml/src/test/resources/sax/baeldung.xml # xml/src/test/resources/xml/websites.xml # xml/src/test/resources/xml/xee_attribute.xml
This commit is contained in:
commit
a51b7b55d9
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
name: Issue Report
|
||||
about: Report an issue to help us improve
|
||||
title: '[ISSUE] '
|
||||
---
|
||||
|
||||
**Article and Module Links**
|
||||
A link to the affected article and the affected module. You can find the link to the module in the Conclusion section in the "on Github" standard phase.
|
||||
|
||||
**Describe the Issue**
|
||||
A clear and concise description of what the issue is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected Behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Environment (please complete the following information):**
|
||||
- OS: [e.g. Windows]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional Context**
|
||||
Add any other context about the issue here.
|
|
@ -0,0 +1,11 @@
|
|||
# Contributing to Baeldung Tutorials
|
||||
First off, thank you for considering contributing to Baeldung Tutorials.
|
||||
|
||||
## Reporting Issues
|
||||
Before you submit an issue, please review the guidelines below:
|
||||
|
||||
1. **No Custom Modifications:** If your issue arises from any custom modifications you've made to the code in the repository, we won't be able to assist. We can only help if the issue is reproducible with the untouched codebase from this repo. If you're working with a modified version, consider asking for help on StackOverflow or other relevant forums.
|
||||
2. **Use a clear and descriptive title** for the issue to identify the problem.
|
||||
3. **Include a link to the article** you're having issues with.
|
||||
4. **Describe the exact steps which reproduce the problem** in as many details as possible.
|
||||
5. **Additional Details:** Offer any other context or descriptions that could be useful. Screenshots, error messages, copy/pasteable snippets, or logs can be immensely helpful.
|
|
@ -0,0 +1,3 @@
|
|||
## Akka
|
||||
|
||||
This module contains modules about Akka.
|
|
@ -0,0 +1,7 @@
|
|||
## Akka HTTP
|
||||
|
||||
This module contains articles about Akka actors.
|
||||
|
||||
### Relevant articles:
|
||||
|
||||
- [Introduction to Akka Actors in Java](https://www.baeldung.com/akka-actors-java)
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>akka-actors</artifactId>
|
||||
<name>akka-actors</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>akka-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor_${scala.version}</artifactId>
|
||||
<version>${typesafe-akka.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-testkit_${scala.version}</artifactId>
|
||||
<version>${typesafe-akka.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<typesafe-akka.version>2.5.11</typesafe-akka.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,32 @@
|
|||
package com.baeldung.akkaactors;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.Props;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
public class FirstActor extends AbstractActor {
|
||||
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
public static Props props() {
|
||||
return Props.create(FirstActor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
log.info("Actor started");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postStop() {
|
||||
log.info("Actor stopped");
|
||||
}
|
||||
|
||||
// Messages will not be handled
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.akkaactors;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
public class MyActor extends AbstractActor {
|
||||
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
@Override
|
||||
public void postStop() {
|
||||
log.info("Stopping actor {}", this);
|
||||
}
|
||||
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.matchEquals("printit", p -> {
|
||||
System.out.println("The address of this actor is: " + getSelf());
|
||||
getSender().tell("Got Message", getSelf());
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.baeldung.akkaactors;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.Props;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
public class PrinterActor extends AbstractActor {
|
||||
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
public static Props props(String text) {
|
||||
return Props.create(PrinterActor.class, text);
|
||||
}
|
||||
|
||||
public static final class PrintFinalResult {
|
||||
Integer totalNumberOfWords;
|
||||
|
||||
public PrintFinalResult(Integer totalNumberOfWords) {
|
||||
this.totalNumberOfWords = totalNumberOfWords;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
log.info("Starting PrinterActor {}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postStop() {
|
||||
log.info("Stopping PrinterActor {}", this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(PrinterActor.PrintFinalResult.class,
|
||||
r -> {
|
||||
log.info("Received PrintFinalResult message from " + getSender());
|
||||
log.info("The text has a total number of {} words", r.totalNumberOfWords);
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package com.baeldung.akkaactors;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.Props;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static akka.pattern.PatternsCS.ask;
|
||||
|
||||
public class ReadingActor extends AbstractActor {
|
||||
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
private String text;
|
||||
|
||||
public ReadingActor(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public static Props props(String text) {
|
||||
return Props.create(ReadingActor.class, text);
|
||||
}
|
||||
|
||||
public static final class ReadLines {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
log.info("Starting ReadingActor {}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postStop() {
|
||||
log.info("Stopping ReadingActor {}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(ReadLines.class, r -> {
|
||||
|
||||
log.info("Received ReadLines message from " + getSender());
|
||||
|
||||
String[] lines = text.split("\n");
|
||||
List<CompletableFuture> futures = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
String line = lines[i];
|
||||
ActorRef wordCounterActorRef = getContext().actorOf(Props.create(WordCounterActor.class), "word-counter-" + i);
|
||||
|
||||
CompletableFuture<Object> future =
|
||||
ask(wordCounterActorRef, new WordCounterActor.CountWords(line), 1000).toCompletableFuture();
|
||||
futures.add(future);
|
||||
}
|
||||
|
||||
Integer totalNumberOfWords = futures.stream()
|
||||
.map(CompletableFuture::join)
|
||||
.mapToInt(n -> (Integer) n)
|
||||
.sum();
|
||||
|
||||
ActorRef printerActorRef = getContext().actorOf(Props.create(PrinterActor.class), "Printer-Actor");
|
||||
printerActorRef.forward(new PrinterActor.PrintFinalResult(totalNumberOfWords), getContext());
|
||||
// printerActorRef.tell(new PrinterActor.PrintFinalResult(totalNumberOfWords), getSelf());
|
||||
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.baeldung.akkaactors;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
|
||||
public class WordCounterActor extends AbstractActor {
|
||||
|
||||
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
|
||||
|
||||
public static final class CountWords {
|
||||
String line;
|
||||
|
||||
public CountWords(String line) {
|
||||
this.line = line;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preStart() {
|
||||
log.info("Starting WordCounterActor {}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(CountWords.class, r -> {
|
||||
try {
|
||||
log.info("Received CountWords message from " + getSender());
|
||||
int numberOfWords = countWordsFromLine(r.line);
|
||||
getSender().tell(numberOfWords, getSelf());
|
||||
} catch (Exception ex) {
|
||||
getSender().tell(new akka.actor.Status.Failure(ex), getSelf());
|
||||
throw ex;
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private int countWordsFromLine(String line) throws Exception {
|
||||
|
||||
if (line == null) {
|
||||
throw new IllegalArgumentException("The text to process can't be null!");
|
||||
}
|
||||
|
||||
int numberOfWords = 0;
|
||||
String[] words = line.split(" ");
|
||||
for (String possibleWord : words) {
|
||||
if (possibleWord.trim().length() > 0) {
|
||||
numberOfWords++;
|
||||
}
|
||||
}
|
||||
return numberOfWords;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package com.baeldung.akkaactors;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.testkit.TestKit;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import scala.concurrent.duration.Duration;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static akka.pattern.PatternsCS.ask;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class AkkaActorsUnitTest {
|
||||
|
||||
private static ActorSystem system = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
system = ActorSystem.create("test-system");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void teardown() {
|
||||
TestKit.shutdownActorSystem(system, Duration.apply(1000, TimeUnit.MILLISECONDS), true);
|
||||
system = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAnActor_sendHimAMessageUsingTell() {
|
||||
|
||||
final TestKit probe = new TestKit(system);
|
||||
ActorRef myActorRef = probe.childActorOf(Props.create(MyActor.class));
|
||||
myActorRef.tell("printit", probe.testActor());
|
||||
|
||||
probe.expectMsg("Got Message");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAnActor_sendHimAMessageUsingAsk() throws ExecutionException, InterruptedException {
|
||||
|
||||
final TestKit probe = new TestKit(system);
|
||||
ActorRef wordCounterActorRef = probe.childActorOf(Props.create(WordCounterActor.class));
|
||||
|
||||
CompletableFuture<Object> future =
|
||||
ask(wordCounterActorRef, new WordCounterActor.CountWords("this is a text"), 1000).toCompletableFuture();
|
||||
|
||||
Integer numberOfWords = (Integer) future.get();
|
||||
assertTrue("The actor should count 4 words", 4 == numberOfWords);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAnActor_whenTheMessageIsNull_respondWithException() {
|
||||
final TestKit probe = new TestKit(system);
|
||||
ActorRef wordCounterActorRef = probe.childActorOf(Props.create(WordCounterActor.class));
|
||||
|
||||
CompletableFuture<Object> future =
|
||||
ask(wordCounterActorRef, new WordCounterActor.CountWords(null), 1000).toCompletableFuture();
|
||||
|
||||
try {
|
||||
future.get(1000, TimeUnit.MILLISECONDS);
|
||||
} catch (ExecutionException e) {
|
||||
assertTrue("Invalid error message", e.getMessage().contains("The text to process can't be null!"));
|
||||
} catch (InterruptedException | TimeoutException e) {
|
||||
fail("Actor should respond with an exception instead of timing out !");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAnAkkaSystem_countTheWordsInAText() {
|
||||
ActorSystem system = ActorSystem.create("test-system");
|
||||
ActorRef myActorRef = system.actorOf(Props.create(MyActor.class), "my-actor");
|
||||
myActorRef.tell("printit", null);
|
||||
// system.stop(myActorRef);
|
||||
// myActorRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
|
||||
// myActorRef.tell(Kill.getInstance(), ActorRef.noSender());
|
||||
|
||||
ActorRef readingActorRef = system.actorOf(ReadingActor.props(TEXT), "readingActor");
|
||||
readingActorRef.tell(new ReadingActor.ReadLines(), ActorRef.noSender()); //ActorRef.noSender() means the sender ref is akka://test-system/deadLetters
|
||||
|
||||
// Future<Terminated> terminateResponse = system.terminate();
|
||||
}
|
||||
|
||||
private static String TEXT = "Lorem Ipsum is simply dummy text\n" +
|
||||
"of the printing and typesetting industry.\n" +
|
||||
"Lorem Ipsum has been the industry's standard dummy text\n" +
|
||||
"ever since the 1500s, when an unknown printer took a galley\n" +
|
||||
"of type and scrambled it to make a type specimen book.\n" +
|
||||
" It has survived not only five centuries, but also the leap\n" +
|
||||
"into electronic typesetting, remaining essentially unchanged.\n" +
|
||||
" It was popularised in the 1960s with the release of Letraset\n" +
|
||||
" sheets containing Lorem Ipsum passages, and more recently with\n" +
|
||||
" desktop publishing software like Aldus PageMaker including\n" +
|
||||
"versions of Lorem Ipsum.";
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
## Akka HTTP
|
||||
|
||||
This module contains articles about Akka HTTP.
|
||||
|
||||
### Relevant articles:
|
||||
|
||||
- [Introduction to Akka HTTP](https://www.baeldung.com/akka-http)
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>akka-http</artifactId>
|
||||
<name>akka-http</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>akka-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-http_${scala.version}</artifactId>
|
||||
<version>${akka.http.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-stream_${scala.version}</artifactId>
|
||||
<version>${akka.stream.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-http-jackson_${scala.version}</artifactId>
|
||||
<version>${akka.http.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-http-testkit_${scala.version}</artifactId>
|
||||
<version>${akka.http.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<akka.http.version>10.0.11</akka.http.version>
|
||||
<akka.stream.version>2.5.11</akka.stream.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
public class User {
|
||||
|
||||
private final Long id;
|
||||
|
||||
private final String name;
|
||||
|
||||
public User() {
|
||||
this.name = "";
|
||||
this.id = null;
|
||||
}
|
||||
|
||||
public User(Long id, String name) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.actor.Props;
|
||||
import akka.japi.pf.FI;
|
||||
import com.baeldung.akkahttp.UserMessages.ActionPerformed;
|
||||
import com.baeldung.akkahttp.UserMessages.CreateUserMessage;
|
||||
import com.baeldung.akkahttp.UserMessages.GetUserMessage;
|
||||
|
||||
|
||||
class UserActor extends AbstractActor {
|
||||
|
||||
private UserService userService = new UserService();
|
||||
|
||||
static Props props() {
|
||||
return Props.create(UserActor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Receive createReceive() {
|
||||
return receiveBuilder()
|
||||
.match(CreateUserMessage.class, handleCreateUser())
|
||||
.match(GetUserMessage.class, handleGetUser())
|
||||
.build();
|
||||
}
|
||||
|
||||
private FI.UnitApply<CreateUserMessage> handleCreateUser() {
|
||||
return createUserMessageMessage -> {
|
||||
userService.createUser(createUserMessageMessage.getUser());
|
||||
sender().tell(new ActionPerformed(String.format("User %s created.", createUserMessageMessage.getUser()
|
||||
.getName())), getSelf());
|
||||
};
|
||||
}
|
||||
|
||||
private FI.UnitApply<GetUserMessage> handleGetUser() {
|
||||
return getUserMessageMessage -> {
|
||||
sender().tell(userService.getUser(getUserMessageMessage.getUserId()), getSelf());
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface UserMessages {
|
||||
|
||||
class ActionPerformed implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String description;
|
||||
|
||||
public ActionPerformed(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
class CreateUserMessage implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final User user;
|
||||
|
||||
public CreateUserMessage(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
class GetUserMessage implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final Long userId;
|
||||
|
||||
public GetUserMessage(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.http.javadsl.marshallers.jackson.Jackson;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.server.HttpApp;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.pattern.PatternsCS;
|
||||
import akka.util.Timeout;
|
||||
import com.baeldung.akkahttp.UserMessages.ActionPerformed;
|
||||
import com.baeldung.akkahttp.UserMessages.CreateUserMessage;
|
||||
import com.baeldung.akkahttp.UserMessages.GetUserMessage;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import static akka.http.javadsl.server.PathMatchers.*;
|
||||
|
||||
class UserServer extends HttpApp {
|
||||
|
||||
private final ActorRef userActor;
|
||||
|
||||
Timeout timeout = new Timeout(Duration.create(5, TimeUnit.SECONDS));
|
||||
|
||||
UserServer(ActorRef userActor) {
|
||||
this.userActor = userActor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Route routes() {
|
||||
return path("users", this::postUser)
|
||||
.orElse(path(segment("users").slash(longSegment()), id ->
|
||||
route(getUser(id))));
|
||||
}
|
||||
|
||||
private Route getUser(Long id) {
|
||||
return get(() -> {
|
||||
CompletionStage<Optional<User>> user = PatternsCS.ask(userActor, new GetUserMessage(id), timeout)
|
||||
.thenApply(obj -> (Optional<User>) obj);
|
||||
|
||||
return onSuccess(() -> user, performed -> {
|
||||
if (performed.isPresent())
|
||||
return complete(StatusCodes.OK, performed.get(), Jackson.marshaller());
|
||||
else
|
||||
return complete(StatusCodes.NOT_FOUND);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private Route postUser() {
|
||||
return route(post(() -> entity(Jackson.unmarshaller(User.class), user -> {
|
||||
CompletionStage<ActionPerformed> userCreated = PatternsCS.ask(userActor, new CreateUserMessage(user), timeout)
|
||||
.thenApply(obj -> (ActionPerformed) obj);
|
||||
|
||||
return onSuccess(() -> userCreated, performed -> {
|
||||
return complete(StatusCodes.CREATED, performed, Jackson.marshaller());
|
||||
});
|
||||
})));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ActorSystem system = ActorSystem.create("userServer");
|
||||
ActorRef userActor = system.actorOf(UserActor.props(), "userActor");
|
||||
UserServer server = new UserServer(userActor);
|
||||
server.startServer("localhost", 8080, system);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class UserService {
|
||||
|
||||
private final static List<User> users = new ArrayList<>();
|
||||
|
||||
static {
|
||||
users.add(new User(1l, "Alice"));
|
||||
users.add(new User(2l, "Bob"));
|
||||
users.add(new User(3l, "Chris"));
|
||||
users.add(new User(4l, "Dick"));
|
||||
users.add(new User(5l, "Eve"));
|
||||
users.add(new User(6l, "Finn"));
|
||||
}
|
||||
|
||||
public Optional<User> getUser(Long id) {
|
||||
return users.stream()
|
||||
.filter(user -> user.getId()
|
||||
.equals(id))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public void createUser(User user) {
|
||||
users.add(user);
|
||||
}
|
||||
|
||||
public List<User> getUsers(){
|
||||
return users;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.baeldung.akkahttp;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.http.javadsl.model.ContentTypes;
|
||||
import akka.http.javadsl.model.HttpEntities;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class UserServerUnitTest extends JUnitRouteTest {
|
||||
|
||||
ActorSystem system = ActorSystem.create("helloAkkaHttpServer");
|
||||
|
||||
ActorRef userActorRef = system.actorOf(UserActor.props(), "userActor");
|
||||
|
||||
TestRoute appRoute = testRoute(new UserServer(userActorRef).routes());
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void whenRequest_thenActorResponds() {
|
||||
|
||||
appRoute.run(HttpRequest.GET("/users/1"))
|
||||
.assertEntity(alice())
|
||||
.assertStatusCode(200);
|
||||
|
||||
appRoute.run(HttpRequest.GET("/users/42"))
|
||||
.assertStatusCode(404);
|
||||
|
||||
appRoute.run(HttpRequest.DELETE("/users/1"))
|
||||
.assertStatusCode(405);
|
||||
|
||||
appRoute.run(HttpRequest.DELETE("/users/42"))
|
||||
.assertStatusCode(405);
|
||||
|
||||
appRoute.run(HttpRequest.POST("/users")
|
||||
.withEntity(HttpEntities.create(ContentTypes.APPLICATION_JSON, zaphod())))
|
||||
.assertStatusCode(201);
|
||||
|
||||
}
|
||||
|
||||
private String alice() {
|
||||
return "{\"id\":1,\"name\":\"Alice\"}";
|
||||
}
|
||||
|
||||
private String zaphod() {
|
||||
return "{\"id\":42,\"name\":\"Zaphod\"}";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
## Akka Streams
|
||||
|
||||
This module contains articles about Akka Streams.
|
||||
|
||||
### Relevant articles
|
||||
|
||||
- [Guide to Akka Streams](https://www.baeldung.com/akka-streams)
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>akka-streams</artifactId>
|
||||
<name>akka-streams</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>akka-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-stream_${scala.version}</artifactId>
|
||||
<version>${akkastreams.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-stream-testkit_${scala.version}</artifactId>
|
||||
<version>${akkastreams.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<akkastreams.version>2.5.2</akkastreams.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.akkastreams;
|
||||
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
public class AverageRepository {
|
||||
CompletionStage<Double> save(Double average) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
System.out.println("saving average: " + average);
|
||||
return average;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.baeldung.akkastreams;
|
||||
|
||||
|
||||
import akka.Done;
|
||||
import akka.NotUsed;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.stream.javadsl.Keep;
|
||||
import akka.stream.javadsl.Sink;
|
||||
import akka.stream.javadsl.Source;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DataImporter {
|
||||
private final ActorSystem actorSystem;
|
||||
private final AverageRepository averageRepository = new AverageRepository();
|
||||
|
||||
public DataImporter(ActorSystem actorSystem) {
|
||||
this.actorSystem = actorSystem;
|
||||
|
||||
}
|
||||
|
||||
private List<Integer> parseLine(String line) {
|
||||
String[] fields = line.split(";");
|
||||
return Arrays.stream(fields)
|
||||
.map(Integer::parseInt)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Flow<String, Integer, NotUsed> parseContent() {
|
||||
return Flow.of(String.class).mapConcat(this::parseLine);
|
||||
}
|
||||
|
||||
private Flow<Integer, Double, NotUsed> computeAverage() {
|
||||
return Flow.of(Integer.class).grouped(2).mapAsyncUnordered(8, integers ->
|
||||
CompletableFuture.supplyAsync(() -> integers
|
||||
.stream()
|
||||
.mapToDouble(v -> v)
|
||||
.average()
|
||||
.orElse(-1.0)));
|
||||
}
|
||||
|
||||
Flow<String, Double, NotUsed> calculateAverage() {
|
||||
return Flow.of(String.class)
|
||||
.via(parseContent())
|
||||
.via(computeAverage());
|
||||
}
|
||||
|
||||
private Sink<Double, CompletionStage<Done>> storeAverages() {
|
||||
return Flow.of(Double.class)
|
||||
.mapAsyncUnordered(4, averageRepository::save)
|
||||
.toMat(Sink.ignore(), Keep.right());
|
||||
}
|
||||
|
||||
|
||||
CompletionStage<Done> calculateAverageForContent(String content) {
|
||||
return Source.single(content)
|
||||
.via(calculateAverage())
|
||||
.runWith(storeAverages(), ActorMaterializer.create(actorSystem))
|
||||
.whenComplete((d, e) -> {
|
||||
if (d != null) {
|
||||
System.out.println("Import finished ");
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -0,0 +1,43 @@
|
|||
package com.baeldung.akkastreams;
|
||||
|
||||
import akka.NotUsed;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.stream.ActorMaterializer;
|
||||
import akka.stream.javadsl.Flow;
|
||||
import akka.stream.javadsl.Source;
|
||||
import akka.stream.testkit.javadsl.TestSink;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class DataImporterUnitTest {
|
||||
private final ActorSystem actorSystem = ActorSystem.create();
|
||||
|
||||
@Test
|
||||
public void givenStreamOfIntegers_whenCalculateAverageOfPairs_thenShouldReturnProperResults() {
|
||||
//given
|
||||
Flow<String, Double, NotUsed> tested = new DataImporter(actorSystem).calculateAverage();
|
||||
String input = "1;9;11;0";
|
||||
|
||||
//when
|
||||
Source<Double, NotUsed> flow = Source.single(input).via(tested);
|
||||
|
||||
//then
|
||||
flow
|
||||
.runWith(TestSink.probe(actorSystem), ActorMaterializer.create(actorSystem))
|
||||
.request(4)
|
||||
.expectNextUnordered(5d, 5.5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStreamOfIntegers_whenCalculateAverageAndSaveToSink_thenShouldFinishSuccessfully() {
|
||||
//given
|
||||
DataImporter dataImporter = new DataImporter(actorSystem);
|
||||
String input = "10;90;110;10";
|
||||
|
||||
//when
|
||||
dataImporter.calculateAverageForContent(input)
|
||||
.thenAccept(d -> actorSystem.terminate());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>akka-modules</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>akka-modules</name>
|
||||
|
||||
<parent>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
<module>akka-actors</module>
|
||||
<module>akka-http</module>
|
||||
<module>akka-streams</module>
|
||||
<module>spring-akka</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<scala.version>2.12</scala.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,6 @@
|
|||
## Spring Akka
|
||||
|
||||
This module contains articles about Spring with Akka
|
||||
|
||||
### Relevant Articles:
|
||||
- [Introduction to Spring with Akka](https://www.baeldung.com/akka-with-spring)
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>
|
||||
<artifactId>spring-akka</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<name>spring-akka</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>akka-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor_${scala.version}</artifactId>
|
||||
<version>${akka.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-framework-bom</artifactId>
|
||||
<version>${spring.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<properties>
|
||||
<spring.version>5.3.25</spring.version>
|
||||
<akka.version>2.4.14</akka.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.akka;
|
||||
|
||||
import akka.actor.ActorSystem;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
public class AppConfiguration {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Bean
|
||||
public ActorSystem actorSystem() {
|
||||
ActorSystem system = ActorSystem.create("akka-spring-demo");
|
||||
SpringExtension.SPRING_EXTENSION_PROVIDER.get(system).initialize(applicationContext);
|
||||
return system;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.baeldung.akka;
|
||||
|
||||
import akka.actor.UntypedActor;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||
public class GreetingActor extends UntypedActor {
|
||||
|
||||
private GreetingService greetingService;
|
||||
|
||||
public GreetingActor(GreetingService greetingService) {
|
||||
this.greetingService = greetingService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Object message) throws Throwable {
|
||||
if (message instanceof Greet) {
|
||||
String name = ((Greet) message).getName();
|
||||
getSender().tell(greetingService.greet(name), getSelf());
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Greet {
|
||||
|
||||
private String name;
|
||||
|
||||
public Greet(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.akka;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class GreetingService {
|
||||
|
||||
public String greet(String name) {
|
||||
return "Hello, " + name;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.baeldung.akka;
|
||||
|
||||
import akka.actor.Actor;
|
||||
import akka.actor.IndirectActorProducer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
public class SpringActorProducer implements IndirectActorProducer {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private String beanActorName;
|
||||
|
||||
public SpringActorProducer(ApplicationContext applicationContext, String beanActorName) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.beanActorName = beanActorName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Actor produce() {
|
||||
return (Actor) applicationContext.getBean(beanActorName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Actor> actorClass() {
|
||||
return (Class<? extends Actor>) applicationContext.getType(beanActorName);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.baeldung.akka;
|
||||
|
||||
import akka.actor.AbstractExtensionId;
|
||||
import akka.actor.ExtendedActorSystem;
|
||||
import akka.actor.Extension;
|
||||
import akka.actor.Props;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
public class SpringExtension extends AbstractExtensionId<SpringExtension.SpringExt> {
|
||||
|
||||
public static final SpringExtension SPRING_EXTENSION_PROVIDER = new SpringExtension();
|
||||
|
||||
@Override
|
||||
public SpringExt createExtension(ExtendedActorSystem system) {
|
||||
return new SpringExt();
|
||||
}
|
||||
|
||||
public static class SpringExt implements Extension {
|
||||
|
||||
private volatile ApplicationContext applicationContext;
|
||||
|
||||
public void initialize(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public Props props(String actorBeanName) {
|
||||
return Props.create(SpringActorProducer.class, applicationContext, actorBeanName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -0,0 +1,46 @@
|
|||
package com.baeldung.akka;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.util.Timeout;
|
||||
import com.baeldung.akka.GreetingActor.Greet;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
import scala.concurrent.Await;
|
||||
import scala.concurrent.Future;
|
||||
import scala.concurrent.duration.FiniteDuration;
|
||||
|
||||
import static akka.pattern.Patterns.ask;
|
||||
import static com.baeldung.akka.SpringExtension.SPRING_EXTENSION_PROVIDER;
|
||||
|
||||
@ContextConfiguration(classes = AppConfiguration.class)
|
||||
public class SpringAkkaIntegrationTest extends AbstractJUnit4SpringContextTests {
|
||||
|
||||
@Autowired
|
||||
private ActorSystem system;
|
||||
|
||||
@Test
|
||||
public void whenCallingGreetingActor_thenActorGreetsTheCaller() throws Exception {
|
||||
ActorRef greeter = system.actorOf(SPRING_EXTENSION_PROVIDER.get(system).props("greetingActor"), "greeter");
|
||||
|
||||
FiniteDuration duration = FiniteDuration.create(1, TimeUnit.SECONDS);
|
||||
Timeout timeout = Timeout.durationToTimeout(duration);
|
||||
|
||||
Future<Object> result = ask(greeter, new Greet("John"), timeout);
|
||||
|
||||
Assert.assertEquals("Hello, John", Await.result(result, duration));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
system.shutdown();
|
||||
system.awaitTermination();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/target/
|
||||
.settings/
|
||||
.classpath
|
||||
.project
|
|
@ -0,0 +1,10 @@
|
|||
## Genetic Algorithms
|
||||
|
||||
This module contains articles about genetic algorithms.
|
||||
|
||||
### Relevant articles:
|
||||
|
||||
- [Introduction to Jenetics Library](https://www.baeldung.com/jenetics)
|
||||
- [Ant Colony Optimization with a Java Example](https://www.baeldung.com/java-ant-colony-optimization)
|
||||
- [Design a Genetic Algorithm in Java](https://www.baeldung.com/java-genetic-algorithm)
|
||||
- [The Traveling Salesman Problem in Java](https://www.baeldung.com/java-simulated-annealing-for-traveling-salesman)
|
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>algorithms-genetic</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>algorithms-genetic</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>algorithms-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>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<io.jenetics.version>3.7.0</io.jenetics.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,38 @@
|
|||
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;
|
||||
|
||||
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 - Simple Genetic Algorithm");
|
||||
System.out.println("3 - Ant Colony");
|
||||
int decision = in.nextInt();
|
||||
switch (decision) {
|
||||
case 1:
|
||||
System.out.println(
|
||||
"Optimized distance for travel: " + SimulatedAnnealing.simulateAnnealing(10, 10000, 0.9995));
|
||||
break;
|
||||
case 2:
|
||||
SimpleGeneticAlgorithm ga = new SimpleGeneticAlgorithm();
|
||||
ga.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111");
|
||||
break;
|
||||
case 3:
|
||||
AntColonyOptimization antColony = new AntColonyOptimization(21);
|
||||
antColony.startAntOptimization();
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown option");
|
||||
break;
|
||||
}
|
||||
in.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
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 = new ArrayList<>(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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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]));
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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(", "));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.algorithms;
|
||||
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.algorithms.ga.ant_colony.AntColonyOptimization;
|
||||
|
||||
class AntColonyOptimizationLongRunningUnitTest {
|
||||
|
||||
@Test
|
||||
void testGenerateRandomMatrix() {
|
||||
AntColonyOptimization antTSP = new AntColonyOptimization(5);
|
||||
assertNotNull(antTSP.generateRandomMatrix(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStartAntOptimization() {
|
||||
AntColonyOptimization antTSP = new AntColonyOptimization(5);
|
||||
assertNotNull(antTSP.solve());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.baeldung.algorithms;
|
||||
|
||||
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.algorithms.ga.binary.SimpleGeneticAlgorithm;
|
||||
|
||||
class BinaryGeneticAlgorithmLongRunningUnitTest {
|
||||
|
||||
@Test
|
||||
void testGA() {
|
||||
SimpleGeneticAlgorithm ga = new SimpleGeneticAlgorithm();
|
||||
assertTrue(ga.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.baeldung.algorithms;
|
||||
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.algorithms.ga.annealing.SimulatedAnnealing;
|
||||
|
||||
class SimulatedAnnealingLongRunningUnitTest {
|
||||
|
||||
@Test
|
||||
void testSimulateAnnealing() {
|
||||
assertTrue(SimulatedAnnealing.simulateAnnealing(10, 1000, 0.9) > 0);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
## Algorithms - Miscellaneous
|
||||
|
||||
This module contains articles about algorithms. Some classes of algorithms, e.g., [sorting](/../algorithms-sorting) and
|
||||
[genetic algorithms](/../algorithms-genetic), have their own dedicated modules.
|
||||
|
||||
### Relevant articles:
|
||||
|
||||
- [Validating Input with Finite Automata in Java](https://www.baeldung.com/java-finite-automata)
|
||||
- [Example of Hill Climbing Algorithm in Java](https://www.baeldung.com/java-hill-climbing-algorithm)
|
||||
- [Introduction to Minimax Algorithm with a Java Implementation](https://www.baeldung.com/java-minimax-algorithm)
|
||||
- [How to Calculate Levenshtein Distance in Java?](https://www.baeldung.com/java-levenshtein-distance)
|
||||
- [How to Find the Kth Largest Element in Java](https://www.baeldung.com/java-kth-largest-element)
|
||||
- More articles: [[next -->]](/algorithms-miscellaneous-2)
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>algorithms-miscellaneous-1</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>algorithms-miscellaneous-1</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>algorithms-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>com.github.dpaukov</groupId>
|
||||
<artifactId>combinatoricslib3</artifactId>
|
||||
<version>${combinatoricslib3.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>${cobertura.plugin.version}</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>
|
||||
<combinatoricslib3.version>3.3.0</combinatoricslib3.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.algorithms.automata;
|
||||
|
||||
/**
|
||||
* Finite state machine.
|
||||
*/
|
||||
public interface FiniteStateMachine {
|
||||
|
||||
/**
|
||||
* Follow a transition, switch the state of the machine.
|
||||
* @param c Char.
|
||||
* @return A new finite state machine with the new state.
|
||||
*/
|
||||
FiniteStateMachine switchState(final CharSequence c);
|
||||
|
||||
/**
|
||||
* Is the current state a final one?
|
||||
* @return true or false.
|
||||
*/
|
||||
boolean canStop();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.algorithms.automata;
|
||||
|
||||
/**
|
||||
* Default implementation of a finite state machine.
|
||||
* This class is immutable and thread-safe.
|
||||
*/
|
||||
public final class RtFiniteStateMachine implements FiniteStateMachine {
|
||||
|
||||
/**
|
||||
* Current state.
|
||||
*/
|
||||
private State current;
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
* @param initial Initial state of this machine.
|
||||
*/
|
||||
public RtFiniteStateMachine(final State initial) {
|
||||
this.current = initial;
|
||||
}
|
||||
|
||||
public FiniteStateMachine switchState(final CharSequence c) {
|
||||
return new RtFiniteStateMachine(this.current.transit(c));
|
||||
}
|
||||
|
||||
public boolean canStop() {
|
||||
return this.current.isFinal();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.baeldung.algorithms.automata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* State in a finite state machine.
|
||||
*/
|
||||
public final class RtState implements State {
|
||||
|
||||
private List<Transition> transitions;
|
||||
private boolean isFinal;
|
||||
|
||||
public RtState() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public RtState(final boolean isFinal) {
|
||||
this.transitions = new ArrayList<>();
|
||||
this.isFinal = isFinal;
|
||||
}
|
||||
|
||||
public State transit(final CharSequence c) {
|
||||
return transitions
|
||||
.stream()
|
||||
.filter(t -> t.isPossible(c))
|
||||
.map(Transition::state)
|
||||
.findAny()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Input not accepted: " + c));
|
||||
}
|
||||
|
||||
public boolean isFinal() {
|
||||
return this.isFinal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State with(Transition tr) {
|
||||
this.transitions.add(tr);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.baeldung.algorithms.automata;
|
||||
|
||||
|
||||
/**
|
||||
* Transition in finite state machine.
|
||||
*/
|
||||
public final class RtTransition implements Transition {
|
||||
|
||||
private String rule;
|
||||
private State next;
|
||||
|
||||
/**
|
||||
* Ctor.
|
||||
* @param rule Rule that a character has to meet
|
||||
* in order to get to the next state.
|
||||
* @param next Next state.
|
||||
*/
|
||||
public RtTransition (String rule, State next) {
|
||||
this.rule = rule;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
public State state() {
|
||||
return this.next;
|
||||
}
|
||||
|
||||
public boolean isPossible(CharSequence c) {
|
||||
return this.rule.equalsIgnoreCase(String.valueOf(c));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.baeldung.algorithms.automata;
|
||||
|
||||
/**
|
||||
* State. Part of a finite state machine.
|
||||
*/
|
||||
public interface State {
|
||||
|
||||
/**
|
||||
* Add a Transition to this state.
|
||||
* @param tr Given transition.
|
||||
* @return Modified State.
|
||||
*/
|
||||
State with(final Transition tr);
|
||||
|
||||
/**
|
||||
* Follow one of the transitions, to get
|
||||
* to the next state.
|
||||
* @param c Character.
|
||||
* @return State.
|
||||
* @throws IllegalStateException if the char is not accepted.
|
||||
*/
|
||||
State transit(final CharSequence c);
|
||||
|
||||
/**
|
||||
* Can the automaton stop on this state?
|
||||
* @return true or false
|
||||
*/
|
||||
boolean isFinal();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.algorithms.automata;
|
||||
|
||||
/**
|
||||
* Transition in a finite State machine.
|
||||
*/
|
||||
public interface Transition {
|
||||
|
||||
/**
|
||||
* Is the transition possible with the given character?
|
||||
* @param c char.
|
||||
* @return true or false.
|
||||
*/
|
||||
boolean isPossible(final CharSequence c);
|
||||
|
||||
/**
|
||||
* The state to which this transition leads.
|
||||
* @return State.
|
||||
*/
|
||||
State state();
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
package com.baeldung.algorithms.hillclimbing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Stack;
|
||||
|
||||
public class HillClimbing {
|
||||
public static void main(String[] args) {
|
||||
HillClimbing hillClimbing = new HillClimbing();
|
||||
String blockArr[] = { "B", "C", "D", "A" };
|
||||
Stack<String> startState = hillClimbing.getStackWithValues(blockArr);
|
||||
String goalBlockArr[] = { "A", "B", "C", "D" };
|
||||
Stack<String> goalState = hillClimbing.getStackWithValues(goalBlockArr);
|
||||
try {
|
||||
List<State> solutionSequence = hillClimbing.getRouteWithHillClimbing(startState, goalState);
|
||||
solutionSequence.forEach(HillClimbing::printEachStep);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void printEachStep(State state) {
|
||||
List<Stack<String>> stackList = state.getState();
|
||||
System.out.println("----------------");
|
||||
stackList.forEach(stack -> {
|
||||
while (!stack.isEmpty()) {
|
||||
System.out.println(stack.pop());
|
||||
}
|
||||
System.out.println(" ");
|
||||
});
|
||||
}
|
||||
|
||||
private Stack<String> getStackWithValues(String[] blocks) {
|
||||
Stack<String> stack = new Stack<>();
|
||||
for (String block : blocks)
|
||||
stack.push(block);
|
||||
return stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method prepares path from init state to goal state
|
||||
*/
|
||||
public List<State> getRouteWithHillClimbing(Stack<String> initStateStack, Stack<String> goalStateStack) throws Exception {
|
||||
List<Stack<String>> initStateStackList = new ArrayList<>();
|
||||
initStateStackList.add(initStateStack);
|
||||
int initStateHeuristics = getHeuristicsValue(initStateStackList, goalStateStack);
|
||||
State initState = new State(initStateStackList, initStateHeuristics);
|
||||
|
||||
List<State> resultPath = new ArrayList<>();
|
||||
resultPath.add(new State(initState));
|
||||
|
||||
State currentState = initState;
|
||||
boolean noStateFound = false;
|
||||
while (!currentState.getState()
|
||||
.get(0)
|
||||
.equals(goalStateStack) || noStateFound) {
|
||||
noStateFound = true;
|
||||
State nextState = findNextState(currentState, goalStateStack);
|
||||
if (nextState != null) {
|
||||
noStateFound = false;
|
||||
currentState = nextState;
|
||||
resultPath.add(new State(nextState));
|
||||
}
|
||||
}
|
||||
|
||||
return resultPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method finds new state from current state based on goal and
|
||||
* heuristics
|
||||
*/
|
||||
public State findNextState(State currentState, Stack<String> goalStateStack) {
|
||||
List<Stack<String>> listOfStacks = currentState.getState();
|
||||
int currentStateHeuristics = currentState.getHeuristics();
|
||||
|
||||
return listOfStacks.stream()
|
||||
.map(stack -> {
|
||||
return applyOperationsOnState(listOfStacks, stack, currentStateHeuristics, goalStateStack);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method applies operations on the current state to get a new state
|
||||
*/
|
||||
public State applyOperationsOnState(List<Stack<String>> listOfStacks, Stack<String> stack, int currentStateHeuristics, Stack<String> goalStateStack) {
|
||||
State tempState;
|
||||
List<Stack<String>> tempStackList = new ArrayList<>(listOfStacks);
|
||||
String block = stack.pop();
|
||||
if (stack.size() == 0)
|
||||
tempStackList.remove(stack);
|
||||
tempState = pushElementToNewStack(tempStackList, block, currentStateHeuristics, goalStateStack);
|
||||
if (tempState == null) {
|
||||
tempState = pushElementToExistingStacks(stack, tempStackList, block, currentStateHeuristics, goalStateStack);
|
||||
}
|
||||
if (tempState == null)
|
||||
stack.push(block);
|
||||
return tempState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Operation to be applied on a state in order to find new states. This
|
||||
* operation pushes an element into a new stack
|
||||
*/
|
||||
private State pushElementToNewStack(List<Stack<String>> currentStackList, String block, int currentStateHeuristics, Stack<String> goalStateStack) {
|
||||
State newState = null;
|
||||
Stack<String> newStack = new Stack<>();
|
||||
newStack.push(block);
|
||||
|
||||
currentStackList.add(newStack);
|
||||
int newStateHeuristics = getHeuristicsValue(currentStackList, goalStateStack);
|
||||
if (newStateHeuristics > currentStateHeuristics) {
|
||||
newState = new State(currentStackList, newStateHeuristics);
|
||||
} else {
|
||||
currentStackList.remove(newStack);
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Operation to be applied on a state in order to find new states. This
|
||||
* operation pushes an element into one of the other stacks to explore new
|
||||
* states
|
||||
*/
|
||||
private State pushElementToExistingStacks(Stack currentStack, List<Stack<String>> currentStackList, String block, int currentStateHeuristics, Stack<String> goalStateStack) {
|
||||
|
||||
Optional<State> newState = currentStackList.stream()
|
||||
.filter(stack -> stack != currentStack)
|
||||
.map(stack -> {
|
||||
return pushElementToStack(stack, block, currentStackList, currentStateHeuristics, goalStateStack);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst();
|
||||
|
||||
return newState.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method pushes a block to the stack and returns new state if its closer to goal
|
||||
*/
|
||||
private State pushElementToStack(Stack stack, String block, List<Stack<String>> currentStackList, int currentStateHeuristics, Stack<String> goalStateStack) {
|
||||
stack.push(block);
|
||||
int newStateHeuristics = getHeuristicsValue(currentStackList, goalStateStack);
|
||||
if (newStateHeuristics > currentStateHeuristics) {
|
||||
return new State(currentStackList, newStateHeuristics);
|
||||
}
|
||||
stack.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns heuristics value for given state with respect to goal
|
||||
* state
|
||||
*/
|
||||
public int getHeuristicsValue(List<Stack<String>> currentState, Stack<String> goalStateStack) {
|
||||
Integer heuristicValue;
|
||||
heuristicValue = currentState.stream()
|
||||
.mapToInt(stack -> {
|
||||
return getHeuristicsValueForStack(stack, currentState, goalStateStack);
|
||||
})
|
||||
.sum();
|
||||
return heuristicValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns heuristics value for a particular stack
|
||||
*/
|
||||
public int getHeuristicsValueForStack(Stack<String> stack, List<Stack<String>> currentState, Stack<String> goalStateStack) {
|
||||
int stackHeuristics = 0;
|
||||
boolean isPositioneCorrect = true;
|
||||
int goalStartIndex = 0;
|
||||
for (String currentBlock : stack) {
|
||||
if (isPositioneCorrect && currentBlock.equals(goalStateStack.get(goalStartIndex))) {
|
||||
stackHeuristics += goalStartIndex;
|
||||
} else {
|
||||
stackHeuristics -= goalStartIndex;
|
||||
isPositioneCorrect = false;
|
||||
}
|
||||
goalStartIndex++;
|
||||
}
|
||||
return stackHeuristics;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.baeldung.algorithms.hillclimbing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class State {
|
||||
private List<Stack<String>> state;
|
||||
private int heuristics;
|
||||
|
||||
public State(List<Stack<String>> state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
State(List<Stack<String>> state, int heuristics) {
|
||||
this.state = state;
|
||||
this.heuristics = heuristics;
|
||||
}
|
||||
|
||||
State(State state) {
|
||||
if (state != null) {
|
||||
this.state = new ArrayList<>();
|
||||
for (Stack s : state.getState()) {
|
||||
Stack s1;
|
||||
s1 = (Stack) s.clone();
|
||||
this.state.add(s1);
|
||||
}
|
||||
this.heuristics = state.getHeuristics();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Stack<String>> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public int getHeuristics() {
|
||||
return heuristics;
|
||||
}
|
||||
|
||||
public void setHeuristics(int heuristics) {
|
||||
this.heuristics = heuristics;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package com.baeldung.algorithms.kthlargest;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class FindKthLargest {
|
||||
|
||||
public int findKthLargestBySorting(Integer[] arr, int k) {
|
||||
Arrays.sort(arr);
|
||||
int targetIndex = arr.length - k;
|
||||
return arr[targetIndex];
|
||||
}
|
||||
|
||||
public int findKthLargestBySortingDesc(Integer[] arr, int k) {
|
||||
Arrays.sort(arr, Collections.reverseOrder());
|
||||
return arr[k - 1];
|
||||
}
|
||||
|
||||
public int findKthElementByQuickSelect(Integer[] arr, int left, int right, int k) {
|
||||
if (k >= 0 && k <= right - left + 1) {
|
||||
int pos = partition(arr, left, right);
|
||||
if (pos - left == k) {
|
||||
return arr[pos];
|
||||
}
|
||||
if (pos - left > k) {
|
||||
return findKthElementByQuickSelect(arr, left, pos - 1, k);
|
||||
}
|
||||
return findKthElementByQuickSelect(arr, pos + 1, right, k - pos + left - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int findKthElementByQuickSelectWithIterativePartition(Integer[] arr, int left, int right, int k) {
|
||||
if (k >= 0 && k <= right - left + 1) {
|
||||
int pos = partitionIterative(arr, left, right);
|
||||
if (pos - left == k) {
|
||||
return arr[pos];
|
||||
}
|
||||
if (pos - left > k) {
|
||||
return findKthElementByQuickSelectWithIterativePartition(arr, left, pos - 1, k);
|
||||
}
|
||||
return findKthElementByQuickSelectWithIterativePartition(arr, pos + 1, right, k - pos + left - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int partition(Integer[] arr, int left, int right) {
|
||||
int pivot = arr[right];
|
||||
Integer[] leftArr;
|
||||
Integer[] rightArr;
|
||||
|
||||
leftArr = IntStream.range(left, right)
|
||||
.filter(i -> arr[i] < pivot)
|
||||
.map(i -> arr[i])
|
||||
.boxed()
|
||||
.toArray(Integer[]::new);
|
||||
|
||||
rightArr = IntStream.range(left, right)
|
||||
.filter(i -> arr[i] > pivot)
|
||||
.map(i -> arr[i])
|
||||
.boxed()
|
||||
.toArray(Integer[]::new);
|
||||
|
||||
int leftArraySize = leftArr.length;
|
||||
System.arraycopy(leftArr, 0, arr, left, leftArraySize);
|
||||
arr[leftArraySize + left] = pivot;
|
||||
System.arraycopy(rightArr, 0, arr, left + leftArraySize + 1, rightArr.length);
|
||||
|
||||
return left + leftArraySize;
|
||||
}
|
||||
|
||||
private int partitionIterative(Integer[] arr, int left, int right) {
|
||||
int pivot = arr[right], i = left;
|
||||
for (int j = left; j <= right - 1; j++) {
|
||||
if (arr[j] <= pivot) {
|
||||
swap(arr, i, j);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
swap(arr, i, right);
|
||||
return i;
|
||||
}
|
||||
|
||||
public int findKthElementByRandomizedQuickSelect(Integer[] arr, int left, int right, int k) {
|
||||
if (k >= 0 && k <= right - left + 1) {
|
||||
int pos = randomPartition(arr, left, right);
|
||||
if (pos - left == k) {
|
||||
return arr[pos];
|
||||
}
|
||||
if (pos - left > k) {
|
||||
return findKthElementByRandomizedQuickSelect(arr, left, pos - 1, k);
|
||||
}
|
||||
return findKthElementByRandomizedQuickSelect(arr, pos + 1, right, k - pos + left - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int randomPartition(Integer arr[], int left, int right) {
|
||||
int n = right - left + 1;
|
||||
int pivot = (int) (Math.random() * n);
|
||||
swap(arr, left + pivot, right);
|
||||
return partition(arr, left, right);
|
||||
}
|
||||
|
||||
private void swap(Integer[] arr, int n1, int n2) {
|
||||
int temp = arr[n2];
|
||||
arr[n2] = arr[n1];
|
||||
arr[n1] = temp;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.algorithms.minimax;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
class GameOfBones {
|
||||
static List<Integer> getPossibleStates(int noOfBonesInHeap) {
|
||||
return IntStream.rangeClosed(1, 3).boxed()
|
||||
.map(i -> noOfBonesInHeap - i)
|
||||
.filter(newHeapCount -> newHeapCount >= 0)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.baeldung.algorithms.minimax;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class MiniMax {
|
||||
private Tree tree;
|
||||
|
||||
public Tree getTree() {
|
||||
return tree;
|
||||
}
|
||||
|
||||
public void constructTree(int noOfBones) {
|
||||
tree = new Tree();
|
||||
Node root = new Node(noOfBones, true);
|
||||
tree.setRoot(root);
|
||||
constructTree(root);
|
||||
}
|
||||
|
||||
private void constructTree(Node parentNode) {
|
||||
List<Integer> listofPossibleHeaps = GameOfBones.getPossibleStates(parentNode.getNoOfBones());
|
||||
boolean isChildMaxPlayer = !parentNode.isMaxPlayer();
|
||||
listofPossibleHeaps.forEach(n -> {
|
||||
Node newNode = new Node(n, isChildMaxPlayer);
|
||||
parentNode.addChild(newNode);
|
||||
if (newNode.getNoOfBones() > 0) {
|
||||
constructTree(newNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean checkWin() {
|
||||
Node root = tree.getRoot();
|
||||
checkWin(root);
|
||||
return root.getScore() == 1;
|
||||
}
|
||||
|
||||
private void checkWin(Node node) {
|
||||
List<Node> children = node.getChildren();
|
||||
boolean isMaxPlayer = node.isMaxPlayer();
|
||||
children.forEach(child -> {
|
||||
if (child.getNoOfBones() == 0) {
|
||||
child.setScore(isMaxPlayer ? 1 : -1);
|
||||
} else {
|
||||
checkWin(child);
|
||||
}
|
||||
});
|
||||
Node bestChild = findBestChild(isMaxPlayer, children);
|
||||
node.setScore(bestChild.getScore());
|
||||
}
|
||||
|
||||
private Node findBestChild(boolean isMaxPlayer, List<Node> children) {
|
||||
Comparator<Node> byScoreComparator = Comparator.comparing(Node::getScore);
|
||||
|
||||
return children.stream()
|
||||
.max(isMaxPlayer ? byScoreComparator : byScoreComparator.reversed())
|
||||
.orElseThrow(NoSuchElementException::new);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.baeldung.algorithms.minimax;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Node {
|
||||
private int noOfBones;
|
||||
private boolean isMaxPlayer;
|
||||
private int score;
|
||||
private List<Node> children;
|
||||
|
||||
public Node(int noOfBones, boolean isMaxPlayer) {
|
||||
this.noOfBones = noOfBones;
|
||||
this.isMaxPlayer = isMaxPlayer;
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
|
||||
int getNoOfBones() {
|
||||
return noOfBones;
|
||||
}
|
||||
|
||||
boolean isMaxPlayer() {
|
||||
return isMaxPlayer;
|
||||
}
|
||||
|
||||
int getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
void setScore(int score) {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
List<Node> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
void addChild(Node newNode) {
|
||||
children.add(newNode);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.algorithms.minimax;
|
||||
|
||||
public class Tree {
|
||||
private Node root;
|
||||
|
||||
Tree() {
|
||||
}
|
||||
|
||||
Node getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
void setRoot(Node root) {
|
||||
this.root = root;
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -0,0 +1,60 @@
|
|||
package com.baeldung.algorithms;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.algorithms.hillclimbing.HillClimbing;
|
||||
import com.baeldung.algorithms.hillclimbing.State;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
|
||||
class HillClimbingAlgorithmUnitTest {
|
||||
private Stack<String> initStack;
|
||||
private Stack<String> goalStack;
|
||||
|
||||
@BeforeEach
|
||||
public void initStacks() {
|
||||
String blockArr[] = { "B", "C", "D", "A" };
|
||||
String goalBlockArr[] = { "A", "B", "C", "D" };
|
||||
initStack = new Stack<>();
|
||||
for (String block : blockArr)
|
||||
initStack.push(block);
|
||||
goalStack = new Stack<>();
|
||||
for (String block : goalBlockArr)
|
||||
goalStack.push(block);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenInitAndGoalState_whenGetPathWithHillClimbing_thenPathFound() {
|
||||
HillClimbing hillClimbing = new HillClimbing();
|
||||
|
||||
List<State> path;
|
||||
try {
|
||||
path = hillClimbing.getRouteWithHillClimbing(initStack, goalStack);
|
||||
assertNotNull(path);
|
||||
assertEquals(path.get(path.size() - 1)
|
||||
.getState()
|
||||
.get(0), goalStack);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenCurrentState_whenFindNextState_thenBetterHeuristics() {
|
||||
HillClimbing hillClimbing = new HillClimbing();
|
||||
List<Stack<String>> initList = new ArrayList<>();
|
||||
initList.add(initStack);
|
||||
State currentState = new State(initList);
|
||||
currentState.setHeuristics(hillClimbing.getHeuristicsValue(initList, goalStack));
|
||||
State nextState = hillClimbing.findNextState(currentState, goalStack);
|
||||
assertTrue(nextState.getHeuristics() > currentState.getHeuristics());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.baeldung.algorithms;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.algorithms.automata.*;
|
||||
|
||||
class RtFiniteStateMachineLongRunningUnitTest {
|
||||
|
||||
@Test
|
||||
void acceptsSimplePair() {
|
||||
String json = "{\"key\":\"value\"}";
|
||||
FiniteStateMachine machine = this.buildJsonStateMachine();
|
||||
for (int i = 0; i < json.length(); i++) {
|
||||
machine = machine.switchState(String.valueOf(json.charAt(i)));
|
||||
}
|
||||
assertTrue(machine.canStop());
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsMorePairs() {
|
||||
String json = "{\"key1\":\"value1\",\"key2\":\"value2\"}";
|
||||
FiniteStateMachine machine = this.buildJsonStateMachine();
|
||||
for (int i = 0; i < json.length(); i++) {
|
||||
machine = machine.switchState(String.valueOf(json.charAt(i)));
|
||||
}
|
||||
assertTrue(machine.canStop());
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingColon() {
|
||||
String json = "{\"key\"\"value\"}";
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
FiniteStateMachine machine = this.buildJsonStateMachine();
|
||||
for (int i = 0; i < json.length(); i++) {
|
||||
machine = machine.switchState(String.valueOf(json.charAt(i)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a finite state machine to validate a simple
|
||||
* Json object.
|
||||
* @return
|
||||
*/
|
||||
private FiniteStateMachine buildJsonStateMachine() {
|
||||
State first = new RtState();
|
||||
State second = new RtState();
|
||||
State third = new RtState();
|
||||
State fourth = new RtState();
|
||||
State fifth = new RtState();
|
||||
State sixth = new RtState();
|
||||
State seventh = new RtState();
|
||||
State eighth = new RtState(true);
|
||||
|
||||
first.with(new RtTransition("{", second));
|
||||
second.with(new RtTransition("\"", third));
|
||||
//Add transitions with chars 0-9 and a-z
|
||||
for (int i = 0; i < 26; i++) {
|
||||
if (i < 10) {
|
||||
third = third.with(new RtTransition(String.valueOf(i), third));
|
||||
sixth = sixth.with(new RtTransition(String.valueOf(i), sixth));
|
||||
}
|
||||
third = third.with(new RtTransition(String.valueOf((char) ('a' + i)), third));
|
||||
sixth = sixth.with(new RtTransition(String.valueOf((char) ('a' + i)), sixth));
|
||||
}
|
||||
third.with(new RtTransition("\"", fourth));
|
||||
fourth.with(new RtTransition(":", fifth));
|
||||
fifth.with(new RtTransition("\"", sixth));
|
||||
sixth.with(new RtTransition("\"", seventh));
|
||||
seventh.with(new RtTransition(",", second));
|
||||
seventh.with(new RtTransition("}", eighth));
|
||||
return new RtFiniteStateMachine(first);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.baeldung.algorithms.kthlargest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class FindKthLargestUnitTest {
|
||||
|
||||
private FindKthLargest findKthLargest;
|
||||
private Integer[] arr = { 3, 7, 1, 2, 8, 10, 4, 5, 6, 9 };
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
findKthLargest = new FindKthLargest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIntArray_whenFindKthLargestBySorting_thenGetResult() {
|
||||
int k = 3;
|
||||
assertThat(findKthLargest.findKthLargestBySorting(arr, k)).isEqualTo(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIntArray_whenFindKthLargestBySortingDesc_thenGetResult() {
|
||||
int k = 3;
|
||||
assertThat(findKthLargest.findKthLargestBySortingDesc(arr, k)).isEqualTo(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIntArray_whenFindKthLargestByQuickSelect_thenGetResult() {
|
||||
int k = 3;
|
||||
int kthLargest = arr.length - k;
|
||||
assertThat(findKthLargest.findKthElementByQuickSelect(arr, 0, arr.length - 1, kthLargest)).isEqualTo(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIntArray_whenFindKthElementByQuickSelectIterative_thenGetResult() {
|
||||
int k = 3;
|
||||
int kthLargest = arr.length - k;
|
||||
assertThat(findKthLargest.findKthElementByQuickSelectWithIterativePartition(arr, 0, arr.length - 1, kthLargest)).isEqualTo(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIntArray_whenFindKthSmallestByQuickSelect_thenGetResult() {
|
||||
int k = 3;
|
||||
assertThat(findKthLargest.findKthElementByQuickSelect(arr, 0, arr.length - 1, k - 1)).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenIntArray_whenFindKthLargestByRandomizedQuickSelect_thenGetResult() {
|
||||
int k = 3;
|
||||
int kthLargest = arr.length - k;
|
||||
assertThat(findKthLargest.findKthElementByRandomizedQuickSelect(arr, 0, arr.length - 1, kthLargest)).isEqualTo(8);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.baeldung.algorithms.minimax;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class MinimaxUnitTest {
|
||||
private Tree gameTree;
|
||||
private MiniMax miniMax;
|
||||
|
||||
@BeforeEach
|
||||
public void initMiniMaxUtility() {
|
||||
miniMax = new MiniMax();
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenMiniMax_whenConstructTree_thenNotNullTree() {
|
||||
assertNull(gameTree);
|
||||
miniMax.constructTree(6);
|
||||
gameTree = miniMax.getTree();
|
||||
assertNotNull(gameTree);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenMiniMax_whenCheckWin_thenComputeOptimal() {
|
||||
miniMax.constructTree(6);
|
||||
boolean result = miniMax.checkWin();
|
||||
assertTrue(result);
|
||||
miniMax.constructTree(8);
|
||||
result = miniMax.checkWin();
|
||||
assertFalse(result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
## Algorithms - Miscellaneous
|
||||
|
||||
This module contains articles about algorithms. Some classes of algorithms, e.g., [sorting](/../algorithms-sorting) and
|
||||
[genetic algorithms](/../algorithms-genetic), have their own dedicated modules.
|
||||
|
||||
### Relevant articles:
|
||||
|
||||
- [Dijkstra Shortest Path Algorithm in Java](https://www.baeldung.com/java-dijkstra)
|
||||
- [Introduction to Cobertura](https://www.baeldung.com/cobertura)
|
||||
- [Test a Linked List for Cyclicity](https://www.baeldung.com/java-linked-list-cyclicity)
|
||||
- [Introduction to JGraphT](https://www.baeldung.com/jgrapht)
|
||||
- [A Maze Solver in Java](https://www.baeldung.com/java-solve-maze)
|
||||
- [Create a Sudoku Solver in Java](https://www.baeldung.com/java-sudoku)
|
||||
- [Displaying Money Amounts in Words](https://www.baeldung.com/java-money-into-words)
|
||||
- [A Collaborative Filtering Recommendation System in Java](https://www.baeldung.com/java-collaborative-filtering-recommendations)
|
||||
- [Implementing A* Pathfinding in Java](https://www.baeldung.com/java-a-star-pathfinding)
|
||||
- More articles: [[<-- prev]](/algorithms-miscellaneous-1) [[next -->]](/algorithms-miscellaneous-3)
|
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
||||
<artifactId>algorithms-miscellaneous-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>algorithms-miscellaneous-2</name>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>algorithms-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jgrapht</groupId>
|
||||
<artifactId>jgrapht-core</artifactId>
|
||||
<version>${org.jgrapht.core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jgrapht</groupId>
|
||||
<artifactId>jgrapht-ext</artifactId>
|
||||
<version>${org.jgrapht.ext.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pl.allegro.finance</groupId>
|
||||
<artifactId>tradukisto</artifactId>
|
||||
<version>${tradukisto.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>cobertura-maven-plugin</artifactId>
|
||||
<version>${cobertura-maven-plugin.version}</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>
|
||||
<org.jgrapht.core.version>1.0.1</org.jgrapht.core.version>
|
||||
<org.jgrapht.ext.version>1.0.1</org.jgrapht.ext.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,28 @@
|
|||
package com.baeldung.algorithms;
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
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("1 - Slope One");
|
||||
System.out.println("2 - Dijkstra");
|
||||
int decision = in.nextInt();
|
||||
switch (decision) {
|
||||
case 1:
|
||||
SlopeOne.slopeOne(3);
|
||||
break;
|
||||
case 2:
|
||||
System.out.println("Please run the DijkstraAlgorithmLongRunningUnitTest.");
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown option");
|
||||
break;
|
||||
}
|
||||
in.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.baeldung.algorithms.astar;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class Graph<T extends GraphNode> {
|
||||
private final Set<T> nodes;
|
||||
|
||||
private final Map<String, Set<String>> connections;
|
||||
|
||||
public Graph(Set<T> nodes, Map<String, Set<String>> connections) {
|
||||
this.nodes = nodes;
|
||||
this.connections = connections;
|
||||
}
|
||||
|
||||
public T getNode(String id) {
|
||||
return nodes.stream()
|
||||
.filter(node -> node.getId().equals(id))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No node found with ID"));
|
||||
}
|
||||
|
||||
public Set<T> getConnections(T node) {
|
||||
return connections.get(node.getId()).stream()
|
||||
.map(this::getNode)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package com.baeldung.algorithms.astar;
|
||||
|
||||
public interface GraphNode {
|
||||
String getId();
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package com.baeldung.algorithms.astar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class RouteFinder<T extends GraphNode> {
|
||||
private final Graph<T> graph;
|
||||
private final Scorer<T> nextNodeScorer;
|
||||
private final Scorer<T> targetScorer;
|
||||
|
||||
public RouteFinder(Graph<T> graph, Scorer<T> nextNodeScorer, Scorer<T> targetScorer) {
|
||||
this.graph = graph;
|
||||
this.nextNodeScorer = nextNodeScorer;
|
||||
this.targetScorer = targetScorer;
|
||||
}
|
||||
|
||||
public List<T> findRoute(T from, T to) {
|
||||
Map<T, RouteNode<T>> allNodes = new HashMap<>();
|
||||
Queue<RouteNode> openSet = new PriorityQueue<>();
|
||||
|
||||
RouteNode<T> start = new RouteNode<>(from, null, 0d, targetScorer.computeCost(from, to));
|
||||
allNodes.put(from, start);
|
||||
openSet.add(start);
|
||||
|
||||
while (!openSet.isEmpty()) {
|
||||
log.debug("Open Set contains: " + openSet.stream().map(RouteNode::getCurrent).collect(Collectors.toSet()));
|
||||
RouteNode<T> next = openSet.poll();
|
||||
log.debug("Looking at node: " + next);
|
||||
if (next.getCurrent().equals(to)) {
|
||||
log.debug("Found our destination!");
|
||||
|
||||
List<T> route = new ArrayList<>();
|
||||
RouteNode<T> current = next;
|
||||
do {
|
||||
route.add(0, current.getCurrent());
|
||||
current = allNodes.get(current.getPrevious());
|
||||
} while (current != null);
|
||||
|
||||
log.debug("Route: " + route);
|
||||
return route;
|
||||
}
|
||||
|
||||
graph.getConnections(next.getCurrent()).forEach(connection -> {
|
||||
double newScore = next.getRouteScore() + nextNodeScorer.computeCost(next.getCurrent(), connection);
|
||||
RouteNode<T> nextNode = allNodes.getOrDefault(connection, new RouteNode<>(connection));
|
||||
allNodes.put(connection, nextNode);
|
||||
|
||||
if (nextNode.getRouteScore() > newScore) {
|
||||
nextNode.setPrevious(next.getCurrent());
|
||||
nextNode.setRouteScore(newScore);
|
||||
nextNode.setEstimatedScore(newScore + targetScorer.computeCost(connection, to));
|
||||
openSet.add(nextNode);
|
||||
log.debug("Found a better route to node: " + nextNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
throw new IllegalStateException("No route found");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.baeldung.algorithms.astar;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
class RouteNode<T extends GraphNode> implements Comparable<RouteNode> {
|
||||
private final T current;
|
||||
private T previous;
|
||||
private double routeScore;
|
||||
private double estimatedScore;
|
||||
|
||||
RouteNode(T current) {
|
||||
this(current, null, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
|
||||
}
|
||||
|
||||
RouteNode(T current, T previous, double routeScore, double estimatedScore) {
|
||||
this.current = current;
|
||||
this.previous = previous;
|
||||
this.routeScore = routeScore;
|
||||
this.estimatedScore = estimatedScore;
|
||||
}
|
||||
|
||||
T getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
T getPrevious() {
|
||||
return previous;
|
||||
}
|
||||
|
||||
double getRouteScore() {
|
||||
return routeScore;
|
||||
}
|
||||
|
||||
double getEstimatedScore() {
|
||||
return estimatedScore;
|
||||
}
|
||||
|
||||
void setPrevious(T previous) {
|
||||
this.previous = previous;
|
||||
}
|
||||
|
||||
void setRouteScore(double routeScore) {
|
||||
this.routeScore = routeScore;
|
||||
}
|
||||
|
||||
void setEstimatedScore(double estimatedScore) {
|
||||
this.estimatedScore = estimatedScore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(RouteNode other) {
|
||||
if (this.estimatedScore > other.estimatedScore) {
|
||||
return 1;
|
||||
} else if (this.estimatedScore < other.estimatedScore) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringJoiner(", ", RouteNode.class.getSimpleName() + "[", "]").add("current=" + current)
|
||||
.add("previous=" + previous).add("routeScore=" + routeScore).add("estimatedScore=" + estimatedScore)
|
||||
.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package com.baeldung.algorithms.astar;
|
||||
|
||||
public interface Scorer<T extends GraphNode> {
|
||||
double computeCost(T from, T to);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.baeldung.algorithms.astar.underground;
|
||||
|
||||
import com.baeldung.algorithms.astar.Scorer;
|
||||
|
||||
public class HaversineScorer implements Scorer<Station> {
|
||||
@Override
|
||||
public double computeCost(Station from, Station to) {
|
||||
double R = 6372.8; // In kilometers
|
||||
|
||||
double dLat = Math.toRadians(to.getLatitude() - from.getLatitude());
|
||||
double dLon = Math.toRadians(to.getLongitude() - from.getLongitude());
|
||||
double lat1 = Math.toRadians(from.getLatitude());
|
||||
double lat2 = Math.toRadians(to.getLatitude());
|
||||
|
||||
double a = Math.pow(Math.sin(dLat / 2),2) + Math.pow(Math.sin(dLon / 2),2) * Math.cos(lat1) * Math.cos(lat2);
|
||||
double c = 2 * Math.asin(Math.sqrt(a));
|
||||
return R * c;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.baeldung.algorithms.astar.underground;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import com.baeldung.algorithms.astar.GraphNode;
|
||||
|
||||
public class Station implements GraphNode {
|
||||
private final String id;
|
||||
private final String name;
|
||||
private final double latitude;
|
||||
private final double longitude;
|
||||
|
||||
public Station(String id, String name, double latitude, double longitude) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringJoiner(", ", Station.class.getSimpleName() + "[", "]").add("id='" + id + "'")
|
||||
.add("name='" + name + "'").add("latitude=" + latitude).add("longitude=" + longitude).toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.algorithms.editdistance;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EditDistanceBase {
|
||||
|
||||
static int costOfSubstitution(char a, char b) {
|
||||
return a == b ? 0 : 1;
|
||||
}
|
||||
|
||||
static int min(int... numbers) {
|
||||
return Arrays.stream(numbers)
|
||||
.min().orElse(Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.algorithms.editdistance;
|
||||
|
||||
public class EditDistanceDynamicProgramming extends EditDistanceBase {
|
||||
|
||||
static int calculate(String x, String y) {
|
||||
int[][] dp = new int[x.length() + 1][y.length() + 1];
|
||||
|
||||
for (int i = 0; i <= x.length(); i++) {
|
||||
for (int j = 0; j <= y.length(); j++) {
|
||||
if (i == 0)
|
||||
dp[i][j] = j;
|
||||
|
||||
else if (j == 0)
|
||||
dp[i][j] = i;
|
||||
|
||||
else {
|
||||
dp[i][j] = min(dp[i - 1][j - 1]
|
||||
+ costOfSubstitution(x.charAt(i - 1), y.charAt(j - 1)),
|
||||
dp[i - 1][j] + 1, dp[i][j - 1] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[x.length()][y.length()];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.baeldung.algorithms.editdistance;
|
||||
|
||||
public class EditDistanceRecursive extends EditDistanceBase {
|
||||
|
||||
static int calculate(String x, String y) {
|
||||
|
||||
if (x.isEmpty()) {
|
||||
return y.length();
|
||||
}
|
||||
|
||||
if (y.isEmpty()) {
|
||||
return x.length();
|
||||
}
|
||||
|
||||
int substitution = calculate(x.substring(1), y.substring(1)) + costOfSubstitution(x.charAt(0), y.charAt(0));
|
||||
int insertion = calculate(x, y.substring(1)) + 1;
|
||||
int deletion = calculate(x.substring(1), y) + 1;
|
||||
|
||||
return min(substitution, insertion, deletion);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class CycleDetectionBruteForce {
|
||||
|
||||
public static <T> CycleDetectionResult<T> detectCycle(Node<T> head) {
|
||||
if (head == null) {
|
||||
return new CycleDetectionResult<>(false, null);
|
||||
}
|
||||
|
||||
Node<T> it1 = head;
|
||||
int nodesTraversedByOuter = 0;
|
||||
while (it1 != null && it1.next != null) {
|
||||
it1 = it1.next;
|
||||
nodesTraversedByOuter++;
|
||||
|
||||
int x = nodesTraversedByOuter;
|
||||
Node<T> it2 = head;
|
||||
int noOfTimesCurrentNodeVisited = 0;
|
||||
|
||||
while (x > 0) {
|
||||
it2 = it2.next;
|
||||
|
||||
if (it2 == it1) {
|
||||
noOfTimesCurrentNodeVisited++;
|
||||
}
|
||||
|
||||
if (noOfTimesCurrentNodeVisited == 2) {
|
||||
return new CycleDetectionResult<>(true, it1);
|
||||
}
|
||||
|
||||
x--;
|
||||
}
|
||||
}
|
||||
|
||||
return new CycleDetectionResult<>(false, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class CycleDetectionByFastAndSlowIterators {
|
||||
|
||||
public static <T> CycleDetectionResult<T> detectCycle(Node<T> head) {
|
||||
if (head == null) {
|
||||
return new CycleDetectionResult<>(false, null);
|
||||
}
|
||||
|
||||
Node<T> slow = head;
|
||||
Node<T> fast = head;
|
||||
|
||||
while (fast != null && fast.next != null) {
|
||||
slow = slow.next;
|
||||
fast = fast.next.next;
|
||||
|
||||
if (slow == fast) {
|
||||
return new CycleDetectionResult<>(true, fast);
|
||||
}
|
||||
}
|
||||
|
||||
return new CycleDetectionResult<>(false, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class CycleDetectionByHashing {
|
||||
|
||||
public static <T> CycleDetectionResult<T> detectCycle(Node<T> head) {
|
||||
if (head == null) {
|
||||
return new CycleDetectionResult<>(false, null);
|
||||
}
|
||||
|
||||
Set<Node<T>> set = new HashSet<>();
|
||||
Node<T> node = head;
|
||||
|
||||
while (node != null) {
|
||||
if (set.contains(node)) {
|
||||
return new CycleDetectionResult<>(true, node);
|
||||
}
|
||||
set.add(node);
|
||||
node = node.next;
|
||||
}
|
||||
|
||||
return new CycleDetectionResult<>(false, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class CycleDetectionResult<T> {
|
||||
boolean cycleExists;
|
||||
Node<T> node;
|
||||
|
||||
public CycleDetectionResult(boolean cycleExists, Node<T> node) {
|
||||
super();
|
||||
this.cycleExists = cycleExists;
|
||||
this.node = node;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.baeldung.algorithms.linkedlist;
|
||||
|
||||
public class CycleRemovalBruteForce {
|
||||
|
||||
public static <T> boolean detectAndRemoveCycle(Node<T> head) {
|
||||
CycleDetectionResult<T> result = CycleDetectionByFastAndSlowIterators.detectCycle(head);
|
||||
|
||||
if (result.cycleExists) {
|
||||
removeCycle(result.node, head);
|
||||
}
|
||||
|
||||
return result.cycleExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loopNodeParam - reference to the node where Flyods cycle
|
||||
* finding algorithm ends, i.e. the fast and the slow iterators
|
||||
* meet.
|
||||
* @param head - reference to the head of the list
|
||||
*/
|
||||
private static <T> void removeCycle(Node<T> loopNodeParam, Node<T> head) {
|
||||
Node<T> it = head;
|
||||
|
||||
while (it != null) {
|
||||
if (isNodeReachableFromLoopNode(it, loopNodeParam)) {
|
||||
Node<T> loopStart = it;
|
||||
findEndNodeAndBreakCycle(loopStart);
|
||||
break;
|
||||
}
|
||||
it = it.next;
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> boolean isNodeReachableFromLoopNode(Node<T> it, Node<T> loopNodeParam) {
|
||||
Node<T> loopNode = loopNodeParam;
|
||||
|
||||
do {
|
||||
if (it == loopNode) {
|
||||
return true;
|
||||
}
|
||||
loopNode = loopNode.next;
|
||||
} while (loopNode.next != loopNodeParam);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static <T> void findEndNodeAndBreakCycle(Node<T> loopStartParam) {
|
||||
Node<T> loopStart = loopStartParam;
|
||||
|
||||
while (loopStart.next != loopStartParam) {
|
||||
loopStart = loopStart.next;
|
||||
}
|
||||
|
||||
loopStart.next = null;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue