From 0dcae84e5f7cb6aaa5e8574c1028565476e27a34 Mon Sep 17 00:00:00 2001 From: norangebit Date: Sun, 17 Mar 2019 19:28:14 +0100 Subject: [PATCH] prefix average - add test - add measure class - add report --- .gitignore | 3 + doc/exercises/prefix_average.md | 57 ++++++++++++++ .../algorithms/exercises/PrefixAverage.kt | 43 +++++++++++ .../algorithms/exercises/MeasureTime.kt | 74 +++++++++++++++++++ .../algorithms/exercises/PrefixAverageTest.kt | 70 ++++++++++++++++++ 5 files changed, 247 insertions(+) create mode 100644 doc/exercises/prefix_average.md create mode 100644 src/main/kotlin/it/norangeb/algorithms/exercises/PrefixAverage.kt create mode 100644 src/test/kotlin/it/norangeb/algorithms/exercises/MeasureTime.kt create mode 100644 src/test/kotlin/it/norangeb/algorithms/exercises/PrefixAverageTest.kt diff --git a/.gitignore b/.gitignore index 12fe925..b1dd38e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 +# pdf +*.pdf + # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml diff --git a/doc/exercises/prefix_average.md b/doc/exercises/prefix_average.md new file mode 100644 index 0000000..94f0600 --- /dev/null +++ b/doc/exercises/prefix_average.md @@ -0,0 +1,57 @@ +--- +author: Raffaele Mignone +title: Caratterizzazione della complessità di un algoritmo per il calcolo della prefix average +keywords: + - Complessità + - Prefix average +subject: Caratterizzazione della complessità +classoption: +papersize: a4 +colorlinks: true +lang: it-IT +--- + +# Prefix average + +## Traccia + +Scrivere un algoritmo per il calcolo del *prefix average* per un array numerico e caratterizzarne la complessità. + +```{#lst:prefixavg .kotlin caption="Algoritmo per il calcolo della prefix average"} +fun prefixAverage(arrayIn: IntArray): IntArray { + + val arrayOut = IntArray(arrayIn.size) + var currentSum = 0 + + for (i in 0 until arrayIn.size) { + currentSum += arrayIn[i] + arrayOut[i] = currentSum / (i + 1) + } + + return arrayOut +} +``` + +## Caratterizzazione della complessità + +La caratterizzazione della complessità dell'algoritmo è stata svolta seguendo due metodologie; il metodo sperimentale e il metodo dell'ordine di grandezza. + +### Metodo sperimentale + +Il metodo sperimentale consiste nell'eseguire una serie di osservazioni sperimentali e di dedurre una legge da esse. + +Nel caso specifico si è misurato il tempo di esecuzione dell'[algoritmo @lst:prefixavg] avente come ingresso un array di `8000` interi casuali. +L'osservazione è stata ripetuta altre quattordici volte raddoppiando ogni volta la dimensione dell'array. + +I dati sono stati riportati in un [foglio di calcolo][spreadsheet] e sono state plottate sia la curva $T(N)$ che la curva $ln(T(N))$. +Le due curve presentano un andamento lineare, soprattutto se non si tiene conto delle prime osservazioni svolte su un numero limitato di elementi e quindi maggiormente influenzate dal calcolatore. + +### Metodo dell'ordine di grandezza + +Il metodo dell'ordine di grandezza consiste nell'assegnare un costo all'operazione fondamentale e vedere come quest'operazione dipende dal numero degli elementi in gioco. + +Nel caso del @lst:prefixavg prendiamo come operazione di riferimento l'accesso ad un elemento dell'array. +Ad ogni iterazione viene letto un elemento dall'array d'ingresso e scritto l'elemento calcolato nell'array d'uscita. +Quindi il tempo dominante nell'esecuzione dell'algoritmo è $2cN$ dove $c$ è il tempo impiegato per accedere ad un elemento dell'array e $N$ è il numero di elementi dell'array; per cui l'ordine di grandezza dell'algoritmo è pari ad $N$, quindi lineare. + +[spreadsheet]: https://docs.google.com/spreadsheets/d/1EySx1UOZ8zoDl1uqVyLpQxZRGkD0-75qb9HeyEri1d4/edit?usp=sharing diff --git a/src/main/kotlin/it/norangeb/algorithms/exercises/PrefixAverage.kt b/src/main/kotlin/it/norangeb/algorithms/exercises/PrefixAverage.kt new file mode 100644 index 0000000..907b2ad --- /dev/null +++ b/src/main/kotlin/it/norangeb/algorithms/exercises/PrefixAverage.kt @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.exercises + +class PrefixAverage { + companion object { + fun prefixAverage(arrayIn: IntArray): IntArray { + + val arrayOut = IntArray(arrayIn.size) + var currentSum = 0 + + for (i in 0 until arrayIn.size) { + currentSum += arrayIn[i] + arrayOut[i] = currentSum / (i + 1) + } + + return arrayOut + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/it/norangeb/algorithms/exercises/MeasureTime.kt b/src/test/kotlin/it/norangeb/algorithms/exercises/MeasureTime.kt new file mode 100644 index 0000000..0b24b67 --- /dev/null +++ b/src/test/kotlin/it/norangeb/algorithms/exercises/MeasureTime.kt @@ -0,0 +1,74 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.exercises + +import java.io.PrintStream +import kotlin.math.roundToInt +import kotlin.random.Random +import kotlin.system.measureNanoTime + +fun main(args: Array) { + val out = try { + PrintStream(args[0]) + } catch (e: Exception) { + System.out + } + + TimeMeasure(out) + .run() +} + +class TimeMeasure(private val out: PrintStream) { + fun run() { + val random = Random(System.currentTimeMillis()) + (0 until NUMBER_OF_ITERATION).map { + val numberOfSamples = DEFAULT_SAMPLES * + Math.pow(GROWTH_FACTOR.toDouble(), it.toDouble()) + .roundToInt() + + val listOfInt = ArrayList() + repeat(numberOfSamples) { + listOfInt.add(random.nextInt(0, 100)) + } + + val arrayIn = listOfInt.toIntArray() + + val totalTime = measureNanoTime { + PrefixAverage.prefixAverage(arrayIn) + } + + Pair(numberOfSamples, totalTime) + }.forEach { + out.println("${it.first}, ${it.second}") + } + } + + companion object { + const val DEFAULT_SAMPLES = 8000 + const val NUMBER_OF_ITERATION = 15 + const val GROWTH_FACTOR = 2 + } +} \ No newline at end of file diff --git a/src/test/kotlin/it/norangeb/algorithms/exercises/PrefixAverageTest.kt b/src/test/kotlin/it/norangeb/algorithms/exercises/PrefixAverageTest.kt new file mode 100644 index 0000000..584ff4e --- /dev/null +++ b/src/test/kotlin/it/norangeb/algorithms/exercises/PrefixAverageTest.kt @@ -0,0 +1,70 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.exercises + +import org.amshove.kluent.`should equal` +import org.junit.jupiter.api.Test + +class PrefixAverageTest { + + @Test + fun testNominalCase() { + val arrayIn = intArrayOf(21, 23, 25, 31, 20, 18, 16) + + val arrayOut = PrefixAverage.prefixAverage(arrayIn) + + arrayOut `should equal` intArrayOf( + 21, 22, 23, 25, 24, 23, 22 + ) + } + + @Test + fun testEmptyArray() { + val arrayIn = intArrayOf() + + val arrayOut = PrefixAverage.prefixAverage(arrayIn) + + arrayOut `should equal` intArrayOf() + } + + @Test + fun testOneElementArray() { + val arrayIn = intArrayOf(25) + + val arrayOut = PrefixAverage.prefixAverage(arrayIn) + + arrayOut `should equal` intArrayOf(25) + } + + @Test + fun testAlwaysSameElementArray() { + val arrayIn = intArrayOf(21, 21, 21, 21, 21) + + val arrayOut = PrefixAverage.prefixAverage(arrayIn) + + arrayOut `should equal` intArrayOf(21, 21, 21, 21, 21) + } +} \ No newline at end of file