Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

L7 #411

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

L7 #411

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions list7/src/BestSolution.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import ParallelResearchUtils.*

object BestSolution {
//wyszukiwanie najlepszego rozwiązania w populacji
// tablica zawierająca ciągi binarne jest przeszukiwana w celu znalezienia osobnika o najlepszym przystosowaniu (najwięcej 1)
// rozwiązanie zrównoleglone jest lepsze dla populacji większych niż 10 000 osobników, próg zrównoleglenia 1000
// wyniki dla powyższych danych: algorytm rónwoległy dwa razy lepszy (156ms do 328ms)


def generateSeriesArray(size: Int ): Array[String] = {
var counter = 0
var array = Array[String]()
while(counter < size){
array = array :+ generateBinSeries(10000)
counter += 1
}
array
}

def generateBinSeries(length: Int): String ={
var series = ""
var count = 0
val rand = scala.util.Random()
while( count < length){
if rand.nextDouble() < 0.5 then series = series + "0"
else series = series + "1"
count += 1
}
series
}

def quality(series: String): Int ={
var index = 0
var quality = 0
while(index < series.length){
if(series.charAt(index) == '1') then quality += 1
index += 1
}
quality
}
def findBestSolutionHelper(wholePopulation: Array[String], start: Int, end: Int): String ={
if(end - start == 1) then
if quality(wholePopulation(start)) < quality(wholePopulation(end)) then wholePopulation(end)
else wholePopulation(start)
else
val partition = (start + end )/2
val f1 = findBestSolutionHelper(wholePopulation, start, partition)
val f2 = findBestSolutionHelper(wholePopulation, partition, end)
if(quality(f1) < quality(f2)) then f2
else f1
}
def findBestSolution(population: Array[String]): String ={
findBestSolutionHelper(population, 0, population.size - 1)
}

def findBestSolutionParallel(population: Array[String]): String ={
def findBestSolutionHelperParallel(wholePopulation: Array[String], start: Int, end: Int): String ={
if(end - start < 1000) then findBestSolutionHelper(wholePopulation, start, end)
else
val partition = (start + end )/2
val (r1, r2) = parallel(findBestSolutionHelperParallel(wholePopulation, start, partition), findBestSolutionHelperParallel(wholePopulation, partition, end))
if(quality(r1) < quality(r2)) then r2
else r1
}
findBestSolutionHelperParallel(population, 0, population.size - 1)
}
}
72 changes: 72 additions & 0 deletions list7/src/BinTreeOperations.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import ParallelResearchUtils.*

object BinTreeOperations {

// Przy klasycznym liczeniu sumy elementów drzewa drzewa binarnego zdecydowana przewaga rozwiązania jednowątkowego
// dla głębokości 15 program zrównoleglony osiagnął wynik 78ms, niezrównoleglony 0ms
// w celu sztucznego wydłużenia obliczeń z każdego elementu liczyłam silnię,
// co przy dużych liczbach i drzewach o głębokości większej od 10 dawało bardzo niewielką przewagę algorytmowi równoległemu
// głebokośc 15, np. równoległy 1266ms, zwykły 1281ms
// problem raczej nie nadaje się do rozwiązania równoległego

sealed trait BinTree[+A]
case object Empty extends BinTree[Nothing]
case class Node[+A](elem: A, left: BinTree[A], right: BinTree[A]) extends BinTree[A]

val rand = scala.util.Random()

def generateTreeOfDepth(depth: Int): BinTree[Int] = {
if depth <= 0 then Empty
else
Node(Math.abs(rand.nextInt()) % 100000, generateTreeOfDepth(depth - 1), generateTreeOfDepth(depth - 1))
}

def sumOfTreeFactorial(tree: BinTree[Int]): Int ={
tree match{
case Node(v, left, right) => factorial(v) + factorial(sumOfTree(left))+ factorial(sumOfTree(right))
case Empty => 0
}
}

def sumOfTreeFactorialParallel(tree: BinTree[Int], depthOfTree: Int): Int = {
if depthOfTree < 10 then sumOfTree(tree)
else
tree match{
case Node(v, left, right) =>
val result = parallel(sumOfTreeParallel(left, depthOfTree - 1), sumOfTreeParallel(right, depthOfTree - 1))
(factorial(v) + factorial(result._1) + factorial(result._2))
case Empty => 0
}
}

def sumOfTree(tree: BinTree[Int]): Int ={
tree match{
case Node(v, left, right) => v + sumOfTree(left)+ sumOfTree(right)
case Empty => 0
}
}

def sumOfTreeParallel(tree: BinTree[Int], depthOfTree: Int): Int = {
if depthOfTree < 10 then sumOfTree(tree)
else
tree match{

case Node(v, left, right) =>
val result = parallel(sumOfTreeParallel(left, depthOfTree - 1), sumOfTreeParallel(right, depthOfTree - 1))
(v + result._1 + result._2)
case Empty => 0
}
}

def factorial(number: Int): Int = {
def factorialHelper(numberTail: Int, acc: Int): Int = {
numberTail match {
case 0 => 1
case 1 => 1
case _ => factorialHelper (numberTail - 1, acc * numberTail)
}
}
if number < 0 then throw new IllegalArgumentException()
else factorialHelper(number, 1)
}
}
43 changes: 43 additions & 0 deletions list7/src/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import MergeSort.*
import BinTreeOperations.*
import BestSolution.*
import QuickSort.*

import ParallelResearchUtils.*
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration

object Main {
def main(args: Array[String]): Unit = {
// val toSort = generateList(50000, Nil)
//
// println(timer(mergesort(isLess, toSort)))
//
// println(timer(mergesortParallel(isLess, toSort)))


// val intTree = generateTreeOfDepth(15)
//
// println(timer(sumOfTree(intTree)))
// println(timer(sumOfTreeParallel(intTree, 15)))
//
// println(timer(sumOfTreeFactorial(intTree)))
// println(timer(sumOfTreeFactorialParallel(intTree, 15)))
//
//
//val array = Array("0101", "1011", "0111", "1011")
val arraySeries = generateSeriesArray(10000)
println("done")

//println(array.toList)
println(timer(findBestSolution(arraySeries)))
println(timer(findBestSolutionParallel(arraySeries)))
//

// val array = generateArray(800000)
// val array2 = array.clone()
// val array1 = array.clone()
// println(timer(quicksort(array1)))
// println(timer(quicksortParallel(array2)))
}
}
62 changes: 62 additions & 0 deletions list7/src/MergeSort.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import scala.annotation.tailrec
import ParallelResearchUtils.*

object MergeSort {
// Widoczna przewaga zrównoleglonego rozwiązania od 100 000 danych przy progu 50 000 - czas dwa razy krótszy (78ms w porównaniu do 141ms)
// dla mniejszych danych wyniki algorytmów są porównywalne dla 50 000 danych przy progu 10 000 (63ms dla równoległego, 78ms dla zwykłego)
// przy mniejszych lepsze rozwiązanie jednowątkowe

val lengthThreshold = 10000
val rand = scala.util.Random()

def generateList(length: Int, acc: List[Int]): List[Int] = {
if length < 0 then throw new IllegalArgumentException()
else if length == 0 then acc
else generateList(length - 1, rand.nextInt() :: acc)
}
val isLess : (Int, Int) => Boolean = (arg1, arg2) => (arg1 < arg2)

def splitList[A](list : List[A], partition : Int) : (List[A], List[A]) ={
@tailrec
def splitIter(sublists :(List[A], List[A]), counter : Int) : (List[A], List[A]) ={
if counter == 0 then (sublists._1.reverse, sublists._2)
else splitIter((sublists._2.head :: sublists._1, sublists._2.tail), counter - 1)
}
splitIter((Nil, list), partition)
}

def merge[A](order: (A, A) => Boolean, listLeft: List[A], listRight: List[A]): List[A] = {
def mergeHelper(lleft: List[A], lright: List[A], acc: List[A]): List[A] = {
(lleft, lright) match
case (Nil, _) => lright.reverse ::: acc
case (_, Nil) => lleft.reverse ::: acc
case (h1 :: t1 , h2 :: t2) =>
if order(h2, h1) then mergeHelper(lleft, t2, h2 :: acc)
else mergeHelper(t1, lright, h1 :: acc)
}
mergeHelper(listLeft, listRight, Nil).reverse
}

def mergesort[A](order: (A, A) => Boolean,list : List[A]) : List[A] = {
val partition = list.length / 2
if partition == 0 then list
else {
val (left, right): (List[A], List[A]) = splitList(list, partition)
merge(order, mergesort(order, left), mergesort(order, right))
}
}

def mergesortParallel[A](order: (A, A) => Boolean,list : List[A]) : List[A] ={
val length = list.length
val partition = length / 2
if length < 2 then list
else {
val (left, right): (List[A], List[A]) = splitList(list, partition)
if length < lengthThreshold then merge(order, left, right)
else {
val (r1, r2): (List[A], List[A]) = parallel(mergesortParallel(order, left), mergesortParallel(order, right))
merge(order, r1, r2)
}
}
}
}
19 changes: 19 additions & 0 deletions list7/src/ParallelResearchUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global

object ParallelResearchUtils {
def parallel[A, B](taskA: => A, taskB: => B): (A,B) = {
val future: Future[B] = Future {
taskB
}
val a: A = taskA
val b: B = Await.result(future, Duration.Inf)
(a, b)
}
def timer[A](task: => A): Long ={
val start = System.currentTimeMillis()
task
System.currentTimeMillis() - start
}
}
65 changes: 65 additions & 0 deletions list7/src/QuickSort.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import ParallelResearchUtils.*

object QuickSort {
// Czas sortowania zrównoleglonego był niższy tylko dla bardzo dużej liczby danych wejściowych ok.700 000, próg zrównoleglenia 300 000,
// przykładowe wyniki dla 800000 danych: równoległy: 78ms, nierównoległy 94 ms
// dla mniejszych wartości zdecydowana przewaga jednowątkowego rozwiązania

def generateArray(length: Int): Array[Int] ={
var array = Array[Int]()
val rand = scala.util.Random()
var currentLength = 0
while(currentLength < length){
array = array :+ rand.nextInt()
currentLength += 1
}
array
}

def swap(tab: Array[Int])(i: Int)(j: Int) : Unit =
var aux = tab(i)
tab(i) = tab(j)
tab(j) = aux

def choose_pivot(tab: Array[Int])(m: Int)(n: Int): Int = tab((m + n)/2)

def partition(tab: Array[Int])(l: Int)(r: Int): (Int, Int) =
var i = l
var j = r
var pivot = choose_pivot(tab)(l)(r)
while i <= j do
while tab(i) < pivot do i += 1;
while pivot < tab(j) do j -= 1;
if i <= j then
swap(tab)(i)(j);
i += 1;
j -= 1;
(i, j)


def quick(tab: Array[Int])(l: Int)(r: Int): Unit =
if l < r then
var (i, j) = partition(tab)(l)(r)
if j - l < r - i then
quick(tab)(l)(j)
quick(tab)(i)(r)
else
quick(tab)(i)(r)
quick(tab)(l)(j)

def quicksort(tab: Array[Int]): Unit =
quick(tab)(0)(tab.length - 1)

def quickParallel(tab: Array[Int])(l: Int)(r: Int): Unit =
if l < r then
if r-l < 300000 then quick(tab)(l)(r)
else
var (i, j) = partition(tab)(l)(r)
if j - l < r - i then
parallel(quickParallel(tab)(l)(j), quickParallel(tab)(i)(r))
else
parallel(quickParallel(tab)(i)(r), quickParallel(tab)(l)(j))

def quicksortParallel(tab: Array[Int]): Unit =
quickParallel(tab)(0)(tab.length - 1)
}