From 2c4ec80f953be55ddd302793276efe96d503c7ee Mon Sep 17 00:00:00 2001 From: AlishChhetri Date: Thu, 25 Apr 2024 15:12:05 -0400 Subject: [PATCH 1/8] feat: added benchmark file --- .devenv/gc/shell | 2 +- .devenv/gc/shell-1-link | 1 - .devenv/gc/shell-2-link | 1 + bosco/benchmark.py | 32 ++++++++++++++++++++++++++++++++ bosco/main.py | 1 - pyproject.toml | 3 +++ 6 files changed, 37 insertions(+), 3 deletions(-) delete mode 120000 .devenv/gc/shell-1-link create mode 120000 .devenv/gc/shell-2-link create mode 100644 bosco/benchmark.py delete mode 100644 bosco/main.py diff --git a/.devenv/gc/shell b/.devenv/gc/shell index 2b5306e..f0d48df 120000 --- a/.devenv/gc/shell +++ b/.devenv/gc/shell @@ -1 +1 @@ -shell-1-link \ No newline at end of file +shell-2-link \ No newline at end of file diff --git a/.devenv/gc/shell-1-link b/.devenv/gc/shell-1-link deleted file mode 120000 index 82d3944..0000000 --- a/.devenv/gc/shell-1-link +++ /dev/null @@ -1 +0,0 @@ -/nix/store/p4y6p2djvxxmck22kpzjymszjqwxp63s-devenv-shell-env \ No newline at end of file diff --git a/.devenv/gc/shell-2-link b/.devenv/gc/shell-2-link new file mode 120000 index 0000000..36221d4 --- /dev/null +++ b/.devenv/gc/shell-2-link @@ -0,0 +1 @@ +/nix/store/kfc3lrq3q6kgp12ic8vhmskgdyah6msf-devenv-shell-env \ No newline at end of file diff --git a/bosco/benchmark.py b/bosco/benchmark.py new file mode 100644 index 0000000..63547e0 --- /dev/null +++ b/bosco/benchmark.py @@ -0,0 +1,32 @@ +"""Conduct doubling experiments for provided algorithms that perform list sorting.""" + +import os +import sys +from timeit import repeat +from typing import List, Tuple + + +def run_sorting_algorithm( + file_path: str, algorithm: str, array: List[int] +) -> Tuple[float, float, float]: + """Run a sorting algorithm and profile it with the timeit package.""" + directory, file_name = os.path.split(file_path) + module_name = os.path.splitext(file_name)[0] + + if directory: + sys.path.append(directory) + + try: + module = __import__(module_name) + algorithm_func = getattr(module, algorithm) + except (ImportError, AttributeError): + raise ValueError(f"Could not import {algorithm} from {file_path}") + + stmt = f"{algorithm_func.__name__}({array})" + times = repeat( + setup=f"from {module_name} import {algorithm}", + stmt=stmt, + repeat=3, + number=10, + ) + return min(times), max(times), sum(times) / len(times) diff --git a/bosco/main.py b/bosco/main.py deleted file mode 100644 index 654869d..0000000 --- a/bosco/main.py +++ /dev/null @@ -1 +0,0 @@ -"""Bosco runs benchmarks to assess the performance of Python functions.""" diff --git a/pyproject.toml b/pyproject.toml index 6ebcffa..f3c266d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,9 @@ description = "" authors = ["Gregory M. Kapfhammer "] readme = "README.md" +[tool.poetry.scripts] +bosco = "bosco.main:cli" + [tool.poetry.dependencies] python = "^3.11" From f7ffca54d2feff64940d21c7d78c943bb690fed6 Mon Sep 17 00:00:00 2001 From: bergasanargya Date: Thu, 25 Apr 2024 15:20:28 -0400 Subject: [PATCH 2/8] push generate to bosco --- bosco/generate.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 bosco/generate.py diff --git a/bosco/generate.py b/bosco/generate.py new file mode 100644 index 0000000..e52522e --- /dev/null +++ b/bosco/generate.py @@ -0,0 +1,12 @@ +"""Generate random container.""" + +import random +from typing import List + + +def generate_random_container( + size: int, +) -> List[int]: + """Generate a random list defined by the size.""" + random_list = [random.randint(1, size * size) for _ in range(size)] + return random_list \ No newline at end of file From c468d4390b8dc882c8cd2c0dfe331932946ec445 Mon Sep 17 00:00:00 2001 From: Miles Date: Thu, 25 Apr 2024 15:22:47 -0400 Subject: [PATCH 3/8] adding main --- bosco/main.py | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 bosco/main.py diff --git a/bosco/main.py b/bosco/main.py new file mode 100644 index 0000000..ad55ad1 --- /dev/null +++ b/bosco/main.py @@ -0,0 +1,98 @@ +import plotly.graph_objs as go +import typer +from plotly.subplots import make_subplots +from rich.console import Console +from tabulate import tabulate + +from bosco import benchmark, generate + +cli = typer.Typer() +console = Console() + + +@cli.command() +def bosco( + starting_size: int = typer.Option(100), + number_doubles: int = typer.Option(5), + file: str = typer.Option("./bosco/sorting.py"), + function_name: str = typer.Option("bubble_sort"), +) -> None: + """Conduct a doubling experiment to measure the performance of list sorting for a specific algorithm.""" + console.print( + "\n๐Ÿ”ฌ Tool Support for Evaluating the Performance of Sorting Algorithms\n" + ) + console.print(f"Path to the desired file: {file}\n") + console.print(f"Name of the desired function: {function_name}\n") + console.print(f"Starting size of the data container: {starting_size}\n") + console.print(f"Number of doubles to execute: {number_doubles}\n") + console.print("๐Ÿ“ˆ Here are the results from running the experiment!\n") + + all_results = [] + + for i in range(number_doubles): + size = starting_size * (2**i) + data_to_sort = generate.generate_random_container(size) + performance_data = benchmark.run_sorting_algorithm( + file, function_name, data_to_sort + ) + + ( + best_time, + worst_time, + average_time, + ) = performance_data # best, worst, and average times + + all_results.append([best_time, worst_time, average_time]) + + header = ["Input Size", "Best Case", "Worst Case", "Average Case"] + data = [ + [starting_size * 2**i, *results] + for i, results in enumerate(all_results) + ] + + table = tabulate( + data, headers=header, tablefmt="fancy_grid", floatfmt=".5f" + ) + console.print(table) + + # plot + fig = make_subplots(rows=1, cols=1) + + x_values = [starting_size * (2**i) for i in range(number_doubles)] + best_case = [results[0] for results in all_results] + worst_case = [results[1] for results in all_results] + average_case = [results[2] for results in all_results] + + trace_best = go.Scatter( + x=x_values, + y=best_case, + mode="lines+markers", + name="Best Case", + ) + trace_worst = go.Scatter( + x=x_values, + y=worst_case, + mode="lines+markers", + name="Worst Case", + ) + trace_average = go.Scatter( + x=x_values, + y=average_case, + mode="lines+markers", + name="Average Case", + ) + + fig.add_trace(trace_best) + fig.add_trace(trace_worst) + fig.add_trace(trace_average) + + fig.update_layout( + title=f"Evaluating the Performance of {function_name}", + xaxis_title="Input Size", + yaxis_title="Execution Time (s)", + showlegend=True, + margin=dict(l=20, r=20, t=60, b=20), + title_x=0.5, + ) + + fig.show() From 3af36a3d400945a82a4e6eb7526157e4ce11622a Mon Sep 17 00:00:00 2001 From: AlishChhetri Date: Thu, 25 Apr 2024 15:33:50 -0400 Subject: [PATCH 4/8] fix: edit first output line --- bosco/__pycache__/__init__.cpython-311.pyc | Bin 0 -> 150 bytes bosco/__pycache__/benchmark.cpython-311.pyc | Bin 0 -> 1951 bytes bosco/__pycache__/generate.cpython-311.pyc | Bin 0 -> 886 bytes bosco/__pycache__/main.cpython-311.pyc | Bin 0 -> 5163 bytes bosco/__pycache__/sorting.cpython-311.pyc | Bin 0 -> 10612 bytes bosco/main.py | 2 +- bosco/sorting.py | 358 ++++++++++++++++++++ 7 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 bosco/__pycache__/__init__.cpython-311.pyc create mode 100644 bosco/__pycache__/benchmark.cpython-311.pyc create mode 100644 bosco/__pycache__/generate.cpython-311.pyc create mode 100644 bosco/__pycache__/main.cpython-311.pyc create mode 100644 bosco/__pycache__/sorting.cpython-311.pyc create mode 100644 bosco/sorting.py diff --git a/bosco/__pycache__/__init__.cpython-311.pyc b/bosco/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fffd47f0e1bcb20f64a758cafbf31ff663cd7ea9 GIT binary patch literal 150 zcmZ3^%ge<81g)l;X(0MBh=2h`DC095kTIPhg&~+hlhJP_LlF~@{~09tOH)51KQ~ps zxTG{CHLpb9$iPTHDZe;5A431nO)2eBt9@R OGBSQ(fDuK^KrsNCRv-xg literal 0 HcmV?d00001 diff --git a/bosco/__pycache__/benchmark.cpython-311.pyc b/bosco/__pycache__/benchmark.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0bac433b8ec0a7a7fc2281d1df2452c707ebb71a GIT binary patch literal 1951 zcmaJ>-HRJl6u*=C$YipcG{Js^wY%fi(#>kS+b*p%TE*5rY*!T23Jt+N7=eyxy1;JSQVX_$V2>r>F-iU7tk8BXWKnBVqgEJyFm*+Y>l8*rAZQc>`0>^BE zEjm(Oa-#Vt=%Ohb61-7UGGm!uRAk6z)Ku70tun84S^ z9(nSDb7>=qzF{SgI; z>5pEFu;h@w0inxWPgw`se@6w~0gt9*+^Z z@4WLw;$U?kRruY}I21!E@YeH2fgX<$hs)(>2 zWf9keifjP1?kRT!I3c{w)=kM;8Sd4Pq97sWLp_dUgQDX@$zf$1g@(0 zusHy*s=EfmHN&E65%nsd8Zd3D1aJ>}NiST{7tCXrCAyqC=LNQ*x*kz2rvx}x%aU5e zo}+GY6I)!iEOwN#+%rF9NP5WXJu6Vr2TYf!;1h>nW}uQAIP)gXrf9_TsnDqf(J$E+ zp>l_rON8?NvQH(wR5D$IDw@{aS<`5A!6Z5%n8s&2hdGb2hiT$@qeccYW zWm(f)-7z(-yFKq%F6AA43HAsa%G;)!Rj>pn!>raYgENg87B&mS!^_(h%OcRY;~4>z zZ%2{33QhFOSSto@0W&aCk!8~NSq{|x*qWSL^c-`_CxHR&W$MKAiK%(dFL*s_x`jnY z$5)P(mg!y`xY~AC(fV89EJTdK>rX>j*U)1bJv;iQLL+T4Tao;KpdLoGReP5vzTX>v7Im&Y6Ocqosz z1wowSTB(uMxq51%k(yYMS{ZeH9|X_LG%_sP|WDVQ6l zySzD^Y9{wIlc{!09G3nlW=cK-1Y8cMDNpX9FPZu+YyKQG@Xe><}te3QGK`=2D=n&A}y9ISEReL$$xErV^elI0RK zcFZaov!({H0rc^f3q8GPdpha-lkd?ZupvAFWJ`Xfi;Y+D2~b)8^=|@!>vLQaT@2C1 z2PjtSJWZt3I!_a2!rilpM#KM`ZD~LEaxfhXR72PUWNU;TD3BGaji5SaH}G zKhAyK@>J0m@~b}49A3A}3s;oxxmwt^8?4}ZEy^sfu)exp*s@*2p4r;0&G}~gJXz!g z8Fr&t>fE0nXwx*>MgNPYZRn<3%3p-1ct#b?zb=e2<>~mLA3Xe28r&JY{JQ!1&2e_^ zB)b+JPB0jY@nw9z##AAM_EWQDoWtdnzf+tvI)CX}94CY4yv6Pc8q6OgAp3+wiGDx$ zbMxoMuMONd&Xi9wh=h9qXG2}*9M-Y=qZk$X9BKlK#VgGLL Nbs*zBfNM;c`9Jd9-n#$* literal 0 HcmV?d00001 diff --git a/bosco/__pycache__/main.cpython-311.pyc b/bosco/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74c1ed5ef9ada40ab11fa138d8e6df0504bd801c GIT binary patch literal 5163 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 Fe*g*u<8A-| literal 0 HcmV?d00001 diff --git a/bosco/main.py b/bosco/main.py index ad55ad1..0ecbe72 100644 --- a/bosco/main.py +++ b/bosco/main.py @@ -19,7 +19,7 @@ def bosco( ) -> None: """Conduct a doubling experiment to measure the performance of list sorting for a specific algorithm.""" console.print( - "\n๐Ÿ”ฌ Tool Support for Evaluating the Performance of Sorting Algorithms\n" + "\n:dog: Bosco is fetching out results!\n" ) console.print(f"Path to the desired file: {file}\n") console.print(f"Name of the desired function: {function_name}\n") diff --git a/bosco/sorting.py b/bosco/sorting.py new file mode 100644 index 0000000..294d635 --- /dev/null +++ b/bosco/sorting.py @@ -0,0 +1,358 @@ +"""Sorting algorithms for lists that contain integer values.""" + +from random import randint +from typing import List + + +def bubble_sort(array: List[int]) -> List[int]: + """Sort an input list called array using bubble sort.""" + n = len(array) + + for i in range(n): + # Create a flag that will allow the function to + # terminate early if there's nothing left to sort + already_sorted = True + + # Start looking at each item of the list one by one, + # comparing it with its adjacent value. With each + # iteration, the portion of the array that you look at + # shrinks because the remaining items have already been + # sorted. + for j in range(n - i - 1): + if array[j] > array[j + 1]: + # If the item you're looking at is greater than its + # adjacent value, then swap them + array[j], array[j + 1] = array[j + 1], array[j] + + # Since you had to swap two elements, + # set the `already_sorted` flag to `False` so the + # algorithm doesn't finish prematurely + already_sorted = False + + # If there were no swaps during the last iteration, + # the array is already sorted, and you can terminate + if already_sorted: + break + + return array + + +def insertion_sort(array: List[int]) -> List[int]: + """Run an insertion sort on the provided array.""" + # Loop from the second element of the array until + # the last element + for i in range(1, len(array)): + # This is the element we want to position in its + # correct place + key_item = array[i] + + # Initialize the variable that will be used to + # find the correct position of the element referenced + # by `key_item` + j = i - 1 + + # Run through the list of items (the left + # portion of the array) and find the correct position + # of the element referenced by `key_item`. Do this only + # if `key_item` is smaller than its adjacent values. + while j >= 0 and array[j] > key_item: + # Shift the value one position to the left + # and reposition j to point to the next element + # (from right to left) + array[j + 1] = array[j] + j -= 1 + + # When you finish shifting the elements, you can position + # `key_item` in its correct location + array[j + 1] = key_item + + return array + + +def merge(left: List[int], right: List[int]) -> List[int]: + """Define a convenience method that supports the merging of lists.""" + # If the first array is empty, then nothing needs + # to be merged, and you can return the second array as the result + if len(left) == 0: + return right + + # If the second array is empty, then nothing needs + # to be merged, and you can return the first array as the result + if len(right) == 0: + return left + + result: List[int] = [] + index_left = index_right = 0 + + # Now go through both arrays until all the elements + # make it into the resultant array + while len(result) < len(left) + len(right): + # The elements need to be sorted to add them to the + # resultant array, so you need to decide whether to get + # the next element from the first or the second array + if left[index_left] <= right[index_right]: + result.append(left[index_left]) + index_left += 1 + else: + result.append(right[index_right]) + index_right += 1 + + # If you reach the end of either array, then you can + # add the remaining elements from the other array to + # the result and break the loop + if index_right == len(right): + result += left[index_left:] + break + + if index_left == len(left): + result += right[index_right:] + break + + return result + + +def merge_sort(array: List[int]) -> List[int]: + """Sort the provided list called array with the merge sort algorithm.""" + # If the input array contains fewer than two elements, + # then return it as the result of the function + if len(array) < 2: + return array + + midpoint = len(array) // 2 + + # Sort the array by recursively splitting the input + # into two equal halves, sorting each half and merging them + # together into the final result + return merge( + left=merge_sort(array[:midpoint]), right=merge_sort(array[midpoint:]) + ) + + +def quick_sort(array: List[int]) -> List[int]: + """Sort the provided list called array with the quick sort algorithm.""" + # If the input array contains fewer than two elements, + # then return it as the result of the function + if len(array) < 2: + return array + + low, same, high = [], [], [] + + # Select your `pivot` element randomly + pivot = array[randint(0, len(array) - 1)] + + for item in array: + # Elements that are smaller than the `pivot` go to + # the `low` list. Elements that are larger than + # `pivot` go to the `high` list. Elements that are + # equal to `pivot` go to the `same` list. + if item < pivot: + low.append(item) + elif item == pivot: + same.append(item) + elif item > pivot: + high.append(item) + + # The final result combines the sorted `low` list + # with the `same` list and the sorted `high` list + return quick_sort(low) + same + quick_sort(high) + + +def insertion_sort_tim(array: List[int], left: int = 0, right=None): + """Use an internal sorting algorithm for the timsort algorithm.""" + if right is None: + right = len(array) - 1 + + # Loop from the element indicated by + # `left` until the element indicated by `right` + for i in range(left + 1, right + 1): + # This is the element we want to position in its + # correct place + key_item = array[i] + + # Initialize the variable that will be used to + # find the correct position of the element referenced + # by `key_item` + j = i - 1 + + # Run through the list of items (the left + # portion of the array) and find the correct position + # of the element referenced by `key_item`. Do this only + # if the `key_item` is smaller than its adjacent values. + while j >= left and array[j] > key_item: + # Shift the value one position to the left + # and reposition `j` to point to the next element + # (from right to left) + array[j + 1] = array[j] + j -= 1 + + # When you finish shifting the elements, position + # the `key_item` in its correct location + array[j + 1] = key_item + + return array + + +def tim_sort(array: List[int]) -> List[int]: + """Sort the list called array with the tim sort algorithm using a special insertion sort.""" + min_run = 32 + n = len(array) + + # Start by slicing and sorting small portions of the + # input array. The size of these slices is defined by + # your `min_run` size. + for i in range(0, n, min_run): + insertion_sort_tim(array, i, min((i + min_run - 1), n - 1)) + + # Now you can start merging the sorted slices. + # Start from `min_run`, doubling the size on + # each iteration until you surpass the length of + # the array. + size = min_run + while size < n: + # Determine the arrays that will + # be merged together + for start in range(0, n, size * 2): + # Compute the `midpoint` (where the first array ends + # and the second starts) and the `endpoint` (where + # the second array ends) + midpoint = start + size - 1 + end = min((start + size * 2 - 1), (n - 1)) + + # Merge the two subarrays. + # The `left` array should go from `start` to + # `midpoint + 1`, while the `right` array should + # go from `midpoint + 1` to `end + 1`. + merged_array = merge( + left=array[start : midpoint + 1], + right=array[midpoint + 1 : end + 1], + ) + + # Finally, put the merged array back into + # your array + array[start : start + len(merged_array)] = merged_array + + # Each iteration should double the size of your arrays + size *= 2 + + return array + + +# Selection Sort algorithm in Python +def selection_sort(array): + for s in range(len(array)): + min_idx = s + + for i in range(s + 1, len(array)): + # For sorting in descending order + # for minimum element in each loop + if array[i] < array[min_idx]: + min_idx = i + + # Arranging min at the correct position + (array[s], array[min_idx]) = (array[min_idx], array[s]) + + +def heapify(array, n, i): + largest = i + l = 2 * i + 1 + r = 2 * i + 2 + + if l < n and array[i] < array[l]: + largest = l + if r < n and array[largest] < array[r]: + largest = r + + if largest != i: + array[i], array[largest] = array[largest], array[i] + heapify(array, n, largest) + + +def heap_sort(array): + n = len(array) + for i in range(n // 2, -1, -1): + heapify(array, n, i) + for i in range(n - 1, 0, -1): + array[i], array[0] = array[0], array[i] + heapify(array, i, 0) + return array + + +def shell_sort(array): + n = len(array) + interval = n // 2 + while interval > 0: + for i in range(interval, n): + temp = array[i] + j = i + while j >= interval and array[j - interval] > temp: + array[j] = array[j - interval] + j -= interval + + array[j] = temp + interval //= 2 + return array + + +# Radix sort in Python + + +# Using counting sort to sort the elements in the basis of significant places +def countingSort_radix(array, place): + size = len(array) + output = [0] * size + count = [0] * 10 + + # Calculate count of elements + for i in range(0, size): + index = array[i] // place + count[index % 10] += 1 + + # Calculate cumulative count + for i in range(1, 10): + count[i] += count[i - 1] + + # Place the elements in sorted order + i = size - 1 + while i >= 0: + index = array[i] // place + output[count[index % 10] - 1] = array[i] + count[index % 10] -= 1 + i -= 1 + + for i in range(0, size): + array[i] = output[i] + + +# Main function to implement radix sort +def radix_sort(array): + # Get maximum element + max_element = max(array) + + # Apply counting sort to sort elements based on place value. + place = 1 + while max_element // place > 0: + countingSort_radix(array, place) + place *= 10 + return array + + +def bucket_sort(arr): + n = len(arr) + buckets = [[] for _ in range(n)] + + # Put array elements in different buckets + for num in arr: + bi = min(int(n * num), n - 1) + buckets[bi].append(num) + + # Sort individual buckets using insertion sort + for bucket in buckets: + insertion_sort(bucket) + + # Concatenate all buckets into arr[] + index = 0 + for bucket in buckets: + for num in bucket: + arr[index] = num + index += 1 + return arr From 21f970465247c58486c376a6d527dbe231b05544 Mon Sep 17 00:00:00 2001 From: AlishChhetri Date: Thu, 25 Apr 2024 15:34:26 -0400 Subject: [PATCH 5/8] fix: out to our typo --- bosco/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bosco/main.py b/bosco/main.py index 0ecbe72..00d634e 100644 --- a/bosco/main.py +++ b/bosco/main.py @@ -19,7 +19,7 @@ def bosco( ) -> None: """Conduct a doubling experiment to measure the performance of list sorting for a specific algorithm.""" console.print( - "\n:dog: Bosco is fetching out results!\n" + "\n:dog: Bosco is fetching our results!\n" ) console.print(f"Path to the desired file: {file}\n") console.print(f"Name of the desired function: {function_name}\n") From 153237d93538b0099595336b736ccc0672012d13 Mon Sep 17 00:00:00 2001 From: Jacob-Allebach Date: Thu, 25 Apr 2024 15:53:38 -0400 Subject: [PATCH 6/8] Add readme for instructions on using tool --- bosco/README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 bosco/README.md diff --git a/bosco/README.md b/bosco/README.md new file mode 100644 index 0000000..2d5a1d8 --- /dev/null +++ b/bosco/README.md @@ -0,0 +1,48 @@ +# How to Use the Bosco Tool + +To run the Bosco tool, you can call it from the main directory using a poetry command formatted like +`poetry run bosco --starting-size 100 --number-doubles 5 --file bosco/sorting.py --function-name bubble_sort`. +The command should use the inputs `--starting-size` for the initial list size to start the doubling experiment, +`--number-doubles` for the number of times the input size will be doubled during the doubling experiment, +`--file` for the path to the file containing the sorting algorithm you want to run the doubling experiment on, +and `--function-name` for the name of the function containing the sorting algorithm you want to test. + +## Example of command and output + +### Command + +```terminal +poetry run bosco --starting-size 100 --number-doubles 5 --file bosco/sorting.py --function-name quick_sort +``` + +### Output + +```terminal +๐Ÿถ Bosco is fetching our results! + +Path to the desired file: bosco/sorting.py + +Name of the desired function: quick_sort + +Starting size of the data container: 100 + +Number of doubles to execute: 5 + +๐Ÿ“ˆ Here are the results from running the experiment! + +โ•’โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•คโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•คโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•คโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•• +โ”‚ Input Size โ”‚ Best Case โ”‚ Worst Case โ”‚ Average Case โ”‚ +โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก +โ”‚ 100 โ”‚ 0.00058 โ”‚ 0.00061 โ”‚ 0.00060 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 200 โ”‚ 0.00129 โ”‚ 0.00155 โ”‚ 0.00139 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 400 โ”‚ 0.00268 โ”‚ 0.00374 โ”‚ 0.00305 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 800 โ”‚ 0.00578 โ”‚ 0.00656 โ”‚ 0.00610 โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 1600 โ”‚ 0.01312 โ”‚ 0.01414 โ”‚ 0.01372 โ”‚ +โ•˜โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•งโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•งโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•งโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•› +``` + +### Graph Produced from Output From 2cb1dc69abde2e4a7c47f44e6ac5690c8550422a Mon Sep 17 00:00:00 2001 From: Jacob-Allebach <70417208+Jacob-Allebach@users.noreply.github.com> Date: Thu, 25 Apr 2024 15:54:57 -0400 Subject: [PATCH 7/8] Update README.md with image --- bosco/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bosco/README.md b/bosco/README.md index 2d5a1d8..47e8ffc 100644 --- a/bosco/README.md +++ b/bosco/README.md @@ -46,3 +46,6 @@ Number of doubles to execute: 5 ``` ### Graph Produced from Output + +![example_graph](https://github.com/Algorithmology/bosco/assets/70417208/0be0e695-f06c-490a-98df-cb3eaaf5ca07) + From 077449aa307a973bae465c01cf90b3b36f9a8c6e Mon Sep 17 00:00:00 2001 From: boulais01 <89533621+boulais01@users.noreply.github.com> Date: Thu, 25 Apr 2024 15:10:21 -0500 Subject: [PATCH 8/8] fix: reimplement docstring --- bosco/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bosco/main.py b/bosco/main.py index 00d634e..ed24d8e 100644 --- a/bosco/main.py +++ b/bosco/main.py @@ -1,3 +1,5 @@ +"""Bosco runs benchmarks to assess the performance of Python functions.""" + import plotly.graph_objs as go import typer from plotly.subplots import make_subplots