From 137e182f5518fd0080887e8d5c9a7a06fee7e8b8 Mon Sep 17 00:00:00 2001 From: Parth Karia Date: Tue, 6 Jun 2017 00:25:47 +0530 Subject: [PATCH] BAEL-875 Example of Hill Climbing algorithm (#1968) * Dependency Injection examples Dependency Injection examples for evaluation article * Junit test cases added for dependency injection Junit test cases added for dependency injection * ClassNotFoundException vs NoClassDefFoundError Example to reproduce ClassNotFoundException & NoClassDefFoundError * JUnit test cases for ClassNotFoundException & NoClassDefFoundError test cases to reproduce ClassNotFoundException & NoClassDefFoundError * Deleting exampls for evaluation article * BAEL-831 Examples for ClassNotFoundException & NoClassDefFoundError * BAEL-831 Removed wrapper class * Removing evaluation article example * BAEL-831 removed wrapper class * BAEL-875 - Hill Climbing Algorithm BAEL-875 - Implementation for Hill Climbing Algorithm * BAEL-875 Modified algorithm with stream api --- .../algorithms/hillclimbing/HillClimbing.java | 199 ++++++++++++++++++ .../algorithms/hillclimbing/State.java | 50 +++++ .../algorithms/HillClimbingAlgorithmTest.java | 58 +++++ 3 files changed, 307 insertions(+) create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/hillclimbing/HillClimbing.java create mode 100644 algorithms/src/main/java/com/baeldung/algorithms/hillclimbing/State.java create mode 100644 algorithms/src/test/java/algorithms/HillClimbingAlgorithmTest.java diff --git a/algorithms/src/main/java/com/baeldung/algorithms/hillclimbing/HillClimbing.java b/algorithms/src/main/java/com/baeldung/algorithms/hillclimbing/HillClimbing.java new file mode 100644 index 0000000000..3523ff07c0 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/hillclimbing/HillClimbing.java @@ -0,0 +1,199 @@ +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; +import java.util.stream.Collectors; + +public class HillClimbing { + public static void main(String[] args) { + HillClimbing hillClimbing = new HillClimbing(); + String blockArr[] = { "B", "C", "D", "A" }; + Stack startState = hillClimbing.getStackWithValues(blockArr); + String goalBlockArr[] = { "A", "B", "C", "D" }; + Stack goalState = hillClimbing.getStackWithValues(goalBlockArr); + try { + List solutionSequence = hillClimbing.getRouteWithHillClimbing(startState, goalState); + solutionSequence.forEach(HillClimbing::printEachStep); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void printEachStep(State state) { + List> stackList = state.getState(); + System.out.println("----------------"); + stackList.forEach(stack -> { + while (!stack.isEmpty()) { + System.out.println(stack.pop()); + } + System.out.println(" "); + }); + } + + public Stack getStackWithValues(String[] blocks) { + Stack stack = new Stack(); + for (String block : blocks) + stack.push(block); + return stack; + } + + /** + * This method prepares path from init state to goal state + * + * @param initStateStack + * @param goalStateStack + * @return + * @throws Exception + */ + public List getRouteWithHillClimbing(Stack initStateStack, Stack goalStateStack) throws Exception { + List> initStateStackList = new ArrayList>(); + initStateStackList.add(initStateStack); + int initStateHeuristics = getHeuristicsValue(initStateStackList, goalStateStack); + State initState = new State(initStateStackList, initStateHeuristics); + + List 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)); + } + } + + if (noStateFound) + throw new Exception("No path found"); + return resultPath; + } + + /** + * This method finds new state from current state based on goal and + * heuristics + * + * @param currentState + * @param goalStateStack + * @return a next state + */ + public State findNextState(State currentState, Stack goalStateStack) { + List> listOfStacks = currentState.getState(); + int currentStateHeuristics = currentState.getHeuristics(); + + Optional newState = listOfStacks.stream() + .map(stack -> { + State tempState = null; + List> 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; + }) + .filter(Objects::nonNull) + .findFirst(); + + return newState.orElse(null); + } + + /** + * Operation to be applied on a state in order to find new states. This + * operation pushes an element into a new stack + * + * @param currentStackList + * @param block + * @param currentStateHeuristics + * @param goalStateStack + * @return a new state + */ + private State pushElementToNewStack(List> currentStackList, String block, int currentStateHeuristics, Stack goalStateStack) { + State newState = null; + Stack 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 + * + * @param stack + * @param currentStackList + * @param block + * @param currentStateHeuristics + * @param goalStateStack + * @return a new state + */ + private State pushElementToExistingStacks(Stack currentStack, List> currentStackList, String block, int currentStateHeuristics, Stack goalStateStack) { + + Optional newState = currentStackList.stream() + .filter(stack -> stack != currentStack) + .map(stack -> { + stack.push(block); + int newStateHeuristics = getHeuristicsValue(currentStackList, goalStateStack); + if (newStateHeuristics > currentStateHeuristics) { + return new State(currentStackList, newStateHeuristics); + } + stack.pop(); + return null; + }) + .filter(Objects::nonNull) + .findFirst(); + + return newState.orElse(null); + } + + /** + * This method returns heuristics value for given state with respect to goal + * state + * + * @param currentState + * @param goalStateStack + * @return + */ + public int getHeuristicsValue(List> currentState, Stack goalStateStack) { + + Integer heuristicValue = 0; + heuristicValue = currentState.stream() + .mapToInt(stack -> { + 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; + }) + .sum(); + return heuristicValue; + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/hillclimbing/State.java b/algorithms/src/main/java/com/baeldung/algorithms/hillclimbing/State.java new file mode 100644 index 0000000000..dc49c782fa --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/hillclimbing/State.java @@ -0,0 +1,50 @@ +package com.baeldung.algorithms.hillclimbing; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class State { + List> state; + int heuristics; + + public State() { + } + + public State(List> state) { + this.state = state; + } + + public State(List> state, int heuristics) { + this.state = state; + this.heuristics = heuristics; + } + + public State(State state) { + if (state != null) { + this.state = new ArrayList>(); + for (Stack s : state.getState()) { + Stack s1 = new Stack(); + s1 = (Stack) s.clone(); + this.state.add(s1); + } + this.heuristics = state.getHeuristics(); + } + } + + public List> getState() { + return state; + } + + public void setState(List> state) { + this.state = state; + } + + public int getHeuristics() { + return heuristics; + } + + public void setHeuristics(int heuristics) { + this.heuristics = heuristics; + } +} diff --git a/algorithms/src/test/java/algorithms/HillClimbingAlgorithmTest.java b/algorithms/src/test/java/algorithms/HillClimbingAlgorithmTest.java new file mode 100644 index 0000000000..f040d3a4ca --- /dev/null +++ b/algorithms/src/test/java/algorithms/HillClimbingAlgorithmTest.java @@ -0,0 +1,58 @@ +package algorithms; + +import com.baeldung.algorithms.hillclimbing.HillClimbing; +import com.baeldung.algorithms.hillclimbing.State; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class HillClimbingAlgorithmTest { + Stack initStack; + Stack goalStack; + + @Before + 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 + public void givenInitAndGoalState_whenGetPathWithHillClimbing_thenPathFound() { + HillClimbing hillClimbing = new HillClimbing(); + + List 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 + public void givenCurrentState_whenFindNextState_thenBetterHeuristics() { + HillClimbing hillClimbing = new HillClimbing(); + List> 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()); + } +}