237 lines
6.6 KiB
Python
237 lines
6.6 KiB
Python
import json
|
|
import random
|
|
from time import time
|
|
from collections import namedtuple
|
|
import util
|
|
from gift_wrapper import rapper
|
|
from graham import graham_scan
|
|
from mbc import mbc, mbc_no_shuffle, mbc2_no_shuffle, mbc2
|
|
from profile import Profiler
|
|
from quick_hull import quick_hull
|
|
import os.path
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
#random.seed(1337_420)
|
|
|
|
TimedResult = namedtuple("TimedResult", "algorithm points running_time")
|
|
|
|
|
|
def time_it(f: callable, args: tuple = ()):
|
|
start = time()
|
|
f(*args)
|
|
return str(time() - start)
|
|
|
|
|
|
def initiate_file(file):
|
|
with open(file, "w+") as tmp:
|
|
tmp.write("algorithm\t\tpoints\t\ttime")
|
|
|
|
|
|
def write_to_log(file, data):
|
|
if not os.path.isfile(file):
|
|
initiate_file(file)
|
|
|
|
tmp = []
|
|
for res in data:
|
|
line = str.join("\t\t", res)
|
|
print(line)
|
|
tmp.append(line)
|
|
|
|
write_string = "\n" + str.join("\n", tmp)
|
|
|
|
with open(file, "a+") as open_file:
|
|
open_file.write(write_string)
|
|
|
|
|
|
def calculate_hulls(number_of_points, points):
|
|
return [TimedResult("graham", number_of_points, time_it(graham_scan, args=(points,))),
|
|
TimedResult("gift", number_of_points, time_it(rapper, args=(points,))),
|
|
TimedResult("quick", number_of_points, time_it(quick_hull, args=(points,))),
|
|
TimedResult("mbch", number_of_points, time_it(mbc, args=(points,))),
|
|
TimedResult("mbch2", number_of_points, time_it(mbc2, args=(points,)))]
|
|
|
|
|
|
def do_square_tests(number_of_points):
|
|
points_square = {util.gen_point(0, 100) for _ in range(number_of_points)}
|
|
number_of_points = str(number_of_points)
|
|
|
|
results = calculate_hulls(number_of_points, points_square)
|
|
write_to_log("square_tests.log", results)
|
|
|
|
|
|
def do_circular_tests(number_of_points):
|
|
points_circular = {util.gen_point(0, 100) for _ in range(number_of_points)}
|
|
|
|
results = calculate_hulls(number_of_points, points_circular)
|
|
write_to_log("circular_tests.log", results)
|
|
|
|
|
|
def do_triangular_tests(number_of_points):
|
|
left, right, top = util.Point(1,1), util.Point(51,1), util.Point(26,40)
|
|
points = {util.gen_triangular_point(left, right, top) for _ in range(number_of_points)}
|
|
|
|
results = calculate_hulls(number_of_points, points)
|
|
write_to_log("triangular_tests.log", results)
|
|
|
|
|
|
def do_quadratic_tests(number_of_points):
|
|
points = {util.gen_weird_point(-10, 10) for _ in range(number_of_points)}
|
|
|
|
results = calculate_hulls(number_of_points, points)
|
|
write_to_log("quadratic_tests.log", results)
|
|
|
|
|
|
def sanity_check():
|
|
points = {util.gen_point(1, 50) for i in range(100)}
|
|
graham = set(graham_scan(points))
|
|
gift = set(rapper(points))
|
|
quick = quick_hull(points)
|
|
mbch = set.union(mbc(points))
|
|
mbch2 = set.union(mbc2(points))
|
|
assert gift == graham == quick == mbch == mbch2
|
|
|
|
|
|
def do_one_profile(num_points):
|
|
print(f"==================================== PROFILE ({num_points}) ====================================")
|
|
random.seed(6)
|
|
points = {util.gen_point(0, 100) for _ in range(num_points)}
|
|
|
|
tests = [
|
|
("graham_scan", graham_scan),
|
|
#("gift_wrapper", rapper),
|
|
("quick_hull", quick_hull),
|
|
("mbc", mbc),
|
|
("mbc_no_shuffle", mbc_no_shuffle),
|
|
("mbc2", mbc2),
|
|
("mbc2_no_shuffle", mbc2_no_shuffle),
|
|
]
|
|
|
|
results = {}
|
|
for algorithm, func in tests:
|
|
Profiler.reset()
|
|
func(points)
|
|
|
|
times = dict(Profiler.results)
|
|
|
|
print(f"-------------- {algorithm} --------------")
|
|
print("Times:", times)
|
|
|
|
total = times[algorithm]
|
|
print("Total:", total)
|
|
|
|
sum_profiled = sum(times.values()) - total
|
|
print("Total Profiled:", sum_profiled)
|
|
|
|
unaccounted = total - sum_profiled
|
|
print("Unaccounted:", unaccounted)
|
|
times["other"] = unaccounted
|
|
|
|
results[algorithm] = {
|
|
"times": times,
|
|
"total": total,
|
|
"total_profiled": sum_profiled,
|
|
"unaccounted": unaccounted,
|
|
}
|
|
|
|
return results
|
|
|
|
|
|
def plot_mbc(results, ax):
|
|
algorithms = list(results.keys())
|
|
steps = (
|
|
"other",
|
|
"finding median",
|
|
"partitioning set",
|
|
"building constraints",
|
|
"solving LP",
|
|
"finding bridge points",
|
|
"pruning between line points",
|
|
"shuffling constraints",
|
|
"extra pruning step",
|
|
)
|
|
util.stacked_bar(ax=ax,
|
|
data=[[result["times"].get(step, 0) * 1000 for result in results.values()] for step in steps],
|
|
series_labels=steps,
|
|
category_labels=algorithms,
|
|
value_format="{:.1f}")
|
|
|
|
|
|
def plot_graham(result, ax):
|
|
steps = (
|
|
"other",
|
|
"sorting points",
|
|
"iterating points",
|
|
"calculating sidedness",
|
|
)
|
|
util.stacked_bar(ax=ax,
|
|
data=[[result["times"][step] * 1000] for step in steps],
|
|
series_labels=steps,
|
|
category_labels=["graham scan"],
|
|
value_format="{:.1f}")
|
|
|
|
|
|
def plot_gift(result, ax):
|
|
steps = (
|
|
"other",
|
|
"calculating angle",
|
|
"calculating vector",
|
|
)
|
|
util.stacked_bar(ax=ax,
|
|
data=[[result["times"][step] * 1000] for step in steps],
|
|
series_labels=steps,
|
|
category_labels=["gift wrapper"],
|
|
value_format="{:.1f}")
|
|
|
|
|
|
def plot_quick(result, ax):
|
|
steps = (
|
|
"other",
|
|
"partitioning set",
|
|
"finding farthest point from line",
|
|
)
|
|
util.stacked_bar(ax=ax,
|
|
data=[[result["times"][step] * 1000] for step in steps],
|
|
series_labels=steps,
|
|
category_labels=["quickhull"],
|
|
value_format="{:.1f}")
|
|
|
|
|
|
def do_profile():
|
|
num_points = 60_000
|
|
results = do_one_profile(num_points)
|
|
|
|
print("================== RESULTS ==================")
|
|
print(json.dumps(results))
|
|
|
|
fig, (ax1, ax2, ax3) = plt.subplots(ncols=3, sharex=False, sharey=True, gridspec_kw={"width_ratios": (1, 1, 4)})
|
|
|
|
fig.add_subplot(111, frameon=False)
|
|
plt.tick_params(labelcolor='none', top='off', bottom='off', left='off', right='off')
|
|
|
|
plt.ylabel("time (ms)")
|
|
|
|
plt.subplots_adjust(wspace=0)
|
|
|
|
plot_graham(results["graham_scan"], ax1)
|
|
|
|
#plot_gift(results["gift_wrapper"], ax2)
|
|
|
|
plot_quick(results["quick_hull"], ax2)
|
|
|
|
plot_mbc({alg: data
|
|
for alg, data in results.items()
|
|
if alg.startswith("mbc")},
|
|
ax3)
|
|
|
|
plt.show()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sanity_check()
|
|
do_profile()
|
|
exit()
|
|
for i in range(50, 1000, 50):
|
|
do_square_tests(i)
|