Guest User

Java Dixon Factoring

a guest
Oct 31st, 2011
399
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 13.65 KB | None | 0 0
  1. // FILE: DixonMain.java
  2. import java.math.BigInteger;
  3. import java.util.Random;
  4. import java.util.Scanner;
  5.  
  6. class DixonMain implements BigFactorTool
  7. {
  8.   private static final Random random = new Random();
  9.   private static final Scanner scanner = new Scanner(System.in);
  10.   public static final boolean debug = false;
  11.  
  12.   public static void main(String[] args)
  13.   {
  14.     if (args.length == 1)
  15.     {
  16.       BigInteger input = new BigInteger(args[0]);
  17.       final DixonCommander commander = new DixonCommander();
  18.       commander.setup(input);
  19.       long start = System.nanoTime(), total;
  20.       commander.start();
  21.       total = System.nanoTime() - start;
  22.       BigInteger[] factors = commander.result();
  23.       if (debug)
  24.       {
  25.         System.out.println("Factored in " + (total / 1000000000.0) + " seconds");
  26.         System.out.println("Factors: " + factors[0] + ", " + factors[1]);
  27.       }
  28.     } else if (args.length == 2)
  29.     {
  30.       BigInteger input = new BigInteger(args[0]);
  31.       final DixonCommander commander = new DixonCommander();
  32.       try
  33.       {
  34.         commander.setup(input, Integer.parseInt(args[1]));
  35.       } catch (NumberFormatException e)
  36.       {
  37.         commander.setup(input);
  38.       }
  39.       long start = System.nanoTime(), total;
  40.       commander.start();
  41.       total = System.nanoTime() - start;
  42.       BigInteger[] factors = commander.result();
  43.       if (debug)
  44.       {
  45.         System.out.println("Factored in " + (total / 1000000000.0) + " seconds");
  46.         System.out.println("Factors: " + factors[0] + ", " + factors[1]);
  47.       }
  48.     } else
  49.     {
  50.       String input, exit = "x";
  51.       BigInteger[] factors;
  52.       long start, total;
  53.       do
  54.       {
  55.         System.out.print("Bits to Factor: ");
  56.         input = scanner.next();
  57.         try
  58.         {
  59.           start = System.nanoTime();
  60.           factors = factor(Integer.parseInt(input));
  61.           total = System.nanoTime() - start;
  62.           System.out.println("Factored in " + (total / 1000000000.0) + " seconds");
  63.           System.out.println("Factors: " + factors[0] + ", " + factors[1]);
  64.         } catch (NumberFormatException e) {}
  65.       } while (!input.equals(exit));
  66.     }
  67.   }
  68.  
  69.   public static BigInteger[] factor(final int bits)
  70.   {
  71.     return (new DixonMain()).factor(generateFactor(bits));
  72.   }
  73.  
  74.   public static BigInteger generateFactor(final int bits)
  75.   {
  76.     final int hbits = bits / 2;
  77.     final BigInteger a = BigInteger.probablePrime(hbits, random);
  78.     final BigInteger b = BigInteger.probablePrime(bits - hbits, random)
  79.     final BigInteger r = a.multiply(b);
  80.     if (debug)
  81.     {
  82.       System.out.println("Input: " + r);
  83.       System.out.println("Factor 1: " + a.toString());
  84.       System.out.println("Factor 2: " + b.toString());
  85.     }
  86.     return r;
  87.   }
  88.  
  89.   public BigInteger[] factor(final BigInteger n)
  90.   {
  91.     final DixonCommander commander = new DixonCommander();
  92.     commander.setup(n);
  93.     commander.start();
  94.     return commander.result();
  95.   }
  96. }
  97.  
  98. // FILE: DixonCommander.java
  99. import java.math.BigInteger;
  100. import java.util.List;
  101. import java.util.LinkedList;
  102.  
  103. class DixonCommander extends Thread
  104. {
  105.   // maximum 256 cores-->byte
  106.   private static final byte cores = (byte) Runtime.getRuntime().availableProcessors();
  107.  
  108.   private final Object rowsLock = new Object();
  109.   private final List<DixonRow> rows;
  110.   private boolean ready = false;
  111.   private DixonMonkey[] monkies;
  112.   private DixonBanana banana;
  113.  
  114.   DixonCommander()
  115.   {
  116.     synchronized (rowsLock)
  117.     {
  118.       rows = new LinkedList<DixonRow>();
  119.     }
  120.     monkies = new DixonMonkey[cores - 1];
  121.     if (DixonMain.debug)
  122.       System.out.println("Constructed");
  123.   }
  124.  
  125.   public void setup(final BigInteger n)
  126.   {
  127.     setup(n, (int) (30 * Math.exp(0.08 * n.bitLength())));
  128.   }
  129.  
  130.   public void setup(final BigInteger n, int factorBase)
  131.   {
  132.     if (DixonMain.debug)
  133.       System.out.println("Setting up...");
  134.     final BigInteger[] base = DixonUtils.bigBase(factorBase);
  135.     if (DixonMain.debug)
  136.     {
  137.       System.out.println("Base Size: " + base.length);
  138.       for (BigInteger b : base)
  139.         System.out.print(b + " ");
  140.       System.out.print("\n");
  141.     }
  142.     banana = new DixonBanana(n, base, rows, (byte) monkies.length);
  143.     for (byte monkey = 0; monkey < monkies.length; monkey++)
  144.       monkies[monkey] = new DixonMonkey(banana);
  145.     ready = true;
  146.     if (DixonMain.debug)
  147.       System.out.println("Complete");
  148.   }
  149.  
  150.   public void run()
  151.   {
  152.     if (DixonMain.debug)
  153.       System.out.println("Running...");
  154.     if (!ready)
  155.     {
  156.       System.out.println("Not ready");
  157.       return;
  158.     }
  159.     for (DixonMonkey monkey : monkies)
  160.       monkey.start();
  161.     banana.clear();
  162.     for (DixonMonkey monkey : monkies)
  163.       monkey.done();
  164.   }
  165.  
  166.   public BigInteger[] result()
  167.   {
  168.     return banana.result();
  169.   }
  170. }
  171.  
  172. // FILE: DixonBanana.java
  173. import java.math.BigInteger;
  174. import java.util.concurrent.ConcurrentLinkedQueue;
  175. import java.util.BitSet;
  176. import java.util.List;
  177. import java.util.LinkedList;
  178.  
  179. class DixonBanana
  180. {
  181.   private static final BigInteger ONE = BigInteger.ONE;
  182.  
  183.   public static final int chunkSize = 10000;
  184.   private static final BigInteger bigChunkSize = BigInteger.valueOf(chunkSize);
  185.  
  186.   public final BigInteger n;
  187.   public final byte monkies;
  188.   public final BigInteger[] base;
  189.   private BigInteger activeRow;
  190.   private final ConcurrentLinkedQueue<DixonRow> incomingRows;
  191.   private int waitingRows = 0;
  192.   private final List<DixonRow> rows;
  193.   private final BitSet columns;
  194.   private List<DixonRow> xColumns;
  195.  
  196.   // for results
  197.   private int resulting = 0;
  198.   private final Object resultLock = new Object();
  199.   private BigInteger result = null;
  200.  
  201.   DixonBanana(final BigInteger n, final BigInteger[] base, final List<DixonRow> rows, final byte monkies)
  202.   {
  203.     this.n = n;
  204.     this.base = base;
  205.     activeRow = DixonUtils.sqrt(n);
  206.     this.rows = rows;
  207.     incomingRows = new ConcurrentLinkedQueue<DixonRow>();
  208.     columns = new BitSet(base.length);
  209.     columns.set(0, base.length);
  210.     xColumns = new LinkedList<DixonRow>();
  211.     this.monkies = monkies;
  212.   }
  213.  
  214.   public BigInteger next()
  215.   {
  216.     synchronized (activeRow)
  217.     {
  218.       BigInteger start = activeRow;
  219.       activeRow = activeRow.add(bigChunkSize);
  220.       return start;
  221.     }
  222.   }
  223.  
  224.   public void addRow(final DixonRow incomingRow)
  225.   {
  226.     incomingRows.offer(incomingRow);
  227.     synchronized (rows)
  228.     {
  229.       if (waitingRows > 0)
  230.       {
  231.         rows.notifyAll();
  232.         waitingRows = 0;
  233.       }
  234.     }
  235.   }
  236.  
  237.   public void addRows(List<DixonRow> r)
  238.   {
  239.     incomingRows.addAll(r);
  240.     synchronized (rows)
  241.     {
  242.       if (waitingRows > 0)
  243.       {
  244.         rows.notifyAll();
  245.         waitingRows = 0;
  246.       }
  247.     }
  248.   }
  249.  
  250.   private void waitRow()
  251.   {
  252.     try
  253.     {
  254.       synchronized (rows)
  255.       {
  256.         if (incomingRows.isEmpty())
  257.         {
  258.           waitingRows++;
  259.           rows.wait();
  260.         }
  261.       }
  262.     } catch (InterruptedException e) {}
  263.   }
  264.  
  265.   public void clear()
  266.   {
  267.     long start = System.nanoTime();
  268.     int rowIndex = 0;
  269.     for (DixonRow currentRow;;)
  270.     {
  271.       waitRow();
  272.       currentRow = incomingRows.poll();
  273.       if (currentRow == null)
  274.         continue;
  275.       currentRow.setRow(rowIndex++);
  276.       if (!columns.isEmpty())
  277.       {
  278.         for (int bit = columns.nextSetBit(0); bit >= 0; bit = columns.nextSetBit(bit + 1))
  279.         {
  280.           if (currentRow.bits.get(bit))
  281.           {
  282.             for (DixonRow col : xColumns)
  283.             {
  284.               if (currentRow.bits.get(bit))
  285.               {
  286.                 currentRow.bits.xor(col.bits);
  287.                 currentRow.augmented.xor(col.augmented);
  288.               }
  289.             }
  290.             for (DixonRow row : rows)
  291.             {
  292.               if (!row.flag && row.bits.get(bit))
  293.               {
  294.                 row.bits.xor(currentRow.bits);
  295.                 row.augmented.xor(currentRow.augmented);
  296.                 if (checkRow(row))
  297.                   return;
  298.               }
  299.             }
  300.             currentRow.setFlag(bit);
  301.             columns.clear(bit);
  302.             xColumns.add(currentRow);
  303.             if (columns.isEmpty() && DixonMain.debug)
  304.               System.out.println("Cleared all columns");
  305.             break;
  306.           }
  307.         }
  308.       }
  309.       if (!currentRow.flag)
  310.       {
  311.         for (DixonRow col : xColumns)
  312.         {
  313.           if (currentRow.bits.get(col.flagIndex))
  314.           {
  315.             currentRow.bits.xor(col.bits);
  316.             currentRow.augmented.xor(col.augmented);
  317.           }
  318.         }
  319.         if (checkRow(currentRow))
  320.           return;
  321.       }
  322.       rows.add(currentRow);
  323.     }
  324.   }
  325.  
  326.   private boolean checkRow(DixonRow row)
  327.   {
  328.     if (!row.bits.isEmpty())
  329.       return false;
  330.     BigInteger r = row.r, fin, fr = row.fr;
  331.     for (DixonRow col : xColumns)
  332.     {
  333.       if (row.augmented.get(col.row))
  334.       {
  335.         r = r.multiply(col.r);
  336.         fr = fr.multiply(col.fr);
  337.       }
  338.     }
  339.     fr = DixonUtils.sqrt(fr);
  340.     fin = r;
  341.     r = r.add(fr).gcd(n);
  342.     if (!r.equals(ONE) && !r.equals(n))
  343.     {
  344.       if (DixonMain.debug)
  345.       {
  346.         System.out.println("Worked Row[" + row.r + ", " + row.fr + "]: " + row.bits);
  347.         System.out.println("Final r: " + fin + ", Final f(r): " + fr);
  348.       }
  349.       notifyResult(r);
  350.       return true;
  351.     }
  352.     return false;
  353.   }
  354.  
  355.   private void notifyResult(BigInteger result)
  356.   {
  357.     synchronized (resultLock)
  358.     {
  359.       this.result = result;
  360.       if (resulting > 0)
  361.       {
  362.         resultLock.notifyAll();
  363.         resulting = 0;
  364.       }
  365.     }
  366.     if (DixonMain.debug)
  367.       System.out.println("Computation Complete.");
  368.   }
  369.  
  370.   public BigInteger[] result()
  371.   {
  372.     try
  373.     {
  374.       synchronized (resultLock)
  375.       {
  376.         if (result == null)
  377.         {
  378.           resulting++;
  379.           resultLock.wait();
  380.         }
  381.       }
  382.     } catch (InterruptedException e)
  383.     {
  384.       return null;
  385.     }
  386.     return new BigInteger[] {result, n.divide(result)};
  387.   }
  388. }
  389.  
  390. // FILE: DixonMonkey.java
  391. import java.math.BigInteger;
  392. import java.util.BitSet;
  393. import java.util.List;
  394. import java.util.ArrayList;
  395.  
  396. class DixonMonkey extends Thread
  397. {
  398.   private static final BigInteger ZERO = BigInteger.ZERO;
  399.   private static final BigInteger ONE = BigInteger.ONE;
  400.   private static final BigInteger TWO = BigInteger.valueOf(2);
  401.  
  402.   private final DixonBanana banana;
  403.   private boolean running;
  404.  
  405.   DixonMonkey(final DixonBanana banana)
  406.   {
  407.     this.banana = banana;
  408.   }
  409.  
  410.   public void run()
  411.   {
  412.     if (DixonMain.debug)
  413.       System.out.println("Monkey away!");
  414.     running = true;
  415.     BitSet set = new BitSet(banana.base.length);
  416.     BigInteger[] checkMap;
  417.     BigInteger ofr, fr, check;
  418.     for (BigInteger r = banana.next(); running; r = banana.next())
  419.     {
  420.       for (int i = 0; i < banana.chunkSize && running; i++)
  421.       {
  422.         ofr = fr = r.multiply(r).mod(banana.n);
  423.         for (int b = 0; b < banana.base.length; b++)
  424.         {
  425.           check = banana.base[b];
  426.           while ((checkMap = fr.divideAndRemainder(check))[1].equals(ZERO))
  427.           {
  428.             fr = checkMap[0];
  429.             set.flip(b);
  430.           }
  431.           if (fr.equals(ONE))
  432.           {
  433.             banana.addRow(new DixonRow(r, ofr, set));
  434.             set = new BitSet(banana.base.length);
  435.             break;
  436.           } else
  437.             set.clear();
  438.         }
  439.         r = r.add(ONE);
  440.       }
  441.     }
  442.     if (DixonMain.debug)
  443.       System.out.println("Monkey down!");
  444.   }
  445.  
  446.   public void done()
  447.   {
  448.     running = false;
  449.   }
  450. }
  451.  
  452. // FILE: DixonRow.java
  453. import java.math.BigInteger;
  454. import java.util.BitSet;
  455.  
  456. class DixonRow
  457. {
  458.   public int row;
  459.   public boolean flag = false;
  460.   public int flagIndex = -1;
  461.   public BigInteger r;
  462.   public BigInteger fr;
  463.   public BitSet bits;
  464.   public BitSet augmented;
  465.  
  466.   DixonRow(final BigInteger r, final BigInteger fr, final BitSet bits)
  467.   {
  468.     this.r = r;
  469.     this.fr = fr;
  470.     this.bits = bits;
  471.     augmented = new BitSet();
  472.   }
  473.  
  474.   public void setRow(int row)
  475.   {
  476.     this.row = row;
  477.     augmented.set(row);
  478.   }
  479.  
  480.   public void setFlag(int fl)
  481.   {
  482.     flag = true;
  483.     flagIndex = fl;
  484.   }
  485. }
  486.  
  487. // FILE: DixonUtils.java
  488. import java.util.List;
  489. import java.util.LinkedList;
  490. import java.math.BigInteger;
  491.  
  492. final class DixonUtils
  493. {
  494.   private static final BigInteger ONE = BigInteger.ONE;
  495.   private static final BigInteger TWO = BigInteger.valueOf(2);
  496.  
  497.   private DixonUtils() {}
  498.  
  499.   public static BigInteger[] bigBase(int limit)
  500.   {
  501.     // TODO: ignore 2, and make it only contain odd numbers?  2x improvement?
  502.     limit--;
  503.     boolean[] stream = makePrecacheBase(limit);
  504.     final List<BigInteger> base = new LinkedList<BigInteger>();
  505.     for (int i = 0, incr; i < limit; i++)
  506.     {
  507.       if (stream[i])
  508.       {
  509.         base.add(BigInteger.valueOf(incr = i + 2));
  510.         for (int j = i + incr; j < limit; j += incr)
  511.           stream[j] = false;
  512.       }
  513.     }
  514.     return base.toArray(new BigInteger[base.size()]);
  515.   }
  516.  
  517.   public static BigInteger sqrt(final BigInteger n)
  518.   {
  519.     BigInteger guess = ONE, antiguess = n.divide(guess), error;
  520.     do
  521.     {
  522.       guess = guess.add(antiguess).divide(TWO);
  523.       antiguess = n.divide(guess);
  524.       error = guess.subtract(antiguess).abs();
  525.     } while (error.compareTo(ONE) > 0);
  526.     return guess;
  527.   }
  528.  
  529.   private static boolean[] makePrecacheBase(int limit)
  530.   {
  531.     boolean[] base = new boolean[limit];
  532.     while (limit-- > 0)
  533.       base[limit] = true;
  534.     return base;
  535.   }
  536. }
  537.  
  538. // FILE: BigFactorTool.java
  539. import java.math.BigInteger;
  540.  
  541. interface BigFactorTool
  542. {
  543.   public BigInteger[] factor(BigInteger n);
  544. }
  545.  
Advertisement
Add Comment
Please, Sign In to add comment