001/* 002 * $Id: GroebnerBaseDistributedHybridEC.java 5869 2018-07-20 15:53:10Z kredel $ 003 */ 004 005package edu.jas.gb; 006 007 008import java.io.IOException; 009import java.util.ArrayList; 010import java.util.Collections; 011import java.util.List; 012import java.util.ListIterator; 013import java.util.concurrent.atomic.AtomicInteger; 014 015import org.apache.logging.log4j.Logger; 016import org.apache.logging.log4j.LogManager; 017 018import edu.jas.poly.ExpVector; 019import edu.jas.poly.GenPolynomial; 020import edu.jas.poly.GenPolynomialRing; 021import edu.jas.poly.PolyUtil; 022import edu.jas.structure.RingElem; 023import edu.jas.util.ChannelFactory; 024import edu.jas.util.DistHashTable; 025import edu.jas.util.DistHashTableServer; 026import edu.jas.util.DistThreadPool; 027import edu.jas.util.RemoteExecutable; 028import edu.jas.util.SocketChannel; 029import edu.jas.util.TaggedSocketChannel; 030import edu.jas.util.Terminator; 031import edu.jas.util.ThreadPool; 032 033 034/** 035 * Groebner Base distributed hybrid algorithm. Implements a distributed memory 036 * with multi-core CPUs parallel version of Groebner bases with executable 037 * channels. Using pairlist class, distributed multi-threaded tasks do 038 * reduction, one communication channel per remote node. 039 * @param <C> coefficient type 040 * @author Heinz Kredel 041 */ 042 043public class GroebnerBaseDistributedHybridEC<C extends RingElem<C>> extends GroebnerBaseAbstract<C> { 044 045 046 private static final Logger logger = LogManager.getLogger(GroebnerBaseDistributedHybridEC.class); 047 048 049 private static final boolean debug = logger.isDebugEnabled(); 050 051 052 /** 053 * Number of threads to use. 054 */ 055 protected final int threads; 056 057 058 /** 059 * Default number of threads. 060 */ 061 protected static final int DEFAULT_THREADS = 2; 062 063 064 /** 065 * Number of threads per node to use. 066 */ 067 protected final int threadsPerNode; 068 069 070 /** 071 * Default number of threads per compute node. 072 */ 073 protected static final int DEFAULT_THREADS_PER_NODE = 1; 074 075 076 /** 077 * Pool of threads to use. 078 */ 079 //protected final ExecutorService pool; // not for single node tests 080 protected transient final ThreadPool pool; 081 082 083 /** 084 * Default server port. 085 */ 086 protected static final int DEFAULT_PORT = 55711; 087 088 089 /** 090 * Default distributed hash table server port. 091 */ 092 protected final int DHT_PORT; 093 094 095 /** 096 * machine file to use. 097 */ 098 protected final String mfile; 099 100 101 /** 102 * Server port to use. 103 */ 104 protected final int port; 105 106 107 /** 108 * Distributed thread pool to use. 109 */ 110 private final transient DistThreadPool dtp; 111 112 113 /** 114 * Distributed hash table server to use. 115 */ 116 private final transient DistHashTableServer<Integer> dhts; 117 118 119 /** 120 * Message tag for pairs. 121 */ 122 public static final Integer pairTag = Integer.valueOf(1); 123 124 125 /** 126 * Message tag for results. 127 */ 128 public static final Integer resultTag = Integer.valueOf(2); 129 130 131 /** 132 * Message tag for acknowledgments. 133 */ 134 public static final Integer ackTag = Integer.valueOf(3); 135 136 137 /** 138 * Constructor. 139 * @param mfile name of the machine file. 140 */ 141 public GroebnerBaseDistributedHybridEC(String mfile) { 142 this(mfile, DEFAULT_THREADS, DEFAULT_PORT); 143 } 144 145 146 /** 147 * Constructor. 148 * @param mfile name of the machine file. 149 * @param threads number of threads to use. 150 */ 151 public GroebnerBaseDistributedHybridEC(String mfile, int threads) { 152 this(mfile, threads, new ThreadPool(threads), DEFAULT_PORT); 153 } 154 155 156 /** 157 * Constructor. 158 * @param mfile name of the machine file. 159 * @param threads number of threads to use. 160 * @param port server port to use. 161 */ 162 public GroebnerBaseDistributedHybridEC(String mfile, int threads, int port) { 163 this(mfile, threads, new ThreadPool(threads), port); 164 } 165 166 167 /** 168 * Constructor. 169 * @param mfile name of the machine file. 170 * @param threads number of threads to use. 171 * @param threadsPerNode threads per node to use. 172 * @param port server port to use. 173 */ 174 public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, int port) { 175 this(mfile, threads, threadsPerNode, new ThreadPool(threads), port); 176 } 177 178 179 /** 180 * Constructor. 181 * @param mfile name of the machine file. 182 * @param threads number of threads to use. 183 * @param pool ThreadPool to use. 184 * @param port server port to use. 185 */ 186 public GroebnerBaseDistributedHybridEC(String mfile, int threads, ThreadPool pool, int port) { 187 this(mfile, threads, DEFAULT_THREADS_PER_NODE, pool, port); 188 } 189 190 191 /** 192 * Constructor. 193 * @param mfile name of the machine file. 194 * @param threads number of threads to use. 195 * @param threadsPerNode threads per node to use. 196 * @param pl pair selection strategy 197 * @param port server port to use. 198 */ 199 public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, PairList<C> pl, 200 int port) { 201 this(mfile, threads, threadsPerNode, new ThreadPool(threads), pl, port); 202 } 203 204 205 /** 206 * Constructor. 207 * @param mfile name of the machine file. 208 * @param threads number of threads to use. 209 * @param threadsPerNode threads per node to use. 210 * @param port server port to use. 211 */ 212 public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, ThreadPool pool, 213 int port) { 214 this(mfile, threads, threadsPerNode, pool, new OrderedPairlist<C>(), port); 215 } 216 217 218 /** 219 * Constructor. 220 * @param mfile name of the machine file. 221 * @param threads number of threads to use. 222 * @param threadsPerNode threads per node to use. 223 * @param pool ThreadPool to use. 224 * @param pl pair selection strategy 225 * @param port server port to use. 226 */ 227 public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, ThreadPool pool, 228 PairList<C> pl, int port) { 229 super(new ReductionPar<C>(), pl); 230 this.threads = threads; 231 if (mfile == null || mfile.length() == 0) { 232 this.mfile = "../util/machines"; // contains localhost 233 } else { 234 this.mfile = mfile; 235 } 236 if (threads < 1) { 237 threads = 1; 238 } 239 this.threadsPerNode = threadsPerNode; 240 if (pool == null) { 241 pool = new ThreadPool(threads); 242 } 243 this.pool = pool; 244 this.port = port; 245 logger.info("machine file " + mfile + ", port = " + port); 246 this.dtp = new DistThreadPool(this.threads, this.mfile); 247 logger.info("running " + dtp); 248 this.DHT_PORT = this.dtp.getEC().getMasterPort() + 100; 249 this.dhts = new DistHashTableServer<Integer>(this.DHT_PORT); 250 this.dhts.init(); 251 logger.info("running " + dhts); 252 } 253 254 255 /** 256 * Cleanup and terminate ThreadPool. 257 */ 258 @Override 259 public void terminate() { 260 terminate(true); 261 } 262 263 264 /** 265 * Terminates the distributed thread pools. 266 * @param shutDown true, if shut-down of the remote executable servers is 267 * requested, false, if remote executable servers stay alive. 268 */ 269 public void terminate(boolean shutDown) { 270 pool.terminate(); 271 dtp.terminate(shutDown); 272 logger.info("dhts.terminate()"); 273 dhts.terminate(); 274 } 275 276 277 /** 278 * Distributed Groebner base. 279 * @param modv number of module variables. 280 * @param F polynomial list. 281 * @return GB(F) a Groebner base of F or null, if a IOException occurs. 282 */ 283 public List<GenPolynomial<C>> GB(int modv, List<GenPolynomial<C>> F) { 284 List<GenPolynomial<C>> Fp = normalizeZerosOnes(F); 285 Fp = PolyUtil.<C> monic(Fp); 286 if (Fp.size() <= 1) { 287 return Fp; 288 } 289 if (!Fp.get(0).ring.coFac.isField()) { 290 throw new IllegalArgumentException("coefficients not from a field"); 291 } 292 293 String master = dtp.getEC().getMasterHost(); 294 //int port = dtp.getEC().getMasterPort(); // wrong port 295 GBHybridExerClient<C> gbc = new GBHybridExerClient<C>(master, threadsPerNode, port, DHT_PORT); 296 for (int i = 0; i < threads; i++) { 297 // schedule remote clients 298 dtp.addJob(gbc); 299 } 300 // run master 301 List<GenPolynomial<C>> G = GBMaster(modv, Fp); 302 return G; 303 } 304 305 306 /** 307 * Distributed hybrid Groebner base. 308 * @param modv number of module variables. 309 * @param F non empty monic polynomial list without zeros. 310 * @return GB(F) a Groebner base of F or null, if a IOException occurs. 311 */ 312 List<GenPolynomial<C>> GBMaster(int modv, List<GenPolynomial<C>> F) { 313 long t = System.currentTimeMillis(); 314 ChannelFactory cf = new ChannelFactory(port); 315 cf.init(); 316 317 List<GenPolynomial<C>> G = F; 318 if (G.isEmpty()) { 319 throw new IllegalArgumentException("empty polynomial list not allowed"); 320 } 321 GenPolynomialRing<C> ring = G.get(0).ring; 322 PairList<C> pairlist = strategy.create(modv, ring); 323 pairlist.put(G); 324 325 /* 326 GenPolynomial<C> p; 327 List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>(); 328 PairList<C> pairlist = null; 329 boolean oneInGB = false; 330 int l = F.size(); 331 int unused; 332 ListIterator<GenPolynomial<C>> it = F.listIterator(); 333 while (it.hasNext()) { 334 p = it.next(); 335 if (p.length() > 0) { 336 p = p.monic(); 337 if (p.isONE()) { 338 oneInGB = true; 339 G.clear(); 340 G.add(p); 341 //return G; must signal termination to others 342 } 343 if (!oneInGB) { 344 G.add(p); 345 } 346 if (pairlist == null) { 347 //pairlist = new OrderedPairlist<C>(modv, p.ring); 348 pairlist = strategy.create(modv, p.ring); 349 if (!p.ring.coFac.isField()) { 350 throw new IllegalArgumentException("coefficients not from a field"); 351 } 352 } 353 // theList not updated here 354 if (p.isONE()) { 355 unused = pairlist.putOne(); 356 } else { 357 unused = pairlist.put(p); 358 } 359 } else { 360 l--; 361 } 362 } 363 //if (l <= 1) { 364 //return G; must signal termination to others 365 //} 366 */ 367 logger.info("start " + pairlist); 368 DistHashTable<Integer, GenPolynomial<C>> theList = new DistHashTable<Integer, GenPolynomial<C>>( 369 "localhost", DHT_PORT); 370 theList.init(); 371 List<GenPolynomial<C>> al = pairlist.getList(); 372 for (int i = 0; i < al.size(); i++) { 373 // no wait required 374 GenPolynomial<C> nn = theList.put(Integer.valueOf(i), al.get(i)); 375 if (nn != null) { 376 logger.info("double polynomials " + i + ", nn = " + nn + ", al(i) = " + al.get(i)); 377 } 378 } 379 380 Terminator finner = new Terminator(threads * threadsPerNode); 381 HybridReducerServerEC<C> R; 382 logger.info("using pool = " + pool); 383 for (int i = 0; i < threads; i++) { 384 R = new HybridReducerServerEC<C>(threadsPerNode, finner, cf, theList, pairlist); 385 pool.addJob(R); 386 //logger.info("server submitted " + R); 387 } 388 logger.info("main loop waiting " + finner); 389 finner.waitDone(); 390 int ps = theList.size(); 391 logger.info("#distributed list = " + ps); 392 // make sure all polynomials arrived: not needed in master 393 // G = (ArrayList)theList.values(); 394 G = pairlist.getList(); 395 if (ps != G.size()) { 396 logger.info("#distributed list = " + theList.size() + " #pairlist list = " + G.size()); 397 } 398 for (GenPolynomial<C> q : theList.getValueList()) { 399 if (debug && q != null && !q.isZERO()) { 400 logger.debug("final q = " + q.leadingExpVector()); 401 } 402 } 403 logger.debug("distributed list end"); 404 long time = System.currentTimeMillis(); 405 List<GenPolynomial<C>> Gp; 406 Gp = minimalGB(G); // not jet distributed but threaded 407 time = System.currentTimeMillis() - time; 408 logger.debug("parallel gbmi time = " + time); 409 G = Gp; 410 logger.debug("server cf.terminate()"); 411 cf.terminate(); 412 logger.debug("server theList.terminate() " + theList.size()); 413 theList.clear(); 414 theList.terminate(); 415 t = System.currentTimeMillis() - t; 416 logger.info("server GB end, time = " + t + ", " + pairlist.toString()); 417 return G; 418 } 419 420 421 /** 422 * GB distributed client part. 423 * @param host the server runs on. 424 * @param port the server runs. 425 * @param dhtport of the DHT server. 426 * @throws IOException 427 */ 428 public static <C extends RingElem<C>> void clientPart(String host, int threadsPerNode, int port, 429 int dhtport) throws IOException { 430 ChannelFactory cf = new ChannelFactory(port + 10); // != port for localhost 431 cf.init(); 432 logger.info("clientPart connecting to " + host + ", port = " + port + ", dhtport = " + dhtport); 433 SocketChannel channel = cf.getChannel(host, port); 434 TaggedSocketChannel pairChannel = new TaggedSocketChannel(channel); 435 pairChannel.init(); 436 437 DistHashTable<Integer, GenPolynomial<C>> theList = new DistHashTable<Integer, GenPolynomial<C>>(host, 438 dhtport); 439 theList.init(); 440 441 ThreadPool pool = new ThreadPool(threadsPerNode); 442 logger.info("client using pool = " + pool); 443 for (int i = 0; i < threadsPerNode; i++) { 444 HybridReducerClientEC<C> Rr = new HybridReducerClientEC<C>(/*threadsPerNode,*/pairChannel, /*i,*/ 445 theList); 446 pool.addJob(Rr); 447 } 448 logger.debug("clients submitted"); 449 450 pool.terminate(); 451 logger.debug("client pool.terminate()"); 452 453 pairChannel.close(); 454 logger.debug("client pairChannel.close()"); 455 456 //master only: theList.clear(); 457 theList.terminate(); 458 cf.terminate(); 459 logger.info("client cf.terminate()"); 460 461 channel.close(); 462 logger.info("client channel.close()"); 463 return; 464 } 465 466 467 /** 468 * Minimal ordered groebner basis. 469 * @param Fp a Groebner base. 470 * @return a reduced Groebner base of Fp. 471 */ 472 @Override 473 public List<GenPolynomial<C>> minimalGB(List<GenPolynomial<C>> Fp) { 474 GenPolynomial<C> a; 475 ArrayList<GenPolynomial<C>> G; 476 G = new ArrayList<GenPolynomial<C>>(Fp.size()); 477 ListIterator<GenPolynomial<C>> it = Fp.listIterator(); 478 while (it.hasNext()) { 479 a = it.next(); 480 if (a.length() != 0) { // always true 481 // already monic a = a.monic(); 482 G.add(a); 483 } 484 } 485 if (G.size() <= 1) { 486 return G; 487 } 488 489 ExpVector e; 490 ExpVector f; 491 GenPolynomial<C> p; 492 ArrayList<GenPolynomial<C>> F; 493 F = new ArrayList<GenPolynomial<C>>(G.size()); 494 boolean mt; 495 496 while (G.size() > 0) { 497 a = G.remove(0); 498 e = a.leadingExpVector(); 499 500 it = G.listIterator(); 501 mt = false; 502 while (it.hasNext() && !mt) { 503 p = it.next(); 504 f = p.leadingExpVector(); 505 mt = e.multipleOf(f); 506 } 507 it = F.listIterator(); 508 while (it.hasNext() && !mt) { 509 p = it.next(); 510 f = p.leadingExpVector(); 511 mt = e.multipleOf(f); 512 } 513 if (!mt) { 514 F.add(a); 515 } else { 516 // System.out.println("dropped " + a.length()); 517 } 518 } 519 G = F; 520 if (G.size() <= 1) { 521 return G; 522 } 523 Collections.reverse(G); // important for lex GB 524 525 @SuppressWarnings("cast") 526 MiReducerServer<C>[] mirs = (MiReducerServer<C>[]) new MiReducerServer[G.size()]; 527 int i = 0; 528 F = new ArrayList<GenPolynomial<C>>(G.size()); 529 while (G.size() > 0) { 530 a = G.remove(0); 531 // System.out.println("doing " + a.length()); 532 List<GenPolynomial<C>> R = new ArrayList<GenPolynomial<C>>(G.size() + F.size()); 533 R.addAll(G); 534 R.addAll(F); 535 mirs[i] = new MiReducerServer<C>(R, a); 536 pool.addJob(mirs[i]); 537 i++; 538 F.add(a); 539 } 540 G = F; 541 F = new ArrayList<GenPolynomial<C>>(G.size()); 542 for (i = 0; i < mirs.length; i++) { 543 a = mirs[i].getNF(); 544 F.add(a); 545 } 546 return F; 547 } 548 549} 550 551 552/** 553 * Distributed server reducing worker proxy threads. 554 * @param <C> coefficient type 555 */ 556class HybridReducerServerEC<C extends RingElem<C>> implements Runnable { 557 558 559 private static final Logger logger = LogManager.getLogger(HybridReducerServerEC.class); 560 561 562 private static final boolean debug = logger.isDebugEnabled(); 563 564 565 private final Terminator finner; 566 567 568 private final ChannelFactory cf; 569 570 571 private TaggedSocketChannel pairChannel; 572 573 574 private final DistHashTable<Integer, GenPolynomial<C>> theList; 575 576 577 private final PairList<C> pairlist; 578 579 580 private final int threadsPerNode; 581 582 583 /** 584 * Message tag for pairs. 585 */ 586 public final Integer pairTag = GroebnerBaseDistributedHybridEC.pairTag; 587 588 589 /** 590 * Message tag for results. 591 */ 592 public final Integer resultTag = GroebnerBaseDistributedHybridEC.resultTag; 593 594 595 /** 596 * Message tag for acknowledgments. 597 */ 598 public final Integer ackTag = GroebnerBaseDistributedHybridEC.ackTag; 599 600 601 /** 602 * Constructor. 603 * @param tpn number of threads per node 604 * @param fin terminator 605 * @param cf channel factory 606 * @param dl distributed hash table 607 * @param L ordered pair list 608 */ 609 HybridReducerServerEC(int tpn, Terminator fin, ChannelFactory cf, 610 DistHashTable<Integer, GenPolynomial<C>> dl, PairList<C> L) { 611 threadsPerNode = tpn; 612 finner = fin; 613 this.cf = cf; 614 theList = dl; 615 pairlist = L; 616 //logger.info("reducer server created " + this); 617 } 618 619 620 /** 621 * Work loop. 622 * @see java.lang.Runnable#run() 623 */ 624 @Override 625 public void run() { 626 logger.info("reducer server running with " + cf); 627 SocketChannel channel = null; 628 try { 629 channel = cf.getChannel(); 630 pairChannel = new TaggedSocketChannel(channel); 631 pairChannel.init(); 632 } catch (InterruptedException e) { 633 logger.debug("get pair channel interrupted"); 634 e.printStackTrace(); 635 return; 636 } 637 if (debug) { 638 logger.info("pairChannel = " + pairChannel); 639 } 640 // record idle remote workers (minus one?) 641 //finner.beIdle(threadsPerNode-1); 642 finner.initIdle(threadsPerNode); 643 AtomicInteger active = new AtomicInteger(0); 644 645 // start receiver 646 HybridReducerReceiverEC<C> receiver = new HybridReducerReceiverEC<C>(/*threadsPerNode,*/finner, 647 active, pairChannel, theList, pairlist); 648 receiver.start(); 649 650 Pair<C> pair; 651 //boolean set = false; 652 boolean goon = true; 653 //int polIndex = -1; 654 int red = 0; 655 int sleeps = 0; 656 657 // while more requests 658 while (goon) { 659 // receive request if thread is reported incactive 660 logger.debug("receive request"); 661 Object req = null; 662 try { 663 req = pairChannel.receive(pairTag); 664 } catch (InterruptedException e) { 665 goon = false; 666 e.printStackTrace(); 667 } catch (IOException e) { 668 goon = false; 669 e.printStackTrace(); 670 } catch (ClassNotFoundException e) { 671 goon = false; 672 e.printStackTrace(); 673 } 674 //logger.info("received request, req = " + req); 675 if (req == null) { 676 goon = false; 677 break; 678 } 679 if (!(req instanceof GBTransportMessReq)) { 680 goon = false; 681 break; 682 } 683 684 // find pair and manage termination status 685 logger.debug("find pair"); 686 while (!pairlist.hasNext()) { // wait 687 if (!finner.hasJobs() && !pairlist.hasNext()) { 688 goon = false; 689 break; 690 } 691 try { 692 sleeps++; 693 if (sleeps % 3 == 0) { 694 logger.info("waiting for reducers, remaining = " + finner); 695 } 696 Thread.sleep(100); 697 } catch (InterruptedException e) { 698 goon = false; 699 break; 700 } 701 } 702 if (Thread.currentThread().isInterrupted()) { 703 goon = false; 704 break; 705 } 706 if (!pairlist.hasNext() && !finner.hasJobs()) { 707 logger.info("termination detection: no pairs and no jobs left"); 708 goon = false; 709 break; //continue; //break? 710 } 711 finner.notIdle(); // before pairlist get!! 712 pair = pairlist.removeNext(); 713 // send pair to client, even if null 714 if (debug) { 715 logger.info("active count = " + active.get()); 716 logger.info("send pair = " + pair); 717 } 718 GBTransportMess msg = null; 719 if (pair != null) { 720 msg = new GBTransportMessPairIndex(pair); //,pairlist.size()-1); // size-1 721 } else { 722 msg = new GBTransportMess(); // not End(); at this time 723 // goon ?= false; 724 } 725 try { 726 red++; 727 pairChannel.send(pairTag, msg); 728 @SuppressWarnings("unused") 729 int a = active.getAndIncrement(); 730 } catch (IOException e) { 731 e.printStackTrace(); 732 goon = false; 733 break; 734 } 735 //logger.debug("#distributed list = " + theList.size()); 736 } 737 logger.info("terminated, send " + red + " reduction pairs"); 738 739 /* 740 * send end mark to clients 741 */ 742 logger.debug("send end"); 743 try { 744 for (int i = 0; i < threadsPerNode; i++) { // -1 745 //do not wait: Object rq = pairChannel.receive(pairTag); 746 pairChannel.send(pairTag, new GBTransportMessEnd()); 747 } 748 // send also end to receiver 749 pairChannel.send(resultTag, new GBTransportMessEnd()); 750 //beware of race condition 751 } catch (IOException e) { 752 if (logger.isDebugEnabled()) { 753 e.printStackTrace(); 754 } 755 } 756 receiver.terminate(); 757 758 int d = active.get(); 759 if (d > 0) { 760 logger.info("remaining active tasks = " + d); 761 } 762 //logger.info("terminated, send " + red + " reduction pairs"); 763 pairChannel.close(); 764 logger.debug("redServ pairChannel.close()"); 765 finner.release(); 766 767 channel.close(); 768 logger.info("redServ channel.close()"); 769 } 770} 771 772 773/** 774 * Distributed server receiving worker thread. 775 * @param <C> coefficient type 776 */ 777class HybridReducerReceiverEC<C extends RingElem<C>> extends Thread { 778 779 780 private static final Logger logger = LogManager.getLogger(HybridReducerReceiverEC.class); 781 782 783 private static final boolean debug = logger.isDebugEnabled(); 784 785 786 private final DistHashTable<Integer, GenPolynomial<C>> theList; 787 788 789 private final PairList<C> pairlist; 790 791 792 private final TaggedSocketChannel pairChannel; 793 794 795 private final Terminator finner; 796 797 798 //private final int threadsPerNode; 799 800 801 private final AtomicInteger active; 802 803 804 private volatile boolean goon; 805 806 807 /** 808 * Message tag for pairs. 809 */ 810 public final Integer pairTag = GroebnerBaseDistributedHybridEC.pairTag; 811 812 813 /** 814 * Message tag for results. 815 */ 816 public final Integer resultTag = GroebnerBaseDistributedHybridEC.resultTag; 817 818 819 /** 820 * Message tag for acknowledgments. 821 */ 822 public final Integer ackTag = GroebnerBaseDistributedHybridEC.ackTag; 823 824 825 /** 826 * Constructor. 827 * @param fin terminator 828 * @param a active remote tasks count 829 * @param pc tagged socket channel 830 * @param dl distributed hash table 831 * @param L ordered pair list 832 */ 833 //param tpn number of threads per node 834 HybridReducerReceiverEC(/*int tpn,*/Terminator fin, AtomicInteger a, TaggedSocketChannel pc, 835 DistHashTable<Integer, GenPolynomial<C>> dl, PairList<C> L) { 836 active = a; 837 //threadsPerNode = tpn; 838 finner = fin; 839 pairChannel = pc; 840 theList = dl; 841 pairlist = L; 842 goon = true; 843 //logger.info("reducer server created " + this); 844 } 845 846 847 /** 848 * Work loop. 849 * @see java.lang.Thread#run() 850 */ 851 @Override 852 public void run() { 853 //Pair<C> pair = null; 854 GenPolynomial<C> H = null; 855 int red = 0; 856 int polIndex = -1; 857 //Integer senderId; // obsolete 858 859 // while more requests 860 while (goon) { 861 // receive request 862 logger.debug("receive result"); 863 //senderId = null; 864 Object rh = null; 865 try { 866 rh = pairChannel.receive(resultTag); 867 @SuppressWarnings("unused") 868 int i = active.getAndDecrement(); 869 } catch (InterruptedException e) { 870 goon = false; 871 //e.printStackTrace(); 872 //?? finner.initIdle(1); 873 break; 874 } catch (IOException e) { 875 e.printStackTrace(); 876 goon = false; 877 finner.initIdle(1); 878 break; 879 } catch (ClassNotFoundException e) { 880 e.printStackTrace(); 881 goon = false; 882 finner.initIdle(1); 883 break; 884 } 885 logger.info("received H polynomial"); 886 if (rh == null) { 887 if (this.isInterrupted()) { 888 goon = false; 889 finner.initIdle(1); 890 break; 891 } 892 //finner.initIdle(1); 893 } else if (rh instanceof GBTransportMessEnd) { // should only happen from server 894 logger.info("received GBTransportMessEnd"); 895 goon = false; 896 //?? finner.initIdle(1); 897 break; 898 } else if (rh instanceof GBTransportMessPoly) { 899 // update pair list 900 red++; 901 GBTransportMessPoly<C> mpi = (GBTransportMessPoly<C>) rh; 902 H = mpi.pol; 903 //senderId = mpi.threadId; 904 if (H != null) { 905 if (debug) { 906 logger.info("H = " + H.leadingExpVector()); 907 } 908 if (!H.isZERO()) { 909 if (H.isONE()) { 910 // finner.allIdle(); 911 polIndex = pairlist.putOne(); 912 theList.putWait(Integer.valueOf(polIndex), H); 913 //goon = false; must wait for other clients 914 //finner.initIdle(1); 915 //break; 916 } else { 917 polIndex = pairlist.put(H); 918 // use putWait ? but still not all distributed 919 //GenPolynomial<C> nn = 920 theList.putWait(Integer.valueOf(polIndex), H); 921 } 922 } 923 } 924 } 925 // only after recording in pairlist ! 926 finner.initIdle(1); 927 try { 928 pairChannel.send(ackTag, new GBTransportMess()); 929 logger.debug("send acknowledgement"); 930 } catch (IOException e) { 931 e.printStackTrace(); 932 goon = false; 933 break; 934 } 935 } // end while 936 goon = false; 937 logger.info("terminated, received " + red + " reductions"); 938 } 939 940 941 /** 942 * Terminate. 943 */ 944 public void terminate() { 945 goon = false; 946 //this.interrupt(); 947 try { 948 this.join(); 949 } catch (InterruptedException e) { 950 // unfug Thread.currentThread().interrupt(); 951 } 952 logger.debug("HybridReducerReceiver terminated"); 953 } 954 955} 956 957 958/** 959 * Distributed clients reducing worker threads. 960 */ 961class HybridReducerClientEC<C extends RingElem<C>> implements Runnable { 962 963 964 private static final Logger logger = LogManager.getLogger(HybridReducerClientEC.class); 965 966 967 private static final boolean debug = logger.isDebugEnabled(); 968 969 970 private final TaggedSocketChannel pairChannel; 971 972 973 private final DistHashTable<Integer, GenPolynomial<C>> theList; 974 975 976 private final ReductionPar<C> red; 977 978 979 //private final int threadsPerNode; 980 981 982 /* 983 * Identification number for this thread. 984 */ 985 //public final Integer threadId; // obsolete 986 987 988 /** 989 * Message tag for pairs. 990 */ 991 public final Integer pairTag = GroebnerBaseDistributedHybridEC.pairTag; 992 993 994 /** 995 * Message tag for results. 996 */ 997 public final Integer resultTag = GroebnerBaseDistributedHybridEC.resultTag; 998 999 1000 /** 1001 * Message tag for acknowledgments. 1002 */ 1003 public final Integer ackTag = GroebnerBaseDistributedHybridEC.ackTag; 1004 1005 1006 /** 1007 * Constructor. 1008 * @param tc tagged socket channel 1009 * @param dl distributed hash table 1010 */ 1011 //param tpn number of threads per node 1012 //param tid thread identification 1013 HybridReducerClientEC(/*int tpn,*/TaggedSocketChannel tc, /*Integer tid,*/ 1014 DistHashTable<Integer, GenPolynomial<C>> dl) { 1015 //threadsPerNode = tpn; 1016 pairChannel = tc; 1017 //threadId = 100 + tid; // keep distinct from other tags 1018 theList = dl; 1019 red = new ReductionPar<C>(); 1020 } 1021 1022 1023 /** 1024 * Work loop. 1025 * @see java.lang.Runnable#run() 1026 */ 1027 @Override 1028 public void run() { 1029 if (debug) { 1030 logger.info("pairChannel = " + pairChannel + " reducer client running"); 1031 } 1032 Pair<C> pair = null; 1033 GenPolynomial<C> pi, pj, ps; 1034 GenPolynomial<C> S; 1035 GenPolynomial<C> H = null; 1036 //boolean set = false; 1037 boolean goon = true; 1038 boolean doEnd = true; 1039 int reduction = 0; 1040 //int sleeps = 0; 1041 Integer pix, pjx, psx; 1042 1043 while (goon) { 1044 /* protocol: 1045 * request pair, process pair, send result, receive acknowledgment 1046 */ 1047 // pair = (Pair) pairlist.removeNext(); 1048 Object req = new GBTransportMessReq(); 1049 logger.debug("send request"); 1050 try { 1051 pairChannel.send(pairTag, req); 1052 } catch (IOException e) { 1053 goon = false; 1054 if (logger.isDebugEnabled()) { 1055 e.printStackTrace(); 1056 } 1057 logger.info("receive pair, IOexception "); 1058 break; 1059 } 1060 logger.debug("receive pair, goon = " + goon); 1061 doEnd = true; 1062 Object pp = null; 1063 try { 1064 pp = pairChannel.receive(pairTag); 1065 } catch (InterruptedException e) { 1066 goon = false; 1067 e.printStackTrace(); 1068 } catch (IOException e) { 1069 goon = false; 1070 if (logger.isDebugEnabled()) { 1071 e.printStackTrace(); 1072 } 1073 break; 1074 } catch (ClassNotFoundException e) { 1075 goon = false; 1076 e.printStackTrace(); 1077 } 1078 if (debug) { 1079 logger.info("received pair = " + pp); 1080 } 1081 H = null; 1082 if (pp == null) { // should not happen 1083 continue; 1084 } 1085 if (pp instanceof GBTransportMessEnd) { 1086 goon = false; 1087 //doEnd = false; 1088 continue; 1089 } 1090 if (pp instanceof GBTransportMessPair || pp instanceof GBTransportMessPairIndex) { 1091 pi = pj = ps = null; 1092 if (pp instanceof GBTransportMessPair) { // obsolet, for tests 1093 GBTransportMessPair<C> tmp = (GBTransportMessPair<C>) pp; 1094 pair = tmp.pair; 1095 if (pair != null) { 1096 pi = pair.pi; 1097 pj = pair.pj; 1098 //logger.debug("pair: pix = " + pair.i 1099 // + ", pjx = " + pair.j); 1100 } 1101 } 1102 if (pp instanceof GBTransportMessPairIndex) { 1103 GBTransportMessPairIndex tmpi = (GBTransportMessPairIndex) pp; 1104 pix = tmpi.i; 1105 pjx = tmpi.j; 1106 psx = tmpi.s; 1107 pi = theList.getWait(pix); 1108 pj = theList.getWait(pjx); 1109 ps = theList.getWait(psx); 1110 //logger.info("pix = " + pix + ", pjx = " + pjx + ", psx = " + psx); 1111 } 1112 if (pi != null && pj != null) { 1113 S = red.SPolynomial(pi, pj); 1114 //logger.info("ht(S) = " + S.leadingExpVector()); 1115 if (S.isZERO()) { 1116 // pair.setZero(); does not work in dist 1117 } else { 1118 if (logger.isDebugEnabled()) { 1119 logger.debug("ht(S) = " + S.leadingExpVector()); 1120 } 1121 H = red.normalform(theList, S); 1122 //logger.info("ht(H) = " + H.leadingExpVector()); 1123 reduction++; 1124 if (H.isZERO()) { 1125 // pair.setZero(); does not work in dist 1126 } else { 1127 H = H.monic(); 1128 if (logger.isInfoEnabled()) { 1129 logger.info("ht(H) = " + H.leadingExpVector()); 1130 } 1131 } 1132 } 1133 } else { 1134 logger.info("pi = " + pi + ", pj = " + pj + ", ps = " + ps); 1135 } 1136 } 1137 if (pp instanceof GBTransportMess) { 1138 logger.debug("null pair results in null H poly"); 1139 } 1140 1141 // send H or must send null, if not at end 1142 if (logger.isDebugEnabled()) { 1143 logger.debug("#distributed list = " + theList.size()); 1144 logger.debug("send H polynomial = " + H); 1145 } 1146 try { 1147 pairChannel.send(resultTag, new GBTransportMessPoly<C>(H)); //,threadId)); 1148 doEnd = false; 1149 } catch (IOException e) { 1150 goon = false; 1151 e.printStackTrace(); 1152 } 1153 //logger.info("done send poly message of " + pp); 1154 try { 1155 //pp = pairChannel.receive(threadId); 1156 pp = pairChannel.receive(ackTag); 1157 } catch (InterruptedException e) { 1158 goon = false; 1159 e.printStackTrace(); 1160 } catch (IOException e) { 1161 goon = false; 1162 if (logger.isDebugEnabled()) { 1163 e.printStackTrace(); 1164 } 1165 break; 1166 } catch (ClassNotFoundException e) { 1167 goon = false; 1168 e.printStackTrace(); 1169 } 1170 if (!(pp instanceof GBTransportMess)) { 1171 logger.error("invalid acknowledgement " + pp); 1172 } 1173 logger.info("received acknowledgment "); 1174 } 1175 logger.info("terminated, " + reduction + " reductions, " + theList.size() + " polynomials"); 1176 if (doEnd) { 1177 try { 1178 pairChannel.send(resultTag, new GBTransportMessEnd()); 1179 } catch (IOException e) { 1180 //e.printStackTrace(); 1181 } 1182 logger.debug("terminated, send done"); 1183 } 1184 } 1185} 1186 1187 1188/** 1189 * Objects of this class are to be send to a ExecutableServer. 1190 */ 1191class GBHybridExerClient<C extends RingElem<C>> implements RemoteExecutable { 1192 1193 1194 String host; 1195 1196 1197 int port; 1198 1199 1200 int dhtport; 1201 1202 1203 int threadsPerNode; 1204 1205 1206 /** 1207 * GBHybridExerClient. 1208 * @param host 1209 * @param port 1210 * @param dhtport 1211 */ 1212 public GBHybridExerClient(String host, int threadsPerNode, int port, int dhtport) { 1213 this.host = host; 1214 this.threadsPerNode = threadsPerNode; 1215 this.port = port; 1216 this.dhtport = dhtport; 1217 } 1218 1219 1220 /** 1221 * run. 1222 */ 1223 public void run() { 1224 try { 1225 GroebnerBaseDistributedHybridEC.<C> clientPart(host, threadsPerNode, port, dhtport); 1226 } catch (Exception e) { 1227 e.printStackTrace(); 1228 } 1229 } 1230 1231 1232 /** 1233 * String representation. 1234 */ 1235 @Override 1236 public String toString() { 1237 StringBuffer s = new StringBuffer("GBHybridExerClient("); 1238 s.append("host=" + host); 1239 s.append(", threadsPerNode=" + threadsPerNode); 1240 s.append(", port=" + port); 1241 s.append(", dhtport=" + dhtport); 1242 s.append(")"); 1243 return s.toString(); 1244 } 1245 1246}