-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBlockIteration_old.py
145 lines (120 loc) · 5.17 KB
/
BlockIteration_old.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import sympy as sy
from ModuleBlockOperators import BlockOperators
from ModulePintGraph import PintGraph
from ModuleErrorEstimator import convergenceEstimator
class Task(object):
def __init__(self, op, res):
self.op = op # Operation (sympy expression)
self.res = res # Result (what is computed by this task)
self.dep = self.find_dependencies() # Find dependencies based on op
# Set a name (only for visualization)
if len(op.args) > 0:
self.name = op.args[0]
else:
self.name = 'unknown'
self.cost = 1 # TODO Make this depend on the task
def find_dependencies(self):
"""
Gets the dependencies from the operation (expects dependencies to start with u)
:return: dependencies
"""
return [item for item in self.op.atoms() if (isinstance(item, sy.Symbol) and item.name.startswith('u'))]
class NameGenerator(object):
def __init__(self, prefix):
self.prefix = prefix
self.counter = 0
def get(self):
if self.counter > 0:
name = sy.symbols(f'{self.prefix}_{self.counter}', commutative=False)
else:
name = sy.symbols(f'{self.prefix}', commutative=False)
self.counter += 1
return name
class BlockIteration():
def __init__(self):
self.taskPool = {}
self.null = 0 * sy.symbols('null', commutative=False)
self.nBlock = 3 # TODO: Do we want to optimize this internally? Or is this a parameter?
# Block operator should be an independent module
self.blockOp = BlockOperators(variant='parareal')
self.blockOperators = self.blockOp.getBlockOperator()
self.f, self.g, self.r, self.p = sy.symbols('f,g, r,p', commutative=False) # TODO: Get this from the module
# The convergence estimator should be an independent module
self.kMax = convergenceEstimator(nBlocks=self.nBlock)
# Graph module
self.pintGraph = PintGraph()
# Run algorithm
# The algo frame is the same for each algorithm variant. The block operator module should define the variation
self.algo()
self.pintGraph.generateGraphFromPool(pool=self.taskPool)
# self.pintGraph.simplify_graph()
self.pintGraph.plotGraph()
self.pintGraph.computeOptimalSchedule(plot=True)
def node(self, n, k):
if k > self.kMax[n]:
return sy.symbols(f'u_{n}^{self.kMax[n]}', commutative=False)
else:
return sy.symbols(f'u_{n}^{k}', commutative=False)
def extractTasks(self, op, res):
node = op
tName = NameGenerator(res)
localTaskPool = {}
def getTasks(node):
if node.func in [sy.Add, sy.Mul]:
name = tName.get()
# Get operation and dependencies
if node.func == sy.Add:
op = '+'
elif node.func == sy.Mul:
op = 'o'
ta = [getTasks(n) for n in node.args]
# Some fix to merge the -1 into one given tasks
if isinstance(ta[0], sy.core.numbers.NegativeOne):
merged = ta[1]
ta = [merged] + ta[2:]
if op == 'o':
cou = 1
tmp = sy.symbols(name.name + f'_{cou}', commutative=False)
while len(ta) > 2:
op_tmp = ta[-2:]
localTaskPool[tmp] = {'op': op, 'task': ta[-2:]}
ta = ta[:-2]
ta.append(tmp)
cou += 1
tmp = sy.symbols(name.name + f'_{cou}', commutative=False)
# Store task in dictionary
localTaskPool[name] = {'op': op, 'task': ta}
else:
name = node
return name
getTasks(node)
return localTaskPool
def taskGenerator(self, op, res):
localTaskPool = self.extractTasks(op=op, res=res)
for key, value in localTaskPool.items():
# Rebuild task
expr = value['task'][0]
for i in range(1, len(value['task'])):
if value['op'] == 'o':
expr *= value['task'][i]
elif value['op'] == '+':
expr += value['task'][i]
self.taskPool[key] = Task(op=expr, res=key)
def buildNextNode(self, n, k):
if k < self.kMax[n + 1]:
newSol = self.null
for op in self.blockOperators:
nMod, kMod = op['dep']
newSol += op['sym'] * self.node(n + 1 + nMod, k + 1 + kMod)
newSol.simplify()
res = self.node(n + 1, k + 1)
self.taskGenerator(op=newSol, res=res)
def algo(self):
self.taskPool[self.node(0, 0)] = Task(op=sy.symbols(f'u_{0}', commutative=False), res=self.node(0, 0))
for n in range(self.nBlock):
self.taskPool[self.node(n + 1, 0)] = Task(op=self.g * self.node(n, 0), res=self.node(n + 1, 0))
for k in range(max(self.kMax)):
for n in range(self.nBlock):
self.buildNextNode(n, k)
if __name__ == '__main__':
BlockIteration()