How do I extract the trees from a graph using Answer Set Programming? - undirected-graph

There is an undirected graph (V,E), weights on the edges w : E → N, a
target k ∈ N, and a threshold O ∈ N. Find a k-vertices tree of the
graph of weight less than the threshold. In other words, select k
vertices and k - 1 edges from V and E respectively such that they
constitute a tree, and the sum of the weights of the selected edges
are less than O.
Write an ASP program that takes V , E, w, k, and O as input, and finds
a selection of edges satisfying the constraints, or outputs
‘unsatisfiable’ if the constraints cannot be satisfied. Selecting the
edges implicitly induces a selection of the vertices, so there is no
need for the selected vertices to be explicitly displayed.
An instance to this problem is provided through predicates vertex/1,
weight/3, target/1, and threshold/1. All edges have weights, so
statements of the form weight(a, b, 10). can be used to declare the
existence of an edge between vertices a and b at the same time as
declaring their weight, and there is no need for any redundant edge/2
predicate.
I tried the following:
% instance
vertex ( v1 ). vertex ( v2 ). vertex ( v3 ).
vertex ( v4 ). vertex ( v5 ). vertex ( v6 ).
vertex ( v7 ). vertex ( v8 ). vertex ( v9 ).
weight ( v1 , v2 ,3). weight ( v1 , v3 ,3).
weight ( v2 , v4 ,1). weight ( v2 , v5 ,5).
weight ( v3 , v4 ,3). weight ( v3 , v6 ,4).
weight ( v4 , v5 ,4). weight ( v4 , v7 ,1).
weight ( v5 , v7 ,7).
weight ( v6 , v7 ,2). weight ( v6 , v8 ,2).
weight ( v7 , v9 ,3).
weight ( v8 , v9 ,2).
target (4).
threshold (4).
% encoding
(P-1) {select(X, Y) : weight(X, Y, Z)} (Q-1) :- target(P), target(Q).
sum(S) :- S = #sum {W,X,Y : select(X,Y), weight(X,Y,W); W,X,Z : select(X,Z), weight(X,Z,W) }.
:- sum(S),threshold(M), S > M.
:- select(A,B), select(C,D), A == C ; A == D ; B == C ; B == D.
#show select/2.
And I get the following output:
clingo version 5.5.0
Reading from stdin
Solving...
Answer: 1
select(v2,v4) select(v4,v7) select(v6,v7)
Answer: 2
select(v2,v4) select(v4,v7) select(v6,v8)
Answer: 3
select(v2,v4) select(v4,v7) select(v8,v9)
SATISFIABLE
Models : 3
Calls : 1
Time : 0.013s (Solving: 0.00s 1st Model: 0.00s Unsat: 0.00s)
CPU Time : 0.000s
I was expecting just
select(v2,v4) select(v4,v7) select(v6,v7)
because the others clearly are not tress.
I think this is because of the problematic line:
:- select(A,B), select(C,D), A == C ; A == D ; B == C ; B == D.
How do I correct this?

Ok, that was rather complicated. I'm pretty sure my solution is not perfect, I'm a beginner too.
Before we start with the code, let's check up the question once more: The requirement is to select k nodes and k-1 edges. If you think about it a bit this can form exactly two patterns: one connected tree or multiple non-connected graphs where there is at least one cycle. So if you make sure not to have a cycle you get one connected tree.
I added some nodes to the facts to check if a tree was formed or if the cheap unconnected cycle was found, and for doing so I had to change target and threshold to higher values.
1
#const n = 5.
vertex ( v1; v2; v3; v4; v5; v6; v7; v8; v9 ).
vertex ( m1; m2; m3 ).
weight ( v1 , v2 ,3). weight ( v1 , v3 ,3).
weight ( v2 , v4 ,1). weight ( v2 , v5 ,5).
weight ( v3 , v4 ,3). weight ( v3 , v6 ,4).
weight ( v4 , v5 ,4). weight ( v4 , v7 ,1).
weight ( v5 , v7 ,7).
weight ( v6 , v7 ,2). weight ( v6 , v8 ,2).
weight ( v7 , v9 ,3).
weight ( v8 , v9 ,2).
weight ( m1 , m2 ,0).
weight ( m2 , m3 ,0).
weight ( m3 , m1 ,0).
target (n).
threshold (6).
And now comes the code, followed by an explanation.
% select subset of nodes and vertices
(P) {select(X) : vertex(X)} (P) :- target(P).
(P-1) {select(X, Y) : weight(X, Y, Z)} (Q-1) :- target(P), target(Q).
% postion does not matter in an undirected graph.
directed(A,B):-select(A,B).
directed(B,A):-select(A,B).
% for every selected edge all nodes are selected
:- directed(A,_), vertex(A), not select(A).
% for every selected node there exists at least one edge
:- select(A), {directed(A,B):vertex(B)}0.
% select a direction for each selected edge
{dir(A,B);dir(B,A)}==1 :- select(A,B).
% force them in an order
{ found(X,1..n) } == 1 :- select(X).
{ found(X,N):select(X) } == 1 :- N = 1..n.
% reject if one edge does not follow the order
:- found(X,NX), found(Y,NY), dir(X,Y), NY<NX.
% reject if 2 different edges end in the same vertex
:- dir(X,Z), dir(Y,Z), X!=Y.
:- threshold(M), M < #sum {W,X,Y : select(X,Y), weight(X,Y,W); W,X,Z : select(X,Z), weight(X,Z,W) }.
#show select/2.
Explanation:
To make it easier for me I added the selected vertices in the select/1 predicate.
Since dealing with undirected graphs always has to check both postions I added the directed/2 predicate which is a directed graph version of the selected edges.
Next I made sure every selected vertex has a selected edge and vice versa.
Now comes the complicated part: to detect cycles. For this I forced every selected edge in one of its two directions by using the predicate dir/2. Testing for a tree is easier in a directed graph.
Next I put an order found/2 to the vertices. The directed edges dir/2 where only allowed to go with this order. This forces cycles to a certain behavior.
Now comes the cycle destroyer: if the selected graph has a cycle then two edges from dir/2 will end in the same vertex. REJECT. If this was just an unlucky guess from clingo then it will find a luckier guess which fullfills this criterion.
Computation of the sum was copy and paste from you.
The output is 16 times
select(v2,v4) select(v4,v7) select(v6,v7) select(v6,v8)
The dublicates come from the fact that the order of the vertices in found/2 can differ but still get the same result.

Related

Modifying Dijkstra to find path with max coloured node

I just saw a solution of a question that modifying Dijkstra to get the shortest path with a max of K coloured edge. I am wondering what if we want find the shortest path with coloured node instead of edge, how are we gonna modify Dijkstra to do the trick?
What I come up with is that on top of Dijkstra, I add an integer variable let say i. Then make a map to record how many coloured node it takes to get there, and if there is a way that passed through less coloured node, update it. And we will take the path with least coloured node. But this seems something is wrong, any suggestion?
Algorithm Dijkstra ( G , s in V(G), c(v) in{black, white}, K )
1. for each vertex u in V(G) do dist[u] <- +infinity
2. dist[s] <- 0 ; p[s] <- null
3. c(s)=black? r <- 1 : r <- 0
4. Q <- ConstructMinHeap(V(G), dist)
5. M <- Map(s, r)
6. while Q != null do
7. u <- DeleteMin(Q)
8. for each v in Adj[u] do
9. if M.value(u) is null then do
10. M <- Map(u, M.value(v) + c(u)=black? 1 : 0)
11. else
12. M.value(u) < (M.value(v) + c(u)=black? 1 : 0)? Update : do nothing
13. end-if
14. if dist[v] > dist[u] + w(u,v) and M.value < K then do
15. dist[v] <- dist[u] + w(u,v)
16. p[v] <- u
17. UpHeap(v,Q)
18. end-if
19. end-for
20. end-while
end
If you use a priority queue to rank your options, consider using both the distance so far and the number of coloured nodes passed through to determine the order of priority. In this manner, you can use the traditional Dijkstra and let the determination of a minimum path be determined by your priority ranking.

How to use segment tree and scanline

Given 300000 segments.
Consider any pair of segments: a = [l1,r1] and b = [l2,r2].
If l2 >= l1 and r2 <= r1 , it is "good" pair.
If a == b, it is "bad" pair.
Overwise, it is "bad" pair.
How to find number of all "good" pairs among given segments using segment tree and scanline?
Sort the segments in increasing order with respect to their l-values and for pairs with same l-values sort them in decreasing order with respect to their r-value.
Suppose for a particular , you want to count the number of good pairs (ai,aj) such that j < i. Let ai=[l1,r1] and aj = [l2,r2]. Then we have l2 <= l1. Now we need to count all the possible values of j such that r2 <= r1. This can be done by maintaining a segment tree for the values of r for all j such that 0 < j < i. After querying for the i-th pair, update the segment tree with the r-value of the i-th segment.
Coming to segment tree part, build a segment tree on the values of r. On updating a value of r in segment tree, add 1 to the value of r in the segment tree and for querying for a particular value of r, query for sum in the range [0,r-1]. This will give total number of segments that fit good with the given segment.
If the values of r are big that would not fit into segment tree, then apply coordinate compression to values first and then use segment tree for the compressed values.

minimum weight shortest path for all pairs of vertices with exactly k blue edges

Basically a subset of the graph has edges which are blue
So I know how to find all pairs shortest paths with DP in O(n^3), but how do I account for color and the exactness of the number of edges required for the problem?
This can be done in O(k^2 . n^3) using a variant of Floydd-Warshall.
Instead of keeping track of the minimum path weight d(i,j) between two nodes i and j, you keep track of the minimum path weight d(i,j,r) for paths between i and j with exactly r blue edges, for 0 ≤ r ≤ k.
The update step when examining paths through a node m, where normally d(i,j) would be updated with the sum of d(i,m) and d(m,j) if it is smaller, becomes:
for u: 0 .. k
for v: 0 .. (k-u)
s = d(i,m,u) + d(m,j,v)
d(i,j,u+v) = min( s, d(i,j,u+v) )
At the end, you then read off d(i,j,k).

constraint programming mesh network

I have a mesh network as shown in figure.
Now, I am allocating values to all edges in this sat network. I want to propose in my program that, there are no closed loops in my allocation. For example the constraint for top-left most square can be written as -
E0 = 0 or E3 = 0 or E4 = 0 or E7 = 0, so either of the link has to be inactive in order not to form a loop. However, in this kind of network, there are many possible loops.
For example loop formed by edges - E0, E3, E7, E11, E15, E12, E5, E1.
Now my problem is that I have to describe each possible combination of loop which can occur in this network. I tried to write constraints in one possible formula, however I was not able to succeed.
Can anyone throw any pointers if there is a possible way to encode this situation?
Just for information, I am using Z3 Sat Solver.
The following encoding can be used with any graph with N nodes and M edges. It is using (N+1)*M variables and 2*M*M 3-SAT clauses. This ipython notebook demonstrates the encoding by comparing the SAT solver results (UNSAT when there is a loop, SAT otherwise) with the results of a straight-forward loop finding algorithm.
Disclaimer: This encoding is my ad-hoc solution to the problem. I'm pretty sure that it is correct but I don't know how it compares performance-wise to other encodings for this problem. As my solution works with any graph it is to be expected that a better solution exists that uses some of the properties of the class of graphs the OP is interested in.
Variables:
I have one variable for each edge. The edge is "active" or "used" if its corresponding variable is set. In my reference implementation the edges have indices 0..(M-1) and this variables have indices 1..M:
def edge_state_var(edge_idx):
assert 0 <= edge_idx < M
return 1 + edge_idx
Then I have an M bits wide state variable for each edge, or a total of N*M state bits (nodes and bits are also using zero-based indexing):
def node_state_var(node_idx, bit_idx):
assert 0 <= node_idx < N
assert 0 <= bit_idx < M
return 1 + M + node_idx*M + bit_idx
Clauses:
When an edge is active, it links the state variables of the two nodes it connects together. The state bits with the same index as the node must be different on both sides and the other state bits must be equal to their corresponding partner on the other node. In python code:
# which edge connects which nodes
connectivity = [
( 0, 1), # edge E0
( 1, 2), # edge E1
( 2, 3), # edge E2
( 0, 4), # edge E3
...
]
cnf = list()
for i in range(M):
eb = edge_state_var(i)
p, q = connectivity[i]
for k in range(M):
pb = node_state_var(p, k)
qb = node_state_var(q, k)
if k == i:
# eb -> (pb != qb)
cnf.append([-eb, -pb, -qb])
cnf.append([-eb, +pb, +qb])
else:
# eb -> (pb == qb)
cnf.append([-eb, -pb, +qb])
cnf.append([-eb, +pb, -qb])
So basically each edge tries to segment the graph it is part of into a half that is on one side of the edge and has all the state bits corresponding to the edge set to 1 and a half that is on the other side of the edge and has the state bits corresponding to the edge set to 0. This is not possible for a loop where all nodes in the loop can be reached from both sides of each edge in the loop.

How to create an evaluation function for a board game(wizwoz) result

The game is named wizwoz:
Two players, red (referred as r) and
gold (referred as g) initially select two values n and k. An n × n board is created with k
"r" and k "g" randomly placed on the board. Starting with player r, each player puts
his/her letter(“r” for player r, “g” for payer g) in one of the empty squares on the board.
After the board is filled, each player's score is equal to the largest connected region on the
board filled with that player's color (where a connected region is one where for any two
squares in the region a path exists consisting of only N/S/E/W moves). The player with
the highest score wins, and is awarded the difference between his/her score and the score
of the other player. Two examples of finished games are shown below, with the largest
connected regions for each player outlined. Note that in the second example the two
sections with 2 r each are not connected.
Im writing the alpha-beta prunning algorithm and stuck with the evaluation function.
Any help? Pseudocode is preferable.
Start with a really simple evaluation function. For example, just use the current size of the largest component. After you get an ai working, you can worry about tuning the evaluation heuristics.
Here's example pseduocode (not tested)
components = {k:set([k]) for k in board}
def contract(k1, k2):
if color(k1) != color(k2):
return
new = components[k1]
if k2 not in new:
new.union_update(components[k2])
for x in components[k2]:
components[x] = new
for x,y:
contract(board[x,y], board[x,y+1])
contract(board[x,y], board[x+1,y])
return max(map(len, components))

Resources