def _update(self, clique_data, parent=None): for c in clique_data['cliques']: self.cliques[c['name']] = v = self.model.variable( c['name'], Domain.inRange(0.0, 1.0), Domain.isInteger() ) for img, cmd in product(c['images'], c['commands']): self.by_img_cmd[img,cmd].append(v) self._obj.append(Expr.mul(float(c['time']), v)) if parent is not None: self.model.constraint( 'c-%s-%s' % (c['name'], parent['name']), Expr.sub(v, self.cliques[parent['name']]), Domain.lessThan(0.0) ) for child in c['children']: self._update(child, c) for inter in clique_data['intersections']: self.model.constraint( 'iter-%d' % self._inter, Expr.add([self.cliques[i] for i in inter]), Domain.lessThan(1.0) ) self._inter += 1
def solve(self, problem, saver): # Construct model. self.problem = problem # Do recursive maximal clique detection. self.clique_data = clique_data = problem.cliques() self.model = model = Model() if self.time is not None: model.setSolverParam('mioMaxTime', 60.0 * int(self.time)) # Each image needs to run all its commands. This keep track of # what variables run each command for each image. self.by_img_cmd = by_img_cmd = defaultdict(list) # Objective is the total cost of all the commands we run. self._obj = [] # x[i,c] = 1 if image i incurs the cost of command c directly self.x = x = {} for img, cmds in problem.images.items(): for cmd in cmds: name = 'x[%s,%s]' % (img, cmd) x[name] = v = self.model.variable( name, Domain.inRange(0.0, 1.0), Domain.isInteger() ) self._obj.append(Expr.mul(float(problem.commands[cmd]), v)) by_img_cmd[img,cmd].append(v) # cliques[i] = 1 if clique i is used, 0 otherwise self.cliques = {} self._inter = 1 self._update(clique_data) # Each image has to run each of its commands. for img_cmd, vlist in by_img_cmd.items(): name = 'img-cmd-%s-%s' % img_cmd self.model.constraint( name, Expr.add(vlist), Domain.equalsTo(1.0) ) model.objective('z', ObjectiveSense.Minimize, Expr.add(self._obj)) model.setLogHandler(sys.stdout) model.acceptedSolutionStatus(AccSolutionStatus.Feasible) model.solve() # Translate the output of this to a schedule. schedule = defaultdict(list) self._translate(schedule, clique_data) for name, v in x.items(): img, cmd = name.replace('x[','').replace(']','').split(',') if v.level()[0] > 0.5: schedule[img].append(cmd) saver(schedule)
def solve(self, problem, saver): # Construct model. self.problem = problem # Do recursive maximal clique detection. self.clique_data = clique_data = problem.cliques() self.model = model = Model() if self.time is not None: model.setSolverParam('mioMaxTime', 60.0 * int(self.time)) # Each image needs to run all its commands. This keep track of # what variables run each command for each image. self.by_img_cmd = by_img_cmd = defaultdict(list) # Objective is the total cost of all the commands we run. self._obj = [] # x[i,c] = 1 if image i incurs the cost of command c directly self.x = x = {} for img, cmds in problem.images.items(): for cmd in cmds: name = 'x[%s,%s]' % (img, cmd) x[name] = v = self.model.variable(name, Domain.inRange(0.0, 1.0), Domain.isInteger()) self._obj.append(Expr.mul(float(problem.commands[cmd]), v)) by_img_cmd[img, cmd].append(v) # cliques[i] = 1 if clique i is used, 0 otherwise self.cliques = {} self._inter = 1 self._update(clique_data) # Each image has to run each of its commands. for img_cmd, vlist in by_img_cmd.items(): name = 'img-cmd-%s-%s' % img_cmd self.model.constraint(name, Expr.add(vlist), Domain.equalsTo(1.0)) model.objective('z', ObjectiveSense.Minimize, Expr.add(self._obj)) model.setLogHandler(sys.stdout) model.acceptedSolutionStatus(AccSolutionStatus.Feasible) model.solve() # Translate the output of this to a schedule. schedule = defaultdict(list) self._translate(schedule, clique_data) for name, v in x.items(): img, cmd = name.replace('x[', '').replace(']', '').split(',') if v.level()[0] > 0.5: schedule[img].append(cmd) saver(schedule)
def _update(self, clique_data, parent=None): for c in clique_data['cliques']: self.cliques[c['name']] = v = self.model.variable( c['name'], Domain.inRange(0.0, 1.0), Domain.isInteger()) for img, cmd in product(c['images'], c['commands']): self.by_img_cmd[img, cmd].append(v) self._obj.append(Expr.mul(float(c['time']), v)) if parent is not None: self.model.constraint( 'c-%s-%s' % (c['name'], parent['name']), Expr.sub(v, self.cliques[parent['name']]), Domain.lessThan(0.0)) for child in c['children']: self._update(child, c) for inter in clique_data['intersections']: self.model.constraint('iter-%d' % self._inter, Expr.add([self.cliques[i] for i in inter]), Domain.lessThan(1.0)) self._inter += 1
# # Image 2: # x_2_a = 1 # x_2_b = 1 # x_2_c = 1 # x_2_d = 1 # # Image 3: # x_3_b = 1 # x_3_c = 1 # x_3_d = 1 r = {'A': 5.0, 'B': 10.0, 'C': 7.0, 'D': 12.0} m = Model() binary = (Domain.inRange(0.0, 1.0), Domain.isInteger()) # Provide a variable for each image and command. This is 1 if the command # is not run as part of a clique for the image. x_1_a = m.variable('x_1_a', *binary) x_1_b = m.variable('x_1_b', *binary) x_2_a = m.variable('x_2_a', *binary) x_2_b = m.variable('x_2_b', *binary) x_2_c = m.variable('x_2_c', *binary) x_2_d = m.variable('x_2_d', *binary) x_3_b = m.variable('x_3_b', *binary) x_3_c = m.variable('x_3_c', *binary) x_3_d = m.variable('x_3_d', *binary)
# # Images: # w_1 = 0 # w_2 = 1 # w_3 = 1 # # Commands: # y_a = 0 # y_b = 1 # y_c = 1 # y_d = 1 r = {'A': 5.0, 'B': 10.0, 'C': 7.0, 'D': 12.0} m = Model() binary = (Domain.inRange(0.0, 1.0), Domain.isInteger()) # Variables to determine if we include commands in the clique. y_a = m.variable('y_a', *binary) y_b = m.variable('y_b', *binary) y_c = m.variable('y_c', *binary) y_d = m.variable('y_d', *binary) # Variables to determine if we include images in the clique. w_1 = m.variable('w_1', *binary) w_2 = m.variable('w_2', *binary) w_3 = m.variable('w_3', *binary) # Variables to enforce relationships between y and w decisions. z_1_a = m.variable('z_1_a', *binary) z_1_b = m.variable('z_1_b', *binary)
def solve(self, problem, saver): # Construct model. self.problem = problem self.model = model = Model() if self.time is not None: model.setSolverParam('mioMaxTime', 60.0 * int(self.time)) # x[1,c] = 1 if the master schedule has (null, c) in its first stage # x[s,c1,c2] = 1 if the master schedule has (c1, c2) in stage s > 1 x = {} for s in problem.all_stages: if s == 1: # First arc in the individual image path. for c in problem.commands: x[1, c] = model.variable('x[1,%s]' % c, 1, Domain.inRange(0.0, 1.0), Domain.isInteger()) else: # Other arcs. for c1, c2 in product(problem.commands, problem.commands): if c1 == c2: continue x[s, c1, c2] = model.variable('x[%s,%s,%s]' % (s, c1, c2), 1, Domain.inRange(0.0, 1.0), Domain.isInteger()) smax = max(problem.all_stages) obj = [0.0] # TODO: deal with images that do not have the same number of commands. # t[s,c] is the total time incurred at command c in stage s t = {} for s in problem.all_stages: for c in problem.commands: t[s, c] = model.variable('t[%s,%s]' % (c, s), 1, Domain.greaterThan(0.0)) if s == 1: model.constraint( 't[1,%s]' % c, Expr.sub(t[1, c], Expr.mul(float(problem.commands[c]), x[1, c])), Domain.greaterThan(0.0)) else: rhs = [0.0] for c1, coeff in problem.commands.items(): if c1 == c: continue else: rhs = Expr.add( rhs, Expr.mulElm(t[s - 1, c1], x[s, c1, c])) model.constraint('t[%s,%s]' % (s, c), Expr.sub(t[1, c], rhs), Domain.greaterThan(0.0)) # Objective function = sum of aggregate comand times if s == smax: obj = Expr.add(obj, t[s, c]) # y[i,1,c] = 1 if image i starts by going to c # y[i,s,c1,c2] = 1 if image i goes from command c1 to c2 in stage s > 1 y = {} for i, cmds in problem.images.items(): for s in problem.stages[i]: if s == 1: # First arc in the individual image path. for c in cmds: y[i, 1, c] = model.variable('y[%s,1,%s]' % (i, c), 1, Domain.inRange(0.0, 1.0), Domain.isInteger()) model.constraint('x_y[i%s,1,c%s]' % (i, c), Expr.sub(x[1, c], y[i, 1, c]), Domain.greaterThan(0.0)) else: # Other arcs. for c1, c2 in product(cmds, cmds): if c1 == c2: continue y[i, s, c1, c2] = model.variable( 'y[%s,%s,%s,%s]' % (i, s, c1, c2), 1, Domain.inRange(0.0, 1.0), Domain.isInteger()) model.constraint( 'x_y[i%s,s%s,c%s,c%s]' % (i, s, c1, c2), Expr.sub(x[s, c1, c2], y[i, s, c1, c2]), Domain.greaterThan(0.0)) for c in cmds: # Each command is an arc destination exactly once. arcs = [y[i, 1, c]] for c1 in cmds: if c1 == c: continue arcs.extend( [y[i, s, c1, c] for s in problem.stages[i][1:]]) model.constraint('y[i%s,c%s]' % (i, c), Expr.add(arcs), Domain.equalsTo(1.0)) # Network balance equations (stages 2 to |stages|-1). # Sum of arcs in = sum of arcs out. for s in problem.stages[i][:len(problem.stages[i]) - 1]: if s == 1: arcs_in = [y[i, 1, c]] else: arcs_in = [y[i, s, c1, c] for c1 in cmds if c1 != c] arcs_out = [y[i, s + 1, c, c2] for c2 in cmds if c2 != c] model.constraint( 'y[i%s,s%s,c%s]' % (i, s, c), Expr.sub(Expr.add(arcs_in), Expr.add(arcs_out)), Domain.equalsTo(0.0)) model.objective('z', ObjectiveSense.Minimize, Expr.add(x.values())) # model.objective('z', ObjectiveSense.Minimize, obj) model.setLogHandler(sys.stdout) model.acceptedSolutionStatus(AccSolutionStatus.Feasible) model.solve() # Create optimal schedule. schedule = defaultdict(list) for i, cmds in problem.images.items(): for s in problem.stages[i]: if s == 1: # First stage starts our walk. for c in cmds: if y[i, s, c].level()[0] > 0.5: schedule[i].append(c) break else: # After that we know what our starting point is. for c2 in cmds: if c2 == c: continue if y[i, s, c, c2].level()[0] > 0.5: schedule[i].append(c2) c = c2 break saver(schedule)
def solve(self, problem, saver): # Construct model. self.problem = problem self.model = model = Model() if self.time is not None: model.setSolverParam('mioMaxTime', 60.0 * int(self.time)) # x[1,c] = 1 if the master schedule has (null, c) in its first stage # x[s,c1,c2] = 1 if the master schedule has (c1, c2) in stage s > 1 x = {} for s in problem.all_stages: if s == 1: # First arc in the individual image path. for c in problem.commands: x[1,c] = model.variable( 'x[1,%s]' % c, 1, Domain.inRange(0.0, 1.0), Domain.isInteger() ) else: # Other arcs. for c1, c2 in product(problem.commands, problem.commands): if c1 == c2: continue x[s,c1,c2] = model.variable( 'x[%s,%s,%s]' % (s,c1,c2), 1, Domain.inRange(0.0, 1.0), Domain.isInteger() ) smax = max(problem.all_stages) obj = [0.0] # TODO: deal with images that do not have the same number of commands. # t[s,c] is the total time incurred at command c in stage s t = {} for s in problem.all_stages: for c in problem.commands: t[s,c] = model.variable( 't[%s,%s]' % (c,s), 1, Domain.greaterThan(0.0) ) if s == 1: model.constraint('t[1,%s]' % c, Expr.sub(t[1,c], Expr.mul(float(problem.commands[c]), x[1,c])), Domain.greaterThan(0.0) ) else: rhs = [0.0] for c1, coeff in problem.commands.items(): if c1 == c: continue else: rhs = Expr.add(rhs, Expr.mulElm(t[s-1,c1], x[s,c1,c])) model.constraint('t[%s,%s]' % (s,c), Expr.sub(t[1,c], rhs), Domain.greaterThan(0.0) ) # Objective function = sum of aggregate comand times if s == smax: obj = Expr.add(obj, t[s,c]) # y[i,1,c] = 1 if image i starts by going to c # y[i,s,c1,c2] = 1 if image i goes from command c1 to c2 in stage s > 1 y = {} for i, cmds in problem.images.items(): for s in problem.stages[i]: if s == 1: # First arc in the individual image path. for c in cmds: y[i,1,c] = model.variable( 'y[%s,1,%s]' % (i,c), 1, Domain.inRange(0.0, 1.0), Domain.isInteger() ) model.constraint('x_y[i%s,1,c%s]' % (i,c), Expr.sub(x[1,c], y[i,1,c]), Domain.greaterThan(0.0) ) else: # Other arcs. for c1, c2 in product(cmds, cmds): if c1 == c2: continue y[i,s,c1,c2] = model.variable( 'y[%s,%s,%s,%s]' % (i,s,c1,c2), 1, Domain.inRange(0.0, 1.0), Domain.isInteger() ) model.constraint('x_y[i%s,s%s,c%s,c%s]' % (i,s,c1,c2), Expr.sub(x[s,c1,c2], y[i,s,c1,c2]), Domain.greaterThan(0.0) ) for c in cmds: # Each command is an arc destination exactly once. arcs = [y[i,1,c]] for c1 in cmds: if c1 == c: continue arcs.extend([y[i,s,c1,c] for s in problem.stages[i][1:]]) model.constraint('y[i%s,c%s]' % (i,c), Expr.add(arcs), Domain.equalsTo(1.0) ) # Network balance equations (stages 2 to |stages|-1). # Sum of arcs in = sum of arcs out. for s in problem.stages[i][:len(problem.stages[i])-1]: if s == 1: arcs_in = [y[i,1,c]] else: arcs_in = [y[i,s,c1,c] for c1 in cmds if c1 != c] arcs_out = [y[i,s+1,c,c2] for c2 in cmds if c2 != c] model.constraint('y[i%s,s%s,c%s]' % (i,s,c), Expr.sub(Expr.add(arcs_in), Expr.add(arcs_out)), Domain.equalsTo(0.0) ) model.objective('z', ObjectiveSense.Minimize, Expr.add(x.values())) # model.objective('z', ObjectiveSense.Minimize, obj) model.setLogHandler(sys.stdout) model.acceptedSolutionStatus(AccSolutionStatus.Feasible) model.solve() # Create optimal schedule. schedule = defaultdict(list) for i, cmds in problem.images.items(): for s in problem.stages[i]: if s == 1: # First stage starts our walk. for c in cmds: if y[i,s,c].level()[0] > 0.5: schedule[i].append(c) break else: # After that we know what our starting point is. for c2 in cmds: if c2 == c: continue if y[i,s,c,c2].level()[0] > 0.5: schedule[i].append(c2) c = c2 break saver(schedule)
def solve(self, problem, saver): # Construct model. self.problem = problem self.model = model = Model() if self.time is not None: model.setSolverParam('mioMaxTime', 60.0 * int(self.time)) # x[i,s,c] = 1 if image i runs command c during stage s, 0 otherwise. self.x = x = {} for i, cmds in problem.images.items(): for s, c in product(problem.stages[i], cmds): x[i,s,c] = model.variable( 'x[%s,%s,%s]' % (i,s,c), 1, Domain.inRange(0.0, 1.0), Domain.isInteger() ) # y[ip,iq,s,c] = 1 if images ip & iq have a shared path through stage # s by running command c during s, 0 otherwise. y = {} for (ip, iq), cmds in problem.shared_cmds.items(): for s, c in product(problem.shared_stages[ip, iq], cmds): y[ip,iq,s,c] = model.variable( 'y[%s,%s,%s,%s]' % (ip,iq,s,c), 1, Domain.inRange(0.0, 1.0), Domain.isInteger() # Domain.inRange(0.0, 1.0) ) # TODO: need to remove presolved commands so the heuristic doesn't try them. # TODO: Add a heuristic initial solution. # TODO: Presolving # Each image one command per stage, and each command once. for i in problem.images: for s in problem.stages[i]: model.constraint('c1[%s,%s]' % (i,s), Expr.add([x[i,s,c] for c in problem.images[i]]), Domain.equalsTo(1.0) ) for c in problem.images[i]: model.constraint('c2[%s,%s]' % (i,c), Expr.add([x[i,s,c] for s in problem.stages[i]]), Domain.equalsTo(1.0) ) # Find shared paths among image pairs. for (ip, iq), cmds in problem.shared_cmds.items(): for s in problem.shared_stages[ip,iq]: for c in cmds: model.constraint('c3[%s,%s,%s,%s]' % (ip,iq,s,c), Expr.sub(y[ip,iq,s,c], x[ip,s,c]), Domain.lessThan(0.0) ) model.constraint('c4[%s,%s,%s,%s]' % (ip,iq,s,c), Expr.sub(y[ip,iq,s,c], x[iq,s,c]), Domain.lessThan(0.0) ) if s > 1: lhs = Expr.add([y[ip,iq,s,c] for c in cmds]) rhs = Expr.add([y[ip,iq,s-1,c] for c in cmds]) model.constraint('c5[%s,%s,%s,%s]' % (ip,iq,s,c), Expr.sub(lhs, rhs), Domain.lessThan(0.0) ) if y: obj = Expr.add(y.values()) else: obj = 0.0 model.objective('z', ObjectiveSense.Maximize, obj) model.setLogHandler(sys.stdout) model.acceptedSolutionStatus(AccSolutionStatus.Feasible) model.solve() # Create optimal schedule. schedule = defaultdict(list) for i, stages in problem.stages.items(): for s in stages: for c in problem.images[i]: if x[i,s,c].level()[0] > 0.5: schedule[i].append(c) break saver(schedule)