Skip to content

Commit 13eccaa

Browse files
parallel algorithm (WIP)
1 parent 22c7e9f commit 13eccaa

File tree

8 files changed

+301
-19
lines changed

8 files changed

+301
-19
lines changed

src/main/java/ch/sebastianhaeni/pancake/Node.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
package ch.sebastianhaeni.pancake;
22

3+
import java.io.Serializable;
34
import java.util.AbstractList;
45
import java.util.ArrayList;
56
import java.util.List;
67

7-
class Node {
8+
class Node implements Serializable {
89
private final int[] pancakes;
910
private final int flipCount;
11+
private final Node parent;
12+
private final int flipPosition;
1013

11-
Node(int[] pancakes, int flipCount) {
14+
Node(int[] pancakes) {
15+
this(pancakes, 0, null, -1);
16+
}
17+
18+
Node(int[] pancakes, int flipCount, Node parent, int flipPosition) {
1219
this.pancakes = pancakes;
1320
this.flipCount = flipCount;
21+
this.parent = parent;
22+
this.flipPosition = flipPosition;
1423
}
1524

1625
int getOptimisticDistanceToSolution() {
@@ -54,7 +63,10 @@ List<Node> nextNodes() {
5463
for (int i = 1; i < pancakes.length; i++) {
5564
int pancake = pancakes[i];
5665
if (pancake - current != 1) {
57-
list.add(flip(i + 1));
66+
int flipPosition = i + 1;
67+
if (flipPosition != this.flipPosition) {
68+
list.add(flip(flipPosition));
69+
}
5870
}
5971
current = pancake;
6072
}
@@ -72,10 +84,15 @@ Node flip(int flipPosition) {
7284

7385
System.arraycopy(pancakes, flipPosition, flipped, flipPosition, pancakes.length - flipPosition);
7486

75-
return new Node(flipped, getFlipCount() + 1);
87+
return new Node(flipped, getFlipCount() + 1, this, flipPosition);
7688
}
7789

7890
int[] getPancakes() {
7991
return pancakes;
8092
}
93+
94+
Node getParent() {
95+
return parent;
96+
}
97+
8198
}
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
package ch.sebastianhaeni.pancake;
2+
3+
import mpi.MPI;
4+
import mpi.Request;
5+
import mpi.Status;
6+
7+
import java.util.Arrays;
8+
import java.util.List;
9+
10+
@SuppressWarnings("Duplicates")
11+
public class ParallelSolver {
12+
private static final int MASTER_RANK = 0;
13+
static int[] workers = new int[]{1, 2, 3, 4};
14+
15+
public static void main(String[] args) {
16+
MPI.Init(args);
17+
int rank = MPI.COMM_WORLD.Rank();
18+
19+
if (rank == MASTER_RANK) {
20+
runMaster();
21+
} else {
22+
runSlave(rank);
23+
}
24+
25+
MPI.Finalize();
26+
}
27+
28+
private static void runSlave(int rank) {
29+
Request finishCommand = MPI.COMM_WORLD.Irecv(new int[0], 0, 0, MPI.INT, MASTER_RANK, Tags.FINISH);
30+
31+
outer:
32+
while (finishCommand.Test() == null) {
33+
WorkPacket[] work = new WorkPacket[1];
34+
Request workRequest = MPI.COMM_WORLD.Irecv(work, 0, 1, MPI.OBJECT, MASTER_RANK, Tags.WORK);
35+
36+
while (workRequest.Test() == null) {
37+
if (finishCommand.Test() != null) {
38+
break outer;
39+
}
40+
try {
41+
Thread.sleep(50);
42+
} catch (InterruptedException e) {
43+
e.printStackTrace();
44+
}
45+
}
46+
47+
// System.out.format("%d just got some work from master\n", rank);
48+
49+
Node node = work[0].getNode();
50+
int bound = work[0].getBound();
51+
52+
SearchResult result = compute(node, bound);
53+
sendResult(result);
54+
}
55+
56+
// System.out.format("%d is done for the day\n", rank);
57+
}
58+
59+
private static SearchResult compute(Node node, int bound) {
60+
int newBound = node.getFlipCount() + node.getOptimisticDistanceToSolution();
61+
62+
if (newBound > bound) {
63+
return new SearchResult(newBound);
64+
}
65+
66+
if (node.isSolution()) {
67+
return new SearchResult(node);
68+
}
69+
70+
int min = Integer.MAX_VALUE;
71+
List<Node> successors = node.nextNodes();
72+
73+
for (Node successor : successors) {
74+
SearchResult result = compute(successor, bound);
75+
76+
if (result.solutionNode != null) {
77+
return result;
78+
}
79+
80+
if (result.bound < min) {
81+
min = result.bound;
82+
}
83+
}
84+
85+
return new SearchResult(min);
86+
}
87+
88+
private static void sendResult(SearchResult searchResult) {
89+
MPI.COMM_WORLD.Isend(new SearchResult[]{searchResult}, 0, 1, MPI.OBJECT, MASTER_RANK, Tags.RESULT);
90+
}
91+
92+
private static void runMaster() {
93+
// Node root = new Node(new int[]{39,47,13,46,11,43,49,14,7,57,59,42,53,37,55,20,28,33,5,27,34,40,19,52,10,35,8,31,48,30,22,45,12,24,32,36,38,17,50,54,41,60,26,4,2,9,58,23,44,1,6,15,16,29,51,18,21,3,56,25});
94+
Node root = new Node(new int[]{17, 2, 5, 13, 3, 7, 8, 4, 20, 11, 9, 18, 6, 14, 1, 10, 16, 15, 12, 19});
95+
// Node root = new Node(new int[]{5, 2, 7, 10, 13, 16, 14, 6, 8, 18, 15, 11, 1, 12, 3, 4, 9, 17});
96+
// Node root = new Node(new int[]{2, 1, 5, 4, 3});
97+
98+
System.out.format("Solving a pancake pile in parallel of height %d.\n", root.getPancakes().length);
99+
100+
long start = System.currentTimeMillis();
101+
Node solution = solve(root);
102+
long end = System.currentTimeMillis();
103+
104+
System.out.format("%dms passed\n", (end - start));
105+
106+
if (solution == null) {
107+
System.out.println("No solution found");
108+
return;
109+
}
110+
System.out.format("Found solution after %d flips.\n", solution.getFlipCount());
111+
112+
StringBuilder sb = new StringBuilder();
113+
Node current = solution;
114+
while (current.getParent() != null) {
115+
sb.insert(0, Arrays.toString(current.getParent().getPancakes()) + "\n");
116+
current = current.getParent();
117+
}
118+
119+
System.out.println(sb.toString());
120+
}
121+
122+
private static Node solve(Node root) {
123+
if (root.isSolution()) {
124+
return root;
125+
}
126+
127+
Node solutionNode = null;
128+
int bound = root.getOptimisticDistanceToSolution();
129+
int maxBound = bound * 10;
130+
131+
while (solutionNode == null) {
132+
SearchResult result = search(root, bound);
133+
134+
if (result.solutionNode != null) {
135+
solutionNode = result.solutionNode;
136+
}
137+
138+
if (result.bound >= maxBound) {
139+
return null;
140+
}
141+
142+
bound = result.bound;
143+
}
144+
145+
for (int worker : workers) {
146+
MPI.COMM_WORLD.Isend(new int[0], 0, 0, MPI.INT, worker, Tags.FINISH);
147+
}
148+
149+
return solutionNode;
150+
}
151+
152+
private static SearchResult search(Node node, int bound) {
153+
int newBound = node.getFlipCount() + node.getOptimisticDistanceToSolution();
154+
155+
if (newBound > bound) {
156+
return new SearchResult(newBound);
157+
}
158+
159+
if (node.isSolution()) {
160+
return new SearchResult(node);
161+
}
162+
163+
int min = Integer.MAX_VALUE;
164+
List<Node> successors = node.nextNodes();
165+
166+
int currentWorker = 0;
167+
for (Node successor : successors) {
168+
WorkPacket packet = new WorkPacket(successor, bound);
169+
int destination = workers[currentWorker % workers.length];
170+
MPI.COMM_WORLD.Isend(new WorkPacket[]{packet}, 0, 1, MPI.OBJECT, destination, Tags.WORK);
171+
currentWorker++;
172+
}
173+
174+
SearchResult[] result = new SearchResult[1];
175+
Request[] requests = new Request[successors.size()];
176+
currentWorker = 0;
177+
178+
for (int i = 0; i < successors.size(); i++) {
179+
int destination = workers[currentWorker % workers.length];
180+
requests[i] = MPI.COMM_WORLD.Irecv(result, 0, 1, MPI.OBJECT, destination, Tags.RESULT);
181+
currentWorker++;
182+
}
183+
184+
int answers = 0;
185+
boolean[] handledRequests = new boolean[requests.length];
186+
while (answers < requests.length) {
187+
for (int i = 0; i < requests.length; i++) {
188+
Request request = requests[i];
189+
Status status;
190+
191+
if (handledRequests[i] || (status = request.Test()) == null) {
192+
continue;
193+
}
194+
195+
answers++;
196+
handledRequests[i] = true;
197+
// System.out.format("Master got result from %d\n", status.source);
198+
if (result[0].solutionNode != null) {
199+
return result[0];
200+
}
201+
202+
if (result[0].bound < min) {
203+
min = result[0].bound;
204+
}
205+
}
206+
207+
try {
208+
Thread.sleep(50);
209+
} catch (InterruptedException e) {
210+
e.printStackTrace();
211+
}
212+
}
213+
214+
return new SearchResult(min);
215+
}
216+
217+
private static class Tags {
218+
static final int WORK = 1;
219+
static final int RESULT = 2;
220+
static final int FINISH = 3;
221+
}
222+
}

src/main/java/ch/sebastianhaeni/pancake/Main.java renamed to src/main/java/ch/sebastianhaeni/pancake/RecursiveSolver.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,40 @@
11
package ch.sebastianhaeni.pancake;
22

3+
import java.util.Arrays;
34
import java.util.List;
45

5-
public class Main {
6+
public class RecursiveSolver {
67

78
public static void main(String[] args) {
89

9-
// Node root = new Node(new int[]{46, 53, 18, 4, 56, 11, 57, 59, 55, 25, 6, 34, 41, 13, 39, 52, 7, 33, 43, 21, 32, 51, 5, 1, 58, 49, 54, 9, 24, 17, 19, 27, 50, 42, 22, 30, 20, 3, 14, 28, 40, 10, 12, 29, 37, 8, 36, 2, 26, 38, 16, 60, 15, 48, 35, 45, 31, 44, 23, 47}, 0);
10-
// Node root = new Node(new int[]{2, 6, 10, 5, 1, 3, 8, 4, 7, 9}, 0);
11-
// Node root = new Node(new int[]{1, 2, 3}, 0);
12-
// Node root = new Node(new int[]{11, 7, 15, 6, 17, 3, 19, 16, 4, 10, 8, 12, 20, 14, 2, 5, 1, 9, 13, 18}, 0);
13-
Node root = new Node(new int[]{5, 2, 7, 10, 13, 16, 14, 6, 8, 15, 11, 1, 12, 3, 4, 9}, 0);
10+
// Node root = new Node(new int[]{46, 53, 18, 4, 56, 11, 57, 59, 55, 25, 6, 34, 41, 13, 39, 52, 7, 33, 43, 21, 32, 51, 5, 1, 58, 49, 54, 9, 24, 17, 19, 27, 50, 42, 22, 30, 20, 3, 14, 28, 40, 10, 12, 29, 37, 8, 36, 2, 26, 38, 16, 60, 15, 48, 35, 45, 31, 44, 23, 47});
11+
// Node root = new Node(new int[]{2, 6, 10, 5, 1, 3, 8, 4, 7, 9});
12+
// Node root = new Node(new int[]{3, 1, 2});
13+
// Node root = new Node(new int[]{11, 7, 15, 6, 17, 3, 19, 16, 4, 10, 8, 12, 20, 14, 2, 5, 1, 9, 13, 18});
14+
Node root = new Node(new int[]{5, 2, 7, 10, 13, 16, 14, 6, 8, 18, 15, 11, 1, 12, 3, 4, 9, 17});
15+
16+
System.out.format("Solving a pancake pile of height %d.\n", root.getPancakes().length);
1417

1518
long start = System.currentTimeMillis();
1619
Node solution = solve(root);
1720
long end = System.currentTimeMillis();
1821

19-
System.out.println((end - start) + "ms passed");
22+
System.out.format("%dms passed\n", (end - start));
2023

2124
if (solution == null) {
2225
System.out.println("No solution found");
2326
return;
2427
}
25-
System.out.println("Found solution after " + solution.getFlipCount() + " flips.");
28+
System.out.format("Found solution after %d flips.\n", solution.getFlipCount());
29+
30+
StringBuilder sb = new StringBuilder();
31+
Node current = solution;
32+
while (current.getParent() != null) {
33+
sb.insert(0, Arrays.toString(current.getParent().getPancakes()) + "\n");
34+
current = current.getParent();
35+
}
36+
37+
System.out.println(sb.toString());
2638
}
2739

2840
private static Node solve(Node root) {

src/main/java/ch/sebastianhaeni/pancake/SearchResult.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package ch.sebastianhaeni.pancake;
22

3-
class SearchResult {
3+
import java.io.Serializable;
4+
5+
class SearchResult implements Serializable {
46
Node solutionNode;
57
int bound;
68

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package ch.sebastianhaeni.pancake;
2+
3+
import java.io.Serializable;
4+
5+
public class WorkPacket implements Serializable {
6+
private final Node node;
7+
private final int bound;
8+
9+
public WorkPacket(Node node, int bound) {
10+
this.node = node;
11+
this.bound = bound;
12+
}
13+
14+
public Node getNode() {
15+
return node;
16+
}
17+
18+
public int getBound() {
19+
return bound;
20+
}
21+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package ch.sebastianhaeni.pancake.parallel;
2+
3+
public class Master {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package ch.sebastianhaeni.pancake.parallel;
2+
3+
public class Slave {
4+
}

0 commit comments

Comments
 (0)