|
| 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 | +} |
0 commit comments