001 002 package algo; 003 004 import thread.Deque; 005 006 import java.util.ArrayList; 007 008 /** 009 * A parallel algorithm for an euclidean 2d TSP Problem. 010 * @author Heinz Kredel. 011 */ 012 public class ParByteLocalTSP implements TSPInf { 013 014 protected Graph graph; 015 protected Point[] points; 016 // protected Path bestPath; // beware of threads 017 protected BestByteLocStore best; 018 protected RunByteLocTSP[] threads; 019 020 protected int number = 0; 021 022 /** 023 * @param p the cities. 024 * @param th number of threads. 025 */ 026 public ParByteLocalTSP(Point[] p, int th) { 027 this.points = p; 028 graph = new PlaneGraph(p); 029 number = th; 030 threads = null; 031 } 032 033 /** 034 * @return number of iterations or 0. 035 */ 036 public long getIterations() { 037 if ( threads == null ) { 038 return 0l; 039 } 040 long iter = 0l; 041 for ( int i = 0; i < threads.length; i++ ) { 042 if ( threads[i] != null ) { 043 iter += threads[i].getIterations(); 044 } 045 } 046 return iter; 047 } 048 049 /** 050 * @return maxiter. 051 */ 052 public long getMaxIterations() { 053 if ( threads == null ) { 054 return Long.MAX_VALUE; 055 } 056 long maxiter = Long.MAX_VALUE; 057 for ( int i = 0; i < threads.length; i++ ) { 058 long mi = threads[i].getMaxIterations(); 059 if ( maxiter > mi ) { 060 maxiter = mi; 061 } 062 } 063 return maxiter; 064 } 065 066 /** 067 * @param m new maxIter. 068 * @return old maxIter. 069 */ 070 public long setMaxIterations(long m){ 071 if ( threads == null ) { 072 return m; 073 } 074 long maxiter = Long.MAX_VALUE; 075 for ( int i = 0; i < threads.length; i++ ) { 076 long mi = threads[i].setMaxIterations(m); 077 if ( maxiter > mi ) { 078 maxiter = mi; 079 } 080 } 081 return maxiter; 082 } 083 084 085 /** 086 * @return best.getPath(). 087 */ 088 public Path actualBest() { 089 if ( best == null ) { 090 return null; 091 } 092 return best.getPath(); 093 } 094 095 /** 096 * @param b new best path. 097 */ 098 public void setBest(Path b) { 099 if ( b == null ) { 100 return; 101 } 102 if ( best == null ) { 103 // best.setPath( b ); 104 return; 105 } 106 if ( b.cost() < best.getPath().cost() ) { 107 best.setPath( b ); 108 } 109 } 110 111 /** 112 * @return getBest(Long.MAX_VALUE). 113 */ 114 public Path getBest() { 115 return getBest(Long.MAX_VALUE); 116 } 117 118 /** 119 * @param max maximal number of iterations. 120 * @return best Path. 121 */ 122 public Path getBest(long max) { 123 Path bestPath = PathByteArray.standardPath(graph); // standard path 124 if ( bestPath.length() <= 2 ) { 125 return bestPath; 126 } 127 best = new BestByteLocStore( bestPath, 0, number ); 128 Path path = PathByteArray.onePath(graph); // one/empty path 129 Deque globalStack = new Deque(10000); 130 try { 131 globalStack.push( path ); 132 } catch (InterruptedException e) { 133 e.printStackTrace(); 134 } 135 threads = new RunByteLocTSP[number]; 136 for ( int i = 0; i < number; i++ ) { 137 threads[i] = new RunByteLocTSP(globalStack,best,max); 138 threads[i].start(); 139 } 140 try { 141 for ( int i = 0; i < number; i++ ) { 142 threads[i].join(); 143 } 144 } catch (InterruptedException e) { 145 e.printStackTrace(); 146 } 147 return best.getPath(); 148 } 149 150 public void getBest(Path path) { 151 System.out.println("method getBest() in ParByteLocalTSP not implemented"); 152 } 153 154 } 155 156 /** 157 * Storage for best path found so far. 158 */ 159 class BestByteLocStore { 160 161 private Path path; 162 private int idlers; 163 public final int threads; 164 165 /** 166 * @param b best known path. 167 * @param i idle threads. 168 * @param t number of threads. 169 */ 170 public BestByteLocStore(Path b, int i, int t) { 171 path = b; 172 idlers = i; 173 threads = t; 174 } 175 176 /** 177 * @return path. 178 */ 179 public Path getPath() { 180 return path; 181 } 182 183 /** 184 * @param p new best path. 185 */ 186 public void setPath(Path p) { 187 path = p; 188 } 189 190 public synchronized void incIdle() { 191 idlers++; 192 } 193 194 public synchronized void decIdle() { 195 idlers--; 196 } 197 198 /** 199 * @return (idlers == threads). 200 */ 201 public synchronized boolean allIdle() { 202 return (idlers == threads); 203 } 204 } 205 206 207 /** 208 * Thread for parallel computation. 209 */ 210 class RunByteLocTSP extends Thread { 211 212 private BestByteLocStore best; 213 private Deque globalStack; 214 private long maxiter; 215 private long iter; 216 private long pushes; 217 private ArrayList stack; 218 public final int COUNT; 219 220 /** 221 * @param s work queue. 222 * @param b storage for best path. 223 * @param max maximal number of iterations. 224 */ 225 public RunByteLocTSP(Deque s, BestByteLocStore b, long max) { 226 globalStack = s; 227 best = b; 228 COUNT = b.getPath().maxsize()+5; //*2 / +5 ? 229 maxiter = max; 230 stack = new ArrayList(500); 231 } 232 233 234 public void run() { 235 iter = 0; 236 pushes = 0; 237 boolean running = true; 238 while (running) { 239 Object o = null; 240 if ( stack.isEmpty() ) { 241 try { 242 best.incIdle(); 243 if ( globalStack.empty() && best.allIdle() ) { 244 for ( int i = 0; i < best.threads-1; i++) { 245 globalStack.push(null); 246 } 247 best.decIdle(); 248 break; //return; 249 } 250 o = globalStack.pop(); 251 best.decIdle(); 252 } catch (InterruptedException e) { 253 e.printStackTrace(); 254 running = false; 255 } 256 } else { 257 o = stack.remove( stack.size()-1 ); 258 } 259 if ( o == null ) { 260 break; //return; 261 } 262 Path path = (Path)o; 263 getBest( path ); 264 } 265 System.out.println("iterations = " + iter + " pushes " + pushes); 266 } 267 268 269 /** 270 * @param path a starting path. 271 */ 272 public void getBest(Path path) { 273 Path[] ps = path.nextPaths(); 274 iter += ps.length; 275 double bestCost = best.getPath().cost(); 276 if ( path.length()+1 == path.maxsize() ) { 277 for ( int i = 0; i < ps.length; i++ ) { // branch 278 if ( ps[i].cost() < bestCost ) { 279 synchronized ( best ) { 280 if ( ps[i].cost() < best.getPath().cost() ) { 281 bestCost = ps[i].cost(); 282 best.setPath( ps[i] ); 283 System.out.println("par best = " + ps[i]); 284 } 285 } 286 } 287 } 288 return; 289 } 290 if ( iter >= maxiter ) { 291 return; 292 } 293 if ( path.length()+5 >= path.maxsize() ) { 294 for ( int i = 0; i < ps.length; i++ ) { // branch 295 if ( ps[i].cost() < bestCost ) { // cut 296 //System.out.print("#"); 297 getBestRec( ps[i].copyMax(), path.length()+1 ); // changes best and bestPath 298 //stack.add( ps[i] ); 299 } 300 } 301 return; 302 } 303 for ( int i = 0; i < ps.length; i++ ) { // branch 304 if ( ps[i].cost() < bestCost ) { // cut 305 // getBest( ps[i] ); // changes best and bestPath 306 //System.out.print("-"); 307 stack.add( ps[i] ); 308 } 309 } 310 if ( stack.size() > COUNT && path.length() <= 3 ) { 311 if ( globalStack.empty() ) { 312 Object o = stack.remove( 0 ); //stack.size()-1, depth first 313 pushes++; 314 try { 315 globalStack.push( o ); // beware of deadlock 316 } catch (InterruptedException e) { 317 e.printStackTrace(); 318 } 319 } 320 } 321 return; 322 } 323 324 /** 325 * @param path a starting path. 326 * @param depth length of this path. 327 */ 328 public void getBestRec(Path path, int depth) { 329 double bestCost = best.getPath().cost(); 330 for ( int k = 0; k < path.maxsize()-depth; k++ ) { // branch 331 Path ps = path.nextPath(k); 332 iter++; 333 if ( depth+1 == path.maxsize() ) { 334 if ( ps.cost() < bestCost ) { 335 synchronized ( best ) { 336 if ( ps.cost() < best.getPath().cost() ) { 337 bestCost = ps.cost(); 338 best.setPath( (Path)ps.clone() ); // had error 339 System.out.println("par best rec = " + ps); 340 } 341 } 342 } 343 } 344 if ( iter >= maxiter ) { 345 return; 346 } 347 if ( ps.cost() < bestCost ) { // cut 348 getBestRec( ps, depth+1 ); // changes best and bestPath 349 //stack.add( ps[i] ); 350 } 351 } 352 return; 353 } 354 355 /** 356 * @return iter. 357 */ 358 public long getIterations() { 359 return iter; 360 } 361 362 /** 363 * @return maxiter. 364 */ 365 public long getMaxIterations() { 366 return maxiter; 367 } 368 369 /** 370 * @param m new maxIter. 371 * @return old maxIter. 372 */ 373 public long setMaxIterations(long m){ 374 long x = maxiter; 375 maxiter = m; 376 return x; 377 } 378 379 }