Skip to content

Commit

Permalink
Minor refcatoring of a few models
Browse files Browse the repository at this point in the history
  • Loading branch information
lecoutre committed Oct 6, 2024
1 parent da3f9c5 commit 3ba0b17
Show file tree
Hide file tree
Showing 12 changed files with 640 additions and 70 deletions.
2 changes: 1 addition & 1 deletion realistic/ACCAP/ACCAP.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
)
)

""" Comments
""" Comments
1) One can also write:
minimize(
Sum(
Expand Down
2 changes: 1 addition & 1 deletion realistic/Auction/Auction.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

satisfy(
# avoiding intersection of bids
Count(within=scp, value=1) <= 1 for scp in [[x[i] for i, bid in enumerate(bids) if item in bid.items] for item in items]
Count(within=scp, value=1) <= 1 for item in items if (scp := [x[i] for i, bid in enumerate(bids) if item in bid.items],)
)

maximize(
Expand Down
12 changes: 2 additions & 10 deletions realistic/CityPosition/CityPosition.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@
n, roads = data
maxDistance = max(road.distance for road in roads)


def approx_distance(x1, y1, x2, y2):
dx, dy = abs(x1 - x2), abs(y1 - y2)
return 1007 * max(dx, dy) + 441 * min(dx, dy)


# x[i] is the x-coordinate of the ith city
x = VarArray(size=n, dom=range(maxDistance + 1))

Expand All @@ -47,11 +41,9 @@ def approx_distance(x1, y1, x2, y2):
)

minimize(
Sum(
abs(distance * 1024 - approx_distance(x[src], y[src], x[dst], y[dst])) for (src, dst, distance) in roads
)
Sum(abs(distance * 1024 - (1007 * max(dx, dy) + 441 * min(dx, dy))) for (i, j, distance) in roads if (dx := abs(x[i] - x[j]), dy := abs(y[i] - y[j])))
)

"""
""" Comments
needs -di=2 with ACE
"""
42 changes: 22 additions & 20 deletions realistic/CollectiveConstruction/CollectiveConstruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@
assert width == depth # for simplicity, the model is built with this assumption
n = width

UNUSED, MOVE, BLOCK = ACTIONS = 0, 1, 2
UNUSED, MOVE, BLOCK = actions = 0, 1, 2

pairs = [(t, i) for t in range(1, horizon - 1) for i in range(n * n)]

def P(start=1, stop=horizon - 1):
return ((t, i) for t in range(start, stop) for i in range(n * n))


def at_border(i):
Expand All @@ -58,7 +60,7 @@ def neighbours(i, *, off=False, itself=False):
dom=lambda t, i: {building[i // n][i % n]} if t >= horizon - 2 and i < n * n else {0} if t < 2 or i >= n * n or at_border(i) else range(height))

# act[t][i] is the action at time t of the agent in the ith position
act = VarArray(size=[horizon, n * n + 2], dom=lambda t, i: {MOVE} if i >= n * n else {UNUSED} if t in {0, horizon - 1} and i < n * n else range(len(ACTIONS)))
act = VarArray(size=[horizon, n * n + 2], dom=lambda t, i: {MOVE} if i >= n * n else {UNUSED} if t in {0, horizon - 1} and i < n * n else range(len(actions)))

# nxt[t][i] is the next position at time t of the agent in the ith position
nxt = VarArray(size=[horizon, n * n + 2], dom=lambda t, i: {i} if i >= n * n else neighbours(i, off=True, itself=True))
Expand All @@ -67,7 +69,7 @@ def neighbours(i, *, off=False, itself=False):
car = VarArray(size=[horizon, n * n + 2], dom=lambda t, i: {1} if i == n * n else {0} if i == n * n + 1 else {0, 1})

# blp[t][i] is the block position at time t of the agent in the ith position
blp = VarArray(size=[horizon, n * n], dom=lambda t, i: {i} if t in {0, horizon - 1} else neighbours(i, itself=True)) # block position
blp = VarArray(size=[horizon, n * n], dom=lambda t, i: {i} if t in {0, horizon - 1} else neighbours(i, itself=True))

# pik[t][i] is 1 if at time t the agent in the ith position makes a pickup
pik = VarArray(size=[horizon, n * n], dom=lambda t, i: {0} if t in {0, horizon - 1} else {0, 1})
Expand All @@ -77,52 +79,52 @@ def neighbours(i, *, off=False, itself=False):

satisfy(
# change in height: the height of a cell evolves of at most 1 at each step
[abs(hgt[t + 1][i] - hgt[t][i]) <= 1 for t in range(horizon - 2) for i in range(n * n)],
[abs(hgt[t + 1][i] - hgt[t][i]) <= 1 for t, i in P(0, horizon - 2)],

# agents stay at the same position when doing a block operation
[
If(
act[t][i] == BLOCK,
Then=nxt[t][i] == i
) for t, i in pairs
) for t, i in P()
],

# when moving, the carrying status remains the same
[
If(
act[t][i] == MOVE,
Then=car[t + 1][nxt[t][i]] == car[t][i]
) for t, i in pairs
) for t, i in P()
],

# when blocking, the carrying status is inverted
[
If(
act[t][i] == BLOCK,
Then=car[t + 1][i] != car[t][i]
) for t, i in pairs
) for t, i in P()
],

# carrying status - pickup
[pik[t][i] == both(act[t][i] == BLOCK, car[t][i] == 0) for t, i in pairs],
[pik[t][i] == both(act[t][i] == BLOCK, car[t][i] == 0) for t, i in P()],

# carrying status - delivery
[dlv[t][i] == both(act[t][i] == BLOCK, car[t][i] == 1) for t, i in pairs],
[dlv[t][i] == both(act[t][i] == BLOCK, car[t][i] == 1) for t, i in P()],

# flow out
[
either(
act[t][i] == UNUSED,
act[t + 1][nxt[t][i]] != UNUSED
) for t, i in pairs
) for t, i in P()
],

# flow in
[
If(
act[t + 1][i] != UNUSED,
Then=Exist(both(act[t][j] != UNUSED, nxt[t][j] == i) for j in neighbours(i, itself=True))
) for t in range(horizon - 1) for i in range(n * n) if not at_border(i)
) for t, i in P(0, horizon - 1) if not at_border(i)
],

# vertex collision
Expand All @@ -133,15 +135,15 @@ def neighbours(i, *, off=False, itself=False):
act[t][i] == BLOCK,
[both(act[t + 1][j] == BLOCK, blp[t + 1][j] == i) for j in neighbours(i)]
) <= 1
for t, i in pairs
for t, i in P()
],

# edge collision
[
If(
act[t][i] == MOVE, nxt[t][i] != i, act[t][nxt[t][i]] == MOVE,
Then=nxt[t][nxt[t][i]] != i
) for t, i in pairs
) for t, i in P()
],

# maximum number of agents
Expand All @@ -158,15 +160,15 @@ def neighbours(i, *, off=False, itself=False):
If(
act[t][i] == MOVE,
Then=abs(hgt[t + 1][nxt[t][i]] - hgt[t][i]) <= 1
) for t in range(1, horizon - 2) for i in range(n * n)
) for t, i in P(1, horizon - 2)
],

# height of wait
[
If(
act[t][i] == MOVE, nxt[t][i] == i,
Then=hgt[t + 1][i] == hgt[t][i]
) for t in range(1, horizon - 2) for i in range(n * n)
) for t, i in P(1, horizon - 2)
],

# height of pickup
Expand All @@ -177,7 +179,7 @@ def neighbours(i, *, off=False, itself=False):
hgt[t][blp[t][i]] == hgt[t][i] + 1,
hgt[t][blp[t][i]] == hgt[t + 1][blp[t][i]] + 1
]
) for t in range(1, horizon - 2) for i in range(n * n)
) for t, i in P(1, horizon - 2)
],

# height of delivery
Expand All @@ -188,15 +190,15 @@ def neighbours(i, *, off=False, itself=False):
hgt[t][blp[t][i]] == hgt[t][i],
hgt[t][blp[t][i]] == hgt[t + 1][blp[t][i]] - 1
]
) for t in range(1, horizon - 2) for i in range(n * n)
) for t, i in P(1, horizon - 2)
],

# height change
[hgt[t + 1][i] == hgt[t][i] + Sum((blp[t][j] == i) * (dlv[t][j] - pik[t][j]) for j in neighbours(i)) for t, i in pairs]
[hgt[t + 1][i] == hgt[t][i] + Sum((blp[t][j] == i) * (dlv[t][j] - pik[t][j]) for j in neighbours(i)) for t, i in P()]
)

minimize(
Sum(act[t][i] != UNUSED for t, i in pairs)
Sum(act[t][i] != UNUSED for t, i in P())
)

""" Comments
Expand Down
2 changes: 0 additions & 2 deletions realistic/CommunityDetection/CommunityDetection.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,7 @@ def modularity_matrix():

""" Comments
1) Precedence(x) is equivalent to Precedence(x, values=range(m))
2) The Cardinality constraint (not posted here) is not useful at all:
Cardinality(x, occurrences={v: range(n + 1) for v in range(maxCommunities)})
3) The heuristic chs is efficient with symmetry-breaking
"""
2 changes: 1 addition & 1 deletion realistic/ConcertHall/ConcertHall.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
Sum(prices[i] * (x[i] >= 0) for i in range(nConcerts))
)

"""
""" Comments
1) Note that:
x[clique]
is a shortcut for:
Expand Down
31 changes: 14 additions & 17 deletions realistic/FAPP/FAPP.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,12 @@
domains, routes, hard_constraints, soft_constraints = data
domains = [domains[route.domain] for route in routes] # we skip the indirection
polarizations = [route.polarization for route in routes]
n, nSofts = len(routes), len(data.softs)
n, nSofts = len(routes), len(soft_constraints)


def table_soft(i, j, eq_relaxation, ne_relaxation, short_table=True):
def calculate_size():
for l in range(kl - 1):
if distance >= t[l]:
return l
return kl - 1

table = [] # we use a list instead of a set because is quite faster to process
def table(i, j, eqr, ner, short_table=True): # table for a soft constraint
eq_relaxation, ne_relaxation = tuple(eqr), tuple(ner)
T = [] # we use a list instead of a set because is quite faster to process
cache = {}
for f1 in domains[i]:
for f2 in domains[j]:
Expand All @@ -56,13 +51,15 @@ def calculate_size():
t = eq_relaxation if p1 == p2 else ne_relaxation # eqRelaxations or neRelaxations
for kl in range(12):
if kl == 11 or distance >= t[kl]: # for kl=11, we suppose t[kl] = 0
suffixes.append((p1, p2, kl, 0 if kl == 0 or distance >= t[kl - 1] else 1, 0 if kl <= 1 else calculate_size()))
w1 = 0 if kl == 0 or distance >= t[kl - 1] else 1
w2 = 0 if kl <= 1 else next((l for l in range(kl - 1) if distance >= t[l]), kl - 1)
suffixes.append((p1, p2, kl, w1, w2))
cache[key] = suffixes
elif short_table:
continue
for suffix in cache[key]:
table.append((distance, *suffix) if short_table else (f1, f2, *suffix))
return table
T.append((distance, *suffix) if short_table else (f1, f2, *suffix))
return T


# f[i] is the frequency of the ith radio-link
Expand All @@ -82,29 +79,29 @@ def calculate_size():

satisfy(
# imperative constraints
dst == gap if eq else dst != gap for (dst, eq, gap) in [(abs(f[i] - f[j] if fq else p[i] - p[j]), eq, gap) for (i, j, fq, eq, gap) in hard_constraints]
dst == gap if eq else dst != gap for (i, j, fq, eq, gap) in hard_constraints if (dst := abs(f[i] - f[j] if fq else p[i] - p[j]),)
)

if not variant():
satisfy(
# soft radio-electric compatibility constraints
(f[i], f[j], p[i], p[j], k, v1[l], v2[l]) in table_soft(i, j, tuple(eqr), tuple(ner), False) for l, (i, j, eqr, ner) in enumerate(soft_constraints)
(f[i], f[j], p[i], p[j], k, v1[q], v2[q]) in table(i, j, eqr, ner, False) for q, (i, j, eqr, ner) in enumerate(soft_constraints)
)

elif variant("short"):
soft_links = [[False] * n for _ in range(n)]
for c in data.softs:
for c in soft_constraints:
soft_links[c.route1][c.route2] = soft_links[c.route2][c.route1] = True

# d[i][j] is the distance between the ith and the jth frequencies (for i < j when a soft link exists)
d = VarArray(size=[n, n], dom=lambda i, j: {abs(f1 - f2) for f1 in domains[i] for f2 in domains[j]} if i < j and soft_links[i][j] else None)

satisfy(
# computing intermediary distances
[d[i][j] == abs(f[i] - f[j]) for i, j in combinations(n, 2) if d[i][j]],
[d[i][j] == abs(f[i] - f[j]) for i, j in combinations(n, 2) if soft_links[i][j]],

# soft radio-electric compatibility constraints
[(d[min(i, j)][max(i, j)], p[i], p[j], k, v1[l], v2[l]) in table_soft(i, j, tuple(er), tuple(nr)) for l, (i, j, er, nr) in enumerate(soft_constraints)]
[(d[min(i, j)][max(i, j)], p[i], p[j], k, v1[q], v2[q]) in table(i, j, eqr, ner) for q, (i, j, eqr, ner) in enumerate(soft_constraints)]
)

minimize(
Expand Down
Loading

0 comments on commit 3ba0b17

Please # to comment.