University stuff.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. import java.util.ArrayList;
  2. import java.util.Arrays;
  3. class Parallel implements Solver {
  4. class SolverWorker implements Runnable {
  5. Sieve sieve;
  6. int step;
  7. int offset;
  8. SolverWorker(Sieve mainSieve, int step, int offset) {
  9. byte[] arr = new byte[mainSieve.arr.length];
  10. System.arraycopy(mainSieve.arr, 0, arr, 0, arr.length);
  11. this.sieve = new Sieve(mainSieve.maxNum, arr);
  12. this.sieve.smallPrimesGenerated = true;
  13. this.step = step;
  14. this.offset = offset;
  15. }
  16. public void run() {
  17. sieve.generatePrimes(step, offset);
  18. }
  19. }
  20. public void solve(Sieve sieve) {
  21. // Generate primes less than sqrt(n)
  22. sieve.generateSmallPrimes();
  23. int nThreads = Runtime.getRuntime().availableProcessors();
  24. nThreads = Math.min(nThreads, 8);
  25. Thread[] threads = new Thread[nThreads];
  26. SolverWorker[] workers = new SolverWorker[nThreads];
  27. // Start threads
  28. for (int i = 0; i < nThreads; ++i) {
  29. SolverWorker w = new SolverWorker(sieve, nThreads, (i * 2) + 1);
  30. workers[i] = w;
  31. Thread t = new Thread(w);
  32. threads[i] = t;
  33. t.start();
  34. }
  35. // Wait for threads
  36. for (Thread t: threads) {
  37. try { t.join(); } catch (InterruptedException ex) {}
  38. }
  39. // Merge
  40. for (int i = 0; i < sieve.arr.length; ++i) {
  41. for (SolverWorker w: workers) {
  42. sieve.arr[i] = (byte)(sieve.arr[i] | w.sieve.arr[i]);
  43. }
  44. }
  45. }
  46. class FactorWorker implements Runnable {
  47. FactorMonitor monitor;
  48. int step;
  49. int offset;
  50. long num;
  51. long currentPrime;
  52. long biggestPossible;
  53. Sieve sieve;
  54. boolean ready = false;
  55. boolean done = false;
  56. // Offset should start at 0
  57. synchronized public void start(FactorMonitor monitor, int step, int offset) {
  58. this.monitor = monitor;
  59. this.step = step;
  60. this.offset = offset;
  61. this.num = monitor.currentNum;
  62. this.biggestPossible = (long)Math.sqrt(num);
  63. this.sieve = monitor.sieve;
  64. notify();
  65. this.ready = true;
  66. this.done = false;
  67. findFirstPrime();
  68. }
  69. void findFirstPrime() {
  70. currentPrime = 3;
  71. for (int i = 0; i < offset; ++i) {
  72. currentPrime += 2;
  73. while (!monitor.isPrime(currentPrime))
  74. currentPrime += 2;
  75. }
  76. }
  77. synchronized public void stop() {
  78. ready = false;
  79. done = true;
  80. notify();
  81. }
  82. void nextPrime() {
  83. if (currentPrime > biggestPossible)
  84. return;
  85. for (int i = 0; i < step; ++i) {
  86. currentPrime += 2;
  87. while (!monitor.isPrime(currentPrime) && currentPrime <= biggestPossible)
  88. currentPrime += 2;
  89. if (currentPrime > biggestPossible) {
  90. this.ready = false;
  91. monitor.foundBiggest();
  92. return;
  93. }
  94. }
  95. }
  96. void findFactor() {
  97. boolean found = false;
  98. while (!found && this.ready) {
  99. if ((num % currentPrime) == 0) {
  100. found = true;
  101. if (!monitor.addFactor(currentPrime, num)) {
  102. this.num = monitor.currentNum;
  103. findFirstPrime();
  104. return;
  105. }
  106. }
  107. nextPrime();
  108. }
  109. }
  110. synchronized public void run() {
  111. while (!ready && !done)
  112. try { wait(); } catch (InterruptedException ex) {}
  113. while (!done) {
  114. while (!monitor.isDone() && this.ready) {
  115. findFactor();
  116. }
  117. ready = false;
  118. while (!ready && !done)
  119. try { wait(); } catch (InterruptedException ex) {}
  120. }
  121. }
  122. }
  123. class FactorMonitor {
  124. Sieve sieve;
  125. long original;
  126. long currentNum;
  127. int biggestLeft;
  128. boolean done = false;
  129. ArrayList<Long> arr = new ArrayList<>();
  130. FactorMonitor(Sieve sieve, long num, int nThreads) {
  131. this.sieve = sieve;
  132. this.original = num;
  133. this.currentNum = num;
  134. this.biggestLeft = nThreads;
  135. // We don't want to have to deal with the fact that 2 is a prime
  136. if (num % 2 == 0)
  137. addFactor(2, num);
  138. }
  139. synchronized boolean addFactor(long factor, long num) {
  140. // If the thread is working with a stale num,
  141. // just discard it and tell the thread to restart.
  142. if (num != currentNum)
  143. return false;
  144. while ((currentNum % factor) == 0) {
  145. currentNum /= factor;
  146. Long i = new Long(factor);
  147. arr.add(i);
  148. }
  149. notify();
  150. return true;
  151. }
  152. synchronized void foundBiggest() {
  153. this.biggestLeft -= 1;
  154. if (biggestLeft == 0) {
  155. done = true;
  156. notify();
  157. }
  158. }
  159. boolean isPrime(long num) {
  160. if (num > sieve.maxNum)
  161. return false;
  162. else
  163. return sieve.isPrime((int)num);
  164. }
  165. synchronized boolean isDone() {
  166. if (done) {
  167. return true;
  168. } else if (isPrime(currentNum)) {
  169. done = true;
  170. if (currentNum != 1)
  171. arr.add(new Long(currentNum));
  172. notify();
  173. return true;
  174. } else {
  175. return false;
  176. }
  177. }
  178. synchronized long[] getFactors() {
  179. while (!isDone())
  180. try { wait(); } catch (InterruptedException ex) {}
  181. Long curr = new Long(currentNum);
  182. if (currentNum > (long)Math.sqrt(original) && !arr.contains(curr))
  183. arr.add(curr);
  184. long[] a = new long[arr.size()];
  185. for (int i = 0; i < a.length; ++i) {
  186. a[i] = arr.get(i);
  187. }
  188. return a;
  189. }
  190. }
  191. FactorWorker[] factorWorkers = null;
  192. Thread[] factorThreadPool = null;
  193. public long[] factor(Sieve sieve, long num) {
  194. int nThreads = Runtime.getRuntime().availableProcessors();
  195. nThreads = Math.min(nThreads, 8);
  196. if (num <= sieve.maxNum && sieve.isPrime((int)num))
  197. return new long[] { num };
  198. // Initiate thread pool
  199. if (factorThreadPool == null) {
  200. factorThreadPool = new Thread[nThreads];
  201. factorWorkers = new FactorWorker[nThreads];
  202. for (int i = 0; i < nThreads; ++i) {
  203. FactorWorker w = new FactorWorker();
  204. factorWorkers[i] = w;
  205. factorThreadPool[i] = new Thread(w);
  206. factorThreadPool[i].start();
  207. }
  208. }
  209. FactorMonitor monitor = new FactorMonitor(sieve, num, nThreads);
  210. // Start workers
  211. for (int i = 0; i < nThreads; ++i) {
  212. FactorWorker w = factorWorkers[i];
  213. w.start(monitor, nThreads, i);
  214. }
  215. long[] arr = monitor.getFactors();
  216. Arrays.sort(arr);
  217. return arr;
  218. }
  219. public void stopThreads() {
  220. if (factorWorkers == null)
  221. return;
  222. for (FactorWorker w: factorWorkers) {
  223. w.stop();
  224. }
  225. }
  226. }