Skip to content
Snippets Groups Projects
Commit 4570fa91 authored by Christoph von Oy's avatar Christoph von Oy
Browse files

Implemented GlobalDynamic

parent 02899a00
Branches
No related tags found
No related merge requests found
...@@ -25,6 +25,59 @@ THE SOFTWARE. ...@@ -25,6 +25,59 @@ THE SOFTWARE.
import pandas as pd import pandas as pd
import pyomo.environ as pyo import pyomo.environ as pyo
class GlobalDynamic:
def __init__(self, d_steps):
self.d_steps = d_steps
self.root_dynamic = TrivialDynamic(self.d_steps, self)
self.dynamics = dict()
self.dynamics[self.root_dynamic] = (dict(), dict())
self.symbol_table = dict()
self.symbol_table[self.root_dynamic] = 0
self.assignments = dict()
def root(self):
return self.root_dynamic
# indices are relative to the root dynamic
def sub_dynamic(self, dynamic, indices):
if isinstance(dynamic, PartialDynamic):
dynamic = dynamic.reference
if tuple(indices) in self.dynamics[dynamic][0].keys():
return self.dynamics[dynamic][0][tuple(indices)]
sub_dynamic = BackedDynamic(dynamic, indices, self)
self.dynamics[dynamic][0][tuple(indices)] = sub_dynamic
self.dynamics[sub_dynamic] = (dict(), dict())
self.symbol_table[sub_dynamic] = len(self.symbol_table)
return sub_dynamic
# start/end are relative to dynamic
def partial_dynamic(self, dynamic, start, end):
if start == 0 and end == dynamic.number_of_steps():
return dynamic
if isinstance(dynamic, PartialDynamic):
start += dynamic.start
end += dynamic.start
dynamic = dynamic.reference
if (start, end) in self.dynamics[dynamic][1].keys():
return self.dynamics[dynamic][1][(start, end)]
partial_dynamic = PartialDynamic(dynamic, start, end, self)
self.dynamics[dynamic][1][(start, end)] = partial_dynamic
self.dynamics[partial_dynamic] = (dict(), dict())
self.symbol_table[partial_dynamic] = len(self.symbol_table)
return partial_dynamic
def display(self):
output = ''
for dynamic, (sub_dynamics, partial_dynamics) in self.dynamics.items():
if len(sub_dynamics) == 0 and len(partial_dynamics) == 0:
continue
output += f'{self.symbol_table[dynamic]}:\n'
for indices, sub_dynamic in sub_dynamics.items():
output += f'\t{indices}: {self.symbol_table[sub_dynamic]}\n'
for (start, end), partial_dynamic in partial_dynamics.items():
output += f'\t{start}-{end}: {self.symbol_table[partial_dynamic]}\n'
return output
# The root dynamic is # The root dynamic is
# for TrivialDynamic: self # for TrivialDynamic: self
# for BackedDynamic: root dynamic of its reference # for BackedDynamic: root dynamic of its reference
...@@ -48,6 +101,10 @@ class Dynamic: ...@@ -48,6 +101,10 @@ class Dynamic:
def time_steps(self): def time_steps(self):
pass pass
# returns all indices in this dynamic
def all_indices(self):
pass
# return true if the dynamic contains the given index # return true if the dynamic contains the given index
# index is relative to the root dynamic # index is relative to the root dynamic
def has_index(self, index): def has_index(self, index):
...@@ -107,20 +164,115 @@ class Dynamic: ...@@ -107,20 +164,115 @@ class Dynamic:
def partial_dynamic(self, i_start, i_end): def partial_dynamic(self, i_start, i_end):
pass pass
def to_string(self): def display(self):
to_print = "[" numbers = self.all_indices()
for p in range(self.number_of_steps()): rows = [[]]
to_print += "(" + str(self.index_of(p)) + ", " + str(self.step_size_p(p)) + ")" row_ends = [0]
if p != self.number_of_steps() - 1: for number in numbers:
to_print += ", " local_position = number - numbers[0]
to_print += "]" row_index = 0
return to_print while row_index < len(rows) and row_ends[row_index] > local_position:
row_index += 1
if row_index == len(rows):
rows.append([])
row_ends.append(0)
rows[row_index].append(number)
row_ends[row_index] = local_position + len(str(number)) + 1
row_strings = []
for items in rows:
row_string = ''
string_end = 0
for number in items:
local_position = number - numbers[0]
row_string += ' ' * (local_position - string_end)
row_string += str(number)
string_end = local_position + len(str(number))
row_strings.append(row_string)
output = ''
for row_index in range(len(row_strings)):
output += row_strings[len(row_strings) - row_index - 1] + '\n'
string_end = 0
for number in numbers:
local_position = number - numbers[0]
output += ' ' * (local_position - string_end)
output += '|'
string_end = local_position + 1
output += '\n'
return output
def display_alignment(self, other):
p_self = 0
p_other = 0
numbers = []
while p_self <= self.number_of_steps() and p_other <= other.number_of_steps():
i_self = self.index_of(p_self)
i_other = other.index_of(p_other)
if i_self < i_other:
numbers.append(i_self)
p_self += 1
elif i_self > i_other:
numbers.append(i_other)
p_other += 1
else:
numbers.append(i_self)
p_self += 1
p_other += 1
while p_self < self.number_of_steps():
numbers.append(self.index_of(p_self))
p_self += 1
else:
while p_other < other.number_of_steps():
numbers.append(other.index_of(p_other))
p_other += 1
rows = [[]]
row_ends = [0]
for number in numbers:
local_position = number - numbers[0]
row_index = 0
while row_index < len(rows) and row_ends[row_index] > local_position:
row_index += 1
if row_index == len(rows):
rows.append([])
row_ends.append(0)
rows[row_index].append(number)
row_ends[row_index] = local_position + len(str(number)) + 1
row_strings = []
for items in rows:
row_string = ''
self_string_end = 0
for number in items:
local_position = number - numbers[0]
row_string += ' ' * (local_position - self_string_end)
row_string += str(number)
self_string_end = local_position + len(str(number))
row_strings.append(row_string)
output = ''
for row_index in range(len(row_strings)):
output += row_strings[len(row_strings) - row_index - 1] + '\n'
self_string = ' ' * (self.index_of(0) - numbers[0])
self_string_end = self.index_of(0) - numbers[0]
for index in self.all_indices():
local_position = index - numbers[0]
self_string += ' ' * (local_position - self_string_end)
self_string += '|'
self_string_end = local_position + 1
output += self_string + '\n'
other_string = ' ' * (other.index_of(0) - numbers[0])
other_string_end = other.index_of(0) - numbers[0]
for index in other.all_indices():
local_position = index - numbers[0]
other_string += ' ' * (local_position - other_string_end)
other_string += '|'
other_string_end = local_position + 1
output += other_string + '\n'
return output
# a dynamic defined by the length of each time step # a dynamic defined by the length of each time step
class TrivialDynamic(Dynamic): class TrivialDynamic(Dynamic):
# d_step: the length all time_steps # d_step: the length all time_steps
def __init__(self, d_steps): def __init__(self, d_steps, global_dynamic):
self.d_steps = d_steps self.d_steps = d_steps
self.global_dynamic = global_dynamic
def root(self): def root(self):
return self return self
...@@ -134,6 +286,9 @@ class TrivialDynamic(Dynamic): ...@@ -134,6 +286,9 @@ class TrivialDynamic(Dynamic):
def time_steps(self): def time_steps(self):
return range(len(self.d_steps)) return range(len(self.d_steps))
def all_indices(self):
return range(len(self.d_steps) + 1)
def has_index(self, index): def has_index(self, index):
return 0 <= index and index <= len(self.d_steps) return 0 <= index and index <= len(self.d_steps)
...@@ -159,25 +314,26 @@ class TrivialDynamic(Dynamic): ...@@ -159,25 +314,26 @@ class TrivialDynamic(Dynamic):
return self.d_steps return self.d_steps
def sub_dynamic_p(self, positions): def sub_dynamic_p(self, positions):
return BackedDynamic(self, positions) return self.global_dynamic.sub_dynamic(self, positions)
def sub_dynamic(self, indices): def sub_dynamic(self, indices):
return BackedDynamic(self, indices) return self.global_dynamic.sub_dynamic(self, indices)
def partial_dynamic_p(self, p_start, p_end): def partial_dynamic_p(self, p_start, p_end):
return PartialDynamic(self, p_start, p_end) return self.global_dynamic.partial_dynamic(self, p_start, p_end)
def partial_dynamic(self, i_start, i_end): def partial_dynamic(self, i_start, i_end):
return PartialDynamic(self, i_start, i_end) return self.global_dynamic.partial_dynamic(self, i_start, i_end)
# a dynamic definied by taking certain time steps form a reference dynamic # a dynamic definied by taking certain time steps form a reference dynamic
class BackedDynamic(Dynamic): class BackedDynamic(Dynamic):
# reference: the dynamic that backs this dynamic # reference: the dynamic that backs this dynamic
# indices: the indicies of the time steps contained in this dynamic with the last index representing the end of the last time step # indices: the indicies of the time steps contained in this dynamic with the last index representing the end of the last time step
# indices are relative to the reference dynamic # indices are relative to the reference dynamic
def __init__(self, reference, indices): def __init__(self, reference, indices, global_dynamic):
self.reference = reference self.reference = reference
self.indices = indices self.indices = indices
self.global_dynamic = global_dynamic
def root(self): def root(self):
return self.reference.root() return self.reference.root()
...@@ -191,6 +347,9 @@ class BackedDynamic(Dynamic): ...@@ -191,6 +347,9 @@ class BackedDynamic(Dynamic):
def time_steps(self): def time_steps(self):
return self.indices[:-1] return self.indices[:-1]
def all_indices(self):
return self.indices
def has_index(self, index): def has_index(self, index):
return index in self.indices return index in self.indices
...@@ -230,22 +389,22 @@ class BackedDynamic(Dynamic): ...@@ -230,22 +389,22 @@ class BackedDynamic(Dynamic):
def sub_dynamic_p(self, positions): def sub_dynamic_p(self, positions):
if any(position < 0 or len(self.indices) <= position for position in positions): if any(position < 0 or len(self.indices) <= position for position in positions):
raise IndexError("The dynamic does not have all requested indices!") raise IndexError("The dynamic does not have all requested indices!")
return BackedDynamic(self.reference, [self.indices[position] for position in positions]) return self.global_dynamic.sub_dynamic(self, [self.indices[position] for position in positions])
def sub_dynamic(self, indices): def sub_dynamic(self, indices):
if any(index not in self.indices for index in indices): if any(index not in self.indices for index in indices):
raise IndexError("The dynamic does not have all requested indices for the sub dynamic!") raise IndexError("The dynamic does not have all requested indices for the sub dynamic!")
return BackedDynamic(self.reference, indices) return self.global_dynamic.sub_dynamic(self, indices)
def partial_dynamic_p(self, p_start, p_end): def partial_dynamic_p(self, p_start, p_end):
if p_start < 0 or len(self.indices) <= p_start or p_end < 0 or len(self.indices) <= p_end: if p_start < 0 or len(self.indices) <= p_start or p_end < 0 or len(self.indices) <= p_end:
raise IndexError("The dynamic does not have all requested positions for the sub dynamic!") raise IndexError("The dynamic does not have all requested positions for the sub dynamic!")
return PartialDynamic(self, p_start, p_end) return self.global_dynamic.partial_dynamic(self, p_start, p_end)
def partial_dynamic(self, i_start, i_end): def partial_dynamic(self, i_start, i_end):
if i_start not in self.indices or i_end not in self.indices: if i_start not in self.indices or i_end not in self.indices:
raise IndexError("The dynamic does not have all requested indices for the sub dynamic!") raise IndexError("The dynamic does not have all requested indices for the sub dynamic!")
return PartialDynamic(self, self.indices.index(i_start), self.indices.index(i_end)) return self.global_dynamic.partial_dynamic(self, self.indices.index(i_start), self.indices.index(i_end))
# a dynamic defined by taking a continuus intervall of time steps from a reference dynamic # a dynamic defined by taking a continuus intervall of time steps from a reference dynamic
class PartialDynamic(Dynamic): class PartialDynamic(Dynamic):
...@@ -253,10 +412,11 @@ class PartialDynamic(Dynamic): ...@@ -253,10 +412,11 @@ class PartialDynamic(Dynamic):
# start: the position in the reference dynamic of the first time step contained in this dynamic # start: the position in the reference dynamic of the first time step contained in this dynamic
# end: the position in the reference dynamic of the end of the last time step contained in this dynamic # end: the position in the reference dynamic of the end of the last time step contained in this dynamic
# start/end are relative to the reference dynamic # start/end are relative to the reference dynamic
def __init__(self, reference, start, end): def __init__(self, reference, start, end, global_dynamic):
self.reference = reference self.reference = reference
self.start = start self.start = start
self.end = end self.end = end
self.global_dynamic = global_dynamic
def root(self): def root(self):
return self.reference.root() return self.reference.root()
...@@ -270,6 +430,9 @@ class PartialDynamic(Dynamic): ...@@ -270,6 +430,9 @@ class PartialDynamic(Dynamic):
def time_steps(self): def time_steps(self):
return self.reference.time_steps()[self.start:self.end] return self.reference.time_steps()[self.start:self.end]
def all_indices(self):
return self.reference.all_indices()[self.start:self.end + 1]
def has_index(self, index): def has_index(self, index):
if self.reference.has_index(index): if self.reference.has_index(index):
reference_position = self.reference.position_of(index) reference_position = self.reference.position_of(index)
...@@ -316,7 +479,7 @@ class PartialDynamic(Dynamic): ...@@ -316,7 +479,7 @@ class PartialDynamic(Dynamic):
def sub_dynamic_p(self, positions): def sub_dynamic_p(self, positions):
if any(position < 0 or self.end - self.start < position for position in positions): if any(position < 0 or self.end - self.start < position for position in positions):
raise IndexError("The dynamic does not have all requested positions for the sub dynamic!") raise IndexError("The dynamic does not have all requested positions for the sub dynamic!")
return self.reference.sub_dynamic_p([self.start + position for position in positions]) return self.global_dynamic.sub_dynamic(self, [self.index_of(position) for position in positions])
def sub_dynamic(self, indices): def sub_dynamic(self, indices):
def filter(index): def filter(index):
...@@ -324,19 +487,19 @@ class PartialDynamic(Dynamic): ...@@ -324,19 +487,19 @@ class PartialDynamic(Dynamic):
return reference_position < self.start or self.end < reference_position return reference_position < self.start or self.end < reference_position
if any(filter(index) for index in indices): if any(filter(index) for index in indices):
raise IndexError("The does not have all requested indices for the sub dynamic!") raise IndexError("The does not have all requested indices for the sub dynamic!")
return self.reference.sub_dynamic(indices) return self.global_dynamic.sub_dynamic(self, indices)
def partial_dynamic_p(self, p_start, p_end): def partial_dynamic_p(self, p_start, p_end):
if p_start < 0 or self.end - self.start < p_start or p_end < 0 or self.end - self.start < p_end: if p_start < 0 or self.end - self.start < p_start or p_end < 0 or self.end - self.start < p_end:
raise IndexError("The dynamic does not have all requested positions for the sub dynamic!") raise IndexError("The dynamic does not have all requested positions for the sub dynamic!")
return PartialDynamic(self.reference, self.start + p_start, self.start + p_end) return self.global_dynamic.partial_dynamic(self, p_start, p_end)
def partial_dynamic(self, i_start, i_end): def partial_dynamic(self, i_start, i_end):
reference_start = self.reference.position_of(i_start) reference_start = self.reference.position_of(i_start)
reference_end = self.reference.position_of(i_end) reference_end = self.reference.position_of(i_end)
if reference_start < self.start or self.end < reference_start or reference_end < self.start or self.end < reference_end: if reference_start < self.start or self.end < reference_start or reference_end < self.start or self.end < reference_end:
raise IndexError("The dynamic does not have all requested indices for the sub dynamic!") raise IndexError("The dynamic does not have all requested indices for the sub dynamic!")
return PartialDynamic(self.reference, reference_start, reference_end) return self.global_dynamic.partial_dynamic(self, self.position_of(i_start), self.position_of(i_end))
# only works if both dynamics share the same root dynamic # only works if both dynamics share the same root dynamic
def resample(values, dynamic, target_dynamic): def resample(values, dynamic, target_dynamic):
...@@ -702,28 +865,39 @@ def test_single_resampling(dynamic, target_dynamic): ...@@ -702,28 +865,39 @@ def test_single_resampling(dynamic, target_dynamic):
print('hey') print('hey')
def test_resampling(): def test_resampling():
dynamics = {} import random
dynamics['d'] = TrivialDynamic([1 for i in range(36)]) random.seed(0)
dynamics['d_1'] = PartialDynamic(dynamics['d'], 0, 36) global_dynamic = GlobalDynamic([1 for i in range(100)])
dynamics['d_2'] = PartialDynamic(dynamics['d'], 1, 35) dynamics = []
dynamics['d_3'] = BackedDynamic(dynamics['d'], [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36]) dynamics.append(global_dynamic.root())
dynamics['d_3_1'] = PartialDynamic(dynamics['d_3'], 0, 18) for i in range(100):
dynamics['d_3_2'] = PartialDynamic(dynamics['d_3'], 1, 17) dynamic_number = random.randint(0, len(dynamics) - 1)
dynamics['d_3_3'] = BackedDynamic(dynamics['d_3'], [0, 4, 8, 12, 16, 20, 24, 28, 32, 36]) dynamic = dynamics[dynamic_number]
dynamics['d_3_3_1'] = PartialDynamic(dynamics['d_3_3'], 0, 9) if random.random() < 0.75:
dynamics['d_3_3_2'] = PartialDynamic(dynamics['d_3_3'], 1, 8) original_indices = list(dynamic.all_indices())
dynamics['d_3_4'] = BackedDynamic(dynamics['d_3'], [2, 6, 10, 14, 18, 22, 26, 30, 34]) number = random.randint(2, len(original_indices))
dynamics['d_3_4_1'] = PartialDynamic(dynamics['d_3_4'], 0, 8) indices = []
dynamics['d_3_4_2'] = PartialDynamic(dynamics['d_3_4'], 1, 7) for i in range(number):
dynamics['d_4'] = BackedDynamic(dynamics['d'], [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33]) choice = random.choice(original_indices)
dynamics['d_4_1'] = PartialDynamic(dynamics['d_4'], 0, 10) original_indices.remove(choice)
dynamics['d_4_2'] = PartialDynamic(dynamics['d_4'], 1, 9) indices.append(choice)
dynamics['d_4_3'] = BackedDynamic(dynamics['d_4'], [3, 9, 15, 21, 27, 33]) indices.sort()
dynamics['d_4_3_1'] = PartialDynamic(dynamics['d_4_3'], 0, 5) sub_dynamic = dynamic.sub_dynamic(indices)
dynamics['d_4_3_2'] = PartialDynamic(dynamics['d_4_3'], 1, 4) if sub_dynamic not in dynamics:
dynamics['d_4_4'] = BackedDynamic(dynamics['d_4'], [6, 12, 18, 24, 30]) dynamics.append(sub_dynamic)
dynamics['d_4_4_1'] = PartialDynamic(dynamics['d_4_4'], 0, 4) else:
dynamics['d_4_4_2'] = PartialDynamic(dynamics['d_4_4'], 1, 3) original_positions = list(range(dynamic.number_of_steps() + 1))
dynamics['d_5'] = BackedDynamic(dynamics['d'], [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36]) positions = []
for i in range(2):
test_single_resampling(dynamics['d'], dynamics['d']) choice = random.choice(original_positions)
original_positions.remove(choice)
positions.append(choice)
positions.sort()
p_start = positions[0]
p_end = positions[1]
partial_dynamic = dynamic.partial_dynamic_p(p_start, p_end)
if partial_dynamic not in dynamics:
dynamics.append(partial_dynamic)
print(global_dynamic.display(), end='')
test_single_resampling(dynamics[0], dynamics[0])
print(dynamics[0].display_alignment(dynamics[0]), end='')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment