def solve_chen_greedy(g: DFGraph, segment_mem_B: int, use_actuation_points: bool = True): with Timer("solve_chen_greedy") as timer_solve: C = g.articulation_points if use_actuation_points else g.v temp = 0 x = 0 checkpoints = set() for v in g.topological_order_fwd: temp += g.cost_ram[v] if v in C and temp > segment_mem_B: x += g.cost_ram[v] temp = 0 checkpoints.add(v) S = gen_s_matrix_fixed_checkpoints(g, checkpoints) R = solve_r_opt(g, S) schedule, aux_data = schedule_from_rs(g, R, S) return ScheduledResult( solve_strategy=SolveStrategy.CHEN_GREEDY if use_actuation_points else SolveStrategy.CHEN_GREEDY_NOAP, solver_budget=segment_mem_B, feasible=True, schedule=schedule, schedule_aux_data=aux_data, solve_time_s=timer_solve.elapsed, )
def solve(self): T = self.g.size with self.profiler("Gurobi model optimization", extra_data={"T": str(T), "budget": str(self.budget)}): with Timer("ILPSolve") as solve_ilp: self.m.optimize() self.solve_time = solve_ilp.elapsed infeasible = self.m.status == GRB.INFEASIBLE try: _ = self.R[0, 0].X _ = self.S[0, 0].X _ = self.U[0, 0].X _ = self.batch_size.X except AttributeError as e: infeasible = True if infeasible: raise ValueError("Infeasible model, check constraints carefully. Insufficient memory?") Rout = np.zeros((T, T), dtype=SOLVER_DTYPE) Sout = np.zeros((T, T), dtype=SOLVER_DTYPE) Uout = np.zeros((T, T), dtype=SOLVER_DTYPE) Free_Eout = np.zeros((T, len(self.g.edge_list)), dtype=SOLVER_DTYPE) batch_size = self.batch_size.X try: for t in range(T): for i in range(T): Rout[t][i] = int(self.R[t, i].X) Sout[t][i] = int(self.S[t, i].X) Uout[t][i] = self.U[t, i].X * self.ram_gcd for e in range(len(self.g.edge_list)): Free_Eout[t][e] = int(self.Free_E[t, e].X) except AttributeError as e: logging.exception(e) return None, None, None, None Rout = solve_r_opt(self.g, Sout) # prune R using optimal recomputation solver ilp_aux_data = ILPAuxData( U=Uout, Free_E=Free_Eout, ilp_approx=False, ilp_time_limit=0, ilp_eps_noise=0, ilp_num_constraints=self.m.numConstrs, ilp_num_variables=self.m.numVars, ) schedule, aux_data = schedule_from_rs(self.g, Rout, Sout) return ( ScheduledResult( solve_strategy=SolveStrategy.OPTIMAL_ILP_GC, solver_budget=self.budget, feasible=True, schedule=schedule, schedule_aux_data=aux_data, solve_time_s=self.solve_time, ilp_aux_data=ilp_aux_data, ), batch_size, )
def solve_checkpoint_all(g: DFGraph): with Timer("solve_checkpoint_all") as timer_solve: s = gen_s_matrix_fixed_checkpoints(g, g.vfwd) r = solve_r_opt(g, s) schedule, aux_data = schedule_from_rs(g, r, s) return ScheduledResult( solve_strategy=SolveStrategy.CHECKPOINT_ALL, solver_budget=0, feasible=True, schedule=schedule, schedule_aux_data=aux_data, solve_time_s=timer_solve.elapsed, )
def solve_checkpoint_last_node(g: DFGraph): """Checkpoint only one node between stages""" with Timer("solve_checkpoint_last_node") as timer_solve: s = np.zeros((g.size, g.size), dtype=SOLVER_DTYPE) np.fill_diagonal(s[1:], 1) r = solve_r_opt(g, s) schedule, aux_data = schedule_from_rs(g, r, s) return ScheduledResult( solve_strategy=SolveStrategy.CHECKPOINT_LAST_NODE, solver_budget=0, feasible=True, schedule=schedule, schedule_aux_data=aux_data, solve_time_s=timer_solve.elapsed, )
def solve_chen_sqrtn(g: DFGraph, use_actuation_points: bool = True) -> ScheduledResult: with Timer("solve_chen_sqrtn") as timer_solve: C = g.articulation_points if use_actuation_points else g.v k = int(math.sqrt(len(C))) checkpoints = [v for idx, v in enumerate(C) if (idx + 1) % k == 0] S = gen_s_matrix_fixed_checkpoints(g, set(checkpoints)) R = solve_r_opt(g, S) schedule, aux_data = schedule_from_rs(g, R, S) return ScheduledResult( solve_strategy=SolveStrategy.CHEN_SQRTN if use_actuation_points else SolveStrategy.CHEN_SQRTN_NOAP, solver_budget=0, feasible=True, schedule=schedule, schedule_aux_data=aux_data, solve_time_s=timer_solve.elapsed, )
def solve_checkmate_cvxpy( g, budget, rounding_thresholds=(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9), solver_override=None, verbose=True ): lpsolver = ILPSolverCVXPY(g, int(0.9 * budget)) # rounding threshold try: r, s, u, free_e = lpsolver.solve(solver_override=solver_override, verbose=verbose) lp_feasible = True except ValueError as e: logging.exception(e) r, s, u, free_e = (None, None, None, None) lp_feasible = False schedule, aux_data, min_threshold = None, None, None if lp_feasible: # round the solution for threshold in rounding_thresholds: s_ = (s >= threshold).astype(np.int) r_ = solve_r_opt(g, s_) schedule_, aux_data_ = schedule_from_rs(g, r_, s_) if aux_data_.activation_ram <= budget and (aux_data is None or aux_data_.cpu <= aux_data.cpu): aux_data = aux_data_ schedule = schedule_ min_threshold = threshold solve_strategy = ( SolveStrategy.APPROX_DET_ROUND_LP_05_THRESH if len(rounding_thresholds) == 1 else SolveStrategy.APPROX_DET_ROUND_LP_SWEEP ) return ScheduledResult( solve_strategy=solve_strategy, solver_budget=budget, feasible=lp_feasible and aux_data is not None, schedule=schedule, schedule_aux_data=aux_data, solve_time_s=lpsolver.solve_time, ilp_aux_data=ILPAuxData( U=u, Free_E=free_e, ilp_approx=False, ilp_time_limit=None, ilp_eps_noise=0.0, ilp_num_constraints=lpsolver.num_vars, ilp_num_variables=lpsolver.num_constraints, approx_deterministic_round_threshold=min_threshold, ), )
def _solve_griewank_to_rs(g: DFGraph, budget: int): S = np.zeros((g.size, g.size), dtype=np.int32) S = setup_implied_s_backwards(g, S) np.fill_diagonal(S[1:], 1) ap_points = list(sorted(g.articulation_points)) metaTfwd = len(ap_points) ap_points = ap_points + [ g.forward_to_backward(p) for p in reversed(ap_points) ] meta_to_real_v = { ap_points.index(ap_point): ap_point for ap_point in ap_points } try: regranges_all = _load_griewank(metaTfwd) except Exception as e: logging.exception(e) return None, None if regranges_all is None: return None, None max_budget = max(regranges_all["budget"]) regranges = regranges_all[regranges_all["budget"] == min( budget, max_budget)] if len(regranges.index) < 1: return None, None def map_time(_t: int) -> int: return min(meta_to_real_v.get(_t, np.inf), g.size) for index, reg_range in regranges.iterrows(): for t in range(map_time(reg_range["timestart"]), map_time(reg_range["timeend"] + 1)): if reg_range["nodeid"] > 0: S[t, meta_to_real_v[reg_range["nodeid"]]] = 1 R = solve_r_opt(g, S) return R, S
def solve_approx_lp_deterministic_sweep( g: DFGraph, budget: int, seed_s: Optional[np.ndarray] = None, approx=True, time_limit: Optional[int] = None, write_log_file: Optional[PathLike] = None, print_to_console=True, write_model_file: Optional[PathLike] = None, eps_noise=0.01, solver_cores=os.cpu_count(), thresholds=(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9), imposed_schedule: ImposedSchedule = ImposedSchedule.FULL_SCHEDULE, allow_return_infeasible_schedule=False, ): param_dict = { "LogToConsole": 1 if print_to_console else 0, "LogFile": str(write_log_file) if write_log_file is not None else "", "Threads": solver_cores, "TimeLimit": math.inf if time_limit is None else time_limit, "OptimalityTol": 1e-2 if approx else 1e-4, "IntFeasTol": 1e-3 if approx else 1e-5, "Presolve": 2, "StartNodeLimit": 10000000, } lpsolver = ILPSolverGurobi( g, int(0.9 * budget), # hack to get values under the budget gurobi_params=param_dict, seed_s=seed_s, integral=False, solve_r=False, eps_noise=eps_noise, imposed_schedule=imposed_schedule, write_model_file=write_model_file, ) lpsolver.build_model() try: r, s, u, free_e = lpsolver.solve() lp_feasible = True except ValueError as e: logging.exception(e) r, s, u, free_e = (None, None, None, None) lp_feasible = False schedule, aux_data, min_threshold = None, None, None if lp_feasible: # round the solution for threshold in thresholds: s_ = (s >= threshold).astype(np.int) r_ = solve_r_opt(g, s_) schedule_, aux_data_ = schedule_from_rs(g, r_, s_) if (allow_return_infeasible_schedule and aux_data is None) or ( aux_data_.activation_ram <= budget and (aux_data is None or aux_data_.cpu <= aux_data.cpu)): aux_data = aux_data_ schedule = schedule_ min_threshold = threshold return ScheduledResult( solve_strategy=SolveStrategy.APPROX_DET_ROUND_LP_SWEEP, solver_budget=budget, feasible=lp_feasible and aux_data is not None, schedule=schedule, schedule_aux_data=aux_data, solve_time_s=lpsolver.solve_time, ilp_aux_data=ILPAuxData( U=u, Free_E=free_e, ilp_approx=approx, ilp_time_limit=time_limit, ilp_eps_noise=eps_noise, ilp_num_constraints=lpsolver.m.numConstrs, ilp_num_variables=lpsolver.m.numVars, approx_deterministic_round_threshold=min_threshold, ), )
def solve_approx_lp_randomized( g: DFGraph, budget: int, seed_s: Optional[np.ndarray] = None, approx=True, time_limit: Optional[int] = None, write_log_file: Optional[PathLike] = None, print_to_console=True, write_model_file: Optional[PathLike] = None, eps_noise=0.01, solver_cores=os.cpu_count(), num_rounds=100, return_rounds=False, ): """Randomized rounding of LP relaxation Args: g: budget: seed_s: approx: time_limit: write_log_file: print_to_console: write_model_file: eps_noise: solver_cores: num_rounds: return_rounds: If True, return tuple (ScheduledResult, rounding_statistics) """ param_dict = { "LogToConsole": 1 if print_to_console else 0, "LogFile": str(write_log_file) if write_log_file is not None else "", "Threads": solver_cores, "TimeLimit": math.inf if time_limit is None else time_limit, "OptimalityTol": 1e-2 if approx else 1e-4, "IntFeasTol": 1e-3 if approx else 1e-5, "Presolve": 2, "StartNodeLimit": 10000000, } lpsolver = ILPSolverGurobi( g, int(0.9 * budget), # hack to get values under the budget gurobi_params=param_dict, seed_s=seed_s, solve_r=False, integral=False, eps_noise=eps_noise, write_model_file=write_model_file, ) lpsolver.build_model() try: r, s, u, free_e = lpsolver.solve() lp_feasible = True except ValueError as e: logging.exception(e) r, s, u, free_e = (None, None, None, None) lp_feasible = False best_solution = (float("inf"), None, None) rounding_cpus = [] rounding_activation_rams = [] rounding_in_budgets = [] if lp_feasible: # round the solution for i in range(num_rounds): s_ = (np.random.rand(*s.shape) <= s).astype(np.int32) r_ = solve_r_opt(g, s_) schedule, aux_data = schedule_from_rs(g, r_, s_) rounding_cpus.append(aux_data.cpu) rounding_activation_rams.append(aux_data.activation_ram) rounding_in_budgets.append(aux_data.activation_ram <= budget) if aux_data.activation_ram <= budget and ( best_solution[2] is None or aux_data.cpu <= best_solution[0]): best_solution = (aux_data.cpu, schedule, aux_data) if (i + 1) % 1 == 0: print( f"Rounded relaxation argmin {i+1} / num_rounds times, best cost {best_solution[0]}" ) schedule, aux_data = best_solution[1], best_solution[2] scheduled_result = ScheduledResult( solve_strategy=SolveStrategy.APPROX_RANDOMIZED_ROUND, solver_budget=budget, feasible=lp_feasible, schedule=schedule, schedule_aux_data=aux_data, solve_time_s=lpsolver.solve_time, ilp_aux_data=ILPAuxData( U=u, Free_E=free_e, ilp_approx=approx, ilp_time_limit=time_limit, ilp_eps_noise=eps_noise, ilp_num_constraints=lpsolver.m.numConstrs, ilp_num_variables=lpsolver.m.numVars, approx_deterministic_round_threshold=None, ), ) if return_rounds: return ( scheduled_result, { "cpu": rounding_cpus, "activation_ram": rounding_activation_rams, "in_budget": rounding_in_budgets }, ) return scheduled_result
def solve(self): T = self.g.size with Timer("Gurobi model optimization", extra_data={ "T": str(T), "budget": str(self.budget) }): if self.seed_s is not None: self.m.Params.TimeLimit = self.GRB_CONSTRAINED_PRESOLVE_TIME_LIMIT self.m.optimize() if self.m.status == GRB.INFEASIBLE: print("Infeasible ILP seed at budget {:.2E}".format( self.budget)) self.m.remove(self.init_constraints) self.m.Params.TimeLimit = self.gurobi_params.get("TimeLimit", 0) self.m.message("\n\nRestarting solve\n\n") with Timer("ILPSolve") as solve_ilp: self.m.optimize() self.solve_time = solve_ilp.elapsed infeasible = self.m.status == GRB.INFEASIBLE if infeasible: raise ValueError( "Infeasible model, check constraints carefully. Insufficient memory?" ) if self.m.solCount < 1: raise ValueError( "Model status is {} (not infeasible), but solCount is {}". format(self.m.status, self.m.solCount)) Rout = np.zeros((T, T), dtype=checkmate.core.utils.solver_common.SOLVER_DTYPE if self.integral else np.float) Sout = np.zeros((T, T), dtype=checkmate.core.utils.solver_common.SOLVER_DTYPE if self.integral else np.float) Uout = np.zeros((T, T), dtype=checkmate.core.utils.solver_common.SOLVER_DTYPE if self.integral else np.float) Free_Eout = np.zeros( (T, len(self.g.edge_list)), dtype=checkmate.core.utils.solver_common.SOLVER_DTYPE) solver_dtype_cast = int if self.integral else float try: for t in range(T): for i in range(T): try: Rout[t][i] = solver_dtype_cast(self.R[t, i].X) except (AttributeError, TypeError) as e: Rout[t][i] = solver_dtype_cast(self.R[t, i]) try: Sout[t][i] = solver_dtype_cast(self.S[t, i]) except (AttributeError, TypeError) as e: Sout[t][i] = solver_dtype_cast(self.S[t, i].X) try: Uout[t][i] = self.U[t, i].X * self.ram_gcd except (AttributeError, TypeError) as e: Uout[t][i] = self.U[t, i] * self.ram_gcd for e in range(len(self.g.edge_list)): try: Free_Eout[t][e] = solver_dtype_cast(self.Free_E[t, e].X) except (AttributeError, TypeError) as e: Free_Eout[t][e] = solver_dtype_cast(self.Free_E[t, e]) except AttributeError as e: logging.exception(e) return None, None, None, None # prune R using closed-form solver if self.solve_r and self.integral: Rout = solve_r_opt(self.g, Sout) return Rout, Sout, Uout, Free_Eout