
// PrimeFactors.java
// Andrew Davison, ad@coe.psu.ac.th, April 2023

/* Get prime factors by using trial division classes, one in 
   JML, and one in Apache Commons Numbers. JML TDiv uses 
   BigInteger, while Number's Primes class uses int.

   Usage:
     > compile PrimeFactors.java
     > run PrimeFactors <number>
   e.g.
     > run PrimeFactors.class 123456789

     > run PrimeFactors 1000000000000000000

     Prime factors for 1000000000000000000: [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]

     Count of repeated factors:
      2: 18
      5: 18

     This example is too big for factorization by 
     Commons Numbers which uses int, but because of that
     Numbers is a lot faster when it can process the input.

*/

import java.math.*;
import java.util.*;

import org.apache.commons.numbers.primes.*;

import de.tilman_neumann.jml.factor.tdiv.TDiv;
import de.tilman_neumann.util.SortedMultiset;
import de.tilman_neumann.util.SortedMultiset_BottomUp;




public class PrimeFactors
{

  public static void main(String[] args)
  {
    if (args.length != 1) {
      System.out.println("Usage: run PrimeFactors <number>");
      return;
    }

    // using de.tilman_neumann ....
    TDiv tdivAlg = new TDiv();
    SortedMultiset<BigInteger> factors =
                                   new SortedMultiset_BottomUp<>();
    System.out.println("Factoring with TDiv...");
    tdivAlg.factor(new BigInteger(args[0]), factors);  // parsed as a BigInteger

    System.out.println("Smallest factor: " + factors.getSmallestElement());
    System.out.println("Biggest factor: " + factors.getBiggestElement());

    List<BigInteger> factorsList = factors.toList();
    System.out.println("Prime factors for " + args[0] + ": " + factorsList);

    System.out.println("\nCount of factors:");
    Set<BigInteger> factorsSet = new HashSet<>(factorsList);
    for (BigInteger f : factorsSet)
      System.out.println(" " + f + ": " + Collections.frequency(factorsList, f));
    System.out.println();

    // using Apache Commons Numbers... 
    int n = Math.abs(Nut.parseInt(args[0]));    // parsed as an int
    System.out.println("\nFactoring with Apache...");
    List<Integer> fList = Primes.primeFactors(n); 
    System.out.println("Prime factors for " + n + ": " + fList);

  } /* main */


}  // end of PrimeFactors class
