001 002 package gui; 003 004 import java.util.Random; 005 import java.io.IOException; 006 import java.io.Serializable; 007 008 import java.awt.event.ActionListener; 009 import java.awt.event.ActionEvent; 010 011 import javax.swing.Timer; 012 //import javax.swing.SwingUtilities; 013 014 import comm.ExecutableServer; 015 import thread.ThreadPool; 016 import comm.ChannelFactory; 017 import comm.SocketChannel; 018 import comm.RemoteExecutable; 019 import algo.Point; 020 import algo.Graph; 021 import algo.Path; 022 import algo.PathByteArray; 023 import algo.PlaneGraph; 024 import algo.TSPInf; 025 import algo.DistTSP; 026 import algo.ParByteLocalTSP; 027 import algo.SeqByteTSP; 028 029 /** 030 * Model class to be viewed and controled by the GUI. 031 * @author Heinz Kredel. 032 */ 033 public class TSPguiModel { 034 035 protected String algorithm = "sequential"; 036 protected int algo = 0; 037 protected String server = "localhost"; 038 protected int port = 9000; 039 protected boolean standAlone = false; 040 protected ExecutableServer es = null; 041 042 043 protected int probSize; 044 protected Point[] points = null; 045 protected Graph graph = null; 046 protected Point[] scaledPoints = null; 047 protected boolean isBestPath = false; 048 protected Path bestPath = null; 049 protected Path actualBestPath = null; 050 protected long iter; 051 protected long maxIter; 052 protected int numThread; 053 protected double iterPercent; 054 055 protected boolean done; 056 private TSPModelConnectThread thread = null; 057 private Timer wecker = null; 058 private TSPguiUpdate updater = null; 059 060 public TSPguiModel() { 061 probSize = 12; 062 done = false; 063 iter = 0l; 064 maxIter = Long.MAX_VALUE; 065 numThread = 1; 066 iterPercent = 0.0; 067 } 068 069 public void generateProblem() { 070 assureStopped(); 071 points = new Point[probSize]; 072 double m = 100; 073 Random r = new Random(); 074 double mx = 0.0; 075 for ( int i = 0; i < probSize; i++ ) { 076 Point p = Point.random(i,r,m); 077 points[i] = p; 078 if ( p.x > mx ) { 079 mx = p.x; 080 } 081 if ( p.y > mx ) { 082 mx = p.y; 083 } 084 } 085 graph = new PlaneGraph(points); 086 scaledPoints = new Point[probSize]; 087 double scale = 1.0 / mx; 088 for ( int i = 0; i < probSize; i++ ) { 089 scaledPoints[i] = Point.scaleTo(points[i],scale); 090 } 091 iter = 0l; 092 bestPath = PathByteArray.standardPath(graph); 093 actualBestPath = bestPath; 094 isBestPath = false; 095 doStatus(); 096 } 097 098 public void solveProblem() { 099 if ( points == null ) { 100 return; 101 } 102 assureStopped(); 103 if ( standAlone && "localhost".equals(server) ) { 104 if ( es == null ) { 105 es = new ExecutableServer(port); 106 System.out.println("es = "+es); 107 es.start(); 108 } 109 } 110 thread = new TSPModelConnectThread(points, 111 algo, 112 numThread, 113 maxIter, 114 server, 115 port, 116 this); 117 thread.start(); 118 } 119 120 /** 121 * @return true if thread is running, else false. 122 */ 123 public boolean isRunning() { 124 if ( thread == null ) { 125 return false; 126 } 127 return thread.isRunning(); 128 } 129 130 // todo: collect history 131 public void waitProblem() { 132 if ( thread == null ) { 133 return; 134 } 135 try { 136 thread.join(); 137 thread = null; 138 } catch (InterruptedException ignored) { 139 } 140 // doStatus(); 141 } 142 143 public void assureStopped() { 144 if ( thread != null ) { 145 if ( thread.isRunning() ) { 146 long curi = thread.getIterations() / numThread; 147 thread.setMaxIterations(curi); 148 //waitProblem(); 149 thread = null; 150 } 151 } 152 } 153 154 public void stopProblem() { 155 if ( thread == null ) { 156 return; 157 } 158 ActionListener joiner = new ActionListener() { 159 public void actionPerformed(ActionEvent evt) { 160 if ( wecker != null ) { 161 wecker.stop(); 162 } 163 assureStopped(); 164 } 165 }; 166 if ( wecker != null ) { 167 wecker.stop(); 168 } 169 wecker = new Timer(100, joiner); 170 //wecker.setLogTimers(true); 171 wecker.setRepeats(false); 172 wecker.start(); 173 } 174 175 176 /** 177 * @return points of the cities. 178 */ 179 public Point[] getPoints() { 180 return points; 181 } 182 183 /** 184 * @return scaled points of the cities, i.e. all coordiates lie within 0.0 and 1.0. 185 */ 186 public Point[] getScaledPoints() { 187 return scaledPoints; 188 } 189 190 /** 191 * @return the graph. 192 */ 193 public Graph getGraph() { 194 return graph; 195 } 196 197 /** 198 * @return true if the actual path is the best path, else false. 199 */ 200 public boolean isBestPath() { 201 return isBestPath; 202 } 203 204 /** 205 * @return return best path if known. 206 */ 207 public Path getBestPath() { 208 if ( thread != null ) { 209 bestPath = thread.getBestPath(); 210 isBestPath = thread.isBestPath(); 211 } 212 return bestPath; 213 } 214 215 /** 216 * @return return actual best path 217 */ 218 public Path getActualBestPath() { 219 if ( thread != null ) { 220 actualBestPath = thread.getActualBestPath(); 221 isBestPath = thread.isBestPath(); 222 } 223 return actualBestPath; 224 } 225 226 /** 227 * @return number of threads used. 228 */ 229 public int getThreads() { 230 return numThread; 231 } 232 233 /** 234 * @param n number of threads to be used. 235 */ 236 public void setThreads(int n) { 237 numThread = n; 238 } 239 240 /** 241 * @return iteration count. 242 */ 243 public long getIterations() { 244 if ( thread != null ) { 245 iter = thread.getIterations(); 246 } 247 return iter; 248 } 249 250 /** 251 * @return maximal iteration count. 252 */ 253 public long getMaxIterations() { 254 if ( thread != null ) { 255 maxIter = thread.getMaxIterations(); 256 } 257 return maxIter; 258 } 259 260 /** 261 * @return per centage of used iterations of total number of possible paths. 262 */ 263 public double getIterPercent() { 264 iter = getIterations(); 265 double ip = 100.0*((double)iter)/((double)facul(points.length-1)); 266 iterPercent = ((int)(ip*100.0))/100.0; 267 return iterPercent; 268 } 269 270 /** 271 * @param n input. 272 * @return n * facul( n-1 ). 273 */ 274 protected long facul(long n) { 275 if ( n <= 1l ) { 276 return 1l; 277 } 278 return n * facul( n-1 ); 279 } 280 281 /** 282 * Set maximal iteration count. 283 * @param m new maximal iteration count. 284 * @return old maximal iteration count. 285 */ 286 public long setMaxIterations(long m){ 287 maxIter = m; 288 if ( thread == null ) { 289 return 0l; 290 } 291 return thread.setMaxIterations(m); 292 } 293 294 /** 295 * @return true if user requests exit. 296 */ 297 public boolean isDone() { 298 return done; 299 } 300 301 public synchronized void setDone() { 302 // do cleanup 303 assureStopped(); 304 if ( es != null ) { 305 es.terminate(); 306 try { 307 es.join(); 308 } catch (InterruptedException ignored) { 309 } 310 } 311 done = true; 312 notify(); 313 } 314 315 public synchronized void waitDone() { 316 if ( done ) { 317 return; 318 } 319 try { 320 wait(); 321 } catch(InterruptedException ignored) { 322 } 323 } 324 325 /** 326 * @return problem size, i.e. number of points / nodes / cities. 327 */ 328 public int getProbSize() { 329 return probSize; 330 } 331 332 /** 333 * @param s new problem size. 334 */ 335 public void setProbSize(int s) { 336 probSize = s; 337 } 338 339 /** 340 * @return the algorithm to be used. 341 */ 342 public String getAlgorithm() { 343 return algorithm; 344 } 345 346 /** 347 * @param alg the new algorithm to be used. 348 */ 349 public void setAlgorithm(String alg) { 350 int a = -1; 351 if ( alg == null ) { 352 return; 353 } 354 if ( alg.compareToIgnoreCase("sequential") == 0 ) { 355 // setThreads(1); doUpdate(); 356 a = 0; 357 } 358 if ( alg.compareToIgnoreCase("parallel") == 0 ) { 359 //if ( getThreads() <= 1 ) { 360 // setThreads(4); doUpdate(); 361 //} 362 a = 1; 363 } 364 if ( alg.compareToIgnoreCase("distributed") == 0 ) { 365 //if ( getThreads() <= 1 ) { 366 // setThreads(2); doUpdate(); 367 //} 368 a = 2; 369 } 370 if ( a >= 0 ) { 371 algo = a; 372 algorithm = alg; 373 } 374 } 375 376 /** 377 * @return name of compute server. 378 */ 379 public String getServer() { 380 return server; 381 } 382 383 /** 384 * @param s name of compute server. 385 */ 386 public void setServer(String s) { 387 server = s; 388 } 389 390 /** 391 * @return port of compute server. 392 */ 393 public int getPort() { 394 return port; 395 } 396 397 /** 398 * @param p port of compute server. 399 */ 400 public void setPort(int p) { 401 port = p; 402 } 403 404 /** 405 * @return true if no remote compute server should be used. 406 */ 407 public boolean getStandAlone() { 408 return standAlone; 409 } 410 411 /** 412 * @param a true if no remote compute server should be used. 413 */ 414 public void setStandAlone(boolean a) { 415 standAlone = a; 416 } 417 418 /** 419 * @param u the TSPguiUpdate. 420 */ 421 public void setUpdater(TSPguiUpdate u) { 422 updater = u; 423 } 424 425 public void doUpdate() { 426 if ( updater != null ) { 427 updater.modelUpdated(); 428 } 429 } 430 431 public void doStatus() { 432 if ( updater != null ) { 433 updater.modelStatus(); 434 } 435 } 436 437 } 438 439 /** 440 * Class to communicate with the thread on the compute server. 441 */ 442 class TSPModelConnectThread extends Thread { 443 444 private Point[] points; 445 private Path path; 446 private int numThread; 447 private int algo; 448 private long iter; 449 private long maxIter; 450 private long maxIterTemp; 451 private boolean isBestPath; 452 private String server = "localhost"; 453 private int port = 9000; 454 private String guiHost = "localhost"; 455 private int guiPort = 9009; 456 private int guiClientPort = port + 100; 457 private TSPguiModel model; 458 private ChannelFactory cf; 459 private SocketChannel comm = null; 460 private ThreadPool pool = null; 461 462 463 /** 464 * @param points array city coordinates. 465 * @param algo algorithm to use. 466 * @param threads number of thread to use. 467 * @param mit maximal iteration count. 468 * @param server host name of compute server. 469 * @param port of compute server. 470 * @param model the TSPguiModel. 471 */ 472 public TSPModelConnectThread(Point[] points, 473 int algo, 474 int threads, 475 long mit, 476 String server, 477 int port, 478 TSPguiModel model) { 479 this.points = points; 480 this.algo = algo; 481 this.numThread = threads; 482 this.model = model; 483 this.server = server; 484 this.port = port; 485 guiClientPort = port + 100; 486 path = null; 487 iter = 0l; 488 maxIter = mit; 489 isBestPath = false; 490 cf = new ChannelFactory(guiPort); 491 pool = new ThreadPool(3); 492 } 493 494 /* (non-Javadoc) 495 * @see java.lang.Runnable#run() 496 */ 497 public void run() { 498 SocketChannel sc = null; 499 try { 500 sc = cf.getChannel(server,port); 501 } catch (IOException e) { 502 e.printStackTrace(); 503 cf.terminate(); 504 return; 505 } 506 guiHost = sc.getSocket().getLocalAddress().getHostAddress(); 507 // guiPort = sc.getSocket().getLocalPort(); 508 //System.out.println("sc.getSocket() = " + sc.getSocket() 509 // + " guiHost = " + guiHost); 510 511 TSPModelRemote thread = new TSPModelRemote(points, 512 algo, 513 numThread, 514 maxIter, 515 guiHost, 516 guiPort, 517 guiClientPort); 518 try { 519 sc.send( thread ); 520 } catch (IOException e) { 521 e.printStackTrace(); 522 sc.close(); 523 cf.terminate(); 524 return; 525 } 526 try { 527 comm = cf.getChannel(server,guiClientPort); // wg firewall 528 // comm = cf.getChannel(); // @ guiPort 529 } catch (IOException e) { 530 e.printStackTrace(); 531 sc.close(); 532 cf.terminate(); 533 return; 534 } 535 Object o = null; 536 try { 537 o = sc.receive(); 538 } catch (IOException e) { 539 e.printStackTrace(); 540 } catch (ClassNotFoundException e) { 541 e.printStackTrace(); 542 } 543 if ( o != null ) { 544 if ( o instanceof String ) { 545 String s = (String)o; 546 if ( s.equals(ExecutableServer.DONE) ) { 547 System.out.println("normal end"); 548 } 549 } 550 } 551 sc.close(); 552 cf.terminate(); 553 model.doStatus(); 554 } 555 556 /** 557 * @return true if thread is runnning. 558 */ 559 public boolean isRunning() { 560 return (comm != null); 561 } 562 563 /** 564 * @return true if path is best path, else false. 565 */ 566 public boolean isBestPath() { 567 // communication done by getActualBestPath 568 return isBestPath; 569 } 570 571 /** 572 * @return iteration count. 573 */ 574 public long getIterations() { 575 // communication done by getActualBestPath 576 return iter; 577 } 578 579 /** 580 * @return actual best path. 581 */ 582 public Path getActualBestPath() { 583 if ( comm == null ) { 584 return path; 585 } 586 Runnable getter = new Runnable() { 587 public void run() { 588 Object o = sendReceive( new TransportContainer() ); 589 if ( o != null ) { 590 if ( o instanceof TransportContainerGet ) { 591 TransportContainerGet t = (TransportContainerGet)o; 592 path = t.path; 593 iter = t.iter; 594 isBestPath = t.best; 595 } 596 } 597 } 598 }; 599 pool.addJob( getter ); 600 return path; // tsp.actualBest(); 601 } 602 603 /** 604 * @return best known path. 605 */ 606 public Path getBestPath() { 607 if ( comm == null ) { 608 return path; 609 } 610 Runnable getter = new Runnable() { 611 public void run() { 612 Object o = sendReceive( new TransportContainer() ); 613 if ( o != null ) { 614 if ( o instanceof TransportContainerGet ) { 615 TransportContainerGet t = (TransportContainerGet)o; 616 path = t.path; 617 iter = t.iter; 618 isBestPath = t.best; 619 } 620 } 621 } 622 }; 623 pool.addJob( getter ); 624 return path; // tsp.getBest(); 625 } 626 627 /** 628 * @return maximal iteration count. 629 */ 630 public long getMaxIterations() { 631 if ( comm == null ) { 632 return maxIter; 633 } 634 Runnable getter = new Runnable() { 635 public void run() { 636 Object o = sendReceive( new TransportContainerMax(maxIter) ); 637 if ( o != null ) { 638 if ( o instanceof TransportContainerMax ) { 639 TransportContainerMax t = (TransportContainerMax)o; 640 maxIter = t.maxIter; 641 } 642 } 643 } 644 }; 645 pool.addJob( getter ); 646 return maxIter; // tsp.getmaxIterations(); 647 } 648 649 /** 650 * @param m new maximal iteration count. 651 * @return old maximal iteration count. 652 */ 653 public long setMaxIterations(final long m){ 654 maxIterTemp = maxIter; 655 maxIter = m; 656 if ( comm == null ) { 657 return maxIterTemp; 658 } 659 Runnable getter = new Runnable() { 660 public void run() { 661 Object o = sendReceive( new TransportContainerMax(maxIter) ); 662 if ( o != null ) { 663 if ( o instanceof TransportContainerMax ) { 664 TransportContainerMax t = (TransportContainerMax)o; 665 maxIterTemp = t.maxIter; 666 } 667 } 668 } 669 }; 670 pool.addJob( getter ); 671 return maxIterTemp; // tsp.setMaxIterations(m); 672 } 673 674 /** 675 * RPC style communication. 676 * @param m a TransportContainer. 677 * @return received Object. 678 */ 679 protected Object sendReceive(TransportContainer m) { 680 Object r = null; 681 try { 682 //synchronized( comm ) { 683 comm.send( m ); 684 //} 685 r = comm.receive(); 686 } catch (IOException e) { 687 //e.printStackTrace(); 688 } catch (ClassNotFoundException e) { 689 //e.printStackTrace(); 690 } 691 return r; 692 } 693 694 } 695 696 697 /** 698 * Objects send to the compute server to execute TSP algorithm. 699 */ 700 class TSPModelRemote implements RemoteExecutable { 701 702 private Point[] points; 703 private Path path; 704 private int threads; 705 private int algo; 706 private TSPInf tsp = null; 707 private long iter; 708 private long maxIter; 709 private boolean isBestPath; 710 private String guiHost = "localhost"; 711 private int guiPort = 9009; 712 private int guiClientPort = 9100; 713 714 /** 715 * @param points array of cities. 716 * @param algo algorithm. 717 * @param threads number of threads. 718 * @param mit maximal iterations. 719 * @param guiHost host name of gui server. Unused because of firewalls. 720 * @param guiPort port of gui server. Unused because of firewalls. 721 * @param guiClientPort port at compute server. 722 */ 723 public TSPModelRemote(Point[] points, 724 int algo, 725 int threads, 726 long mit, 727 String guiHost, 728 int guiPort, 729 int guiClientPort) { 730 this.points = points; 731 this.algo = algo; 732 this.threads = threads; 733 this.guiHost = guiHost; 734 this.guiPort = guiPort; 735 this.guiClientPort = guiClientPort; 736 path = null; 737 iter = 0l; 738 maxIter = mit; 739 isBestPath = false; 740 } 741 742 public void run() { 743 TSPModelCommRemote communi = new TSPModelCommRemote(this, 744 guiHost, 745 guiPort, 746 guiClientPort); 747 communi.start(); 748 switch ( algo ) { 749 case 0: tsp = new SeqByteTSP(points); 750 break; 751 case 1: tsp = new ParByteLocalTSP(points,threads); 752 break; 753 case 2: tsp = new DistTSP(points,threads); 754 break; 755 default: tsp = new SeqByteTSP(points); 756 } 757 long mi = maxIter; 758 path = tsp.getBest(maxIter); // blocks 759 if ( mi <= maxIter ) { 760 isBestPath = true; 761 //System.out.println("isBestPath = " + isBestPath ); 762 } 763 // model.doStatus(); 764 tsp = null; 765 communi.terminate(); 766 } 767 768 /** 769 * @return true if tsp is executing. 770 */ 771 public boolean isRunning() { 772 return (tsp != null); 773 } 774 775 /** 776 * @return best known path. 777 */ 778 public Path getBestPath() { 779 return path; 780 } 781 782 /** 783 * @return true if path is best path. 784 */ 785 public boolean isBestPath() { 786 return isBestPath; 787 } 788 789 /** 790 * @return actual best path. 791 */ 792 public Path getActualBestPath() { 793 if ( tsp == null ) { 794 return path; 795 } 796 return tsp.actualBest(); 797 } 798 799 /** 800 * @return iteration count. 801 */ 802 public long getIterations() { 803 if ( tsp != null ) { 804 iter = tsp.getIterations(); 805 } 806 return iter; 807 } 808 809 /** 810 * @return maximal iteration count. 811 */ 812 public long getMaxIterations() { 813 if ( tsp != null ) { 814 return tsp.getMaxIterations(); 815 } 816 return maxIter; 817 } 818 819 /** 820 * @param m new maximal iteration count. 821 * @return old maximal iteration count. 822 */ 823 public long setMaxIterations(long m){ 824 long x = maxIter; 825 maxIter = m; 826 if ( tsp != null ) { 827 x = tsp.setMaxIterations(m); 828 } 829 return x; 830 } 831 832 } 833 834 835 /** 836 * Container for transport of path, iterations, etc. 837 */ 838 class TransportContainer implements Serializable { 839 public TransportContainer() { 840 } 841 } 842 843 /** 844 * Get message. 845 */ 846 class TransportContainerGet extends TransportContainer { 847 final Path path; 848 final long iter; 849 final boolean best; 850 851 /** 852 * @param p a path. 853 * @param i iteration count. 854 * @param b true if p is best path. 855 */ 856 public TransportContainerGet(Path p, long i, boolean b) { 857 super(); 858 path = p; 859 iter = i; 860 best = b; 861 } 862 } 863 864 /** 865 * Set maximal iteration count message. 866 */ 867 class TransportContainerMax extends TransportContainer { 868 final long maxIter; 869 870 /** 871 * @param m maximal iteration count. 872 */ 873 public TransportContainerMax(long m) { 874 super(); 875 maxIter = m; 876 } 877 } 878 879 880 /** 881 * Class to communicate with the gui server. 882 */ 883 class TSPModelCommRemote extends Thread { 884 /* 885 public static final String COMM_getActualBestPath = "getActualBestPath"; 886 public static final String COMM_getBestPath = "getBestPath"; 887 public static final String COMM_getMaxIterations = "getMaxIterations"; 888 public static final String COMM_setMaxIterations = "setMaxIterations"; 889 */ 890 private TSPModelRemote rem; 891 private SocketChannel comm; 892 private String guiHost = "localhost"; 893 private int guiPort = 9009; 894 private int guiClientPort = 9100; 895 896 /** 897 * @param rem master process for call back. 898 * @param guiHost host name of gui server. Unused because of firewalls. 899 * @param guiPort port of gui server. Unused because of firewalls. 900 * @param guiClientPort my local port for communication with gui. 901 */ 902 public TSPModelCommRemote(TSPModelRemote rem, 903 String guiHost, 904 int guiPort, 905 int guiClientPort) { 906 this.rem = rem; 907 this.guiHost = guiHost; 908 this.guiPort = guiPort; 909 this.guiClientPort = guiClientPort; 910 ChannelFactory cf = new ChannelFactory(guiClientPort); 911 try { 912 //comm = cf.getChannel(guiHost,guiPort); 913 comm = cf.getChannel(); // wg. firewall 914 } catch (InterruptedException e) { 915 e.printStackTrace(); 916 return; 917 } 918 cf.terminate(); 919 } 920 921 public void terminate() { 922 try { // wg isBestPath before comm.close() 923 Thread.sleep(200); 924 } catch (InterruptedException e) { 925 } 926 if ( comm != null ) { 927 comm.close(); 928 } 929 try { 930 while ( this.isAlive() ) { 931 //System.out.print("."); 932 this.interrupt(); 933 this.join(100); 934 } 935 //System.out.println("TSPModelCommRemote terminated"); 936 } catch (InterruptedException e) { 937 } 938 } 939 940 public void run() { 941 if ( comm == null ) { 942 return; 943 } 944 while ( true ) { // protocoll: receive send 945 Object m = null; 946 try { 947 m = comm.receive(); 948 } catch (IOException e) { 949 //e.printStackTrace(); 950 } catch (ClassNotFoundException e) { 951 e.printStackTrace(); 952 } 953 //System.out.println("TSPModelCommRemote, receive = " + o); 954 if ( m == null ) { 955 break; 956 } 957 if ( ! (m instanceof TransportContainer) ) { 958 break; 959 } 960 TransportContainer t = (TransportContainer)m; 961 Object response = null; 962 if ( t instanceof TransportContainerMax ) { 963 TransportContainerMax x = (TransportContainerMax)t; 964 long ml = x.maxIter; 965 response = new TransportContainerMax( 966 rem.setMaxIterations(ml) 967 ); 968 } else { 969 // TransportContainerGet g = (TransportContainerGet)t; 970 response = new TransportContainerGet( 971 rem.getActualBestPath(), 972 rem.getIterations(), 973 rem.isBestPath() 974 ); 975 //} else if ( t instanceof TransportContainerGet ) { 976 } 977 try { 978 comm.send( response ); 979 } catch (IOException e) { 980 //e.printStackTrace(); 981 break; 982 } 983 } 984 System.out.println("TSPModelCommRemote done"); 985 comm.close(); 986 } 987 988 }