def solve(self): with timing('Solver.solve2'): server_score = lambda s: -s.efficiency pool_score = lambda p: self.solution.pool_score(p) row_score = lambda r: self.memories.free_space(r) random.seed(self.seed) pools = list(range(self.problem.pools)) rows = list(range(self.problem.rows)) with timing('Solver.solve.assign_pages'): servers = sorted(self.problem.servers, key=server_score) for i, server in enumerate(servers): try: if server.page is None: # row = max(rows, key=row_score) row = i % self.problem.rows server.page = self.memories.row_alloc( row=row, size=server.size) self.assign(server, row=row) except: pass assigned = len([s for s in servers if s.page]) print(f'assigned: {assigned}/{len(servers)}') with timing('Solver.solve.assign_pools'): servers = sorted(self.problem.servers, key=server_score) for i, server in enumerate(servers): if server.page: pool_id = min(pools, key=pool_score) self.assign(server, pool_id=pool_id) return self.solution
def try_solve(self, solution: SATSolution): with timing('Sat3Solver.try_solve'): wrongs = self.problem.wrong_clauses(solution) while len(wrongs) > 0 and len(solution.unassigned) > 0: free_vars = set([var.vid for var in solution.unassigned]) clauses = [ (cid, np.argwhere(self.problem.clauses[cid] != 0).flatten()) for cid in wrongs ] clauses = list( filter(lambda c: len(free_vars.intersection(c[1])) > 0, clauses)) if len(clauses) == 0: break # select clause random.shuffle(clauses) clause = clauses[0] # clause = max(clauses, key=lambda c: len(free_vars.intersection(c[1]))) # select new (var_id, val) cid, vars = clause vars = free_vars.intersection(vars) var_id = vars.pop() val = self.problem.clauses[cid, var_id] > 0 solution.variables[var_id].val = val wrongs = self.problem.wrong_clauses(solution) return solution, wrongs
def pool_score(self, pool_id: int): with timing('Solution.pool_score'): score = 1_000_000_000 for failure in range(self.problem.rows): tmp_score = sum([ self.pool_row_scores[pool_id][r] for r in range(self.problem.rows) if r != failure ]) score = min(score, tmp_score) return score
def easy_solve_single_pass(clauses: np.ndarray, solution: SATSolution): with timing('SATHelper.easy_solve_single_pass'): found = False for var in solution.unassigned: vid = var.vid clauses, val = SATHelper.try_assign_var(clauses, vid) solution.variables[vid].val = val if val is not None: found = True return clauses, found
def load(self, path: Path): with timing('Solution.load'): with path.open() as _: for server in self.problem.servers: line = _.readline().strip() if line == 'x': server.page = MemPage.empty() else: row, offset, pool_id = line.split(' ') server.page = MemPage(mem_id=int(row), offset=int(offset), size=int(server.size)) server.pool_id = int(pool_id) self.update_scores() return self
def solve(self, max_retries: int = 100): with timing('Sat3Solver.solve'): solution = SATSolution(self.problem.var_number) clauses, _ = SATHelper.easy_solve(self.problem.clauses, solution) best = solution best_score = len(clauses) print(f'easy solution: {best_score}') for retries in range(max_retries): solution, wrongs = self.try_solve(solution.copy()) score = len(wrongs) if score < best_score: best = solution best_score = score print(f'retries: {retries} wrong: {score} ') if score == 0: break return best, clauses
def save(self, path: Path): with timing('Solution.save'): with path.open('w') as _: for server in self.problem.servers: line = f'{server.page.mem_id} {server.page.offset} {server.pool_id}' if server.pool_id and server.page else 'x' _.write(line + '\n')
def search(self, size: int, offset: int = None): with timing('Memory.search'): if offset is not None: return list(filter(lambda mem: mem.offset <= offset and mem.end > offset + size, self.free_memory)) return list(filter(lambda mem: mem.size >= size, self.free_memory))
def search(self, size: int): with timing('Memory2D.search'): pages = [] for mem in self.memories: pages.extend(mem.search(size=size)) return pages