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 }