2018-10-21 13:52:02 +00:00
|
|
|
import json
|
2018-10-11 12:38:59 +00:00
|
|
|
import random
|
|
|
|
from time import time
|
2018-10-17 10:56:46 +00:00
|
|
|
from collections import namedtuple
|
2018-10-11 12:38:59 +00:00
|
|
|
import util
|
|
|
|
from gift_wrapper import rapper
|
|
|
|
from graham import graham_scan
|
2018-10-18 16:41:18 +00:00
|
|
|
from mbc import mbc, mbc_no_shuffle, mbc2_no_shuffle, mbc2
|
|
|
|
from profile import Profiler
|
2018-10-11 12:38:59 +00:00
|
|
|
from quick_hull import quick_hull
|
2018-10-17 10:56:46 +00:00
|
|
|
import os.path
|
|
|
|
|
|
|
|
#random.seed(1337_420)
|
|
|
|
|
|
|
|
TimedResult = namedtuple("TimedResult", "algorithm points running_time")
|
|
|
|
|
|
|
|
|
2018-10-18 16:41:18 +00:00
|
|
|
def time_it(f: callable, args: tuple = ()):
|
2018-10-17 10:56:46 +00:00
|
|
|
start = time()
|
2018-10-18 16:41:18 +00:00
|
|
|
f(*args)
|
2018-10-17 10:56:46 +00:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
2018-10-18 16:41:18 +00:00
|
|
|
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,)))]
|
2018-10-18 10:07:08 +00:00
|
|
|
|
2018-10-17 10:56:46 +00:00
|
|
|
|
2018-10-18 16:41:18 +00:00
|
|
|
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)
|
2018-10-11 12:38:59 +00:00
|
|
|
|
2018-10-18 16:41:18 +00:00
|
|
|
results = calculate_hulls(number_of_points, points_square)
|
|
|
|
write_to_log("square_tests.log", results)
|
2018-10-11 13:54:52 +00:00
|
|
|
|
2018-10-17 10:56:46 +00:00
|
|
|
|
2018-10-18 16:41:18 +00:00
|
|
|
def do_circular_tests(number_of_points):
|
|
|
|
points_circular = {util.gen_point(0, 100) for _ in range(number_of_points)}
|
2018-10-17 10:56:46 +00:00
|
|
|
|
2018-10-18 16:41:18 +00:00
|
|
|
results = calculate_hulls(number_of_points, points_circular)
|
2018-10-17 10:56:46 +00:00
|
|
|
write_to_log("circular_tests.log", results)
|
|
|
|
|
|
|
|
|
2018-10-18 16:41:18 +00:00
|
|
|
def do_triangular_tests(number_of_points):
|
2018-10-17 10:56:46 +00:00
|
|
|
left, right, top = util.Point(1,1), util.Point(51,1), util.Point(26,40)
|
2018-10-18 16:41:18 +00:00
|
|
|
points = {util.gen_triangular_point(left, right, top) for _ in range(number_of_points)}
|
2018-10-17 10:56:46 +00:00
|
|
|
|
2018-10-18 16:41:18 +00:00
|
|
|
results = calculate_hulls(number_of_points, points)
|
2018-10-17 10:56:46 +00:00
|
|
|
write_to_log("triangular_tests.log", results)
|
|
|
|
|
|
|
|
|
2018-10-18 16:41:18 +00:00
|
|
|
def do_quadratic_tests(number_of_points):
|
|
|
|
points = {util.gen_weird_point(-10, 10) for _ in range(number_of_points)}
|
2018-10-17 10:56:46 +00:00
|
|
|
|
2018-10-18 16:41:18 +00:00
|
|
|
results = calculate_hulls(number_of_points, points)
|
2018-10-17 10:56:46 +00:00
|
|
|
write_to_log("quadratic_tests.log", results)
|
|
|
|
|
|
|
|
|
2018-10-18 10:07:08 +00:00
|
|
|
def sanity_check():
|
|
|
|
points = {util.gen_point(1, 50) for i in range(100)}
|
2018-10-11 13:54:52 +00:00
|
|
|
graham = set(graham_scan(points))
|
|
|
|
gift = set(rapper(points))
|
|
|
|
quick = quick_hull(points)
|
|
|
|
mbch = set.union(mbc(points))
|
2018-10-18 16:41:18 +00:00
|
|
|
mbch2 = set.union(mbc2(points))
|
|
|
|
assert gift == graham == quick == mbch == mbch2
|
|
|
|
|
|
|
|
|
2018-10-21 13:52:02 +00:00
|
|
|
def do_one_profile(num_points):
|
|
|
|
print(f"==================================== PROFILE ({num_points}) ====================================")
|
2018-10-18 16:41:18 +00:00
|
|
|
random.seed(6)
|
2018-10-21 13:52:02 +00:00
|
|
|
points = {util.gen_point(0, 100) for _ in range(num_points)}
|
2018-10-18 16:41:18 +00:00
|
|
|
|
|
|
|
tests = [
|
2018-10-21 13:52:02 +00:00
|
|
|
#("graham_scan", graham_scan),
|
|
|
|
#("gift_wrapper", rapper),
|
|
|
|
#("quick_hull", quick_hull),
|
2018-10-18 16:41:18 +00:00
|
|
|
("mbc", mbc),
|
|
|
|
("mbc2", mbc2),
|
|
|
|
("mbc_no_shuffle", mbc_no_shuffle),
|
|
|
|
("mbc2_no_shuffle", mbc2_no_shuffle),
|
|
|
|
]
|
|
|
|
|
2018-10-21 13:52:02 +00:00
|
|
|
results = {}
|
2018-10-18 16:41:18 +00:00
|
|
|
for algorithm, func in tests:
|
|
|
|
Profiler.reset()
|
|
|
|
func(points)
|
|
|
|
|
2018-10-21 13:52:02 +00:00
|
|
|
times = dict(Profiler.results)
|
2018-10-18 16:41:18 +00:00
|
|
|
|
|
|
|
print(f"-------------- {algorithm} --------------")
|
|
|
|
print("Times:", times)
|
|
|
|
|
|
|
|
total = times[algorithm]
|
|
|
|
print("Total:", total)
|
|
|
|
|
|
|
|
sum_profiled = sum(times.values()) - total
|
|
|
|
print("Total Profiled:", sum_profiled)
|
|
|
|
|
2018-10-21 13:52:02 +00:00
|
|
|
unaccounted = total - sum_profiled
|
|
|
|
print("Unaccounted:", unaccounted)
|
|
|
|
|
|
|
|
results[algorithm] = {
|
|
|
|
"times": times,
|
|
|
|
"total": total,
|
|
|
|
"total_profiled": sum_profiled,
|
|
|
|
"unaccounted": unaccounted,
|
|
|
|
}
|
|
|
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
|
|
def do_profile():
|
|
|
|
import pandas as pd
|
|
|
|
import numpy as np
|
|
|
|
import altair as alt
|
|
|
|
|
|
|
|
### GATHER DATA ###
|
|
|
|
|
|
|
|
#results = {num_points: do_one_profile(num_points) for num_points in (10_000, 30_000, 60_000)}
|
|
|
|
results = {"10000": {"mbc": {"times": {"finding median": 0.0010907649993896484, "partitioning set": 0.00837850570678711, "shuffling constraints": 0.01737236976623535, "solving 1D LP": 0.018637895584106445, "solving 2D LP": 0.023772716522216797, "finding bridge points": 0.00942373275756836, "pruning between line points": 0.0062139034271240234, "mbc": 0.08948898315429688}, "total": 0.08948898315429688, "total_profiled": 0.08488988876342773, "unaccounted": 0.004599094390869141}, "mbc2": {"times": {"extra pruning step": 0.021185636520385742, "finding median": 0.00042319297790527344, "partitioning set": 0.002390623092651367, "shuffling constraints": 0.00530552864074707, "solving 1D LP": 0.002721548080444336, "solving 2D LP": 0.004323244094848633, "finding bridge points": 0.0038061141967773438, "pruning between line points": 0.0017795562744140625, "mbc2": 0.0463566780090332}, "total": 0.0463566780090332, "total_profiled": 0.04193544387817383, "unaccounted": 0.004421234130859375}, "mbc_no_shuffle": {"times": {"finding median": 0.0011930465698242188, "partitioning set": 0.008675098419189453, "solving 1D LP": 0.012013912200927734, "solving 2D LP": 0.016475915908813477, "finding bridge points": 0.009999275207519531, "pruning between line points": 0.006704092025756836, "mbc_no_shuffle": 0.0634622573852539}, "total": 0.0634622573852539, "total_profiled": 0.05506134033203125, "unaccounted": 0.008400917053222656}, "mbc2_no_shuffle": {"times": {"extra pruning step": 0.020714282989501953, "finding median": 0.0004355907440185547, "partitioning set": 0.0022919178009033203, "solving 1D LP": 0.004298210144042969, "solving 2D LP": 0.005736112594604492, "finding bridge points": 0.004106044769287109, "pruning between line points": 0.0017347335815429688, "mbc2_no_shuffle": 0.04152178764343262}, "total": 0.04152178764343262, "total_profiled": 0.03931689262390137, "unaccounted": 0.00220489501953125}}, "30000": {"mbc": {"times": {"finding median": 0.0033922195434570312, "partitioning set": 0.027561187744140625, "shuffling constraints": 0.03943347930908203, "solving 1D LP": 0.03251838684082031, "solving 2D LP": 0.04914522171020508, "finding bridge points": 0.02995467185974121, "pruning between line points": 0.018335342407226562, "mbc": 0.23250341415405273}, "total": 0.23250341415405273, "total_profiled": 0.20034050941467285, "unaccounted": 0.03216290473937988}, "mbc2": {"times": {"extra pruning step": 0.07657957077026367, "finding median": 0.0013115406036376953, "partitioning set": 0.009799957275390625, "shuffling constraints": 0.01538705825805664, "solving 1D LP": 0.018373966217041016, "solving 2D LP": 0.023766040802001953, "finding bridge points": 0.01176595687866211, "pruning between line points": 0.0074269771575927734, "mbc2": 0.1977553367614746}, "total": 0.1977553367614746, "total_profiled": 0.16441106796264648, "unaccounted": 0.033344268798828125}, "mbc_no_shuffle": {"times": {"finding median": 0.003788471221923828, "partitioning set": 0.0294649600982666, "solving 1D LP": 0.01887059211730957, "solving 2D LP": 0.028406858444213867, "finding bridge points": 0.026410341262817383, "pruning between line points": 0.01907038688659668, "mbc_no_shuffle": 0.16133356094360352}, "total": 0.16133356094360352, "total_profiled": 0.12601161003112793, "unaccounted": 0.035321950912475586}, "mbc2_no_shuffle": {"times": {"extra pruning step": 0.07852339744567871, "finding median": 0.0014028549194335938, "partitioning set": 0.010036468505859375, "solving 1D LP": 0.008901834487915039, "solving 2D LP": 0.012744665145874023, "finding bridge points": 0.012570381164550781, "pruning between line points": 0.007673025131225586, "mbc2_no_shuffle": 0.14619135856628418}, "total": 0.14619135856628418, "total_profiled": 0.1318526268005371, "unaccounted": 0.01433873176574707}}, "60000": {"mbc": {"times": {"finding median": 0.006650209426879883, "partitioning set": 0.06662178039550781, "shuffling constraints": 0.08104324340820312, "solving 1D LP": 0.08928251266479492, "solving 2D LP": 0.12702107429504395, "finding bridge points": 0.060240983963012695, "pruning between lin
|
|
|
|
print("================== RESULTS ==================")
|
|
|
|
print(json.dumps(results))
|
|
|
|
|
|
|
|
### PREPARE DATA ###
|
|
|
|
|
|
|
|
num_points = list(results.keys())
|
|
|
|
algorithms = [algorithm for algorithm in results[num_points[0]].keys()]
|
|
|
|
|
|
|
|
steps = (
|
|
|
|
"finding median",
|
|
|
|
"partitioning set",
|
|
|
|
"solving 1D LP",
|
|
|
|
"solving 2D LP",
|
|
|
|
"finding bridge points",
|
|
|
|
"pruning between line points",
|
|
|
|
"shuffling constraints",
|
|
|
|
"extra pruning step",
|
|
|
|
)
|
|
|
|
|
|
|
|
def prep_df(df, name):
|
|
|
|
df = df.stack().reset_index()
|
|
|
|
df.columns = ['c1', 'c2', 'values']
|
|
|
|
df['DF'] = name
|
|
|
|
return df
|
|
|
|
|
|
|
|
dfs = []
|
|
|
|
for step in steps:
|
|
|
|
res = [[data["times"].get(step, 0)
|
|
|
|
for algorithm, data in results[points].items()]
|
|
|
|
for points in num_points]
|
|
|
|
df = pd.DataFrame(res, index=num_points, columns=algorithms)
|
|
|
|
dfs.append(prep_df(df, step))
|
|
|
|
|
|
|
|
df = pd.concat(dfs)
|
|
|
|
|
|
|
|
### PLOT DATA ###
|
|
|
|
|
|
|
|
chart = alt.Chart(df).mark_bar().encode(
|
|
|
|
|
|
|
|
# tell Altair which field to group columns on
|
|
|
|
x=alt.X('c2:N',
|
|
|
|
axis=alt.Axis(
|
|
|
|
title='')),
|
|
|
|
|
|
|
|
# tell Altair which field to use as Y values and how to calculate
|
|
|
|
y=alt.Y('sum(values):Q',
|
|
|
|
axis=alt.Axis(
|
|
|
|
grid=False,
|
|
|
|
title='')),
|
|
|
|
|
|
|
|
# tell Altair which field to use to use as the set of columns to be represented in each group
|
|
|
|
column=alt.Column('c1:N',
|
|
|
|
axis=alt.Axis(
|
|
|
|
title='')),
|
|
|
|
|
|
|
|
# tell Altair which field to use for color segmentation
|
|
|
|
color=alt.Color('DF:N',
|
|
|
|
scale=alt.Scale(
|
|
|
|
# make it look pretty with an enjoyable color pallet
|
|
|
|
range=['#96ceb4', '#ffcc5c', '#ff6f69'],
|
|
|
|
),
|
|
|
|
)) \
|
|
|
|
.configure_facet_cell(
|
|
|
|
# remove grid lines around column clusters
|
|
|
|
strokeWidth=0.0)
|
|
|
|
chart.savechart('chart.html')
|
2018-10-11 13:54:52 +00:00
|
|
|
|
2018-10-17 10:56:46 +00:00
|
|
|
|
2018-10-18 09:53:43 +00:00
|
|
|
if __name__ == '__main__':
|
2018-10-18 10:07:08 +00:00
|
|
|
sanity_check()
|
2018-10-18 16:41:18 +00:00
|
|
|
do_profile()
|
|
|
|
exit()
|
2018-10-18 09:53:43 +00:00
|
|
|
for i in range(50, 1000, 50):
|
|
|
|
do_square_tests(i)
|