Skip to content

Commit

Permalink
cleanup and docstring
Browse files Browse the repository at this point in the history
  • Loading branch information
vc1492a committed Feb 13, 2020
1 parent b514178 commit 379ab28
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 44 deletions.
49 changes: 40 additions & 9 deletions comparisons/interval_balancing.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
from operator import itemgetter
import datetime
from typing import Union


def create_interval(start, finish, keys, key):
"""Returns a properly formed interval dictionary object."""
new_interval = {"start": start, "finish": finish}
def create_interval(start: Union[str, int, float, 'datetime.datetime'], finish: Union[str, int, float, 'datetime.datetime'], keys: dict, key: Union[str, int, float, 'datetime.datetime']) -> dict:
"""
Takes a set of data pertaining to an interval and creates a properly formed interval dictionary object.
:param start: A string, integer, float, or datetime object indicating the start of an interval.
:param finish: A string, integer, float, or datetime object indicating the finish of an interval.
:param keys: A set of keys for the interval, usually indicating its source.
:param key: A string, integer, float, or datetime object to use as the key for the interval.
:return: a properly formed interval dictionary object.
"""

new_interval = dict({"start": start, "finish": finish})
new_interval[key] = keys
return new_interval


def reconstruct_intervals_from_vertices(vtx_list, key):
"""Takes a list of vertices from deconstructed, potentially conflicting intervals and returns a list of deconflicted intervals."""
def reconstruct_intervals_from_vertices(vtx_list: list, key: Union[str, int, float, 'datetime.datetime']) -> list:
"""
Takes a list of vertices from deconstructed, potentially conflicting intervals and returns a list of deconflicted
intervals.
:param vtx_list: A list of vertices from deconstructed, potentially conflicting intervals.
:param key: A string, integer, float, or datetime object to use as the key for the intervals.
:return: A list of deconflicted intervals.
"""

vtx_list = sorted(vtx_list, key=lambda x: x["point"])
intervals = []
open_ints = set()
Expand All @@ -22,15 +38,30 @@ def reconstruct_intervals_from_vertices(vtx_list, key):
return intervals


def create_vertex(interval, label, key):
vertex = {"point": interval[label], "keys": interval[key], "label": label}
def create_vertex(interval: list, label: Union[str, int, float, 'datetime.datetime'], key: Union[str, int, float, 'datetime.datetime']) -> dict:
"""
Creates a vertex for an interval with information about the point, label, and keys for the interval.
:param interval: The interval in which to create a vertex for.
:param label: A string, integer, float, or datetime object used to indicate which label to use for the point.
:param key: A string, integer, float, or datetime object to use as the key for the interval.
:return: A dictionary representing the vertex for the provided interval.
"""

vertex = dict({"point": interval[label], "keys": interval[key], "label": label})
return vertex


class Merge:

@staticmethod
def union(intervals: list, key: str = "set_items"):
"""Combines a list of potentially conflicting intervals into a list of de-conflicted intervals with joined labels."""
"""
Combines a list of potentially conflicting intervals into a list of de-conflicted intervals with joined labels
:param intervals: A list of intervals.
:param key: A string to use as the key for the interval.
:return: A set of merged intervals.
"""

vtx_list = []
for i, interval in enumerate(intervals):
interval[key] = interval[key] if key in interval else {i}
Expand Down
54 changes: 41 additions & 13 deletions comparisons/interval_generator.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,45 @@
import random
import datetime
from typing import Union


class IntervalGenerator:

def __init__(self, interval_type="int"):
self.interval_type = interval_type


def cast_value(self, value, interval_type):
@staticmethod
def cast_value(value: Union[int, float, str, 'datetime'], interval_type: str) -> Union[eval, 'datetime', chr]:
"""
THis function casts a value based on the interval type.
:param value: The value to be cast.
:param interval_type: The type of interval.
:return: A value cast into the type corresponding to the interval_type.
"""

if interval_type in ["int", "float", "number"]:
return eval(f"{interval_type}({value})")
elif interval_type == "datetime":
return datetime.datetime(1, 1, 1, 0) + datetime.timedelta(days=value)
elif interval_type in ["char", "str"]:
return chr(ord("a") + value)

def generate_random(self, count: int = 1, min_value: int = 0, max_value: int = 100, interval_type=None, seed=None) -> list:
"""
Generates random intervals based on the type, count, min_value and max_value.
:param count: The number of intervals to generate.
:param min_value: The minimum start value.
:param max_value: The maximum finish value.
:param interval_type: The type of interval to be generated.
:param seed: A seed interval, if any.
:return: A list of intervals.
"""

def generate_random(self, count: int = 1, min_value: int = 0, max_value: int = 100, interval_type=None, seed=None):
interval_type = interval_type if interval_type else self.interval_type

intervals = []
intervals = list()
for i in range(count):
interval = {}
interval = dict()
random.seed(seed + i if seed is not None else seed)
start = random.randint(min_value, max_value - 1)
interval["start"] = self.cast_value(start, interval_type)
Expand All @@ -31,30 +50,39 @@ def generate_random(self, count: int = 1, min_value: int = 0, max_value: int = 1
return intervals

def generate_sequential(self, count: int = 1, start: int = 0, interval_type=None):
"""
Generates sequential intervals based on the count, start, and interval type.
:param count: The number of intervals to generate.
:param start: The initial start value.
:param interval_type: The type of interval to be generated.
:return: A list of intervals.
"""

interval_type = interval_type if interval_type else self.interval_type

intervals = []
intervals = list()
for i in range(count):
interval = {}
interval = dict()
interval["start"] = self.cast_value(start + i, interval_type)
interval["finish"] = self.cast_value(start + i + 2, interval_type)
interval["set_items"] = {i}
intervals.append(interval)

return intervals


if __name__ == "__main__":

interval_gen = IntervalGenerator()

import time

from copy_mieda.intervals import Merge as mieda_merge
from mieda.intervals import Merge as mieda_merge
from interval_balancing import Merge as interval_balancing

algorithms = {"mieda": mieda_merge, "interval_balancing": interval_balancing}
total_intervals = [interval_gen.generate_sequential(i, i) for i in range(1,1000,10)]

total_intervals = [interval_gen.generate_sequential(i, i) for i in range(1, 1000, 10)]

for algorithm_name, algorithm in algorithms.items():
avg_time = None
Expand All @@ -63,6 +91,6 @@ def generate_sequential(self, count: int = 1, start: int = 0, interval_type=None
single_start = time.process_time()
test = algorithm.union(intervals)
elapsed = time.process_time() - single_start
avg_time = (elapsed + avg_time)/2 if avg_time else elapsed
avg_time = (elapsed + avg_time) / 2 if avg_time else elapsed
print(f"Elapsed for {algorithm_name}:", time.process_time() - start_time)
print("Average Time/Set:", avg_time)
print("Average Time/Set:", avg_time)
86 changes: 64 additions & 22 deletions comparisons/iterative.py
Original file line number Diff line number Diff line change
@@ -1,77 +1,119 @@
def createInterval(start, finish, keys, key):
new_interval = {}
new_interval["start"] = start
new_interval["finish"] = finish
new_interval[key] = keys.copy()
import datetime
from typing import Tuple, Union


def create_interval(start: Union[str, int, float, 'datetime.datetime'], finish: Union[str, int, float, 'datetime.datetime'], keys: dict, key: Union[str, int, float, 'datetime.datetime']) -> dict:
"""
Takes a set of data pertaining to an interval and creates a properly formed interval dictionary object.
:param start: A string, integer, float, or datetime object indicating the start of an interval.
:param finish: A string, integer, float, or datetime object indicating the finish of an interval.
:param keys: A set of keys for the interval, usually indicating its source.
:param key: A string, integer, float, or datetime object to use as the key for the interval.
:return: a properly formed interval dictionary object.
"""

new_interval = dict({"start": start, "finish": finish})
new_interval[key] = keys
return new_interval


def getMainPermutations(intervals, key):
def get_main_permutations(intervals: list, key: Union[str, int, float, 'datetime.datetime']) -> Tuple[bool, list]:
"""
Takes a set of intervals and returns the main permutations and a boolean indicating whether a conflict is
present in the intervals passed.
:param intervals: A list of intervals.
:param key: A string, integer, float, or datetime object to use as the key for the intervals.
:return: A boolean and list of intervals.
"""

conflicts = False
new_intervals = []
new_intervals = list()
for start_interval in intervals:
for compare_interval in intervals:
if start_interval["start"] >= compare_interval["finish"] or start_interval["finish"] <= compare_interval["start"]:
if start_interval["start"] >= compare_interval["finish"] or start_interval["finish"] <= compare_interval[
"start"]:
continue
conflicts = True

first_finish = start_interval["start"]
if start_interval["start"] != compare_interval["start"]:
first_start = min(start_interval["start"], compare_interval["start"])
first_finish = max(start_interval["start"], compare_interval["start"])
keys = start_interval[key] if start_interval["start"] < compare_interval["start"] else compare_interval[key]
new_interval = createInterval(first_start, first_finish, keys, key)
keys = start_interval[key] if start_interval["start"] < compare_interval["start"] else compare_interval[
key]
new_interval = create_interval(first_start, first_finish, keys, key)
if new_interval not in new_intervals:
new_intervals.append(new_interval)

last_start = start_interval["finish"]
if start_interval["finish"] != compare_interval["finish"]:
last_start = min(start_interval["finish"], compare_interval["finish"])
last_finish = max(start_interval["finish"], compare_interval["finish"])
keys = start_interval[key] if start_interval["finish"] > compare_interval["finish"] else compare_interval[key]
new_interval = createInterval(last_start, last_finish, keys, key)
keys = start_interval[key] if start_interval["finish"] > compare_interval["finish"] else \
compare_interval[key]
new_interval = create_interval(last_start, last_finish, keys, key)
if new_interval not in new_intervals:
new_intervals.append(new_interval)

new_interval = createInterval(first_finish, last_start, start_interval[key].union(compare_interval[key]), key)
new_interval = create_interval(first_finish, last_start, start_interval[key].union(compare_interval[key]),
key)
if new_interval not in new_intervals:
new_intervals.append(new_interval)
return conflicts, new_intervals


def resolveConflicts(intervals, key):
resolved_intervals = []
skip = {}
def resolve_conflicts(intervals: list, key: Union[str, int, float, 'datetime.datetime']) -> Tuple[bool, list]:
"""
Takes a list of intervals and returns a new list of intervals and a boolean indicating whether or not the
conflicts have been resolved.
:param intervals: A list of intervals.
:param key: A string, integer, float, or datetime object to use as the key for the intervals.
:return: A boolean and list of intervals.
"""

resolved_intervals = list()
skip = dict()
unresolved = False
for i, start_interval in enumerate(intervals):
if (start_interval["start"], start_interval["finish"]) in skip:
continue

conflict = False
for j, compare_interval in enumerate(intervals):
if start_interval["start"] == compare_interval["start"] and start_interval["finish"] > compare_interval["finish"]:
if start_interval["start"] == compare_interval["start"] and start_interval["finish"] > compare_interval[
"finish"]:
compare_interval[key] = compare_interval[key].union(start_interval[key])
conflict = True
break

if start_interval["start"] < compare_interval["start"] < start_interval["finish"]:
unresolved = True

elif (start_interval["start"], start_interval["finish"]) == (compare_interval["start"], compare_interval["finish"]):
elif (start_interval["start"], start_interval["finish"]) == (
compare_interval["start"], compare_interval["finish"]):
start_interval[key] = start_interval[key].union(compare_interval[key])
skip[(start_interval["start"], start_interval["finish"])] = True

if not conflict:
resolved_intervals.append(start_interval)
return unresolved, resolved_intervals


class Merge:

@staticmethod
def union(intervals: list, key: str = "set_items"):
"""
Combines a list of potentially conflicting intervals into a list of de-conflicted intervals with joined labels
:param intervals: A list of intervals.
:param key: A string to use as the key for the interval.
:return: A set of merged intervals.
"""

while True:
conflict, intervals = getMainPermutations(intervals, key)
unresolved, intervals = resolveConflicts(intervals, key) if conflict else (False, intervals)
conflict, intervals = get_main_permutations(intervals, key)
unresolved, intervals = resolve_conflicts(intervals, key) if conflict else (False, intervals)
if not unresolved:
break
return intervals

return intervals

0 comments on commit 379ab28

Please sign in to comment.