├── LICENSE ├── README.md ├── _config.yml └── src ├── main └── scala │ ├── additionalArithmetics │ └── Rational.scala │ ├── asynchronous │ ├── UsefulFuture.scala │ └── UsefulOption.scala │ ├── charOperations │ ├── CharProperties.scala │ └── miscellaneous │ │ └── ImportantConstants.scala │ ├── combinatorics │ └── combinatorics.scala │ ├── complexOperations │ ├── Complex.scala │ └── package.scala │ ├── cryptographyOperations │ ├── decoders │ │ ├── GrayDecoder.scala │ │ ├── HuffmanDecoder.scala │ │ ├── MorseDecoder.scala │ │ └── RLE_Decoder.scala │ └── encoders │ │ ├── GrayEncoder.scala │ │ ├── HuffmanEncoder.scala │ │ ├── MorseEncoder.scala │ │ └── RLE_Encoder.scala │ ├── dataStructures │ ├── BinaryTree.scala │ ├── Heap.scala │ ├── LinkedList.scala │ ├── Queue.scala │ ├── RedBlackTree.scala │ ├── Set.scala │ ├── Stack.scala │ └── miscellaneous │ │ ├── DataStructureException.scala │ │ └── DataStructuresExceptionMessages.scala │ ├── doubleOperations │ └── DoubleProperties.scala │ ├── integerOperations │ ├── IntegerGenerators.scala │ ├── IntegerGeneratorsMath.scala │ ├── IntegerMath.scala │ └── IntegerProperties.scala │ ├── lambdaCalculus │ ├── PolymorphicLambdaCalculus.scala │ └── PureLambdaCalculus.scala │ ├── listOperations │ ├── Changes.scala │ ├── ListProperties.scala │ └── miscellaneous │ │ ├── CustomCaseClasses.scala │ │ └── CustomImplicitConversions.scala │ ├── sortingAlgorithms │ ├── BubbleSort.scala │ ├── HeapSort.scala │ ├── InsertionSort.scala │ ├── MergeSort.scala │ ├── QuickSort.scala │ ├── SelectionSort.scala │ └── unseriousAlgorithms │ │ ├── Bogosort.scala │ │ └── SleepSort.scala │ ├── statistics │ └── KolmogorovSmirnov.scala │ ├── time │ └── Time.scala │ └── utils │ ├── ExceptionMessages.scala │ ├── InputException.scala │ └── MathConstants.scala └── test └── scala └── unitTests ├── CharTests.scala ├── ComplexOperationsTests.scala ├── DataStructuresTests.scala ├── DoubleTests.scala ├── EncodersDecodersTests.scala ├── IntegerGeneratorsMathTests.scala ├── IntegerGeneratorsTests.scala ├── IntegerTests.scala ├── ListsTests.scala ├── OperationTests.scala ├── RationalOperationsTest.scala ├── SortingAlgorithmsTests.scala └── TimeTests.scala /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Tekunov Daniil 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Purity project 4 | 5 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/7b1a99f92fb34e7487bdaa1a145e3bc8)](https://app.codacy.com/app/ditekunov/Purity-Project?utm_source=github.com&utm_medium=referral&utm_content=ditekunov/Purity-Project&utm_campaign=badger) 6 | 7 | This project contains realisations of common-used math functions and classical algorithms, written in Scala's pure-functional style. 8 | 9 | Some of them are a new sight at Scala's standard library, some are persistent data structures, some are completely new functions. 10 | 11 | The main purpose of this library is to spread ideas of a functional programming in Scala and to challenge yourself by creating classical imperative algorithms in a new way. 12 | 13 | Would be great, if you contribute, in case that presented algorithms are not as effective as they can be, and you know how to fix this, or if you have ideas, that can be added in the future. 14 | 15 | # Current list of supported algorithms: 16 | 17 | ### Sorting algorithms: 18 | 1) Quick sort [`sortingAlgorithms/QuickSort`](src/main/scala/sortingAlgorithms/QuickSort.scala) 19 | 20 | 2) Bogosort [`sortingAlgorithms/unseriousAlgorithms/Bogosort`](src/main/scala/sortingAlgorithms/unseriousAlgorithms/Bogosort.scala) 21 | 22 | 3) Sleep sort [`sortingAlgorithms/unseriousAlgorithms/SleepSort`](src/main/scala/sortingAlgorithms/unseriousAlgorithms/SleepSort.scala) 23 | 24 | 4) Bubble sort [`sortingAlgorithms/BubbleSort`](src/main/scala/sortingAlgorithms/BubbleSort.scala) 25 | 26 | 5) Merge sort [`sortingAlgorithms/MergeSort`](src/main/scala/sortingAlgorithms/MergeSort.scala) 27 | 28 | 6) Insertion sort [`sortingAlgorithms/InsertionSort`](src/main/scala/sortingAlgorithms/InsertionSort.scala) 29 | 30 | 7) Selection sort [`sortingAlgorithms.SelectionSort`](src/main/scala/sortingAlgorithms/SelectionSort.scala) 31 | 32 | 8) Heap sort [`sortingAlgorithms.HeapSort`](src/main/scala/sortingAlgorithms/HeapSort.scala) 33 | 34 | ### Persistent data structures: 35 | 1) LinkedList [`dataStructures.LinkedList`](src/main/scala/dataStructures/LinkedList.scala) 36 | 37 | 2) Queue [`dataStructures.Queue`](src/main/scala/dataStructures/Queue.scala) 38 | 39 | 3) Stack [`dataStructures.Stack`](src/main/scala/dataStructures/Stack.scala) 40 | 41 | 4) Set [`dataStructures.Set`](src/main/scala/dataStructures/Set.scala) 42 | 43 | 5) Binary tree [`dataStructures.BinaryTree`](src/main/scala/dataStructures/BinaryTree.scala) 44 | 45 | 6) Heap [`dataStructures.Heap`](src/main/scala/dataStructures/Heap.scala) 46 | 47 | 7) Red-Black Tree [`dataStructures.RedBlackTree`](src/main/scala/dataStructures/RedBlackTree.scala) 48 | 49 | ### Lambda calculus basics: 50 | 51 | 1) Polymorphic lambda calculus [`lambdaCalculus/PolymorphicLambdaCalculus`](/src/main/scala/lambdaCalculus/PolymorphicLambdaCalculus.scala) 52 | 53 | 2) Pure Lambda Calculus PureLambdaCalculus.scala [`lambdaCalculus/PureLambdaCalculus`](/src/main/scala/lambdaCalculus/PureLambdaCalculus.scala) 54 | 55 | ### Integer operations: 56 | [`integerOperations.IntegerProperties`](src/main/scala/integerOperations/IntegerProperties.scala) 57 | 1) .isOdd 58 | 59 | 2) .isEven 60 | 61 | 3) .isSquared 62 | 63 | 4) .sumOfDigits 64 | 65 | 5) .compositionOfDigits 66 | 67 | 6) .numOfDigits 68 | 69 | 7) .divisors 70 | 71 | 10) .nthGreatestDivisor(n) 72 | 73 | 11) .numOfDivisors 74 | 75 | 12) .sumOfDivisors 76 | 77 | 13) .isPrime, works with O(sqrt(n)) speed 78 | 79 | 14) .isPrimeFermat(). works with O(log(n)) speed 80 | 81 | 15) .sqr 82 | 83 | 16) .powN() 84 | 85 | 17) .gcdWith(secondInt) 86 | 87 | 18) .isPrimeFermatStrict (does not fail on Carmichael numbers, works slowly) 88 | 89 | 19) .isPrimeFermatFast (does not fail on Carmichael numbers, works fast, only with Ints) 90 | 91 | 20) .lcmWith(secondInt) 92 | 93 | 21) Factorial (!) 94 | 95 | 22) Double factorial (!!) 96 | 97 | 23) Convolution of a number (127 -> 1+2+7 -> 10 -> 1+0 -> 1) 98 | 99 | ### Additional Integers math: 100 | [`integerOperations.IntegerMath`](src/main/scala/integerOperations/IntegerMath.scala) 101 | 1) .isFreeOfSquares 102 | 103 | 2) .isCarmichael 104 | 105 | 3) .isLuc_Carmichael 106 | 107 | 4) .isFibonacci 108 | 109 | 5) .nthCatalan 110 | 111 | 6) .binaryPower(), works with O(log(n)) speed 112 | 113 | 7) .isZuckerman 114 | 115 | 8) .isHarshad 116 | 117 | 9) .gcdExtendedWith() 118 | 119 | 120 | ### Integer lists generators: 121 | [`integerOperations.IntegerGenerators`](src/main/scala/integerOperations/IntegerGenerators.scala) 122 | 1) Arithmetic regression 123 | 124 | 2) Arithmetic progression 125 | 126 | 3) Squares until N 127 | 128 | 4) Divisors of N 129 | 130 | 5) Binary divisors of N 131 | 132 | 6) Divisors, multiple by N 133 | 134 | 7) Prime divisors 135 | 136 | 8) Carmichael numbers 137 | 138 | 9) Luc-Carmichael numbers 139 | 140 | 10) Fibonacci numbers 141 | 142 | 11) Random ints 143 | 144 | 12) Catalan numbers 145 | 146 | ### Additional math generators: 147 | [`integerOperations.IntegerGeneratorsMath`](src/main/scala/integerOperations/IntegerGeneratorsMath.scala) 148 | 1) Fermat numbers 149 | 150 | 2) Eratosthenes primes sieve O(log(log(n))) 151 | 152 | ### Char operations: 153 | [`charOperations.CharProperties`](src/main/scala/charOperations/CharProperties.scala) 154 | 1) .isVowel 155 | 156 | 2) .isConsonant 157 | 158 | ### Double operations: 159 | [`doubleOperations.DoubleProperties`](src/main/scala/doubleOperations/DoubleProperties.scala) 160 | 1) .inverse 161 | 162 | 2) .sqrDouble 163 | 164 | 3) .abs 165 | 166 | 4) .toDegrees 167 | 168 | 5) .incDouble 169 | 170 | ### List/values operations: 171 | [`listOperations`](src/main/scala/listOperations) 172 | 1) get(List[A], index) 173 | 174 | 2) isPalindrome(List[A]) 175 | 176 | 3) isPalindrome([A]) 177 | 178 | 3) Counter for the number of sign changes in a list of integers 179 | 180 | 4) Counter for the number of letter changes from vowel to consonant in a list of integers 181 | 182 | 5) .isSorted 183 | 184 | 6) binary search in a list 185 | 186 | 7) linear search in a list 187 | 188 | 8) permutations(List[A], len) 189 | 190 | ### Basic combinatorics: 191 | [`combinatorics`](src/main/scala/combinatorics) 192 | 1) permutationsCount 193 | 194 | 2) accomodations 195 | 196 | 3) combinations 197 | 198 | 4) accomodations with repeats 199 | 200 | 5) combinations with repeats 201 | 202 | ### Encoders: 203 | 1) RLE [`cryptographyOperations.encoders.RLE_Encoder`](src/main/scala/cryptographyOperations/encoders/RLE_Encoder.scala) 204 | 205 | 2) Huffman [`cryptographyOperations.encoders.HuffmanEncoder`](src/main/scala/cryptographyOperations/encoders/HuffmanEncoder.scala) 206 | 207 | 3) Gray [`cryptographyOperations.encoders.GrayEncoder`](src/main/scala/cryptographyOperations/encoders/GrayEncoder.scala) 208 | 209 | 4) Morse [`cryptographyOperations.encoders.MorseEncoder`](src/main/scala/cryptographyOperations/encoders/MorseEncoder.scala) 210 | 211 | ### Decoders: 212 | 1) RLE [`functionalAlgorithms.decoders.RLE_Decoder`](src/main/scala/cryptographyOperations/decoders/RLE_Decoder.scala) 213 | 214 | 2) Huffman [`functionalAlgorithms.decoders.HuffmanDecoder`](src/main/scala/cryptographyOperations/decoders/HuffmanDecoder.scala) 215 | 216 | 3) Gray [`functionalAlgorithms.decoders.GrayDecoder`](src/main/scala/cryptographyOperations/decoders/GrayDecoder.scala) 217 | 218 | 4) Morse [`functionalAlgorithms.decoders.MorseDecoder`](src/main/scala/cryptographyOperations/decoders/MorseDecoder.scala) 219 | 220 | ### Additional arithmetics: 221 | 1) Rational numbers [`additionalArithmetics.Rational`](src/main/scala/additionalArithmetics/Rational.scala) 222 | 223 | 2) Complex numbers [`complexOperations.Complex`](src/main/scala/complexOperations/Complex.scala) 224 | 225 | ### Useful asynchronous functions with Futures: 226 | [`asynchronous.UsefulFuture`](src/main/scala/asynchronous/UsefulFuture.scala) 227 | 228 | 1) .bypassOnComplete() 229 | 230 | 2) .ifFailure() 231 | 232 | 3) .result 233 | 234 | 4) .completeAndThen() 235 | 236 | 5) .completeAndThenComplete() 237 | 238 | ### Useful asynchronous functions with Option: 239 | [`asynchronous.UsefulOption`](src/main/scala/asynchronous/UsefulOption.scala) 240 | 241 | 1) .getOrZero 242 | 243 | 2) .getOrZeroL 244 | 245 | 3) .getOrThrow 246 | 247 | 4) .getOrEmpty 248 | 249 | 5) .getOrMax 250 | 251 | ### Math constants: 252 | [`MathConstants`](src/main/scala/utils/MathConstants.scala) 253 | 1) Pi 254 | 255 | 2) Tau 256 | 257 | 3) E 258 | 259 | 4) Pythagoras constant 260 | 261 | 5) Theodorus constant 262 | 263 | 6) Gamma 264 | 265 | 7) Phi 266 | 267 | 8) Plastic number 268 | 269 | ### Time operations: 270 | [`time.Time`](src/main/scala/time/Time.scala) 271 | 272 | 1) Conversions of hours, seconds and minutes. 273 | 274 | 275 | ##### Planned: 276 | 1) Operations with double 277 | 278 | # Some sources, that were used via development: 279 | 280 | 0) Martin Odersky's "Functional Programming in Scala Specialization "https://www.coursera.org/specializations/scala" (English) 281 | 282 | 1) Chris Okasaki's "Purely Functional Data Structures" (English) 283 | 284 | 2) Richard Bird's "Pearls of Functional Algorithm Design" (English) 285 | 286 | 3) Denis Shevchenko's "About Haskell in a human way": https://www.ohaskell.guide (Russian) 287 | 288 | 4) Louis Botterill's mostly software and techy Blog: http://louisbotterill.blogspot.ru (English) 289 | 290 | 5) Alvin Alexander's scala blog: https://alvinalexander.com (English) 291 | 292 | 6) Richard G.E. Pinch "The Carmichael numbers up to 10^18" https://arxiv.org/pdf/math/0604376v1.pdf (English) 293 | 294 | 7) Site about algorithms http://e-maxx.ru (Russian/English) 295 | 296 | 8) "Rosetta code" website about algorithms: https://rosettacode.org/wiki/Rosetta_Code (English) 297 | 298 | 9) Vladimir Kostykov's Scala algorithms library: https://github.com/vkostyukov/scalacaster (English) 299 | 300 | 10) Raul Rojas's "A Tutorial Introduction to the Lambda Calculus": http://www.inf.fu-berlin.de/lehre/WS03/alpi/lambda.pdf (English) 301 | 302 | 11) ITMO University's wiki: https://neerc.ifmo.ru/wiki/index.php?title=Лямбда-исчисление (Russian) 303 | 304 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /src/main/scala/additionalArithmetics/Rational.scala: -------------------------------------------------------------------------------- 1 | package rationalOperations 2 | 3 | import integerOperations.IntegerProperties._ 4 | 5 | /** 6 | * Contains operations in a field of rational numbers. 7 | * 8 | * Purity project by Daniil Tekunov. 9 | */ 10 | class Rational(numerator: Int, denominator: Int) { 11 | require(denominator != 0) 12 | 13 | private val gcd = numerator.abs gcdWith denominator.abs 14 | 15 | private val num: Int = numerator / gcd 16 | 17 | private val denom: Int = denominator / gcd 18 | 19 | override def toString: String = num + "/" + denom 20 | 21 | def this(firstInt: Int) = this(firstInt, 1) 22 | 23 | def +(secondRational: Rational) = new Rational( 24 | num * secondRational.denom + secondRational.num * denom, 25 | denom * secondRational.denom) 26 | 27 | def *(secondRational: Rational) = new Rational( 28 | num * secondRational.num, 29 | denom * secondRational.denom) 30 | 31 | def /(secondRational: Rational) = new Rational( 32 | num * secondRational.denom, 33 | denom * secondRational.num) 34 | 35 | def -(secondRational: Rational) = new Rational( 36 | num * secondRational.denom - secondRational.num * denom, 37 | denom * secondRational.denom) 38 | 39 | def >(secondRational: Rational): Boolean = 40 | this.num * secondRational.denom > this.denom * secondRational.num 41 | 42 | def <(secondRational: Rational): Boolean = 43 | this.num * secondRational.denom < this.denom * secondRational.num 44 | 45 | def >=(secondRational: Rational): Boolean = 46 | this.num * secondRational.denom >= this.denom * secondRational.num 47 | 48 | def <=(secondRational: Rational): Boolean = 49 | this.num * secondRational.denom =< this.denom * secondRational.num 50 | 51 | def sqr = new Rational(num * num, denom * denom) 52 | } 53 | -------------------------------------------------------------------------------- /src/main/scala/asynchronous/UsefulFuture.scala: -------------------------------------------------------------------------------- 1 | package asynchronous 2 | 3 | import java.util.concurrent.TimeUnit 4 | import scala.concurrent.duration.{Duration, TimeUnit} 5 | import scala.concurrent.{Await, ExecutionContext, Future} 6 | import scala.util.{Failure, Success} 7 | 8 | object UsefulFuture { 9 | 10 | /** 11 | * Contains functions, affecting futures. 12 | * 13 | * Purity project by Daniil Tekunov. 14 | */ 15 | implicit class UsefulFuture[T](future: Future[T])(implicit ec: ExecutionContext) { 16 | 17 | /** 18 | * Applies a given function to a result of a future without affecting the future itself 19 | */ 20 | def bypassOnComplete[A](function: T => A): Future[T] = { 21 | future onComplete { 22 | case Success(outcome) => function(outcome) 23 | case Failure(_) => Future.failed(new Exception) 24 | } 25 | future 26 | } 27 | 28 | /** 29 | * Throws a given exception if a future failed and applies a given function to it 30 | */ 31 | def ifFailure(functionFail: => Unit, exception: Option[Throwable] = None): Future[T] = { 32 | future transformWith { 33 | case Failure(ex) => 34 | functionFail 35 | Future.failed(exception getOrElse ex) 36 | 37 | case _ => future 38 | } 39 | } 40 | 41 | /** 42 | * Returns the result of a future within given time 43 | */ 44 | def result(awaitTime: Long, timeUnit: TimeUnit = TimeUnit.MICROSECONDS): T = 45 | Await.result(future, Duration(awaitTime, timeUnit)) 46 | 47 | 48 | /** 49 | * Completes first future and returns second future if first one completes 50 | */ 51 | def completeAndThen(anotherFuture: Future[T]): Future[T] = { 52 | future andThen { 53 | case Success(_) => anotherFuture 54 | case Failure(ex) => ex 55 | } 56 | } 57 | 58 | /** 59 | * Completes first future and then completes second future 60 | */ 61 | def completeAndThenComplete(anotherFuture: Future[T]): Future[T] = { 62 | future andThen { 63 | case Success(_) => anotherFuture andThen { 64 | case Success(x) => x 65 | case Failure(ex) => ex 66 | } 67 | case Failure(ex) => ex 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/scala/asynchronous/UsefulOption.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains functions that affect Option. 3 | * 4 | * Purity project by Daniil Tekunov. 5 | */ 6 | object UsefulOption { 7 | 8 | /** 9 | * Contains useful functions for built-in Int type 10 | */ 11 | implicit class IntOption(input: Option[Int]) { 12 | def getOrZero: Int = input.getOrElse(0) 13 | 14 | def getOrMax: Int = input.getOrElse(2147483647) 15 | } 16 | 17 | /** 18 | * Contains useful functions for built-in Long type 19 | */ 20 | implicit class LongOption(input: Option[Long]) { 21 | def getOrZeroL: Long = input.getOrElse(0L) 22 | 23 | def getOrMaxL: Long = input.getOrElse(9223372036854775807L) 24 | } 25 | 26 | /** 27 | * Contains useful functions for built-in String type 28 | */ 29 | implicit class StringOption(input: Option[String]) { 30 | def getOrEmpty: String = input.getOrElse("") 31 | } 32 | 33 | /** 34 | * Contains useful functions for throwable type 35 | */ 36 | implicit class ThrowableOption[T](input: Option[T]) { 37 | def getOrThrow(ex: Throwable) = input.getOrElse(ex) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/scala/charOperations/CharProperties.scala: -------------------------------------------------------------------------------- 1 | package charOperations 2 | 3 | import charOperations.miscellaneous.ImportantConstants._ 4 | import utils.InputException 5 | import utils.ExceptionMessages.DeprecatedSymbolInput 6 | 7 | 8 | /** 9 | * Contains functions, affecting char properties. 10 | * 11 | * Purity project by Daniil Tekunov. 12 | */ 13 | class CharProperties(val firstChar: Char) { 14 | import CharProperties._ 15 | 16 | /** 17 | * Checks, whether the char is vowel 18 | */ 19 | def isVowel: Boolean = { 20 | if (Vowels.contains(firstChar.toLower)) true 21 | else if (Consonants.contains(firstChar.toLower) || firstChar == '\0') false 22 | else throw new InputException("\"isVowel\" " + DeprecatedSymbolInput) 23 | } 24 | 25 | /** 26 | * Checks, whether the char is consonant 27 | */ 28 | def isConsonant: Boolean = { 29 | if (Consonants.contains(firstChar.toLower)) true 30 | else if (Vowels.contains(firstChar.toLower) || firstChar == '\0') false 31 | else throw new InputException("\"isConsonant\" " + DeprecatedSymbolInput) 32 | } 33 | 34 | } 35 | 36 | object CharProperties { 37 | implicit def charToImplicitProps(a: Char): CharProperties = new CharProperties(a) 38 | } 39 | -------------------------------------------------------------------------------- /src/main/scala/charOperations/miscellaneous/ImportantConstants.scala: -------------------------------------------------------------------------------- 1 | package charOperations.miscellaneous 2 | 3 | object ImportantConstants { 4 | /** 5 | * Contains a set of vowels in English 6 | */ 7 | final lazy val Vowels: Set[Char] = Set('a', 'e', 'i', 'o', 'u', 'y') 8 | 9 | /** 10 | * Contains a set of consonants in English 11 | */ 12 | final lazy val Consonants: Set[Char] = Set('b', 'c', 'd', 'f', 'g', 13 | 'h', 'j', 'k', 'l', 'm', 14 | 'n', 'p', 'q', 'r', 's', 15 | 't', 'v', 'w', 'x', 'z') 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/scala/combinatorics/combinatorics.scala: -------------------------------------------------------------------------------- 1 | package object combinatorics { 2 | 3 | /** 4 | * Contains basic combinatorics formulas. 5 | * 6 | * Purity project by Daniil Tekunov. 7 | */ 8 | import integerOperations.IntegerProperties._ 9 | 10 | /** 11 | * Returns number of permutations of n objects. 12 | */ 13 | def permutationsCount(n: Int): Int = n! 14 | 15 | /** 16 | * Returns number of accomodations of n objects at m places. 17 | */ 18 | def accomodations(m: Int, n: Int): Int = (n!) / ((n - m)!) 19 | 20 | /** 21 | * Returns number of combinations of n objects at m places. 22 | */ 23 | def combinations(m : Int, n: Int) = (n!) / ( ((n - m)!) * (m!) ) 24 | 25 | /** 26 | * Returns number of combinations with repeats of n objects at m places. 27 | */ 28 | def combinationsWithRepeats(m : Int, n: Int): Int = ((n + m - 1)!) / ((m!) * (n - 1)!) 29 | 30 | /** 31 | * Returns number of accomodations with repeats of n objects at m places. 32 | */ 33 | def accomodationsWithRepeats(m : Int, n: Int): Int = n.powN(m) 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/main/scala/complexOperations/Complex.scala: -------------------------------------------------------------------------------- 1 | package complexOperations 2 | 3 | case class Complex(realPart: Double = 0.0, imagPart: Double = 0.0) { 4 | 5 | def this(s: String) = 6 | this("[\\d.]+(?!i)".r findFirstIn s getOrElse "0" toDouble, 7 | "[\\d.]+(?=i)".r findFirstIn s getOrElse "0" toDouble) 8 | 9 | private val real = realPart 10 | 11 | private val imaginary = imagPart 12 | 13 | override def toString = real + " + " + imaginary + "i" 14 | 15 | def +(secondsComplex: Complex): Complex = new Complex(real + secondsComplex.real, imaginary + secondsComplex.imaginary) 16 | 17 | def -(secondComplex: Complex): Complex = new Complex(real - secondComplex.real, imaginary - secondComplex.imaginary) 18 | 19 | def *(secondComplex: Complex): Complex = new Complex( 20 | real * secondComplex.real - imaginary * secondComplex.imaginary, 21 | real * secondComplex.imaginary + imaginary * secondComplex.real) 22 | 23 | def inverse: Complex = { 24 | val denominator = real * real + imaginary * imaginary 25 | new Complex(real / denominator, -imaginary / denominator) 26 | } 27 | 28 | def /(secondComplex: Complex): Complex = this * secondComplex.inverse 29 | } 30 | 31 | object Complex { 32 | def apply(s: String) = new Complex(s) 33 | } 34 | -------------------------------------------------------------------------------- /src/main/scala/complexOperations/package.scala: -------------------------------------------------------------------------------- 1 | package object complexOperations { 2 | val i: Complex = Complex(0, 1) 3 | 4 | implicit def fromDouble(d: Double): Complex = Complex(d) 5 | implicit def fromInt(i: Int): Complex = Complex(i.toDouble) 6 | } 7 | -------------------------------------------------------------------------------- /src/main/scala/cryptographyOperations/decoders/GrayDecoder.scala: -------------------------------------------------------------------------------- 1 | package cryptographyOperations.decoders 2 | 3 | import utils.InputException 4 | import utils.ExceptionMessages.NegativeOrZeroInput 5 | 6 | import scala.annotation.tailrec 7 | 8 | /** 9 | * Contains realisation of a Gray decoder: https://en.wikipedia.org/wiki/Gray_code 10 | * 11 | * Purity project by Daniil Tekunov. 12 | */ 13 | object GrayDecoder { 14 | def decode(input: Int) = { 15 | if (input > -1) decodeLogic(input) 16 | else throw new InputException("\"GrayDecoder\" " + NegativeOrZeroInput)} 17 | 18 | @tailrec 19 | private def decodeLogic(cur: Int, outcome: Int = 0): Int = { 20 | if (cur != 0) decodeLogic(cur >> 1, outcome ^ cur) 21 | else outcome 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/scala/cryptographyOperations/decoders/HuffmanDecoder.scala: -------------------------------------------------------------------------------- 1 | package cryptographyOperations.decoders 2 | 3 | import cryptographyOperations.encoders.HuffmanEncoder.{CodeTree, Fork, Leaf} 4 | 5 | object HuffmanDecoder { 6 | 7 | /** 8 | * Function, that decodes given List[Int] of Huffman codes to a normal string. 9 | * 10 | * Usage: 11 | * 12 | * HuffmanDecoder.decode(HuffmanEncoder.createCodeTree(String), String) 13 | * 14 | * Purity project by Daniil Tekunov. 15 | */ 16 | def decode(tree: CodeTree, bits: List[Int]): String = { 17 | def traverse(remaining: CodeTree, bits: List[Int]): List[Char] = remaining match { 18 | case Leaf(c, _) if bits.isEmpty => List(c) 19 | case Leaf(c, _) => c :: traverse(tree, bits) 20 | case Fork(left, right, _, _) if bits.head == 0 => traverse(left, bits.tail) 21 | case Fork(left, right, _, _) => traverse(right, bits.tail) 22 | } 23 | 24 | traverse(tree, bits) 25 | }.mkString("") 26 | 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/scala/cryptographyOperations/decoders/MorseDecoder.scala: -------------------------------------------------------------------------------- 1 | package cryptographyOperations.decoders 2 | 3 | import utils.InputException 4 | import utils.ExceptionMessages.DeprecatedSymbolInput 5 | 6 | import scala.util.{Failure, Success, Try} 7 | 8 | /** 9 | * Contains realisation of Morse decoding: https://en.wikipedia.org/wiki/Morse_code 10 | * 11 | * | is a separator between letters in a word (equivalent to three units in official Morse) 12 | * 13 | * / is a separator between words in a sentence (equivalent to seven units in official Morse) 14 | * 15 | * Purity project by Daniil Tekunov. 16 | */ 17 | object MorseDecoder { 18 | 19 | private final val Codes: Map[String, Char] = Map( 20 | 'a' -> ".-", 'b' -> "-...", 'c' -> "-.-.", 'd' -> "-..", 21 | 'e' -> ".", 'f' -> "..-.", 'g' -> "--.", 'h' -> "....", 22 | 'i' -> "..", 'j' -> ".---", 'k' -> "-.-", 'l' -> ".-..", 23 | 'm' -> "--", 'n' -> "-.", 'o' -> "---", 'p' -> ".--.", 24 | 'q' -> "--.-", 'r' -> ".-.", 's' -> "...", 't' -> "-", 25 | 'u' -> "..-", 'v' -> "...-", 'w' -> ".--", 'x' -> "-..-", 26 | 'y' -> "-.--", 'z' -> "--..", '1' -> ".----", '2' -> "..---", 27 | '3' -> "...--", '4' -> "....-", '5' -> ".....", '6' -> "-....", 28 | '7' -> "--...", '8' -> "---..", '9' -> "----.", '0' -> "-----", 29 | ' ' -> "/").map(_.swap) 30 | 31 | def decode(input: String): String = Try(decodeLogic(input)) match { 32 | case Success(string) => string 33 | case Failure(ex) => throw new InputException(ex + DeprecatedSymbolInput) 34 | } 35 | 36 | private def decodeLogic(input: String): String = (input.split('|') map Codes).mkString 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/scala/cryptographyOperations/decoders/RLE_Decoder.scala: -------------------------------------------------------------------------------- 1 | package cryptographyOperations.decoders 2 | 3 | import utils.ExceptionMessages.EmptyInput 4 | import utils.InputException 5 | 6 | import scala.annotation.tailrec 7 | 8 | /** 9 | * Contains realisation of RLE decoder: https://en.wikipedia.org/wiki/Run-length_encoding 10 | * 11 | * Purity project by Daniil Tekunov. 12 | */ 13 | object RLE_Decoder { 14 | 15 | /** 16 | * Decoder itself, returns outcome List. 17 | */ 18 | @tailrec 19 | private def makeList[A](countOfElements: Int, element: A, customList: List[A] = List()): List[A] = 20 | countOfElements match { 21 | case 0 => customList 22 | case _ => makeList(countOfElements - 1, element, customList :+ element) 23 | } 24 | 25 | /** 26 | * Sub-function for decoder, that checks input and flatmaps the List. 27 | */ 28 | def decode[A](input: List[(Int, A)]): List[A] = { 29 | if (input.isEmpty) throw new InputException("\"getElement\" " + EmptyInput) 30 | else input flatMap { element => makeList(element._1, element._2) } 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/scala/cryptographyOperations/encoders/GrayEncoder.scala: -------------------------------------------------------------------------------- 1 | package cryptographyOperations.encoders 2 | 3 | import utils.InputException 4 | import utils.ExceptionMessages.NegativeOrZeroInput 5 | 6 | /** 7 | * Contains realisation of a Gray encoding: https://en.wikipedia.org/wiki/Gray_code 8 | * 9 | * Purity project by Daniil Tekunov. 10 | */ 11 | object GrayEncoder { 12 | def encode(input: Int): Int = { 13 | if (input >= 0) input ^ (input >> 1) 14 | else throw new InputException("\"Gray encode\" " + NegativeOrZeroInput) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/scala/cryptographyOperations/encoders/HuffmanEncoder.scala: -------------------------------------------------------------------------------- 1 | package cryptographyOperations.encoders 2 | 3 | import collection.immutable.Queue 4 | import scala.annotation.tailrec 5 | 6 | /** 7 | * Contains functional realisation of a Huffman encoding algorithm. 8 | * 9 | * Usage: 10 | * 11 | * HuffmanEncoder.encode() - to encode a string 12 | * 13 | * HuffmanEncoder.createCodeTree - to create a tree for decoder 14 | * 15 | * Purity project by Daniil Tekunov. 16 | */ 17 | object HuffmanEncoder { 18 | 19 | //TODO: Finalize the doc 20 | /** 21 | * Basic object, that contains: 22 | * 23 | * weight - function, that checks, whether the Node is a list and returns weight 24 | * 25 | * chars - Puts a weight to a List 26 | * 27 | * makeCodeTree - Forks a tree to a binary tree 28 | * 29 | * times - returns the frequencies of a symbol 30 | * 31 | */ 32 | abstract class CodeTree 33 | 34 | case class Fork(left: CodeTree, right: CodeTree, chars: List[Char], weight: Int) extends CodeTree 35 | 36 | case class Leaf(char: Char, weight: Int) extends CodeTree 37 | 38 | private def weight(tree: CodeTree): Int = tree match { 39 | case Fork(_, _, _, w) => w 40 | case Leaf(_, w) => w 41 | } 42 | 43 | private def chars(tree: CodeTree): List[Char] = tree match { 44 | case Fork(_, _, cs, _) => cs 45 | case Leaf(c, _) => List(c) 46 | } 47 | 48 | private def makeCodeTree(left: CodeTree, right: CodeTree) = 49 | Fork(left, right, chars(left) ::: chars(right), weight(left) + weight(right)) 50 | 51 | private def times(chars: List[Char]): List[(Char, Int)] = { 52 | def incr(acc: Map[Char, Int], c: Char) = { 53 | val count = (acc get c).getOrElse(0) + 1 54 | acc + ((c, count)) 55 | } 56 | 57 | (Map[Char, Int]() /: chars) (incr).iterator.toList 58 | } 59 | 60 | private def makeOrderedLeafList(freqs: List[(Char, Int)]): List[Leaf] = { 61 | freqs.sortWith((f1, f2) => f1._2 < f2._2).map((f) => Leaf(f._1, f._2)) 62 | } 63 | 64 | private def singleton(trees: List[CodeTree]): Boolean = trees.size == 1 65 | 66 | private def combine(trees: List[CodeTree]): List[CodeTree] = trees match { 67 | case left :: right :: cs => (makeCodeTree(left, right) :: cs) 68 | .sortWith((t1, t2) => weight(t1) < weight(t2)) 69 | case _ => trees 70 | } 71 | 72 | @tailrec 73 | private def until(p: List[CodeTree] => Boolean, f: List[CodeTree] => List[CodeTree])(trees: List[CodeTree]): List[CodeTree] = { 74 | if (p(trees)) trees 75 | else until(p, f)(f(trees)) 76 | } 77 | 78 | def createCodeTree(inputChars: String): CodeTree = { 79 | val chars = inputChars.toList 80 | until(singleton, combine)(makeOrderedLeafList(times(chars))).head 81 | } 82 | 83 | def encode(inputText: String): List[Int] = { 84 | val text = inputText.toList 85 | val tree = createCodeTree(inputText) 86 | def lookup(tree: CodeTree)(c: Char): List[Int] = tree match { 87 | case Leaf(_, _) => List() 88 | case Fork(left, right, _, _) if chars(left).contains(c) => 0 :: lookup(left)(c) 89 | case Fork(left, right, _, _) => 1 :: lookup(right)(c) 90 | } 91 | 92 | text flatMap lookup(tree) 93 | } 94 | } -------------------------------------------------------------------------------- /src/main/scala/cryptographyOperations/encoders/MorseEncoder.scala: -------------------------------------------------------------------------------- 1 | package cryptographyOperations.encoders 2 | 3 | import utils.InputException 4 | import utils.ExceptionMessages.DeprecatedSymbolInput 5 | 6 | import scala.util.{Failure, Success, Try} 7 | 8 | 9 | /** 10 | * Contains realisation of Morse encoding: https://en.wikipedia.org/wiki/Morse_code 11 | * 12 | * | is a separator between letters in a word (equivalent to three units in official Morse) 13 | * 14 | * / is a separator between words in a sentence (equivalent to seven units in official Morse) 15 | * 16 | * Purity project by Daniil Tekunov. 17 | */ 18 | object MorseEncoder { 19 | private final val Codes: Map[Char, String] = Map( 20 | 'a' -> ".-", 'b' -> "-...", 'c' -> "-.-.", 'd' -> "-..", 21 | 'e' -> ".", 'f' -> "..-.", 'g' -> "--.", 'h' -> "....", 22 | 'i' -> "..", 'j' -> ".---", 'k' -> "-.-", 'l' -> ".-..", 23 | 'm' -> "--", 'n' -> "-.", 'o' -> "---", 'p' -> ".--.", 24 | 'q' -> "--.-", 'r' -> ".-.", 's' -> "...", 't' -> "-", 25 | 'u' -> "..-", 'v' -> "...-", 'w' -> ".--", 'x' -> "-..-", 26 | 'y' -> "-.--", 'z' -> "--..", '1' -> ".----", '2' -> "..---", 27 | '3' -> "...--", '4' -> "....-", '5' -> ".....", '6' -> "-....", 28 | '7' -> "--...", '8' -> "---..", '9' -> "----.", '0' -> "-----", 29 | ' ' -> "/") 30 | 31 | def encode(input: String): String = Try(encodeLogic(input)) match { 32 | case Success(string) => string 33 | case Failure(ex) => throw new InputException(ex + DeprecatedSymbolInput) 34 | } 35 | 36 | private def encodeLogic(input: String): String = input.toLowerCase.toList.map(cur => Codes(cur) + "|").mkString 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/scala/cryptographyOperations/encoders/RLE_Encoder.scala: -------------------------------------------------------------------------------- 1 | package cryptographyOperations.encoders 2 | 3 | import utils.InputException 4 | import utils.ExceptionMessages.EmptyInput 5 | 6 | /** 7 | * Contains realisation of RLE encoder: https://en.wikipedia.org/wiki/Run-length_encoding 8 | * 9 | * Purity project by Daniil Tekunov. 10 | */ 11 | object RLE_Encoder { 12 | 13 | /** 14 | * Packs repeated elements in a list of lists 15 | */ 16 | private def pack[A](input: List[A]): List[List[A]] = { 17 | if (input.isEmpty) List(List()) 18 | else { 19 | val (packed, next) = input span { _ == input.head } 20 | 21 | if (next == Nil) List(packed) 22 | else packed :: pack(next) 23 | } 24 | } 25 | 26 | /** 27 | * Returns RLE-encoded sequence of tuples in (7, 'a) style 28 | */ 29 | def encode[A](input: List[A]): List[(Int, A)] = { 30 | ( if (input.isEmpty) throw new InputException("\"RLE encoding\" " + EmptyInput) 31 | else { 32 | val (packed, next) = input span { _ == input.head } 33 | 34 | if (next == Nil) List(packed) 35 | else packed :: pack(next) 36 | 37 | }) map { element => (element.length, element.head) } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/scala/dataStructures/BinaryTree.scala: -------------------------------------------------------------------------------- 1 | package dataStructures 2 | 3 | import dataStructures.miscellaneous.DataStructureException 4 | import dataStructures.miscellaneous.DataStructuresExceptionMessages.EmptyLeafException 5 | import dataStructures.miscellaneous.DataStructuresExceptionMessages.EmptyTreeException 6 | import utils.InputException 7 | 8 | import scala.annotation.tailrec 9 | 10 | /** 11 | * Contains functional realisation of a standard binary tree. 12 | * 13 | * https://en.wikipedia.org/wiki/Linked_list 14 | * 15 | * Purity project by Daniil Tekunov. 16 | */ 17 | abstract sealed class BinaryTree[+A] { 18 | 19 | /** 20 | * Value of a node 21 | */ 22 | def value: Int 23 | 24 | /** 25 | * Left branch 26 | */ 27 | def left: BinaryTree[A] 28 | 29 | /** 30 | * Right branch 31 | */ 32 | def right: BinaryTree[A] 33 | 34 | /** 35 | * Size of a tree 36 | */ 37 | def size: Int 38 | 39 | /** 40 | * Whether the tree is empty 41 | */ 42 | def isEmpty: Boolean 43 | 44 | /** 45 | * Checks, whether the tree is a valid binary tree 46 | */ 47 | def isValid: Boolean = { 48 | if (isEmpty) true 49 | else if (left.isEmpty && right.isEmpty) true 50 | else if (left.isEmpty) right.value >= value && right.isValid 51 | else if (right.isEmpty) left.value <= value && left.isValid 52 | else (left.value <= value && left.isValid) && right.value >= value && right.isValid 53 | } 54 | /** 55 | * Adds an element to a tree 56 | */ 57 | def addElement(element: Int): BinaryTree[A] = { 58 | if (isEmpty) BinaryTree.make(element) 59 | else if (element < value) BinaryTree.make(value, left.addElement(element), right) 60 | else if (element > value) BinaryTree.make(value, left, right.addElement(element)) 61 | else this 62 | } 63 | 64 | /** 65 | * Removes an element from a tree 66 | */ 67 | def removeElement(element: Int): BinaryTree[A] = { 68 | if (isEmpty) throw new InputException(EmptyTreeException) 69 | else if (element < value) BinaryTree.make(value, left.removeElement(element), right) 70 | else if (element > value) BinaryTree.make(value, left, right.removeElement(element)) 71 | else { 72 | if (left.isEmpty && right.isEmpty) BinaryTree.empty 73 | else if (left.isEmpty) right 74 | else if (right.isEmpty) left 75 | else { 76 | val found = right.min 77 | BinaryTree.make(found, left, right.removeElement(found)) 78 | } 79 | } 80 | } 81 | 82 | /** 83 | * Finds a minimum value in a tree 84 | */ 85 | def min: Int = { 86 | @tailrec 87 | def find(tree: BinaryTree[A], cur: Int): Int = 88 | if (tree.isEmpty) cur 89 | else find(tree.left, tree.value) 90 | 91 | if (isEmpty) throw new InputException(EmptyTreeException) 92 | else find(left, value) 93 | } 94 | 95 | 96 | } 97 | 98 | /** 99 | * Basic object to describe a leaf 100 | */ 101 | case object Leaf extends BinaryTree[Nothing] { 102 | def value = throw new DataStructureException(EmptyLeafException) 103 | def left = throw new DataStructureException(EmptyLeafException) 104 | def right = throw new DataStructureException(EmptyLeafException) 105 | def size = 0 106 | def isEmpty = true 107 | } 108 | 109 | /** 110 | * Basic case class, to describe a branch 111 | */ 112 | case class Branch[A](value: Int, 113 | left: BinaryTree[A], 114 | right: BinaryTree[A], 115 | size: Int) extends BinaryTree[A] { 116 | def isEmpty: Boolean = false 117 | } 118 | 119 | object BinaryTree { 120 | 121 | def empty[A]: BinaryTree[A] = Leaf 122 | 123 | def make[A](element: Int, left: BinaryTree[A] = Leaf, right: BinaryTree[A] = Leaf): BinaryTree[A] = 124 | Branch(element, left, right, left.size + right.size + 1) 125 | } 126 | -------------------------------------------------------------------------------- /src/main/scala/dataStructures/Heap.scala: -------------------------------------------------------------------------------- 1 | package dataStructures 2 | 3 | import integerOperations.IntegerProperties._ 4 | import dataStructures.miscellaneous.DataStructureException 5 | import dataStructures.miscellaneous.DataStructuresExceptionMessages.EmptyHeapException 6 | 7 | case class HeapBranch(min: Int, left: Heap[Int], right: Heap[Int], size: Int, height: Int) extends Heap { 8 | def isEmpty: Boolean = false 9 | } 10 | 11 | case object Leaf extends Heap { 12 | def min: Nothing = throw new DataStructureException(EmptyHeapException) 13 | def left: Heap[Nothing] = throw new DataStructureException(EmptyHeapException) 14 | def right: Heap[Nothing] = throw new DataStructureException(EmptyHeapException) 15 | def size: Int = 0 16 | def height: Int = 0 17 | def isEmpty: Boolean = true 18 | } 19 | 20 | abstract sealed class Heap[+Int] { 21 | 22 | def min: Int 23 | def left: Int 24 | def right: Int 25 | def size: Int 26 | def height: Int 27 | def isEmpty: Boolean 28 | 29 | def insert(x: Int): Heap[Int] = 30 | if (isEmpty) Heap.make(x) 31 | else if (left.size < math.pow(2, left.height) - 1) 32 | Heap.bubbleUp(min, left.insert(x), right) 33 | else if (right.size < math.pow(2, right.height) - 1) 34 | Heap.bubbleUp(min, left, right.insert(x)) 35 | else if (right.height < left.height) 36 | Heap.bubbleUp(min, left, right.insert(x)) 37 | else Heap.bubbleUp(min, left.insert(x), right) 38 | } 39 | 40 | case object Leaf extends Heap[Nothing] { 41 | def min: Nothing = throw new DataStructureException(EmptyHeapException) 42 | def left: Heap[Nothing] = throw new DataStructureException(EmptyHeapException) 43 | def right: Heap[Nothing] = throw new DataStructureException(EmptyHeapException) 44 | def size: Int = 0 45 | def height: Int = 0 46 | def isEmpty: Boolean = true 47 | } 48 | 49 | object Heap { 50 | 51 | def empty: Heap[Int] = Leaf 52 | 53 | def make(x: Int, l: Heap[Int] = Leaf, r: Heap[Int] = Leaf): Heap[Int] = 54 | HeapBranch(x, l, r, l.size + r.size + 1, math.max(l.height, r.height) + 1) 55 | 56 | private[Heap] def bubbleUp(x: Int, l: Heap[Int], r: Heap[Int]): Heap[Int] = (l, r) match { 57 | case (HeapBranch(y, lt, rt, _, _), _) if x > y => 58 | Heap.make(y, Heap.make(x, lt, rt), r) 59 | case (_, HeapBranch(z, lt, rt, _, _)) if x > z => 60 | Heap.make(z, l, Heap.make(x, lt, rt)) 61 | case (_, _) => Heap.make(x, l, r) 62 | } 63 | 64 | private[Heap] def bubbleDown(x: Int, l: Heap[Int], r: Heap[Int]): Heap[Int] = (l, r) match { 65 | case (HeapBranch(y, _, _, _, _), HeapBranch(z, lt, rt, _, _)) if z < y && x > z => 66 | Heap.make(z, l, Heap.bubbleDown(x, lt, rt)) 67 | case (HeapBranch(y, lt, rt, _, _), _) if x > y => 68 | Heap.make(y, Heap.bubbleDown(x, lt, rt), r) 69 | case (_, _) => Heap.make(x, l, r) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/scala/dataStructures/LinkedList.scala: -------------------------------------------------------------------------------- 1 | package dataStructures 2 | 3 | import utils.ExceptionMessages.NegativeInput 4 | import dataStructures.miscellaneous.DataStructuresExceptionMessages.{EmptyHeadException, EmptyListException, EmptyTailException} 5 | import dataStructures.miscellaneous.DataStructureException 6 | 7 | /** 8 | * Contains functional realisation of a standard linked list. 9 | * 10 | * https://en.wikipedia.org/wiki/Linked_list 11 | * 12 | * Purity project by Daniil Tekunov. 13 | */ 14 | abstract sealed class LinkedList[+A] { 15 | 16 | /** 17 | * First element of a list 18 | */ 19 | def head: A 20 | 21 | /** 22 | * Tail of the list 23 | */ 24 | def tail: LinkedList[A] 25 | 26 | /** 27 | * Basic function to check whether the list is empty 28 | */ 29 | def isEmpty: Boolean 30 | 31 | /** 32 | * Appends an element to a list 33 | */ 34 | def join[B >: A](element: B): LinkedList[B] = 35 | if (isEmpty) LinkedList.create(element) 36 | else LinkedList.create(head, tail.join(element)) 37 | 38 | /** 39 | * Adds an element to a list 40 | */ 41 | def add[B >: A](element: B): LinkedList[B] = LinkedList.create(element, this) 42 | 43 | /** 44 | * Concatenates two lists 45 | */ 46 | def concatenate[B >: A](addingPart: LinkedList[B]): LinkedList[B] = 47 | if (isEmpty) addingPart 48 | else tail.concatenate(addingPart).add(head) 49 | 50 | /** 51 | * Removes an element from a list 52 | */ 53 | def remove[B >: A](element: B): LinkedList[B] = 54 | if (isEmpty) throw new DataStructureException(EmptyListException) 55 | else if (element == head) tail 56 | else LinkedList.create(head, tail.remove(element)) 57 | 58 | /** 59 | * Finds an element in a list by index 60 | */ 61 | def apply(element: Int): A = 62 | if (isEmpty) throw new DataStructureException(EmptyListException) 63 | else if (element < 0) throw new DataStructureException(NegativeInput) 64 | else if (element == 0) head 65 | else tail(element - 1) 66 | 67 | /** 68 | * Checks, whether the list contains an element 69 | */ 70 | def contains[B >: A](element: B): Boolean = 71 | if (isEmpty) false 72 | else if (element != head) tail.contains(element) 73 | else true 74 | } 75 | 76 | case object NilType extends LinkedList[Nothing] { 77 | def head: Nothing = throw new DataStructureException(EmptyHeadException) 78 | def tail: LinkedList[Nothing] = throw new DataStructureException(EmptyTailException) 79 | def isEmpty: Boolean = true 80 | } 81 | 82 | case class ListStructure[A](head: A, tail: LinkedList[A]) extends LinkedList[A] { 83 | def isEmpty: Boolean = false 84 | } 85 | 86 | object LinkedList { 87 | 88 | def empty[A]: LinkedList[A] = NilType 89 | 90 | /** 91 | * Basic creation of a list 92 | */ 93 | def create[A](element: A, tail: LinkedList[A] = NilType): LinkedList[A] = ListStructure(element, tail) 94 | 95 | } -------------------------------------------------------------------------------- /src/main/scala/dataStructures/Queue.scala: -------------------------------------------------------------------------------- 1 | package dataStructures 2 | import miscellaneous.DataStructureException 3 | import miscellaneous.DataStructuresExceptionMessages.EmptyQueueException 4 | 5 | /** 6 | * Contains functional realisation of a standard queue. 7 | * 8 | * https://en.wikipedia.org/wiki/Queue_(abstract_data_type) 9 | * 10 | * Purity project by Daniil Tekunov. 11 | */ 12 | class Queue[+A](in: List[A] = Nil, out: List[A] = Nil) { 13 | 14 | /** 15 | * Checks, whether the queue is empty. 16 | */ 17 | def isEmpty: Boolean = (in, out) match { 18 | case (Nil, Nil) => true 19 | case (_, _) => false 20 | } 21 | 22 | /** 23 | * Adds an element to a queue. 24 | */ 25 | def enqueue[B >: A](element: B): Queue[B] = new Queue(element :: in, out) 26 | 27 | /** 28 | * Removes an element from a queue. 29 | */ 30 | def dequeue: (A, Queue[A]) = out match { 31 | case last :: previous => (last, new Queue(in, previous)) 32 | case Nil => in.reverse match { 33 | case last :: previous => (last, new Queue(in, previous)) 34 | case Nil => throw new DataStructureException(EmptyQueueException) 35 | } 36 | } 37 | 38 | /** 39 | * Takes the first element from a queue. 40 | */ 41 | def first: A = dequeue match {case (element, _) => element} 42 | 43 | /** 44 | * Takes the whole queue, except the last element. 45 | */ 46 | def init: Queue[A] = dequeue match {case (_, element) => element } 47 | 48 | } 49 | 50 | object Queue { def createEmptyQueue[A]: Queue[A] = new Queue() } 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/main/scala/dataStructures/RedBlackTree.scala: -------------------------------------------------------------------------------- 1 | package dataStructures 2 | 3 | import dataStructures.miscellaneous.DataStructuresExceptionMessages.EmptyRBTreeException 4 | 5 | /** 6 | * Colors of a tree 7 | */ 8 | abstract sealed class Color 9 | case object Red extends Color 10 | case object Black extends Color 11 | 12 | abstract sealed class RedBlackTree[+A] { 13 | 14 | /** 15 | * Color of a tree 16 | */ 17 | def color: Color 18 | 19 | /** 20 | * Current value 21 | */ 22 | def value: Int 23 | 24 | /** 25 | * The left branch of a tree 26 | */ 27 | def left: RedBlackTree[Int] 28 | 29 | /** 30 | * The right branch of a tree 31 | */ 32 | def right: RedBlackTree[Int] 33 | 34 | /** 35 | * Checks whether this tree is empty or not 36 | */ 37 | def isEmpty: Boolean 38 | 39 | /** 40 | * Adds an element into a tree 41 | */ 42 | def add(x: Int): RedBlackTree[Int] = { 43 | def balancedAdd(t: RedBlackTree[Int]): RedBlackTree[Int] = 44 | if (t.isEmpty) RedBlackTree.make(Red, x) 45 | else if (x < t.value) balanceLeft(t.color, t.value, balancedAdd(t.left), t.right) 46 | else if (x > t.value) balanceRight(t.color, t.value, t.left, balancedAdd(t.right)) 47 | else t 48 | 49 | def balanceLeft(c: Color, x: Int, l: RedBlackTree[Int], r: RedBlackTree[Int]) = (c, l, r) match { 50 | case (Black, RBBranch(Red, y, RBBranch(Red, z, a, b), c), d) => 51 | RedBlackTree.make(Red, y, RedBlackTree.make(Black, z, a, b), RedBlackTree.make(Black, x, c, d)) 52 | case (Black, RBBranch(Red, z, a, RBBranch(Red, y, b, c)), d) => 53 | RedBlackTree.make(Red, y, RedBlackTree.make(Black, z, a, b), RedBlackTree.make(Black, x, c, d)) 54 | case _ => RedBlackTree.make(c, x, l, r) 55 | } 56 | 57 | def balanceRight(c: Color, x: Int, l: RedBlackTree[Int], r: RedBlackTree[Int]) = (c, l, r) match { 58 | case (Black, a, RBBranch(Red, y, b, RBBranch(Red, z, c, d))) => 59 | RedBlackTree.make(Red, y, RedBlackTree.make(Black, x, a, b), RedBlackTree.make(Black, z, c, d)) 60 | case (Black, a, RBBranch(Red, z, RBBranch(Red, y, b, c), d)) => 61 | RedBlackTree.make(Red, y, RedBlackTree.make(Black, x, a, b), RedBlackTree.make(Black, z, c, d)) 62 | case _ => RedBlackTree.make(c, x, l, r) 63 | } 64 | 65 | def blacken(t: RedBlackTree[Int]) = RedBlackTree.make(Black, t.value, t.left, t.right) 66 | 67 | blacken(balancedAdd(this)) 68 | } 69 | 70 | def height: Int = 71 | if (isEmpty) 0 72 | else math.max(left.height, right.height) + 1 73 | } 74 | 75 | case class RBBranch[Int](color: Color, 76 | value: Int, 77 | left: RedBlackTree[Int], 78 | right: RedBlackTree[Int]) extends RedBlackTree[Int] { 79 | def isEmpty = false 80 | } 81 | 82 | case object Leaf extends RedBlackTree[Nothing] { 83 | def color: Color = Black 84 | def value: Nothing = EmptyRBTreeException() 85 | def left: RedBlackTree[Nothing] = EmptyRBTreeException() 86 | def right: RedBlackTree[Nothing] = EmptyRBTreeException() 87 | def isEmpty = true 88 | } 89 | 90 | object RedBlackTree { 91 | 92 | /** 93 | * Returns an empty red-black tree 94 | */ 95 | def empty[Int]: RedBlackTree[Int] = Leaf 96 | 97 | /** 98 | * Creates a branch 99 | */ 100 | def make(c: Color, x: Int, l: RedBlackTree[Int] = Leaf, r: RedBlackTree[Int] = Leaf): RedBlackTree[Int] = 101 | RBBranch(c, x, l, r) 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/scala/dataStructures/Set.scala: -------------------------------------------------------------------------------- 1 | package dataStructures 2 | 3 | import scala.annotation.tailrec 4 | 5 | /** 6 | * Contains functional realisation of a mathematical meaning of a set. 7 | * 8 | * https://en.wikipedia.org/wiki/Set_(mathematics) 9 | * 10 | * Purity project by Daniil Tekunov. 11 | */ 12 | object Set { 13 | 14 | type Set[A] = A => Boolean 15 | 16 | /** 17 | * Fundamental operation for a mathematical set, realised via apply operation. 18 | */ 19 | def contains[A](set: Set[A], element: A): Boolean = set(element) 20 | 21 | /** 22 | * Creation of a basic set, that contains a single element. 23 | */ 24 | def basicSet[A](element: A): Set[A] = (param: A) => param == element 25 | 26 | /** 27 | * Realisation of operation. 28 | * 29 | * An element should be either in a first Set, or in the second Set 30 | */ 31 | def union[A](firstSet: Set[A], secondSet: Set[A]): Set[A] = (param: A) => firstSet(param) || secondSet(param) 32 | 33 | /** 34 | * Realisation of operation. 35 | * 36 | * An element should be either in both sets. 37 | */ 38 | def intersect[A](firstSet: Set[A], secondSet: Set[A]): Set[A] = (param: A) => firstSet(param) && secondSet(param) 39 | 40 | /** 41 | * Realisation of operation. 42 | * 43 | * An element should be in a first set, but should not be in a second. 44 | */ 45 | def difference[A](firstSet: Set[A], secondSet: Set[A]): Set[A] = (param: A) => firstSet(param) && !secondSet(param) 46 | 47 | /** 48 | * Realisation of a filter using given function. 49 | * 50 | * Returns elements in a given set, that exist in a given function. 51 | */ 52 | def filter[A](firstSet: Set[A], f: A => Boolean): Set[A] = (param: A) => firstSet(param) && f(param) 53 | 54 | /** 55 | * Realisation of a forall using given function. 56 | * 57 | * Returns whether elements refer to a given function in a given range. 58 | */ 59 | def forall(firstSet: Set[Int], f: Int => Boolean, rangeWithinZero: Int): Boolean = { 60 | 61 | @tailrec 62 | def check(cur: Int = -rangeWithinZero): Boolean = { 63 | if (cur > rangeWithinZero) true 64 | else if (firstSet(cur) && !f(cur)) false 65 | else check(cur + 1) 66 | } 67 | 68 | check() 69 | } 70 | 71 | /** 72 | * Realisation of exists using given function. 73 | * 74 | * Returns whether there exists a bounded element, that satisfies a given function. 75 | */ 76 | def exists(firstSet: Set[Int], f: Int => Boolean, rangeWithinZero: Int): Boolean = 77 | !forall(firstSet, param => !f(param), rangeWithinZero) 78 | 79 | /** 80 | * Converts a set to a string. 81 | */ 82 | def convertToString(s: Set[Int], rangeWithinZero: Int): String = { 83 | val xs = for (i <- -rangeWithinZero to rangeWithinZero if contains(s, i)) yield i 84 | xs.mkString("{", ",", "}") 85 | } 86 | } 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/main/scala/dataStructures/Stack.scala: -------------------------------------------------------------------------------- 1 | package dataStructures 2 | 3 | import dataStructures.miscellaneous.DataStructuresExceptionMessages.EmptyStackException 4 | import dataStructures.miscellaneous.DataStructureException 5 | 6 | 7 | /** 8 | * Contains functional realisation of a standard stack. 9 | * 10 | * https://en.wikipedia.org/wiki/Stack_(abstract_data_type) 11 | * 12 | * Purity project by Daniil Tekunov. 13 | */ 14 | class Stack[+A](inPart: List[A] = Nil) { 15 | 16 | /** 17 | * Checks, whether the stack is empty. 18 | */ 19 | def isEmpty: Boolean = inPart match { 20 | case Nil => true 21 | case _ => false 22 | } 23 | 24 | /** 25 | * Adds an element to a stack. 26 | */ 27 | def add[B >: A](element: B): Stack[B] = new Stack(element :: inPart) 28 | 29 | /** 30 | * Removes an element from a queue. 31 | */ 32 | def remove: (A, Stack[A]) = inPart match { 33 | case outcomeElement :: tail => (outcomeElement, new Stack(tail)) 34 | case Nil => throw new DataStructureException(EmptyStackException) 35 | } 36 | 37 | /** 38 | * Takes the first element from a queue. 39 | */ 40 | def first: A = inPart match { 41 | case element :: tail => element 42 | case Nil => throw new DataStructureException(EmptyStackException) 43 | } 44 | 45 | /** 46 | * Returns the tail of a stack. 47 | */ 48 | def init: Stack[A] = new Stack(inPart.tail) 49 | } 50 | 51 | 52 | object Stack { def createEmptyStack[A]: Stack[A] = new Stack() } -------------------------------------------------------------------------------- /src/main/scala/dataStructures/miscellaneous/DataStructureException.scala: -------------------------------------------------------------------------------- 1 | package dataStructures.miscellaneous 2 | 3 | /** 4 | * Basic class for handling data structures exceptions. 5 | */ 6 | class DataStructureException(message: String = null, cause: Exception = null) extends Exception(message, cause) { 7 | def this() { 8 | this(null, null) 9 | } 10 | 11 | def this(message: String) { 12 | this(message, null) 13 | } 14 | 15 | def this(cause: Exception) { 16 | this(null, cause) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/dataStructures/miscellaneous/DataStructuresExceptionMessages.scala: -------------------------------------------------------------------------------- 1 | package dataStructures.miscellaneous 2 | 3 | /** 4 | * Utility messages to handle data structure exceptions. 5 | */ 6 | object DataStructuresExceptionMessages { 7 | lazy val EmptyTailException: String = " tail is empty" 8 | lazy val EmptyHeadException: String = " head is empty" 9 | lazy val EmptyListException: String = " list is empty" 10 | lazy val EmptyQueueException: String = " queue is empty" 11 | lazy val EmptyStackException: String = " stack is empty" 12 | lazy val EmptyTreeException: String = " tree is empty" 13 | lazy val EmptyLeafException: String = " leaf is empty" 14 | lazy val EmptyRBTreeException: String = " RB tree is empty" 15 | } 16 | -------------------------------------------------------------------------------- /src/main/scala/doubleOperations/DoubleProperties.scala: -------------------------------------------------------------------------------- 1 | package doubleOperations 2 | 3 | import utils.InputException 4 | import utils.ExceptionMessages.ZeroInput 5 | import utils.MathConstants.pi 6 | 7 | /** 8 | * Contains functions, affecting double properties. 9 | * 10 | * Purity project by Daniil Tekunov. 11 | */ 12 | class DoubleProperties(val firstDouble: Double) { 13 | 14 | import DoubleProperties._ 15 | 16 | /** 17 | * Returns the number, inversed via 1 18 | */ 19 | def inverse: Double = firstDouble match { 20 | case 0 => throw new InputException("\"inverse\" " + ZeroInput) 21 | case _ => 1 / firstDouble 22 | } 23 | 24 | /** 25 | * Returns square of a Double 26 | */ 27 | def sqrDouble: Double = firstDouble * firstDouble 28 | 29 | /** 30 | * Returns absolute value of a Double 31 | */ 32 | def abs: Double = if (firstDouble < 0) -firstDouble else firstDouble 33 | 34 | /** 35 | * Returns double, converted to degrees 36 | */ 37 | def toDegrees: Double = firstDouble * 180.0 / pi 38 | } 39 | 40 | object DoubleProperties { 41 | implicit def doubleToLocalProps(a: Double): DoubleProperties = new DoubleProperties(a) 42 | } 43 | -------------------------------------------------------------------------------- /src/main/scala/integerOperations/IntegerGenerators.scala: -------------------------------------------------------------------------------- 1 | package integerOperations 2 | 3 | import utils.InputException 4 | import utils.ExceptionMessages.{NegativeOrZeroInput, StackOverflowInput, NegativeInput} 5 | import scala.util.{Failure, Random, Success, Try} 6 | import IntegerProperties._ 7 | import IntegerMath._ 8 | 9 | import scala.annotation.tailrec 10 | 11 | /** 12 | * Contains functions, that generate different lists of Integers. 13 | * 14 | * Purity project by Daniil Tekunov. 15 | */ 16 | class IntegerGenerators(val til: Int) { 17 | 18 | import IntegerGenerators._ 19 | 20 | /** 21 | * Generates list in range from until to 1 22 | */ 23 | def generateArithmeticRegression: List[Int] = Try(generateArithmeticRegressionLogic()) match { 24 | case Success(something) => something 25 | case Failure(ex) => throw new InputException("\"generateArithmeticRegression\" got " + ex.toString) 26 | } 27 | 28 | /** 29 | * Sub-function for generateArithmeticRegression 30 | */ 31 | @tailrec 32 | private def generateArithmeticRegressionLogic(cur: Int = til, regressionList: List[Int] = List()): List[Int] = { 33 | if (til < 0) throw new InputException("\"generateArithmeticRegression\" " + NegativeOrZeroInput) 34 | if (cur == 0) regressionList 35 | else generateArithmeticRegressionLogic(cur - 1, regressionList :+ cur) 36 | } 37 | 38 | /** 39 | * Generates list in range from 1 to until 40 | * 41 | * https://en.wikipedia.org/wiki/Arithmetic_progression 42 | */ 43 | def generateArithmeticProgression: List[Int] = Try(generateArithmeticProgressionLogic()) match { 44 | case Success(something) => something 45 | case Failure(ex) => throw new InputException("\"generateArithmeticProgression\" " + ex.toString) 46 | } 47 | 48 | /** 49 | * Sub-function for generateArithmeticProgression 50 | */ 51 | @tailrec 52 | private def generateArithmeticProgressionLogic(cur: Int = 1, regressionList: List[Int] = List()): List[Int] = { 53 | if (til < 0) throw new InputException("\"generateArithmeticProgression\" " + NegativeOrZeroInput) 54 | if (cur == til) regressionList :+ cur 55 | else generateArithmeticProgressionLogic(cur + 1, regressionList :+ cur) 56 | } 57 | 58 | /** 59 | * Generates squares in range from 2 to firstInt 60 | * 61 | * https://en.wikipedia.org/wiki/Square_number 62 | */ 63 | def generateSquares: List[Int] = Try(generateSquaresLogic()) match { 64 | case Success(something) => something 65 | case Failure(ex) => throw new InputException("\"generateSquares\" got " + ex.toString) 66 | } 67 | 68 | /** 69 | * Sub-function for generateSquares 70 | */ 71 | @tailrec 72 | private def generateSquaresLogic(squaresList: List[Int] = List(), cur: Int = 2): List[Int] = { 73 | if (til <= 0) throw new InputException(NegativeInput) 74 | else if (cur * cur > til) squaresList 75 | else generateSquaresLogic(squaresList :+ cur * cur, cur + 1) 76 | } 77 | 78 | /** 79 | * Returns the list of all the binary divisors of a number. 80 | * 81 | * https://en.wikipedia.org/wiki/Divisor 82 | */ 83 | def generateBinaryDivisors: List[Int] = Try(generateBinaryDivisorsLogic()) match { 84 | case Success(something) => something 85 | case Failure(ex) => throw new InputException("\"listBinaryDivisors\" got " + ex.toString) 86 | } 87 | 88 | /** 89 | * Sub-function for listBinaryDivisors(), to provide deep recursion handling. 90 | */ 91 | @tailrec 92 | private def generateBinaryDivisorsLogic(divisorsList: List[Int] = List(), total: Int = 2): List[Int] = { 93 | if (total == til) divisorsList :+ til 94 | else if (total > til) divisorsList 95 | else if (til % total == 0) generateBinaryDivisorsLogic(divisorsList :+ total, total * 2) 96 | else generateBinaryDivisorsLogic(divisorsList, total * 2) 97 | } 98 | 99 | /** 100 | * Returns the list of all the n-multiply divisors of a number. 101 | * 102 | * https://en.wikipedia.org/wiki/Divisor 103 | */ 104 | def generateN_MultipleDivisors(n: Int): List[Int] = { 105 | if (n != 1) 106 | Try(generateN_MultipleDivisorsLogic(n, total = n)) match { 107 | case Success(something) => something 108 | case Failure(ex) => throw new InputException("\"listN_MultipleDivisors\" got " + ex.toString) 109 | } 110 | else generateArithmeticRegressionLogic(til).reverse 111 | } 112 | 113 | /** 114 | * Sub-function for listN_MultipleDivisors(), to provide deep recursion handling. 115 | */ 116 | @tailrec 117 | private def generateN_MultipleDivisorsLogic(n: Int, divisorsList: List[Int] = List(), total: Int): List[Int] = { 118 | if (total == til) divisorsList :+ til 119 | else if (total > til) divisorsList 120 | else if (til % total == 0) generateN_MultipleDivisorsLogic(n, divisorsList :+ total, total * n) 121 | else generateN_MultipleDivisorsLogic(n, divisorsList, total * n) 122 | } 123 | 124 | /** 125 | * Returns the list of all the divisors of a number. 126 | * 127 | * https://en.wikipedia.org/wiki/Divisor 128 | */ 129 | def generateDivisors: List[Int] = Try(generateDivisorsLogic()) match { 130 | case Success(something) => something.sorted 131 | case Failure(ex) => throw new InputException(ex.toString) 132 | } 133 | 134 | /** 135 | * Sub-function for listDivisors(), to provide deep recursion handling. 136 | */ 137 | @tailrec 138 | private def generateDivisorsLogic(divisorsList: List[Int] = List(til), total: Int = 1): List[Int] = { 139 | if (til < 0) throw new InputException("\"listDivisors\" " + NegativeOrZeroInput) 140 | else if (total == til / 2 + 1) divisorsList 141 | else if (total > til / 2) divisorsList 142 | else if (til % total == 0) generateDivisorsLogic(divisorsList :+ total, total + 1) 143 | else generateDivisorsLogic(divisorsList, total + 1) 144 | } 145 | 146 | /** 147 | * Returns the list of all the divisors of a number. 148 | * 149 | * https://en.wikipedia.org/wiki/Prime_number 150 | */ 151 | def generatePrimeDivisors: List[Int] = Try(generatePrimeDivisorsLogic()) match { 152 | case Success(something) => something.sorted 153 | case Failure(ex) => throw new InputException(ex.toString) 154 | } 155 | 156 | /** 157 | * Sub-function for generatePrimeDivisors. 158 | */ 159 | private def generatePrimeDivisorsLogic(divisorsList: List[Int] = List()): List[Int] = { 160 | if (til < 0) throw new InputException("\"listDivisors\" " + NegativeOrZeroInput) 161 | else til.generateDivisors.filter { cur =>( cur == 1 || cur.isPrime) && cur != 1 } 162 | } 163 | 164 | 165 | /** 166 | * Generates Carmichael numbers in a range from 1 to until. 167 | * 168 | * WARNING: in case of using factorisation, input over 100.000 is hard-code deprecated. 169 | * 170 | * https://en.wikipedia.org/wiki/Carmichael_number 171 | */ 172 | def generateCarmichaelNumbers: List[Int] = Try(generateCarmichaelNumbersLogic()) match { 173 | case Success(something) => something.sorted 174 | case Failure(ex) => throw new InputException(ex.toString) 175 | } 176 | 177 | /** 178 | * Sub-function for generateCarmichaelNumbers. 179 | */ 180 | @tailrec 181 | private def generateCarmichaelNumbersLogic(outcomeList: List[Int] = List(), cur: Int = 3): List[Int] = { 182 | if (til > 100000) throw new InputException(StackOverflowInput) 183 | else if (til <= 1) throw new InputException(NegativeInput) 184 | else if (cur > til) outcomeList 185 | else if (cur.isCarmichael) generateCarmichaelNumbersLogic(outcomeList :+ cur, cur + 1) 186 | else generateCarmichaelNumbersLogic(outcomeList, cur + 1) 187 | } 188 | 189 | /** 190 | * Generates Lucas-Carmichael numbers in a range from 1 to until. 191 | * 192 | * WARNING: in case of using factorisation, input over 100.000 is hard-code deprecated. 193 | * 194 | * https://en.wikipedia.org/wiki/Lucas–Carmichael_number 195 | */ 196 | def generateLucasCarmichaelNumbers: List[Int] = Try(generateLucasCarmichaelNumbersLogic()) match { 197 | case Success(something) => something.sorted 198 | case Failure(ex) => throw new InputException(ex.toString) 199 | } 200 | 201 | /** 202 | * Sub-function for generateLucasCarmichaelNumbers. 203 | */ 204 | @tailrec 205 | private def generateLucasCarmichaelNumbersLogic(outcomeList: List[Int] = List(), cur: Int = 3): List[Int] = { 206 | if (til > 100000) throw new InputException(StackOverflowInput) 207 | else if (til <= 1) throw new InputException(NegativeInput) 208 | else if (cur > til) outcomeList 209 | else if (cur.isLucas_Carmichael) generateLucasCarmichaelNumbersLogic(outcomeList :+ cur, cur + 1) 210 | else generateLucasCarmichaelNumbersLogic(outcomeList, cur + 1) 211 | } 212 | 213 | /** 214 | * Generates Fibonacci numbers in a range from 1 to until. 215 | * 216 | * https://en.wikipedia.org/wiki/Fibonacci_number 217 | */ 218 | def generateFibonacci: List[Int] = Try(generateFibonacciLogic()) match { 219 | case Success(something) => something.sorted 220 | case Failure(ex) => throw new InputException(ex.toString) 221 | } 222 | 223 | /** 224 | * Sub-function for generateFibonacci. 225 | */ 226 | @tailrec 227 | private def generateFibonacciLogic(outcomeList: List[Int] = List(0), cur: Int = 1): List[Int] = { 228 | if (til < 0) throw new InputException("\"generateFibonacci\" " + NegativeOrZeroInput) 229 | else if (cur > til) outcomeList 230 | else generateFibonacciLogic(outcomeList :+ cur, cur + outcomeList.last) 231 | } 232 | 233 | /** 234 | * Generates random numbers in a range from 1 to until. 235 | * 236 | * https://en.wikipedia.org/wiki/Pseudorandom_number_generator 237 | */ 238 | def generateRandomInts: List[Int] = Try(generateRandomIntsLogic()) match { 239 | case Success(something) => something.sorted 240 | case Failure(ex) => throw new InputException(ex.toString) 241 | } 242 | 243 | /** 244 | * Sub-function for generateRandomInts 245 | */ 246 | private def generateRandomIntsLogic(outcomeList: List[Int] = List(), cur: Int = 1): List[Int] = { 247 | def random(n: Int): Int = { 248 | val random = new Random() 249 | random.nextInt(n) 250 | } 251 | 252 | if (til < 0) throw new InputException("\"generateRandomInts\" " + NegativeOrZeroInput) 253 | else if (cur > til) outcomeList 254 | else generateFibonacciLogic(outcomeList :+ random(til), cur + 1) 255 | } 256 | 257 | /** 258 | * Generates Catalan numbers in a range from 1 to until. 259 | * 260 | * https://en.wikipedia.org/wiki/Catalan_number 261 | */ 262 | def generateCatalanNumbers: List[Int] = Try(generateCatalanNumbersLogic()) match { 263 | case Success(something) => something 264 | case Failure(ex) => throw new InputException(ex.toString) 265 | } 266 | 267 | /** 268 | * Sub-function for generateCatalanNumbers. 269 | */ 270 | @tailrec 271 | private def generateCatalanNumbersLogic(outcomeList: List[Int] = List(1), cur: Int = 1 ): List[Int] = { 272 | if (til < 0) throw new InputException("\"generateCatalanNumbers\" " + NegativeInput) 273 | else if ( outcomeList.last > til) outcomeList.init 274 | else generateCatalanNumbersLogic(outcomeList :+ cur.nthCatalan, cur + 1) 275 | } 276 | 277 | } 278 | 279 | 280 | object IntegerGenerators { 281 | implicit def intToLocalImplicit(a: Int): IntegerGenerators = new IntegerGenerators(a) 282 | } 283 | -------------------------------------------------------------------------------- /src/main/scala/integerOperations/IntegerGeneratorsMath.scala: -------------------------------------------------------------------------------- 1 | package integerOperations 2 | 3 | import utils.InputException 4 | import utils.ExceptionMessages.NegativeInput 5 | import integerOperations.IntegerProperties._ 6 | 7 | import scala.annotation.tailrec 8 | import scala.util.{Failure, Success, Try} 9 | 10 | /** 11 | * Contains generators, that use more specific math or algorithms. 12 | * 13 | * Purity project by Daniil Tekunov. 14 | */ 15 | class IntegerGeneratorsMath(val til: Int) { 16 | 17 | import IntegerGeneratorsMath._ 18 | 19 | /** 20 | * Generates prime numbers using Sieve of Eratosthenes. 21 | */ 22 | def generateEratosthenesPrimes: List[Int] = 23 | Try(generateEratosthenesPrimesLogic(Stream.from(2)).take(til)) match { 24 | case Success(something) => something.toList 25 | case Failure(ex) => throw new InputException(ex.toString) 26 | } 27 | 28 | /** 29 | * Sub-function for generateEratosthenesPrimes 30 | */ 31 | private def generateEratosthenesPrimesLogic(input: Stream[Int]): Stream[Int] = 32 | input.head #:: generateEratosthenesPrimesLogic(input.tail.filter(_ % input.head != 0)) 33 | 34 | /** 35 | * Generates Fermat numbers in range from 1 to until. 36 | */ 37 | def generateFermatNumbers: List[Int] = Try(generateFermatNumbersLogic()) match { 38 | case Success(something) => 39 | if (something == List(3)) something 40 | else something.tail 41 | 42 | case Failure(ex) => throw new InputException(ex.toString) 43 | } 44 | 45 | /** 46 | * Sub-function for generateFermatNumbers 47 | */ 48 | @tailrec 49 | private def generateFermatNumbersLogic(outcomeList: List[Int] = List(3), cur: Int = 3): List[Int] = { 50 | if (til < 3) throw new InputException("\"generateCatalanNumbers\" " + NegativeInput) 51 | else if (til < 5) List(3) 52 | else if (outcomeList.last > til) outcomeList.init 53 | else generateFermatNumbersLogic(outcomeList :+ cur, (cur - 1).sqr + 1) 54 | } 55 | 56 | } 57 | 58 | object IntegerGeneratorsMath { 59 | implicit def intToGenerators(a: Int): IntegerGeneratorsMath = new IntegerGeneratorsMath(a) 60 | } -------------------------------------------------------------------------------- /src/main/scala/integerOperations/IntegerMath.scala: -------------------------------------------------------------------------------- 1 | package integerOperations 2 | 3 | import utils.InputException 4 | import utils.ExceptionMessages._ 5 | import IntegerGenerators._ 6 | import IntegerProperties._ 7 | 8 | import scala.util.{Failure, Success, Try} 9 | 10 | /** 11 | * Contains functions, that use more specific math or algorithms. 12 | * 13 | * Purity project by Daniil Tekunov. 14 | */ 15 | class IntegerMath(val firstInt: Int) { 16 | 17 | import IntegerMath._ 18 | 19 | /** 20 | * Checks, if a number is free of squares. 21 | * 22 | * https://en.wikipedia.org/wiki/Square-free_integer 23 | */ 24 | def isFreeOfSquares: Boolean = { 25 | if (firstInt <= 1) throw new InputException(NegativeInput) 26 | else (for {cur <- firstInt.generateSquares if firstInt % cur == 0} yield true).isEmpty 27 | } 28 | 29 | /** 30 | * Checks, if an Int is a Carmichael number. 31 | * 32 | * https://en.wikipedia.org/wiki/Carmichael_number 33 | */ 34 | def isCarmichael: Boolean = { 35 | if (firstInt <= 1) throw new InputException(NegativeInput) 36 | else if (firstInt.isFreeOfSquares && firstInt.isOdd) { 37 | val curFactorisation: List[Int] = firstInt.generatePrimeDivisors.filter {cur => cur != firstInt} 38 | 39 | (for {cur <- curFactorisation if (firstInt - 1) % (cur - 1) == 0} yield true).length == curFactorisation.length && 40 | curFactorisation.nonEmpty 41 | } 42 | else false 43 | } 44 | 45 | /** 46 | * Checks, if an Int is a Lucas-Carmichael number. 47 | * 48 | * https://en.wikipedia.org/wiki/Lucas–Carmichael_number 49 | */ 50 | def isLucas_Carmichael: Boolean = { 51 | if (firstInt <= 1) throw new InputException(NegativeInput) 52 | else if (firstInt.isFreeOfSquares && firstInt.isOdd) { 53 | val curFactorisation: List[Int] = firstInt.generatePrimeDivisors.filter {cur => cur != firstInt} 54 | 55 | (for {cur <- curFactorisation if (firstInt + 1) % (cur + 1) == 0} yield true).length == curFactorisation.length && 56 | curFactorisation.nonEmpty 57 | } 58 | else false 59 | } 60 | 61 | /** 62 | * Checks, if an Int is a Fibonacci number. 63 | * 64 | * https://en.wikipedia.org/wiki/Fibonacci_number 65 | */ 66 | def isFibonacci: Boolean = { 67 | if (firstInt < 0) throw new InputException(NegativeInput) 68 | else firstInt.generateFibonacci.contains(firstInt) 69 | } 70 | 71 | /** 72 | * Generates Catalan number with `firstInt` index. 73 | * 74 | * https://en.wikipedia.org/wiki/Catalan_number 75 | */ 76 | def nthCatalan: Int = Try(nthCatalanLogic(firstInt)) match { 77 | case Success(something) => something 78 | case Failure(ex) => throw new InputException(ex.toString) 79 | } 80 | 81 | /** 82 | * Sub-function for nthCatalan 83 | */ 84 | private def nthCatalanLogic(input: Int): Int = { 85 | if (input <= 1) 1 86 | else (0 until input).map(i => nthCatalanLogic(i) * nthCatalanLogic(input - i - 1)).sum 87 | } 88 | 89 | /** 90 | * Realisation of a binary 'N' power of an Int. 91 | * 92 | * https://en.wikipedia.org/wiki/Exponentiation_by_squaring 93 | * 94 | * Works with O(log(n)) speed. 95 | */ 96 | def binaryPower(n: Int): Int = Try(binaryPowerLogic(firstInt, n)) match { 97 | case Success(something) => something 98 | case Failure(ex) => throw new InputException(ex.toString) 99 | } 100 | 101 | /** 102 | * Sub-function for binaryPower 103 | */ 104 | private def binaryPowerLogic(cur: Int, n: Int): Int = { 105 | if (n == 0) 1 106 | else if (n % 2 == 1) binaryPowerLogic(cur, n - 1) * cur 107 | else binaryPowerLogic(cur, n / 2) * binaryPowerLogic(cur, n / 2) 108 | } 109 | 110 | /** 111 | * Checks, whether the number is a Zuckerman number 112 | * 113 | * http://www.numbersaplenty.com/set/Zuckerman_number/ 114 | */ 115 | def isZuckerman: Boolean = 116 | (firstInt.compositionOfDigits > 0) && (firstInt % firstInt.compositionOfDigits == 0) && (firstInt > 0) 117 | 118 | /** 119 | * Checks, whether the number is a Harshad number 120 | * 121 | * https://en.wikipedia.org/wiki/Harshad_number 122 | */ 123 | def isHarshad: Boolean = (firstInt == 0) || (firstInt % firstInt.sumOfDigits == 0) && (firstInt > 0) 124 | 125 | /** 126 | * Extended version of the Euclid's algorithm for gcd 127 | * 128 | * https://e-maxx.ru/algo/extended_euclid_algorithm 129 | */ 130 | def gcdExtendedWith(secondInt: Int): (Int, Int) = Try(gcdExtendedLogic(firstInt, secondInt)) match { 131 | case Success(something) => (something._2, something._3) 132 | case Failure(ex) => throw new InputException(ex.toString) 133 | } 134 | 135 | /** 136 | * Sub-function for gcdExtended. 137 | */ 138 | private def gcdExtendedLogic(first: Int, second: Int): (Int, Int, Int) = second match { 139 | case 0 => (firstInt, 1, 0) 140 | case _ => 141 | val (d, x, y) = gcdExtendedLogic(second, first % second) 142 | (d, y, x - y * (first / second)) 143 | } 144 | 145 | 146 | 147 | 148 | 149 | } 150 | 151 | object IntegerMath { 152 | implicit def intToMathImplicit(a: Int): IntegerMath = new IntegerMath(a) 153 | } 154 | 155 | -------------------------------------------------------------------------------- /src/main/scala/integerOperations/IntegerProperties.scala: -------------------------------------------------------------------------------- 1 | package integerOperations 2 | 3 | 4 | import utils.InputException 5 | 6 | import scala.util.{Failure, Random, Success, Try} 7 | import utils.ExceptionMessages.{BorderInput, NegativeInput, NegativeOrZeroInput} 8 | import integerOperations.IntegerGenerators._ 9 | 10 | import scala.annotation.tailrec 11 | 12 | /** 13 | * Contains functions, affecting Integer properties. 14 | * 15 | * Purity project by Daniil Tekunov. 16 | */ 17 | class IntegerProperties(val firstInt: Int) { 18 | 19 | import IntegerProperties._ 20 | 21 | /** 22 | * Checks, whether the number is even. 23 | * 24 | * https://en.wikipedia.org/wiki/Parity_(mathematics) 25 | */ 26 | def isEven: Boolean = firstInt % 2 == 0 27 | 28 | /** 29 | * Checks, whether the number is odd 30 | * 31 | * https://en.wikipedia.org/wiki/Parity_(mathematics) 32 | */ 33 | def isOdd: Boolean = firstInt % 2 != 0 34 | 35 | /** 36 | * Checks, whether the number is a square of two numbers 37 | */ 38 | def isSquared(secondInt: Int = firstInt, multiplier: Int = 3): Boolean = { 39 | if (secondInt > 0) secondInt match { 40 | case 1 => true 41 | case 0 => false 42 | case _ => isSquared(secondInt - multiplier, multiplier + 2) 43 | } 44 | else firstInt == 0 45 | } 46 | 47 | /** 48 | * Finds the sum of number's digits. 49 | */ 50 | def sumOfDigits: Int = Try(sumOfDigitsLogic()) match { 51 | case Success(something) => something 52 | case Failure(ex) => throw new InputException(ex.toString) 53 | } 54 | 55 | /** 56 | * Sub-function for sumOfDigits(), to provide errors handling. 57 | */ 58 | @tailrec 59 | private def sumOfDigitsLogic(cur: Int = firstInt, sum: Int = 0): Int = cur match { 60 | case 0 => sum 61 | case _ => sumOfDigitsLogic(cur / 10, sum + (cur % 10)) 62 | } 63 | 64 | /** 65 | * Finds the composition of number's digits. 66 | */ 67 | def compositionOfDigits: Int = Try(compositionOfDigitsLogic()) match { 68 | case Success(something) => something 69 | case Failure(ex) => throw new InputException(ex.toString) 70 | } 71 | 72 | /** 73 | * Sub-function for compositionOfDigits(), to provide errors handling. 74 | */ 75 | @tailrec 76 | private def compositionOfDigitsLogic(cur: Int = firstInt, comp: Int = 1): Int = cur match { 77 | case 0 => if (firstInt == 0) 0 else comp 78 | case _ => compositionOfDigitsLogic(cur / 10, comp * (cur % 10)) 79 | } 80 | 81 | /** 82 | * Finds the number of digits in a number. 83 | */ 84 | def numOfDigits: Int = Try(numOfDigitsLogic()) match { 85 | case Success(something) => something 86 | case Failure(ex) => throw new InputException(ex.toString) 87 | } 88 | 89 | /** 90 | * Sub-function for numOfDigits(), to provide errors handling. 91 | */ 92 | @tailrec 93 | private def numOfDigitsLogic(cur: Int = firstInt, comp: Int = 0): Int = cur match { 94 | case 0 => if (firstInt == 0) 1 else comp 95 | case _ => numOfDigitsLogic(cur / 10, comp + 1) 96 | } 97 | 98 | /** 99 | * Finds the greatest divisor of a number. 100 | */ 101 | def nthGreatestDivisor(nPosition: Int): Int = { 102 | if (nPosition < 0) throw new InputException("\"nthGreatestDivisor\" " + NegativeOrZeroInput) 103 | else Try(firstInt.generateDivisors.sortWith(_ > _)(nPosition)) match { 104 | case Success(something) => something 105 | case Failure(ex) => throw new InputException("\"nthGreatestDivisor\" got " + ex.toString) 106 | } 107 | 108 | } 109 | 110 | /** 111 | * Returns the number of total divisors of an Int. 112 | */ 113 | def numOfDivisors: Int = firstInt.generateDivisors.length 114 | 115 | /** 116 | * Returns the sum of all the divisors of an Int. 117 | * 118 | * https://en.wikipedia.org/wiki/Divisor_function 119 | */ 120 | def sumOfDivisors:Int = firstInt.generateDivisors.sum 121 | 122 | /** 123 | * Checks, whether the Int is prime with O(sqrt(n)) speed. 124 | * 125 | * https://en.wikipedia.org/wiki/Prime_number 126 | */ 127 | def isPrime:Boolean = Try(isPrimeLogic()) match { 128 | case Success(something) => something 129 | case Failure(ex) => throw new InputException("\"isPrime\" " + ex) 130 | } 131 | 132 | /** 133 | * Sub-function for isPrime. 134 | */ 135 | @tailrec 136 | private def isPrimeLogic(cur: Int = 2): Boolean = { 137 | if (firstInt == 2 || firstInt == 3) true 138 | else if (firstInt < 2) throw new InputException("\"isPrime\" " + BorderInput) 139 | else if (cur.toLong > Math.sqrt(firstInt.toLong)) true 140 | else if (firstInt % cur == 0) false 141 | else isPrimeLogic(cur + 1) 142 | } 143 | 144 | /** 145 | * Returns the greatest common divisor of two Integers 146 | * 147 | * https://en.wikipedia.org/wiki/Greatest_common_divisor 148 | */ 149 | def gcdWith(secondInt: Int): Int = Try(gcdWithLogic(first = firstInt, second = secondInt)) match { 150 | case Success(something) => something 151 | case Failure(ex) => throw new InputException("\"gcdWith\" " + ex) 152 | } 153 | 154 | /** 155 | * Sub-function for gcdWith 156 | */ 157 | @tailrec 158 | private def gcdWithLogic(first: Int, second: Int): Int = { 159 | if (first < 0 || second < 0) throw new InputException(NegativeInput) 160 | else if (second == 0) first 161 | else gcdWithLogic(second, first % second) 162 | } 163 | 164 | /** 165 | * Returns the square of an Integer. 166 | * 167 | * https://en.wikipedia.org/wiki/Square_number 168 | */ 169 | def sqr: Int = firstInt * firstInt 170 | 171 | /** 172 | * Returns the N power of an Integer 173 | * 174 | * https://en.wikipedia.org/wiki/Exponentiation 175 | */ 176 | def powN(n: Int): BigInt = Try(sqrNLogic(localIterations = n)) match { 177 | case Success(something) => something 178 | case Failure(ex) => throw new InputException("\"sqrN\" " + ex) 179 | } 180 | 181 | /** 182 | * Sub-function for powN 183 | */ 184 | @tailrec 185 | private def sqrNLogic(localIterations: Int, total: Int = 1): BigInt = localIterations match { 186 | case 0 => total 187 | case _ => 188 | if (localIterations > 0 && firstInt >= 0) sqrNLogic(localIterations - 1, total * firstInt) 189 | else throw new InputException(NegativeOrZeroInput) 190 | } 191 | 192 | /** 193 | * Checks, whether the Int is prime with Fermat method with O(log(n)) speed. 194 | * 195 | * https://en.wikipedia.org/wiki/Fermat_primality_test 196 | */ 197 | def isPrimeFermat(iterations: Int = 100): Boolean = Try(isPrimeFermatBorders(localIterations = iterations)) match { 198 | case Success(something) => something 199 | case Failure(ex) => throw new InputException("\"isPrimeFermat\" " + ex) 200 | } 201 | 202 | /** 203 | * Sub-functions for isPrimeFermat 204 | */ 205 | @tailrec 206 | private def isPrimeFermatBorders(first : Int = firstInt, localIterations : Int) : Boolean = { 207 | if (localIterations == 0) true 208 | else if (isPrimeFermatLogic(first)) isPrimeFermatBorders(first, localIterations - 1) 209 | else false 210 | } 211 | 212 | private def isPrimeFermatLogic(n : Int) : Boolean = { 213 | def checkWithRandomize(a : Int) : Boolean = { 214 | val res = expmod(a, n, n) 215 | res == a % n 216 | } 217 | checkWithRandomize(random(n - 1) + 1) 218 | } 219 | 220 | private def expmod(base : Int, exp : Int, m : Int) : Int = { 221 | if (exp == 0) 1 222 | else if (exp.isEven) expmod(base, exp / 2, m).sqr % m 223 | else base * expmod(base, exp - 1, m) % m 224 | } 225 | 226 | /** 227 | * Service function, that returns a random Int between 1 and n. 228 | */ 229 | private def random(n: Int) : Int = { 230 | val random = new Random() 231 | random.nextInt(n) 232 | } 233 | 234 | /** 235 | * Checks, whether to numbers are co-prime. 236 | * 237 | * https://en.wikipedia.org/wiki/Coprime_integers 238 | */ 239 | def isCoPrimeWith(secondInt: Int) = firstInt.gcdWith(secondInt) == 1 240 | 241 | /** 242 | * Checks, whether Int is prime with Fermat method. 243 | * 244 | * Additionally, checks, whether Int is a Carmichael number to ensure this. 245 | * 246 | * https://en.wikipedia.org/wiki/Fermat_primality_test 247 | * 248 | * https://en.wikipedia.org/wiki/Carmichael_number 249 | */ 250 | def isPrimeFermatStrict(iterations: Int = 100): Boolean = 251 | Try(isPrimeFermatBorders(localIterations = iterations)) match { 252 | case Success(something) => something && !firstInt.generateCarmichaelNumbers.contains(firstInt) 253 | case Failure(ex) => throw new InputException("\"isPrimeFermat\" " + ex) 254 | } 255 | 256 | /** 257 | * Checks, whether Int is prime with Fermat method with O(log(n)) speed. 258 | * 259 | * Does not generate Carmichaels, so it works only with Ints up to BigInt. 260 | * 261 | * https://en.wikipedia.org/wiki/Fermat_primality_test 262 | * 263 | * https://en.wikipedia.org/wiki/Carmichael_number 264 | */ 265 | private final lazy val CarmichaelsTilBigInt: Set[Int] = Set(561, 41041, 825265, 321197185) 266 | 267 | def isPrimeFermatFast(iterations: Int = 100): Boolean = 268 | Try(isPrimeFermatBorders(localIterations = iterations)) match { 269 | case Success(something) => something && !CarmichaelsTilBigInt.contains(firstInt) 270 | case Failure(ex) => throw new InputException("\"isPrimeFermat\" " + ex) 271 | } 272 | 273 | /** 274 | * Returns lcm of two numbers 275 | */ 276 | def lcmWith(secondInt: Int): Int = (firstInt * secondInt) / firstInt.gcdWith(secondInt) 277 | 278 | /** 279 | * Convolutes the number like: 280 | * 281 | * 127 -> 1+2+7 -> 10 -> 1+0 -> 1 282 | */ 283 | def convolute: Int = 284 | if (firstInt < 0) throw new InputException(NegativeInput) 285 | else convoluteLogic(firstInt) 286 | 287 | private def convoluteLogic(num: Int): Int = 288 | if (num / 10 <= 0) num 289 | else convoluteLogic(num.toString.map(_.asDigit).toList.sum) 290 | 291 | /** 292 | * Returns factorial of a number. 293 | */ 294 | def ! : Int = { 295 | def logic(n: Int = firstInt, total: Int = 1): Int = n match { 296 | case 1 => total 297 | case _ => logic(n-1, total * n) 298 | } 299 | 300 | if (firstInt > 0) logic() 301 | else if (firstInt == 0) 1 302 | else throw new InputException(NegativeInput) 303 | } 304 | 305 | /** 306 | * Returns double factorial of a number. 307 | */ 308 | def !! : Int = { 309 | def logic(n: Int = firstInt, total: Int = 1): Int = n match { 310 | case 1 => total 311 | case 0 => total 312 | case _ => logic(n-2, total * n) 313 | } 314 | 315 | if (firstInt > 0) logic() 316 | else if (firstInt == 0) 1 317 | else throw new InputException(NegativeInput) 318 | } 319 | } 320 | 321 | object IntegerProperties { 322 | implicit def intToPropsImplicit(a: Int): IntegerProperties = new IntegerProperties(a) 323 | } 324 | -------------------------------------------------------------------------------- /src/main/scala/lambdaCalculus/PolymorphicLambdaCalculus.scala: -------------------------------------------------------------------------------- 1 | package lambdaCalculus 2 | 3 | /** 4 | * Purity Project by Daniil Tekunov 5 | */ 6 | object PolymorphicDataCalculus { 7 | 8 | /** 9 | * Basic types for polymorphic lambda calculus 10 | */ 11 | type λ_Typed[T] = T => T => T 12 | 13 | type λ_λ_Typed[T] = λ_Typed[λ_Typed[T]] 14 | 15 | type λ_λ_λ_Typed[T] = λ_λ_Typed[T] => λ_Typed[T] => λ_Typed[T] 16 | 17 | type λ_λ_λ_λ_Typed[T] = (λ_Typed[T]) => T => T 18 | 19 | 20 | /** 21 | * Boolean constants for polymorphic lambda calculus 22 | */ 23 | def λtrue[T]: λ_Typed[T] = (s: T) => (z: T) => s 24 | 25 | def λfalse[T]: λ_Typed[T] = (s: T) => (z: T) => z 26 | 27 | 28 | /** 29 | * Boolean constants, realised via abstractions 30 | */ 31 | def abstract_λtrue[T]: λ_Typed[T] = λnot(λfalse) 32 | 33 | def abstract_λfalse[T]: λ_Typed[T] = λnot(λtrue) 34 | 35 | 36 | /** 37 | * Boolean operators for polymorphic lambda calculus 38 | */ 39 | def λif[T](p: λ_Typed[T]): λ_Typed[T] = (t: T) => (e: T) => p(t)(e) 40 | 41 | def λand[T](n: λ_λ_Typed[T])(m: λ_Typed[T]): λ_Typed[T] = n(m)(λfalse) 42 | 43 | def λor[T](n: λ_λ_Typed[T])(m: λ_Typed[T]): λ_Typed[T] = n(λtrue)(m) 44 | 45 | def λnot[T](n: λ_λ_Typed[T]): λ_Typed[T] = n(λfalse)(λtrue) 46 | 47 | 48 | /** 49 | * Realizes "pair" operation, that combines two numbers in polymorphic lambda calculus 50 | */ 51 | def pair[T](a: λ_λ_Typed[T]): λ_λ_Typed[T] = (b: λ_Typed[T]) => (t: λ_Typed[T]) => a(b)(t) 52 | 53 | def first[T]: λ_λ_λ_Typed[T] = (p: λ_λ_Typed[T]) => p(λtrue) 54 | 55 | def second[T]: λ_λ_λ_Typed[T] = (p: λ_λ_Typed[T]) => p(λfalse) 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/scala/lambdaCalculus/PureLambdaCalculus.scala: -------------------------------------------------------------------------------- 1 | package lambdaCalculus 2 | 3 | object PureLambdaCalculus { 4 | 5 | /** 6 | * Axiomatic types for lambda calculus 7 | */ 8 | type λ_T[T] = T => T 9 | 10 | type λ_λ_T[T] = λ_T[T] => T => T 11 | 12 | type λ_λ_λ_T[T] = λ_λ_T[T] => λ_λ_T[T] 13 | 14 | /** 15 | * Basic Church numbers realised on basic abstractions 16 | */ 17 | def zero[T]: λ_λ_λ_T[T] = (s: λ_λ_T[T]) => (z: λ_T[T]) => z 18 | 19 | def one[T]: λ_λ_λ_T[T] = (s: λ_λ_T[T]) => (z: λ_T[T]) => s(z) 20 | 21 | def two[T]: λ_λ_λ_T[T] = (s: λ_λ_T[T]) => (z: λ_T[T]) => s(s(z)) 22 | 23 | /** 24 | * Realizes "successor" operation, that adds a value to a number in Church numbers 25 | */ 26 | def successor[T](n: λ_λ_λ_T[T]): λ_λ_λ_T[T] = (s: λ_λ_T[T]) => (z: λ_T[T]) => s( n(s)(z) ) 27 | 28 | /** 29 | * Realizes "addition" operation, that adds a number to another number in Church numbers 30 | */ 31 | def addition[T](n: λ_λ_λ_T[T])(m: λ_λ_λ_T[T]): λ_λ_λ_T[T] = (s: λ_λ_T[T]) => (z: λ_T[T]) => n(s)( m(s)(z) ) 32 | 33 | /** 34 | * Realizes "multiplication" operation, that multiplies a number with another number in Church numbers 35 | */ 36 | def multiplication[T](n: λ_λ_λ_T[T])(m: λ_λ_λ_T[T]): λ_λ_λ_T[T] = (s: λ_λ_T[T]) => (z: λ_T[T]) => n(m(s))(z) 37 | 38 | 39 | def one_succ[T]: λ_λ_T[T] = successor(zero) 40 | 41 | def two_succ[T]: λ_λ_T[T] = successor(one) 42 | } 43 | -------------------------------------------------------------------------------- /src/main/scala/listOperations/Changes.scala: -------------------------------------------------------------------------------- 1 | package listOperations 2 | 3 | import charOperations.CharProperties._ 4 | import listOperations.miscellaneous.CustomImplicitConversions._ 5 | import listOperations.miscellaneous.{CurrentAndPositiveNegativeCounters, CurrentAndVowelConsonantCounters} 6 | import utils.ExceptionMessages.EmptyInput 7 | import utils.InputException 8 | 9 | /** 10 | * Purity project by Daniil Tekunov. 11 | */ 12 | object Changes { 13 | 14 | /** 15 | * Checks if element's sign changed from positive to negative 16 | */ 17 | private def isPositiveToNegative(a: Int, b: Int): Boolean = a > 0 && b < 0 18 | 19 | /** 20 | * Checks if element changed from vowel to consonant 21 | */ 22 | private def isVowelToConsonant(a: Char, b: Char): Boolean = a.isVowel && b.isConsonant 23 | 24 | /** 25 | * Counts, whether there were changes from positive integer to negative integer in a list 26 | */ 27 | def countSignChanges(input: List[Int]): List[Int] = input match { 28 | case List() => 29 | throw new InputException("\"Sign changes counter\" " + EmptyInput) 30 | case _ => 31 | val outcomeTuple = input.foldLeft(CurrentAndPositiveNegativeCounters()) ( 32 | (fin: CurrentAndPositiveNegativeCounters, cur: Int) => 33 | (cur, 34 | if (isPositiveToNegative(fin.current, cur)) fin.counterOfPositiveToNegative + 1 35 | else fin.counterOfPositiveToNegative, 36 | 37 | if (isPositiveToNegative(cur, fin.current)) fin.counterOfNegativeToPositive + 1 38 | else fin.counterOfNegativeToPositive) 39 | ) 40 | 41 | List(outcomeTuple.counterOfPositiveToNegative, outcomeTuple.counterOfNegativeToPositive) 42 | } 43 | 44 | /** 45 | * Counts, whether there were changes from vowel to consonant letter in a list 46 | */ 47 | def countLetterChanges(input: List[Char]): List[Int] = input match { 48 | case List() => 49 | throw new InputException("\"Letter changes counter\" " + EmptyInput) 50 | case _ => 51 | val outcomeTuple = input.foldLeft(CurrentAndVowelConsonantCounters()) ( 52 | (fin: CurrentAndVowelConsonantCounters, cur: Char) => 53 | (cur, 54 | if (isVowelToConsonant(fin.current, cur)) fin.counterOfVowelToConsonant + 1 55 | else fin.counterOfVowelToConsonant, 56 | 57 | if (isVowelToConsonant(cur, fin.current)) fin.counterOfConsonantToVowel + 1 58 | else fin.counterOfConsonantToVowel) 59 | ) 60 | 61 | List(outcomeTuple.counterOfVowelToConsonant, outcomeTuple.counterOfConsonantToVowel) 62 | } 63 | 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/scala/listOperations/ListProperties.scala: -------------------------------------------------------------------------------- 1 | package listOperations 2 | 3 | import utils.ExceptionMessages.{EmptyInput, NoneInput, BorderInput} 4 | import utils.InputException 5 | 6 | import scala.annotation.tailrec 7 | import scala.util.{Failure, Success, Try} 8 | 9 | /** 10 | * Contains different functions, that affect lists. 11 | * 12 | * Purity project by Daniil Tekunov. 13 | */ 14 | object ListProperties { 15 | 16 | /** 17 | * Returns nth element of a list. 18 | */ 19 | def get[A](input: List[A], index: Int): A = (index, input) match { 20 | case (0, element :: _) => element 21 | case (n, _ :: tail ) => get(tail, n - 1) 22 | case (_, Nil ) => throw new InputException("\"getElement\" " + EmptyInput) 23 | } 24 | 25 | /** 26 | * Checks, whether a list is a palindrome. 27 | */ 28 | def isPalindrome[A](input: List[A]): Boolean = { 29 | if (input.isEmpty) throw new InputException("\"isPalindrome\" " + EmptyInput) 30 | else input == input.reverse 31 | } 32 | 33 | /** 34 | * Checks, whether a value is a palindrome. 35 | */ 36 | def isPalindrome[A](input: A): Boolean = input match { 37 | case None => throw new InputException("\"isPalindrome\" " + NoneInput) 38 | 39 | case Some(element) => element.toString == element.toString.reverse 40 | } 41 | 42 | /** 43 | * Checks whether the list is sorted. 44 | */ 45 | def isSorted(input: List[Int])(implicit ord: Ordering[Int]): Boolean = input match { 46 | case List() => true 47 | case List(_) => true 48 | case _ => input.sliding(2).forall { 49 | case List(firstElement, secondElement) => ord.lteq(firstElement, secondElement) 50 | } 51 | } 52 | 53 | /** 54 | * Realisation of a standard binary search. 55 | * 56 | * https://en.wikipedia.org/wiki/Binary_search_algorithm 57 | * 58 | * Worst speed: O(log(n)) 59 | * 60 | * Average speed: O(log(n)) 61 | * 62 | * Best speed: O(1) 63 | * 64 | */ 65 | @tailrec 66 | def binarySearch(input: List[Int], element: Int): Int = { 67 | @tailrec 68 | def binarySearchLogic(enter: Int = 0, exit: Int = input.length - 1): Option[Int] = 69 | enter + (exit - enter) / 2 match { 70 | case between if input(between) > element => binarySearchLogic(enter, exit - between) 71 | case between if input(between) < element => binarySearchLogic(enter + between) 72 | case between if input(between) == element => Some(between) 73 | case _ if enter < exit => None 74 | } 75 | 76 | if (input.isEmpty) throw new InputException(EmptyInput) 77 | else if (!isSorted(input)) binarySearch(input.sorted, element) 78 | else if (input.last == element) input.length - 1 79 | else Try(binarySearchLogic()) match { 80 | case Success(something) => something.get 81 | case Failure(_) => throw new InputException(NoneInput) 82 | } 83 | } 84 | 85 | /** 86 | * Realisation of a standard linear search. 87 | * 88 | * https://en.wikipedia.org/wiki/Linear_search 89 | * 90 | * Worst speed: O(n) 91 | * 92 | * Average speed: O(n/2) 93 | * 94 | * Best speed: O(1) 95 | * 96 | */ 97 | def linearSearch[A](input: List[A], element: A): Int = { 98 | 99 | @tailrec 100 | def linearSearchLogic[B](input: List[B], element: B, iter: Int = 0): Int = input match { 101 | case elem :: tail => 102 | if (elem == element) iter 103 | else linearSearchLogic(tail, element, iter + 1) 104 | case Nil => throw new InputException() 105 | } 106 | 107 | if (input.nonEmpty) linearSearchLogic(input, element) 108 | else throw new InputException(NoneInput) 109 | } 110 | 111 | /** 112 | * Generates all possible combiantions of a given list. 113 | */ 114 | def generatePermutations[A](input: List[A], listLen: Int): List[List[A]] = 115 | if (listLen > input.size) throw new InputException(BorderInput) 116 | else if (listLen == 1) input.map(List(_)) 117 | else generatePermutations(input.tail, listLen - 1).map(_ + input.head) ++ combinations(input.tail, listLen) 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/scala/listOperations/miscellaneous/CustomCaseClasses.scala: -------------------------------------------------------------------------------- 1 | package listOperations.miscellaneous 2 | 3 | /** 4 | * Saves values of current element in foldLeft and count of changes of negative to positive and positive to negative 5 | */ 6 | case class CurrentAndPositiveNegativeCounters(current: Int = 0, 7 | counterOfPositiveToNegative: Int = 0, 8 | counterOfNegativeToPositive: Int = 0) 9 | 10 | /** 11 | * Saves values of current element in foldLeft and count of changes of vowel to consonant and consonant to vowel 12 | */ 13 | case class CurrentAndVowelConsonantCounters(current: Char = '\0', 14 | counterOfVowelToConsonant: Int = 0, 15 | counterOfConsonantToVowel: Int = 0) 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/scala/listOperations/miscellaneous/CustomImplicitConversions.scala: -------------------------------------------------------------------------------- 1 | package listOperations.miscellaneous 2 | 3 | object CustomImplicitConversions { 4 | 5 | /** 6 | * Applies Tuple3[Int, Int, Int] to a case class implicitly. 7 | */ 8 | implicit def tuple3ToSignCounters(a: (Int, Int, Int)): CurrentAndPositiveNegativeCounters = { 9 | CurrentAndPositiveNegativeCounters.apply( 10 | current = a._1, 11 | counterOfPositiveToNegative = a._2, 12 | counterOfNegativeToPositive = a._3) 13 | } 14 | 15 | /** 16 | * Applies Tuple3[Char, Int, Int] to a case class implicitly. 17 | */ 18 | implicit def tuple3ToLetterCounters(a: (Char, Int, Int)): CurrentAndVowelConsonantCounters = { 19 | CurrentAndVowelConsonantCounters.apply( 20 | current = a._1, 21 | counterOfVowelToConsonant = a._2, 22 | counterOfConsonantToVowel = a._3) 23 | } 24 | 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/main/scala/sortingAlgorithms/BubbleSort.scala: -------------------------------------------------------------------------------- 1 | package sortingAlgorithms 2 | import scala.annotation.tailrec 3 | 4 | /** 5 | * This object contains function, that realises bubble sorting algorithm. 6 | * 7 | * https://en.wikipedia.org/wiki/Bubble_sort 8 | * 9 | * Worst speed: O(pow(n)) 10 | * 11 | * Average speed: O(pow(n)) 12 | * 13 | * Best speed: O(n) 14 | * 15 | * Purity project by Daniil Tekunov. 16 | */ 17 | object BubbleSort { 18 | 19 | def bubbleSort(basicList: List[Int]): List[Int] = basicList match { 20 | case List() => List() 21 | case _ => bubble(basicList, Nil, Nil) 22 | } 23 | 24 | @tailrec 25 | private def bubble(basic: List[Int], rest: List[Int], sorted: List[Int]): List[Int] = basic match { 26 | // If we have a single element in a basic list 27 | case element :: Nil => 28 | // end the rest list is empty, we add that element to a sorted list 29 | if (rest.isEmpty) element :: sorted 30 | // else we add this element to a sorted list and call the function again, without that element 31 | else bubble(rest, Nil, element :: sorted) 32 | // If we have 2+ elements 33 | case firstElement :: secondElement :: next => 34 | // if first found element is greater, than another, we call the function again, without second element 35 | // and we add second element to the rest list 36 | if (firstElement > secondElement) bubble(firstElement :: next, secondElement :: rest, sorted) 37 | //else we realize that operation, via swapped elements 38 | else bubble(secondElement :: next, firstElement :: rest, sorted) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/scala/sortingAlgorithms/HeapSort.scala: -------------------------------------------------------------------------------- 1 | package sortingAlgorithms 2 | 3 | import scala.annotation.tailrec 4 | 5 | /** 6 | * This object contains Heap sort 7 | * 8 | * https://en.wikipedia.org/wiki/Heapsort 9 | * 10 | * Worst speed: O(n*log(n)) 11 | * 12 | * Average speed: O(n*log(n)) 13 | * 14 | * Best speed: O(n*log(n) 15 | * 16 | * Purity project by Daniil Tekunov. 17 | */ 18 | sealed abstract class HeapSort[+A] { def rank: Int } 19 | case object EmptyHeapSort extends HeapSort[Nothing] { def rank = 0 } 20 | case class NonEmptyHeapSort(rank: Int, element: Int, left: HeapSort[Int], right: HeapSort[Int]) extends HeapSort[Int] 21 | 22 | object HeapSort { 23 | def apply(x: Int): HeapSort[Int] = 24 | this(x, EmptyHeapSort, EmptyHeapSort) 25 | 26 | def apply(x: Int, a: HeapSort[Int], b: HeapSort[Int]): HeapSort[Int] = 27 | if (a.rank > b.rank) 28 | NonEmptyHeapSort(b.rank + 1, x, a, b) 29 | else 30 | NonEmptyHeapSort(a.rank + 1, x, b, a) 31 | 32 | private def merge(a: HeapSort[Int], b: HeapSort[Int]): HeapSort[Int] = 33 | (a, b) match { 34 | case (x, EmptyHeapSort) => x 35 | case (EmptyHeapSort, x) => x 36 | case (x: NonEmptyHeapSort, y: NonEmptyHeapSort) => 37 | if (x.element >= y.element) 38 | HeapSort(x.element, x.left, merge(x.right, y)) 39 | else 40 | HeapSort(y.element, y.left, merge(x, y.right)) 41 | } 42 | 43 | private def toList(heap: HeapSort[Int]): List[Int] = 44 | toListWithMemory(List(), heap) 45 | 46 | @tailrec 47 | private def toListWithMemory(memo: List[Int], heap: HeapSort[Int]): List[Int] = 48 | heap match { 49 | case EmptyHeapSort => memo 50 | case x: NonEmptyHeapSort => 51 | toListWithMemory(x.element :: memo, merge(x.left, x.right)) 52 | } 53 | 54 | def heapSort(xs: List[Int]): List[Int] = 55 | toList(xs.foldLeft(EmptyHeapSort: HeapSort[Int])((memo, x) => merge(HeapSort(x), memo))) 56 | } 57 | -------------------------------------------------------------------------------- /src/main/scala/sortingAlgorithms/InsertionSort.scala: -------------------------------------------------------------------------------- 1 | package sortingAlgorithms 2 | 3 | import scala.annotation.tailrec 4 | 5 | /** 6 | * This object contains function, that realises insertion sorting algorithm. 7 | * 8 | * https://en.wikipedia.org/wiki/Insertion_sort 9 | * 10 | * Worst speed: O(pow(n)) 11 | * 12 | * Average speed: O(pow(n)) 13 | * 14 | * Best speed: O(n) 15 | * 16 | * Purity project by Daniil Tekunov. 17 | */ 18 | object InsertionSort { 19 | 20 | def insertionSort(list: List[Int]): List[Int] = sorting(list, Nil) match { 21 | case Nil => List() 22 | case something => something 23 | } 24 | 25 | @tailrec 26 | private def sorting(basis: List[Int], finalisedList: List[Int]): List[Int] = basis match { 27 | // if a list contains more than a single element, we insert the first element into thr outcome list 28 | case element :: tailElements => sorting(tailElements, insertion(element, finalisedList)) 29 | // else we return outcome list 30 | case Nil => finalisedList 31 | } 32 | 33 | private def insertion(incomeElement: Int, outputList: List[Int]): List[Int] = outputList match { 34 | // if an income element is greater than first element in output list 35 | case element :: tailElements if incomeElement > element => 36 | // we sort outcome list and insert the element at the beginning of it 37 | element :: insertion(incomeElement, tailElements) 38 | // else we put income element athe beginning of a list 39 | case _ => incomeElement :: outputList 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/scala/sortingAlgorithms/MergeSort.scala: -------------------------------------------------------------------------------- 1 | package sortingAlgorithms 2 | 3 | /** 4 | * This object contains function, that realises merge sort algorithm. 5 | * 6 | * https://en.wikipedia.org/wiki/Merge_sort 7 | * 8 | * Worst speed: O(n*log(n)) 9 | * 10 | * Average speed: O(n*log(n)) 11 | * 12 | * Best speed: O(n*log(n)) 13 | * 14 | * Purity project by Daniil Tekunov. 15 | */ 16 | object MergeSort { 17 | 18 | def mergeSort(input: List[Int]): List[Int] = { 19 | // If length of a list is 0, then we just return an empty list 20 | if (input.length / 2 == 0) input 21 | else { 22 | // else, we split the list by two parts - left and right 23 | val (left, right) = input.splitAt(input.length / 2) 24 | // and merge recursively parts of the list 25 | merge(mergeSort(left), mergeSort(right)) 26 | } 27 | } 28 | 29 | private def merge(left: List[Int], right: List[Int]): List[Int] = (left, right) match { 30 | // if the left part of a list is a single element, we return this element 31 | case (_, Nil) => left 32 | // if the right part of a list is a single element, we return this element 33 | case (Nil, _) => right 34 | // if they are both non-empty, 35 | case (leftHead :: leftTail, rightHead :: rightTail) => 36 | // we merge the biggest part of a list with merged smaller part 37 | if (leftHead < rightHead) leftHead::merge(leftTail, right) 38 | else rightHead :: merge(left, rightTail) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/scala/sortingAlgorithms/QuickSort.scala: -------------------------------------------------------------------------------- 1 | package sortingAlgorithms 2 | 3 | /** 4 | * This object contains function, that realises quick sorting algorithm. 5 | * 6 | * https://en.wikipedia.org/wiki/Quicksort 7 | * 8 | * Worst speed: O(pow(n)) 9 | * 10 | * Average speed: O(n*log(n)) 11 | * 12 | * Best speed: O(n*log(n)) 13 | * 14 | * In case that we take first element as pivot, algorithm works worse with sorted lists. 15 | * 16 | * Purity project by Daniil Tekunov. 17 | */ 18 | object QuickSort { 19 | 20 | def quickSort(list: List[Int]): List[Int] = { 21 | list match { 22 | // If a list contains no elements, we do not return anything. 23 | case Nil => Nil 24 | // If a list contains only one element, we just return it. 25 | case singleElement :: Nil => List(singleElement) 26 | // If a list contains more than one element, 27 | case middleElem :: tail => 28 | // we quickSort the part of the list, that is less than middle element, 29 | quickSort(tail.filter(lessElem => lessElem <= middleElem)) ::: 30 | // we add middle element to a sorted part above. 31 | List(middleElem) ::: 32 | // and we quickSort the part of the list, that is greater than middle element and add it to a list above. 33 | quickSort(tail.filter(greaterElem => greaterElem > middleElem)) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/scala/sortingAlgorithms/SelectionSort.scala: -------------------------------------------------------------------------------- 1 | package sortingAlgorithms 2 | 3 | import scala.annotation.tailrec 4 | 5 | /** 6 | * This object contains function, that realises selection sorting algorithm. 7 | * 8 | * https://en.wikipedia.org/wiki/Selection_sort 9 | * 10 | * Worst speed: O(pow(n)) 11 | * 12 | * Average speed: O(pow(n)) 13 | * 14 | * Best speed: O(pow(n)) 15 | * 16 | */ 17 | object SelectionSort { 18 | 19 | def selectionSort(list: List[Int]): List[Int] = { 20 | 21 | def reWrite(firstPart: List[Int], secondPart: List[Int]): List[Int] = firstPart match { 22 | case element :: next => select(element, next, Nil, secondPart) 23 | case Nil => secondPart 24 | } 25 | 26 | @tailrec 27 | def select(firstElement: Int, secondElement: List[Int], firstPart: List[Int], secondPart: List[Int]): List[Int] = 28 | secondElement match { 29 | case element :: next => 30 | if (firstElement > element) select(firstElement, next, element :: firstPart, secondPart) 31 | else select(element, next, firstElement :: firstPart, secondPart) 32 | case Nil => reWrite(firstPart, firstElement :: secondPart) 33 | } 34 | 35 | reWrite(list, Nil) 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/scala/sortingAlgorithms/unseriousAlgorithms/Bogosort.scala: -------------------------------------------------------------------------------- 1 | package sortingAlgorithms.unseriousAlgorithms 2 | 3 | import listOperations.ListProperties.isSorted 4 | 5 | import scala.annotation.tailrec 6 | import scala.util.Random.shuffle 7 | 8 | 9 | /** 10 | * This object contains function, that realises bogosort algorithm. 11 | * 12 | * https://en.wikipedia.org/wiki/Bogosort 13 | * 14 | * Worst speed: Unbounded 15 | * 16 | * Average speed: O((n+1)!) 17 | * 18 | * Best speed: O(n) 19 | * 20 | * Purity project by Daniil Tekunov. 21 | */ 22 | object Bogosort { 23 | 24 | @tailrec 25 | def bogosort(input: List[Int]): List[Int] = 26 | if (isSorted(input)) input 27 | else bogosort(shuffle(input)) 28 | } 29 | -------------------------------------------------------------------------------- /src/main/scala/sortingAlgorithms/unseriousAlgorithms/SleepSort.scala: -------------------------------------------------------------------------------- 1 | package sortingAlgorithms.unseriousAlgorithms 2 | 3 | /** 4 | * This object contains function, that realises sleep sort algorithm. 5 | * 6 | * https://rosettacode.org/wiki/Sorting_algorithms/Sleep_sort 7 | * 8 | * Worst speed: O(max(input) + n) 9 | * 10 | * Average speed: O(max(input) + n) 11 | * 12 | * Best speed: O(max(input) + n) 13 | * 14 | * Purity project by Daniil Tekunov. 15 | */ 16 | object SleepSort { 17 | 18 | def sleepSort(input: List[Int]): Unit = 19 | input.foreach(i => new Thread { 20 | override def run() { 21 | Thread.sleep(i * 30) 22 | print(i + "|") 23 | } 24 | }.start()) 25 | } 26 | -------------------------------------------------------------------------------- /src/main/scala/statistics/KolmogorovSmirnov.scala: -------------------------------------------------------------------------------- 1 | import scala.math.{abs, sqrt} 2 | 3 | /** 4 | * Purity project by Daniil Tekunov. 5 | */ 6 | object KolmogorovSmirnovTest { 7 | 8 | /** 9 | * Returns, whether the distribution of the value increased or not, using Kolmogorov-Smirnov test. 10 | */ 11 | def ColmogorovSmirnov(n: List[Int], m: List[Int]): Boolean = { 12 | 13 | val nLen = n.length 14 | 15 | val mLen = m.length 16 | 17 | val tRange = n ++ m 18 | 19 | val t = tRange.min until tRange.max 20 | 21 | (for (i <- t) yield { 22 | val localN = n.count { x => x <= i } / nLen 23 | 24 | val localM = m.count { x => x <= i } / mLen 25 | 26 | (localN - localM).abs 27 | 28 | }).max > 1.36 * sqrt((nLen + mLen) / (nLen * mLen)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/scala/time/Time.scala: -------------------------------------------------------------------------------- 1 | package time 2 | 3 | import utils.InputException 4 | import utils.ExceptionMessages.WrongTimeInput 5 | 6 | class Time(val input: Int) { 7 | import Time._ 8 | 9 | /** 10 | * Service functions 11 | */ 12 | private def up60: Int = 13 | if (input < 0) throw new InputException(WrongTimeInput) 14 | else input * 60 15 | 16 | private def down60: Int = 17 | if (input < 0) throw new InputException(WrongTimeInput) 18 | else input / 60 19 | 20 | /** 21 | * Converts seconds to hours 22 | */ 23 | def hoursToSeconds: Int = (input up60) up60 24 | 25 | /** 26 | * Converts minutes to hours 27 | */ 28 | def minutesToSeconds: Int = input up60 29 | 30 | /** 31 | * Converts seconds to minutes 32 | */ 33 | def secondsToMinutes: Int = input down60 34 | 35 | /** 36 | * Converts seconds to hours 37 | */ 38 | def secondsToHours: Int = (input down60) down60 39 | 40 | /** 41 | * Converts hours to minutes 42 | */ 43 | def hoursToMinutes: Int = input up60 44 | 45 | /** 46 | * Converts minutes to hours 47 | */ 48 | def minutesToHours: Int = input down60 49 | 50 | } 51 | 52 | object Time { 53 | implicit def intToTime(a: Int): Time = new Time(a) 54 | } 55 | -------------------------------------------------------------------------------- /src/main/scala/utils/ExceptionMessages.scala: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | /** 4 | * Utility messages to handle exceptions 5 | */ 6 | object ExceptionMessages { 7 | lazy val EmptyInput: String = "function got empty input" 8 | lazy val NoneInput: String = "function got None instead of Some()" 9 | lazy val NegativeOrZeroInput: String = "function got negative input, expected n >= 0" 10 | lazy val ZeroInput: String = "function got 0, expected n != 0" 11 | lazy val NegativeInput: String = "function got negative input, expected n > 0" 12 | lazy val PositiveInput: String = "function got positive input, expected n < 0" 13 | lazy val BorderInput: String = "function got border input, expected valid n" 14 | lazy val StackOverflowInput: String = "function's recursion in too deep, expected smaller input" 15 | lazy val DeprecatedSymbolInput: String = "function got deprecated symbol" 16 | lazy val OverflowInput: String = "input is too big" 17 | lazy val WrongTimeInput: String = "time converter got wrong input" 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/utils/InputException.scala: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | 4 | /** 5 | * Default class+object for handling Input exceptions 6 | */ 7 | class InputException(message: String = null, cause: Exception = null) extends Exception(message, cause) { 8 | def this() { 9 | this(null, null) 10 | } 11 | 12 | def this(message: String) { 13 | this(message, null) 14 | } 15 | 16 | def this(cause: Exception) { 17 | this(null, cause) 18 | } 19 | } 20 | object EmptyInputException { 21 | def apply(message: String) = new InputException(message, null) 22 | def apply(cause: Exception) = new InputException(null, cause) 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/scala/utils/MathConstants.scala: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | /** 4 | * Contains some important math constants. 5 | * 6 | * Purity project by Daniil Tekunov. 7 | */ 8 | object MathConstants { 9 | 10 | /** 11 | * https://en.wikipedia.org/wiki/Pi 12 | */ 13 | final val pi: Double = 3.141592653589793 14 | 15 | /** 16 | * https://en.wikipedia.org/wiki/Turn_(geometry)#Tau_proposals 17 | */ 18 | final val tau: Double = 6.283185307179586 19 | 20 | /** 21 | * https://en.wikipedia.org/wiki/E_(mathematical_constant) 22 | */ 23 | final val e: Double = 2.718281828459045 24 | 25 | /** 26 | * https://en.wikipedia.org/wiki/Square_root_of_2 27 | */ 28 | final val PythagorasConst: Double = 1.414213562373095 29 | 30 | /** 31 | * https://en.wikipedia.org/wiki/Square_root_of_3 32 | */ 33 | final val TheodorusConst: Double = 1.732050807568877 34 | 35 | /** 36 | * https://en.wikipedia.org/wiki/Euler–Mascheroni_constant 37 | */ 38 | final val gamma: Double = 0.577215664901532 39 | 40 | /** 41 | * https://en.wikipedia.org/wiki/Golden_ratio 42 | */ 43 | final val phi: Double = 1.618033988749894 44 | 45 | /** 46 | * https://en.wikipedia.org/wiki/Plastic_number 47 | */ 48 | final val plasticNumber: Double = 1.324717957244746 49 | } 50 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/CharTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.Matchers._ 4 | import charOperations.CharProperties._ 5 | import org.scalatest.FunSuite 6 | import utils.InputException 7 | 8 | 9 | 10 | class CharTests extends FunSuite { 11 | 12 | final val Vowels: List[Char] = List( 13 | 'a', 'e', 'i', 'o', 'u', 'y', 14 | 'A', 'E', 'I', 'O', 'U', 'Y') 15 | 16 | final val Consonants: List[Char] = List( 17 | 'b', 'c', 'd', 'f', 'g', 18 | 'h', 'j', 'k', 'l', 'm', 19 | 'n', 'p', 'q', 'r', 's', 20 | 't', 'v', 'w', 'x', 'z') 21 | 22 | test("Testing of isVowel") { 23 | Vowels.foreach { cur: Char => cur.isVowel shouldBe true } 24 | Vowels.foreach { cur: Char => cur.isConsonant shouldBe false } 25 | assertThrows[InputException] { 26 | ','.isVowel 27 | } 28 | } 29 | 30 | test("Testing of isConsonant") { 31 | Consonants.foreach { cur: Char => cur.isConsonant shouldBe true } 32 | Consonants.foreach { cur: Char => cur.toUpper.isConsonant shouldBe true } 33 | Consonants.foreach { cur: Char => cur.isVowel shouldBe false } 34 | assertThrows[InputException] { 35 | ','.isConsonant 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/ComplexOperationsTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.Matchers._ 4 | import org.scalatest.FunSuite 5 | import complexOperations.Complex 6 | 7 | class ComplexOperationsTests extends FunSuite { 8 | 9 | val firstRational = new Complex(12,1) 10 | val secondRational = new Complex(8,2) 11 | 12 | test("Testing of the basic rational operations") { 13 | (firstRational / secondRational).toString should be 14 | (firstRational * secondRational).toString should be 15 | (firstRational - secondRational).toString should be 16 | (firstRational + secondRational).toString should be 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/DataStructuresTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.FunSuite 4 | import org.scalatest.Matchers._ 5 | import dataStructures.{ListStructure, NilType, Queue, Stack} 6 | import dataStructures.LinkedList._ 7 | import dataStructures.miscellaneous.DataStructureException 8 | import dataStructures.Queue._ 9 | import dataStructures.Stack._ 10 | 11 | 12 | class DataStructuresTests extends FunSuite { 13 | 14 | test("CRUD testing of a LinkedList") { 15 | create(1) shouldBe ListStructure(1, NilType) 16 | 17 | val a = create(1, create(2)) 18 | a shouldBe ListStructure(1, ListStructure(2, NilType)) 19 | 20 | val b = a.remove(1) 21 | b shouldBe ListStructure(2, NilType) 22 | 23 | val c = b.remove(2) 24 | c shouldBe NilType 25 | } 26 | 27 | test("Additional testing of a LinkedList") { 28 | 29 | } 30 | 31 | test("CRUD testing of a Queue") { 32 | val a: Queue[Nothing] = createEmptyQueue 33 | 34 | a.isEmpty shouldBe true 35 | 36 | val b = a.enqueue("Element1") 37 | 38 | val (c, d): (String, Queue[String]) = b.dequeue 39 | 40 | //d shouldBe a 41 | 42 | c shouldBe "Element1" 43 | } 44 | 45 | test("CRUD testing of a Stack") { 46 | val a: Stack[Nothing] = createEmptyStack 47 | 48 | a.isEmpty shouldBe true 49 | 50 | val b: Stack[String] = a.add("Element1") 51 | 52 | val (c, d): (String, Stack[String]) = b.remove 53 | 54 | //d shouldBe a 55 | 56 | c shouldBe "Element1" 57 | } 58 | 59 | test("Testing of a Set") { 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/DoubleTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | import org.scalatest.FunSuite 3 | import org.scalatest.Matchers._ 4 | import doubleOperations.DoubleProperties._ 5 | 6 | class DoubleTests extends FunSuite { 7 | 8 | test("Testing of inverse") { 9 | 17.inverse shouldBe 0.058823529411764705 10 | 2.inverse shouldBe 0.5 11 | -1.inverse shouldBe -1 12 | } 13 | 14 | test("Testing of sqrDouble") { 15 | 17.0.sqrDouble shouldBe 289.0 16 | 0.sqrDouble shouldBe 0 17 | -1.0.sqrDouble shouldBe 1 18 | } 19 | 20 | test("Testing of the abs") { 21 | (17.0).abs shouldBe 17.0 22 | (-17.0).abs shouldBe 17.0 23 | } 24 | 25 | test("Testing of the toDegrees") { 26 | (17.0).toDegrees should be 27 | (-17.0).toDegrees should be 28 | } 29 | 30 | test("Testing of the incDouble") { 31 | (17.0).incDouble shouldBe 18.0 32 | (-17.0).incDouble shouldBe (-16.0) 33 | } 34 | 35 | 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/EncodersDecodersTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.Matchers._ 4 | import cryptographyOperations.encoders.{GrayEncoder, HuffmanEncoder, MorseEncoder, RLE_Encoder} 5 | import cryptographyOperations.decoders.{GrayDecoder, MorseDecoder, RLE_Decoder} 6 | import org.scalatest.FunSuite 7 | import utils.InputException 8 | 9 | class EncodersDecodersTests extends FunSuite { 10 | 11 | test("Testing of RLE encoder/decoder") { 12 | 13 | val TestList = List('a, 'a, 'a, 'b, 'b, 'b, 'a, 'a, 'c) 14 | val RLE_EncodedResult: List[(Int, Symbol)] = List((3, 'a), (3, 'b), (2, 'a), (1, 'c)) 15 | 16 | val encodeResult: List[(Int, Symbol)] = RLE_Encoder.encode(TestList) 17 | val decodeResult: List[Symbol] = RLE_Decoder.decode(RLE_EncodedResult) 18 | encodeResult shouldBe RLE_EncodedResult 19 | decodeResult shouldBe TestList 20 | } 21 | 22 | test("Testing of the Huffman encoder") { 23 | val testString = "I am string, that really wants to be encoded. I may contain some rare symbols, like ~ or ^&." 24 | 25 | val encodedHuffmanString = List(1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 26 | 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 27 | 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 28 | 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 29 | 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 30 | 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 31 | 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 32 | 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 33 | 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 34 | 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 35 | 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0) 36 | 37 | HuffmanEncoder.encode(testString) shouldBe encodedHuffmanString 38 | 39 | } 40 | 41 | test("Testing of Gray encoder/decoder") { 42 | 43 | GrayEncoder.encode(4) shouldBe 6 44 | assertThrows[InputException] { 45 | GrayEncoder.encode(-1) 46 | } 47 | 48 | GrayDecoder.decode(6) shouldBe 4 49 | assertThrows[InputException] { 50 | GrayDecoder.decode(-1) 51 | } 52 | 53 | } 54 | 55 | test("Testing of Morse encoder/decoder") { 56 | MorseDecoder.decode(MorseEncoder.encode("sos")) shouldBe "sos" 57 | 58 | assertThrows[InputException] { 59 | MorseEncoder.encode(";;;;;;") 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/IntegerGeneratorsMathTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.FunSuite 4 | import utils.InputException 5 | import integerOperations.IntegerGeneratorsMath._ 6 | import org.scalatest.Matchers._ 7 | 8 | class IntegerGeneratorsMathTests extends FunSuite { 9 | 10 | test("Testing of generateFermatNumbers") { 11 | 258.generateFermatNumbers shouldBe List(3, 5, 17, 257) 12 | assertThrows[InputException] { 13 | (-1).generateFermatNumbers 14 | } 15 | 3.generateFermatNumbers shouldBe List(3) 16 | } 17 | 18 | test("Testing of generateEratosthenesPrimes") { 19 | 17.generateEratosthenesPrimes shouldBe List(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59) 20 | (-1).generateEratosthenesPrimes shouldBe List() 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/IntegerGeneratorsTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.FunSuite 4 | import integerOperations.IntegerGenerators._ 5 | import org.scalatest.Matchers._ 6 | import utils.InputException 7 | 8 | 9 | class IntegerGeneratorsTests extends FunSuite { 10 | 11 | final val emptyList = List() 12 | 13 | test("Testing of arithmeticProgression") { 14 | 10.generateArithmeticProgression shouldBe List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 15 | 1.generateArithmeticProgression shouldBe List(1) 16 | 17 | } 18 | 19 | test("Testing of arithmeticRegression") { 20 | 10.generateArithmeticRegression shouldBe List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).reverse 21 | 1.generateArithmeticRegression shouldBe List(1) 22 | 23 | } 24 | 25 | test("Testing of listDivisors") { 26 | 0.generateDivisors shouldBe List(0) 27 | 100.generateDivisors shouldBe List(1, 2, 4, 5, 10, 20, 25, 50, 100) 28 | /** 29 | * WORKS SLOWLY (2-3 sec) can be activated/deactivated 30 | */ 31 | //1000000000.listDevisors should be 32 | } 33 | 34 | test("Testing of listBinaryDivisors") { 35 | 100.generateBinaryDivisors shouldBe List(2, 4) 36 | 64.generateBinaryDivisors shouldBe List(2, 4, 8, 16, 32, 64) 37 | 3.generateBinaryDivisors shouldBe emptyList 38 | } 39 | 40 | test("Testing of listN_MultipleDivisors") { 41 | 100.generateN_MultipleDivisors(100) shouldBe List(100) 42 | 10.generateN_MultipleDivisors(1) shouldBe List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 43 | 44 | } 45 | 46 | test("Testing of generatePrimeNumbers") { 47 | 100.generatePrimeDivisors shouldBe List(2, 5) 48 | 21.generatePrimeDivisors shouldBe List(3, 7) 49 | } 50 | 51 | test("Testing of generateCarmichaelNumbers") { 52 | 100.generateCarmichaelNumbers shouldBe emptyList 53 | 561.generateCarmichaelNumbers shouldBe List(561) 54 | } 55 | 56 | test("Testing of generateLucCarmichaelNumbers") { 57 | 100.generateLucasCarmichaelNumbers shouldBe emptyList 58 | 399.generateLucasCarmichaelNumbers shouldBe List(399) 59 | } 60 | 61 | test("Testing of generateFinonacci") { 62 | 100.generateFibonacci shouldBe List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89) 63 | 1.generateFibonacci shouldBe List(0, 1, 1) 64 | assertThrows[InputException] { 65 | (-1).generateFibonacci 66 | } 67 | } 68 | 69 | test("Testing of generateRandomInts") { 70 | 100.generateRandomInts should be 71 | assertThrows[InputException] { 72 | (-10).generateRandomInts 73 | } 74 | } 75 | 76 | test("Testing of generateCatalanNumbers") { 77 | 14.generateCatalanNumbers shouldBe List(1, 1, 2, 5, 14) 78 | assertThrows[InputException] { 79 | (-10).generateCatalanNumbers 80 | } 81 | 1.generateCatalanNumbers shouldBe List(1, 1) 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/IntegerTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.FunSuite 4 | import org.scalatest.Matchers._ 5 | import integerOperations.IntegerProperties._ 6 | import integerOperations.IntegerGenerators._ 7 | import utils.InputException 8 | import integerOperations.IntegerMath._ 9 | 10 | class IntegerTests extends FunSuite { 11 | 12 | final val testEvenList: List[Int] = List(2,6,222,-2, 10000000) 13 | final val testOddList: List[Int] = List(1,3,15,275,100000001) 14 | final val testSquaresList: List[Int] = List(4,9,625,1000000) 15 | final val emptyList = List() 16 | 17 | test("Testing of isEven") { 18 | testEvenList.foreach { cur: Int => cur.isEven shouldBe true } 19 | testOddList.foreach { cur: Int => cur.isEven shouldBe false } 20 | } 21 | 22 | test("Testing of isOdd") { 23 | testEvenList.foreach { cur: Int => cur.isOdd shouldBe false } 24 | testOddList.foreach { cur: Int => cur.isOdd shouldBe true } 25 | } 26 | 27 | test("Testing of isSquared") { 28 | testEvenList.foreach { cur: Int => cur.isSquared() shouldBe false } 29 | testSquaresList.foreach {cur: Int => cur.isSquared() shouldBe true} 30 | } 31 | 32 | test("Testing of sumOfDigits") { 33 | 0.sumOfDigits shouldBe 0 34 | 50.sumOfDigits shouldBe 5 35 | 123456789.sumOfDigits shouldBe 45 36 | } 37 | 38 | test("Testing of compositionOfDigits") { 39 | 0.compositionOfDigits shouldBe 0 40 | 50.compositionOfDigits shouldBe 0 41 | 999999999.compositionOfDigits shouldBe 387420489 42 | } 43 | 44 | test("Testing of numOfDigits") { 45 | 0.numOfDigits shouldBe 1 46 | 50.numOfDigits shouldBe 2 47 | 999999999.numOfDigits shouldBe 9 48 | } 49 | 50 | test("Testing of nthGreatestDivisor") { 51 | 100.nthGreatestDivisor(0) shouldBe 100 52 | 100.nthGreatestDivisor(2) shouldBe 25 53 | assertThrows[InputException] { 54 | 100.nthGreatestDivisor(100) 55 | } 56 | } 57 | 58 | test("Testing of numOfDivisors") { 59 | 100.numOfDivisors shouldBe 9 60 | 0.numOfDivisors shouldBe 1 61 | } 62 | 63 | test("Testing of sumOfDivisors") { 64 | 100.sumOfDivisors shouldBe 217 65 | 0.sumOfDivisors shouldBe 0 66 | assertThrows[InputException] { 67 | -1.sumOfDivisors 68 | } 69 | } 70 | 71 | test("Testing of isPrime") { 72 | 10.isPrime shouldBe false 73 | 17.isPrime shouldBe true 74 | 289.isPrime shouldBe false 75 | assertThrows[InputException] { 76 | 1.isPrime 77 | } 78 | } 79 | 80 | test("Testing of gcdWith") { 81 | 14.gcdWith(7) shouldBe 7 82 | 21.gcdWith(7) shouldBe 7 83 | } 84 | 85 | test("Testing of sqr") { 86 | 0.sqr shouldBe 0 87 | 7.sqr shouldBe 49 88 | -2.sqr shouldBe 4 89 | } 90 | 91 | test("Testing of powN") { 92 | 0.powN(3) shouldBe 0 93 | 10.powN(2) shouldBe 100 94 | assertThrows[InputException] { 95 | -2.powN(5) 96 | } 97 | } 98 | 99 | test("Testing of isPrimeFermat") { 100 | 2.isPrimeFermat() shouldBe true 101 | 17.isPrimeFermat(100) shouldBe true 102 | 49.isPrimeFermat(200) shouldBe false 103 | 13.isPrimeFermat(200) shouldBe true 104 | } 105 | 106 | test("Testing of isCarmichael") { 107 | 561.isCarmichael shouldBe true 108 | 8911.isCarmichael shouldBe true 109 | 17777.isCarmichael shouldBe false 110 | } 111 | 112 | test("Testing of isLuc_Carmichael") { 113 | 399.isLucas_Carmichael shouldBe true 114 | 935.isLucas_Carmichael shouldBe true 115 | 17777.isLucas_Carmichael shouldBe false 116 | } 117 | 118 | test("Testing of isFibonacci") { 119 | 0.isFibonacci shouldBe true 120 | 1.isFibonacci shouldBe true 121 | 4.isFibonacci shouldBe false 122 | assertThrows[InputException] { 123 | (-1).isFibonacci 124 | } 125 | } 126 | 127 | test("Testing of nthCatalan") { 128 | 7.nthCatalan shouldBe 429 129 | } 130 | 131 | test("Testing of binaryPower") { 132 | 10.binaryPower(2) shouldBe 100 133 | -10.binaryPower(2) shouldBe 100 134 | -10.binaryPower(3) shouldBe (-1000) 135 | 0.binaryPower(5) shouldBe 0 136 | } 137 | 138 | test("Testing of isPrimeFermatStrict") { 139 | 2.isPrimeFermatStrict() shouldBe true 140 | 561.isPrimeFermatStrict() shouldBe false 141 | } 142 | 143 | test("Testing of isPrimeFermatFast") { 144 | 2.isPrimeFermatFast() shouldBe true 145 | 561.isPrimeFermatFast() shouldBe false 146 | } 147 | 148 | test("Testing of isZuckerman") { 149 | 3.isZuckerman shouldBe true 150 | 212.isZuckerman shouldBe true 151 | 10.isZuckerman shouldBe false 152 | } 153 | 154 | test("Testing of isHarshad") { 155 | 3.isHarshad shouldBe true 156 | 21.isHarshad shouldBe true 157 | 11.isHarshad shouldBe false 158 | } 159 | 160 | test("Testing of the gcdExtended") { 161 | 17.gcdExtendedWith(4) shouldBe (1, -4) 162 | (-5).gcdExtendedWith(4) shouldBe (2, 3) 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/ListsTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.FunSuite 4 | import org.scalatest.Matchers._ 5 | import listOperations.ListProperties._ 6 | import utils.InputException 7 | 8 | class ListsTests extends FunSuite { 9 | 10 | final lazy val testListOFChars = List('A', 'B', 'C', 'D') 11 | final lazy val sortedTestListOfIntegers = List(1, 2, 3, 4, 5) 12 | final lazy val unsortedListOfIntegers = List(5, 3, 5, 1, 9, 77) 13 | final lazy val emptyList = List() 14 | 15 | test("Testing of get()") { 16 | 17 | get(testListOFChars, 3) shouldBe 'D' 18 | assertThrows[InputException] { 19 | get(testListOFChars, 4) 20 | } 21 | get(sortedTestListOfIntegers, 3) shouldBe 4 22 | } 23 | 24 | test("Testing of isPalindrome") { 25 | 26 | } 27 | 28 | test("Testing of isSorted") { 29 | isSorted(sortedTestListOfIntegers) shouldBe true 30 | isSorted(unsortedListOfIntegers) shouldBe false 31 | isSorted(emptyList) shouldBe true 32 | } 33 | 34 | test("Testing of binarySearch") { 35 | binarySearch(sortedTestListOfIntegers, 3) shouldBe 2 36 | binarySearch(sortedTestListOfIntegers, 5) shouldBe 4 37 | binarySearch(sortedTestListOfIntegers, 1) shouldBe 0 38 | } 39 | 40 | test("Testing of linearSearch") { 41 | linearSearch(sortedTestListOfIntegers, 3) shouldBe 2 42 | linearSearch(sortedTestListOfIntegers, 5) shouldBe 4 43 | linearSearch(sortedTestListOfIntegers, 1) shouldBe 0 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/OperationTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.Matchers._ 4 | import org.scalatest.FunSuite 5 | import listOperations.Changes._ 6 | import utils.InputException 7 | 8 | class OperationTests extends FunSuite { 9 | 10 | final val emptyList = List() 11 | 12 | test("Testing of countSignChanges") { 13 | 14 | val intTestingSignChangesList1: List[Int] = List(-1, 2, -1, 2, -1, -21, -10, 20, 20, 20, 35, -11) 15 | val intTestingSignChangesList2: List[Int] = List(1, 1, 1, 1, 1, 1) 16 | 17 | countSignChanges(intTestingSignChangesList1) shouldBe List(3, 3) 18 | countSignChanges(intTestingSignChangesList2) shouldBe List(0, 0) 19 | 20 | assertThrows[InputException] { 21 | countSignChanges(emptyList) 22 | } 23 | } 24 | 25 | test("Testing of countLetterChanges") { 26 | val testingLetterChangesList1: List[Char] = List('a', 'A', 'b', 'B', 'a', 'b', 'c', 'C') 27 | val testingLetterChangesList2: List[Char] = List('a', 'a', 'a', 'a') 28 | 29 | countLetterChanges(testingLetterChangesList1) shouldBe List(2, 1) 30 | countLetterChanges(testingLetterChangesList2) shouldBe List(0, 0) 31 | 32 | assertThrows[InputException] { 33 | countLetterChanges(emptyList) 34 | } 35 | } 36 | 37 | 38 | 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/RationalOperationsTest.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.Matchers._ 4 | import org.scalatest.FunSuite 5 | import rationalOperations.Rational 6 | 7 | class RationalOperationsTests extends FunSuite { 8 | 9 | val firstRational = new Rational(12,1) 10 | val secondRational = new Rational(8,2) 11 | 12 | test("Testing of the basic rational operations") { 13 | (firstRational / secondRational).toString shouldBe "3/1" 14 | (firstRational * secondRational).toString shouldBe "48/1" 15 | (firstRational - secondRational).toString shouldBe "3/1" 16 | (firstRational + secondRational).toString shouldBe "3/1" 17 | (firstRational > secondRational) shouldBe True 18 | (firstRational < secondRational) shouldBe False 19 | (firstRational >= secondRational) shouldBe True 20 | (firstRational <= secondRational) shouldBe False 21 | firstRational.sqr.toString shouldBe "144/1" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/SortingAlgorithmsTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.FunSuite 4 | import org.scalatest.Matchers._ 5 | import sortingAlgorithms._ 6 | import sortingAlgorithms.unseriousAlgorithms._ 7 | 8 | class SortingAlgorithmsTests extends FunSuite { 9 | final lazy val unsortedList = List(8, 4, 6, 1, 7, 3, 8, 4, 7, 9, 2, 7) 10 | final lazy val sortedList = List(1, 2, 3, 4, 5, 6, 7, 8) 11 | final lazy val emptyList = List() 12 | 13 | final lazy val unsortedToSortedList = List(1, 2, 3, 4, 4, 6, 7, 7, 7, 8, 8, 9) 14 | 15 | test("Testing of the quickSort") { 16 | QuickSort.quickSort(unsortedList) shouldBe unsortedToSortedList 17 | QuickSort.quickSort(sortedList) shouldBe sortedList 18 | QuickSort.quickSort(emptyList) shouldBe emptyList 19 | } 20 | 21 | test("Testing of the bogosort") { 22 | Bogosort.bogosort(sortedList) shouldBe sortedList 23 | Bogosort.bogosort(List(3, 2, 1)) shouldBe List(1, 2, 3) 24 | Bogosort.bogosort(emptyList) shouldBe emptyList 25 | } 26 | 27 | test("Testing of the sleepSort") { 28 | SleepSort.sleepSort(unsortedList) should be 29 | SleepSort.sleepSort(sortedList) should be 30 | SleepSort.sleepSort(emptyList) should be 31 | } 32 | 33 | test("Testing of the bubbleSort") { 34 | BubbleSort.bubbleSort(sortedList) shouldBe sortedList 35 | BubbleSort.bubbleSort(unsortedList) shouldBe unsortedToSortedList 36 | BubbleSort.bubbleSort(emptyList) shouldBe emptyList 37 | } 38 | 39 | test("Testing of the mergeSort") { 40 | MergeSort.mergeSort(sortedList) shouldBe sortedList 41 | MergeSort.mergeSort(unsortedList) shouldBe unsortedToSortedList 42 | MergeSort.mergeSort(emptyList) shouldBe emptyList 43 | } 44 | 45 | test("Testing of the insertionSort") { 46 | InsertionSort.insertionSort(sortedList) shouldBe sortedList 47 | InsertionSort.insertionSort(unsortedList) shouldBe unsortedToSortedList 48 | InsertionSort.insertionSort(emptyList) shouldBe emptyList 49 | } 50 | 51 | test("Testing of the selectionSort") { 52 | SelectionSort.sort(sortedList) shouldBe sortedList 53 | SelectionSort.sort(unsortedList) shouldBe unsortedToSortedList 54 | SelectionSort.sort(emptyList) shouldBe emptyList 55 | } 56 | 57 | test("Testing of the heapSort") { 58 | HeapSort.heapSort(sortedList) shouldBe sortedList 59 | HeapSort.heapSort(unsortedList) shouldBe unsortedToSortedList 60 | HeapSort.heapSort(emptyList) shouldBe emptyList 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/scala/unitTests/TimeTests.scala: -------------------------------------------------------------------------------- 1 | package unitTests 2 | 3 | import org.scalatest.Matchers._ 4 | import org.scalatest.FunSuite 5 | import utils.InputException 6 | import time.Time._ 7 | 8 | 9 | class TimeTests extends FunSuite { 10 | 11 | test("Testing of basic time functions") { 12 | 10.hoursToSeconds shouldBe 3600 13 | 360.secondsToHours shouldBe 1 14 | 60.secondsToMinutes shouldBe 1 15 | 10.minutesToSeconds shouldBe 60 16 | 17 | assertThrows[InputException] { 18 | -1.secondsToMinutes 19 | } 20 | } 21 | --------------------------------------------------------------------------------