From dd3b6173ad84d94e7c88a18f170108a7367da124 Mon Sep 17 00:00:00 2001
From: Marcel Becker <stu117960@mail.uni-kiel.de>
Date: Sun, 12 Dec 2021 19:40:22 +0100
Subject: [PATCH] Added GuessStrategy Interface Implementation

---
 .../searchstrategy/GuessStrategy.kt           | 22 +++++++++++++++++
 .../InitialGuessSearchStrategy.kt             | 18 +++++++-------
 .../searchstrategy/PrevResourceMinGuess.kt    | 24 +++++++++++++++++++
 .../searchstrategy/SearchStrategy.kt          |  4 +++-
 .../InitialGuessSearchStrategyTest.kt         | 16 ++++++++-----
 5 files changed, 68 insertions(+), 16 deletions(-)
 create mode 100644 theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/GuessStrategy.kt
 create mode 100644 theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/PrevResourceMinGuess.kt

diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/GuessStrategy.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/GuessStrategy.kt
new file mode 100644
index 000000000..786a3baf1
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/GuessStrategy.kt
@@ -0,0 +1,22 @@
+package theodolite.strategies.searchstrategy
+
+import io.quarkus.runtime.annotations.RegisterForReflection
+import theodolite.util.Resource
+
+/**
+ * Base class for the implementation of Guess strategies. Guess strategies are strategies to determine the resource
+ * demand we start with in our initial guess search strategy.
+ */
+
+@RegisterForReflection
+abstract class GuessStrategy {
+    /**
+     * Computing the resource demand for the initial guess search strategy to start with.
+     *
+     * @param resources List of all possible [Resource]s.
+     * @param lastLowestResource Previous resource demand needed for the given load.
+     *
+     * @return Returns the resource demand to start the initial guess search strategy with or null
+     */
+    abstract fun firstGuess(resources: List<Resource>, lastLowestResource: Resource?): Resource?
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt
index 44d6928d6..432f08fde 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt
@@ -8,23 +8,23 @@ import theodolite.util.Resource
 private val logger = KotlinLogging.logger {}
 
 /**
- *  Search strategy implementation for determining the smallest suitable number of instances, which takes the
- *  resource demand of the previous load into account as a starting point for the search.
+ *  Search strategy implementation for determining the smallest suitable resource demand.
+ *  Starting with a resource amount provided by a guess strategy.
  *
  * @param benchmarkExecutor Benchmark executor which runs the individual benchmarks.
+ * @param guessStrategy Strategy that provides us with a guess for the first resource amount.
  */
-class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor) : SearchStrategy(benchmarkExecutor) {
+class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor, guessStrategy: GuessStrategy) : SearchStrategy(benchmarkExecutor, guessStrategy) {
 
     override fun findSuitableResource(load: LoadDimension, resources: List<Resource>, lastLowestResource: Resource?): Resource? {
 
-        var lastLowestResourceToUse = lastLowestResource
-
-        // This Search strategy needs a resource demand to start the search with,
-        // if this is not provided it will be set to the first resource of the given resource-list
-        if(lastLowestResource == null && resources.isNotEmpty()){
-            lastLowestResourceToUse = resources[0]
+        if(guessStrategy == null){
+            logger.info { "Your InitialGuessSearchStrategy doesn't have a GuessStrategy. This is not supported." }
+            return null
         }
 
+        var lastLowestResourceToUse = this.guessStrategy.firstGuess(resources, lastLowestResource)
+
         if (lastLowestResourceToUse != null) {
             val resourcesToCheck: List<Resource>
             val startIndex: Int = resources.indexOf(lastLowestResourceToUse)
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/PrevResourceMinGuess.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/PrevResourceMinGuess.kt
new file mode 100644
index 000000000..413eecea2
--- /dev/null
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/PrevResourceMinGuess.kt
@@ -0,0 +1,24 @@
+package theodolite.strategies.searchstrategy
+
+import theodolite.util.Resource
+
+/**
+ * This Guess strategy takes the minimal resource demand of the previous load, which is given as an argument for the
+ * firstGuess function.
+ */
+
+class PrevResourceMinGuess() : GuessStrategy(){
+
+    /**
+     * @param resources List of all possible [Resource]s.
+     * @param lastLowestResource Previous resource demand needed for the given load.
+     *
+     * @return the value of lastLowestResource if given otherwise the first element of the resource list or null
+     */
+    override fun firstGuess(resources: List<Resource>, lastLowestResource: Resource?): Resource? {
+
+        if (lastLowestResource != null) return lastLowestResource
+        else if(resources.isNotEmpty()) return resources[0]
+        else return null
+    }
+}
\ No newline at end of file
diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/SearchStrategy.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/SearchStrategy.kt
index b7994617b..e37cc32b5 100644
--- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/SearchStrategy.kt
+++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/SearchStrategy.kt
@@ -9,14 +9,16 @@ import theodolite.util.Resource
  *  Base class for the implementation for SearchStrategies. SearchStrategies determine the smallest suitable number of instances.
  *
  * @param benchmarkExecutor Benchmark executor which runs the individual benchmarks.
+ * @param guessStrategy Guess strategy for the initial resource amount in case the InitialGuessStrategy is selected.
  */
 @RegisterForReflection
-abstract class SearchStrategy(val benchmarkExecutor: BenchmarkExecutor) {
+abstract class SearchStrategy(val benchmarkExecutor: BenchmarkExecutor, val guessStrategy: GuessStrategy? = null) {
     /**
      * Find smallest suitable resource from the specified resource list for the given load.
      *
      * @param load the [LoadDimension] to be tested.
      * @param resources List of all possible [Resource]s.
+     * @param lastLowestResource Previous resource demand needed for the given load.
      *
      * @return suitable resource for the specified load, or null if no suitable resource exists.
      */
diff --git a/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt b/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt
index f90b96ee1..f7f52a6da 100644
--- a/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt
+++ b/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt
@@ -9,6 +9,7 @@ import theodolite.util.LoadDimension
 import theodolite.util.Resource
 import theodolite.util.Results
 import mu.KotlinLogging
+import theodolite.strategies.searchstrategy.PrevResourceMinGuess
 
 private val logger = KotlinLogging.logger {}
 
@@ -16,7 +17,7 @@ private val logger = KotlinLogging.logger {}
 class InitialGuessSearchStrategyTest {
 
     @Test
-    fun testEnd2EndInitialGuessSearch() {
+    fun testInitialGuessSearch() {
         val mockResults = arrayOf(
             arrayOf(true, true, true, true, true, true, true),
             arrayOf(false, false, true, true, true, true, true),
@@ -30,9 +31,10 @@ class InitialGuessSearchStrategyTest {
         val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) }
         val results = Results()
         val benchmark = TestBenchmark()
+        val guessStrategy = PrevResourceMinGuess()
         val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
         val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
-        val strategy = InitialGuessSearchStrategy(benchmarkExecutor)
+        val strategy = InitialGuessSearchStrategy(benchmarkExecutor,guessStrategy)
 
         val actual: ArrayList<Resource?> = ArrayList()
         val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 3, 4, 6).map { x -> Resource(x, emptyList()) })
@@ -56,7 +58,7 @@ class InitialGuessSearchStrategyTest {
     }
 
     @Test
-    fun testEnd2EndInitialGuessSearchLowerResourceDemandHigherLoad() {
+    fun testInitialGuessSearchLowerResourceDemandHigherLoad() {
         val mockResults = arrayOf(
             arrayOf(true, true, true, true, true, true, true),
             arrayOf(false, false, true, true, true, true, true),
@@ -70,9 +72,10 @@ class InitialGuessSearchStrategyTest {
         val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) }
         val results = Results()
         val benchmark = TestBenchmark()
+        val guessStrategy = PrevResourceMinGuess()
         val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
         val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
-        val strategy = InitialGuessSearchStrategy(benchmarkExecutor)
+        val strategy = InitialGuessSearchStrategy(benchmarkExecutor,guessStrategy)
 
         val actual: ArrayList<Resource?> = ArrayList()
         val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 1, 4, 6).map { x -> Resource(x, emptyList()) })
@@ -96,7 +99,7 @@ class InitialGuessSearchStrategyTest {
     }
 
     @Test
-    fun testEnd2EndInitialGuessSearchFirstNotDoable() {
+    fun testInitialGuessSearchFirstNotDoable() {
         val mockResults = arrayOf(
                 arrayOf(false, false, false, false, false, false, false),
                 arrayOf(false, false, true, true, true, true, true),
@@ -110,9 +113,10 @@ class InitialGuessSearchStrategyTest {
         val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) }
         val results = Results()
         val benchmark = TestBenchmark()
+        val guessStrategy = PrevResourceMinGuess()
         val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
         val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
-        val strategy = InitialGuessSearchStrategy(benchmarkExecutor)
+        val strategy = InitialGuessSearchStrategy(benchmarkExecutor, guessStrategy)
 
         val actual: ArrayList<Resource?> = ArrayList()
         var expected: ArrayList<Resource?> = ArrayList(listOf(2, 3, 0, 4, 6).map { x -> Resource(x, emptyList()) })
-- 
GitLab