"""Biên Pareto chính xác trên tập ứng viên nhỏ, không dùng thêm thư viện.""" from fractions import Fraction import clingo PROGRAM = r""" cost(a,0,6). cost(b,2,5). cost(c,4,0). cost(d,3,6). 1 { choose(L) : cost(L,X,Y) } 1. point(L,X,Y) :- choose(L), cost(L,X,Y). #show point/3. """ def solve(extra="", optimize=False): args = ["0", "--opt-mode=optN"] if optimize else ["0"] ctl = clingo.Control(args) ctl.add("base", [], PROGRAM + extra) ctl.ground([("base", [])]) found = set() def collect(model): if optimize and not model.optimality_proven: return # Chỉ lấy giai đoạn liệt kê nghiệm đã chứng nhận tối ưu. for atom in model.symbols(shown=True): l, x, y = atom.arguments found.add((str(l), x.number, y.number)) result = ctl.solve(on_model=collect) assert result.exhausted and not result.interrupted return found points = solve() def dominates(p, q): return p[1] <= q[1] and p[2] <= q[2] and (p[1] < q[1] or p[2] < q[2]) front = {p for p in points if not any(dominates(q, p) for q in points)} assert front == {("a", 0, 6), ("b", 2, 5), ("c", 4, 0)} # Để B thắng A cần w1/w2 <= 1/2; để B thắng C cần >= 5/2. assert Fraction(5, 2) > Fraction(1, 2) # Không có tỉ lệ dương thỏa cả hai. bounded = solve(":- point(L,X,Y), Y > 5.\n#minimize { X,L : point(L,X,Y) }.", True) assert bounded == {("b", 2, 5)} print("Biên Pareto:", sorted(front)) print("Giới hạn mục tiêu Y <= 5, tối ưu X:", sorted(bounded))