All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bnd.math.business.sym.twodim.TwoDimSymmetricConfigurationEnumerator Maven / Gradle / Ivy

The newest version!
package com.bnd.math.business.sym.twodim;

import com.bnd.function.enumerator.ListEnumerator;
import com.bnd.function.enumerator.ListEnumeratorFactory;
import org.apache.commons.math3.util.ArithmeticUtils;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class TwoDimSymmetricConfigurationEnumerator {

	protected final int size;
	protected final int alphabetSize;
	protected final ListEnumeratorFactory enumerator;

	public TwoDimSymmetricConfigurationEnumerator(
		int size,
		int alphabetSize,
		ListEnumeratorFactory enumerator
	) {
		this.size = size;
		this.alphabetSize = alphabetSize;
		this.enumerator = enumerator;
	}

	private static boolean isDivisibleBy(int num, Collection divisors) {
		for (Integer divisor : divisors) {
			if (num % divisor == 0) {
				return true;
			}
		}
		return false;
	}

	public static List calcPrimeDivisors(int num) {
		List primeDivisors = new ArrayList();
		for (int divisor = 2; divisor <= num; divisor++) {
			if (num % divisor == 0 && !isDivisibleBy(divisor, primeDivisors)) {
				primeDivisors.add(divisor);
			}			
		}
		return primeDivisors;
	}

	public BigInteger enumerateAll() {
		return enumerateAll(alphabetSize);
	}

	public BigInteger enumerateAll2() {
		return enumerateAll2(alphabetSize);
	}

    public BigInteger enumerateAll3() {
        return enumerateAll3(alphabetSize);
    }

	protected BigInteger enumerateAll(int alphabetSize) {
		final List primeDivisors = calcPrimeDivisors(size);
		final int omega = primeDivisors.size();
		List rangeFrom = new ArrayList();
		List rangeTo = new ArrayList();
		for (int i = 0; i < omega; i++) {
			rangeFrom.add(0);
			rangeTo.add(primeDivisors.get(i) + 1);
		}
		final ListEnumerator lCombEnumerator = enumerator.createInstance(true, rangeFrom, rangeTo);

		BigInteger sum = BigInteger.valueOf(0);
		BigInteger alphabet = BigInteger.valueOf(alphabetSize);
		for (List l : lCombEnumerator.enumerate(omega)) {
			BigInteger binomProduct = BigInteger.ONE;
			int primeProduct = 1;
			long lSum = 0;

			for (int i = 0; i < omega; i++) {
				BigInteger binom = binomialCoefficientBigInteger((primeDivisors.get(i) + 1), l.get(i));
				binomProduct = binomProduct.multiply(binom);
				primeProduct *= Math.pow(primeDivisors.get(i), Math.min(l.get(i), 2));
				lSum += l.get(i);
			}

			if (lSum != 0) {
				BigInteger partialSum = binomProduct.multiply(alphabet.pow(size * size / primeProduct));
				if (lSum % 2 == 0)
					sum = sum.subtract(partialSum);
				else
					sum = sum.add(partialSum);
			}
		}
		return sum;
	}

	protected BigInteger enumerateAll2(int alphabetSize) {
		final List primeDivisors = calcPrimeDivisors(size);
		final int omega = primeDivisors.size();
		final ListEnumerator kCombEnumerator = enumerator.createInstance(true, 0, 2);

		BigInteger sum = BigInteger.valueOf(0);
		BigInteger alphabet = BigInteger.valueOf(alphabetSize);
		for (List k : kCombEnumerator.enumerate(omega)) {
			int primeProduct = 1;
			long kSum = 0;

			for (int i = 0; i < omega; i++) {
				primeProduct *= Math.pow(primeDivisors.get(i), k.get(i));
				kSum += k.get(i);
			}
			
			if (kSum != 0) {
				BigInteger commonCoef = alphabet.pow(size * size / primeProduct);

				List rangeFrom = new ArrayList();
				List rangeTo = new ArrayList();
				for (int i = 0; i < omega; i++) {
					int ki = k.get(i);
					rangeFrom.add(ki);
					rangeTo.add((ki < 2) ? ki : primeDivisors.get(i) + 1);					
				}
				final ListEnumerator lCombEnumerator = enumerator.createInstance(true, rangeFrom, rangeTo);

				BigInteger partialSum = BigInteger.ZERO;
				for (List l : lCombEnumerator.enumerate(omega)) {
					BigInteger binomProduct = BigInteger.ONE;
					long lSum = 0;

					for (int i = 0; i < omega; i++) {
						BigInteger binom = binomialCoefficientBigInteger((primeDivisors.get(i) + 1), l.get(i));
						binomProduct = binomProduct.multiply(binom);
						lSum += l.get(i);
					}

					if (lSum % 2 == 0)
						partialSum = partialSum.subtract(binomProduct);
					else
						partialSum = partialSum.add(binomProduct);
				}
				sum = sum.add(commonCoef.multiply(partialSum));
			}
		}
		return sum;
	}

	protected BigInteger enumerateAll3(int alphabetSize) {
		final List primeDivisors = calcPrimeDivisors(size);
		final int omega = primeDivisors.size();
		final ListEnumerator kCombEnumerator = enumerator.createInstance(true, 0, 2);

		BigInteger sum = BigInteger.ZERO;
		BigInteger alphabet = BigInteger.valueOf(alphabetSize);
		for (List k : kCombEnumerator.enumerate(omega)) {
			int primeProduct = 1;
            int combProduct = 1;
			long kSum = 0;

			for (int i = 0; i < omega; i++) {
                int prime = primeDivisors.get(i);
                int exp = k.get(i);

                if (exp != 0) {
                    primeProduct *= Math.pow(prime, exp);

                    if (exp == 1)
                        combProduct *= (prime + 1);
                    else if (exp == 2)
                        combProduct *= prime;
                }
				kSum += exp;
			}

			if (kSum != 0) {
                BigInteger partial = alphabet.pow(size * size / primeProduct).multiply(BigInteger.valueOf(combProduct));

                if (kSum % 2 == 1)
                    sum = sum.add(partial);
				else
                    sum = sum.subtract(partial);
			}
		}
		return sum;
	}

	public BigInteger enumerate(int activeCellsNum) {
		if (activeCellsNum == 0) { 
			return enumerateAll(alphabetSize - 1);
		}
		final List gcdPrimeDivisors = calcPrimeDivisors(ArithmeticUtils.gcd(size, activeCellsNum));
		if (gcdPrimeDivisors.isEmpty())
			return BigInteger.valueOf(0);

		final int omega = gcdPrimeDivisors.size();
		List rangeFrom = new ArrayList();
		List rangeTo = new ArrayList();
		for (int i = 0; i < omega; i++) {
			rangeFrom.add(0);
			rangeTo.add(gcdPrimeDivisors.get(i) + 1);
		}
		final ListEnumerator lCombEnumerator = enumerator.createInstance(true, rangeFrom, rangeTo);

		BigInteger alphabetMinusOne = BigInteger.valueOf(alphabetSize - 1);
		BigInteger sum = BigInteger.ZERO;
		for (List l : lCombEnumerator.enumerate(omega)) {
			BigInteger binomProduct = BigInteger.ONE;
			int primeProduct = 1;
			long lSum = 0;

			for (int i = 0; i < omega; i++) {
                BigInteger binom = binomialCoefficientBigInteger((gcdPrimeDivisors.get(i) + 1), l.get(i));
				binomProduct = binomProduct.multiply(binom);
				primeProduct *= Math.pow(gcdPrimeDivisors.get(i), Math.min(l.get(i), 2));
				lSum += l.get(i);
			}

			if (lSum != 0 && activeCellsNum % primeProduct == 0) {
				final BigInteger powElement = alphabetMinusOne.pow((size * size - activeCellsNum) / primeProduct);
                final BigInteger binom = binomialCoefficientBigInteger(size * size / primeProduct, activeCellsNum / primeProduct);
                final BigInteger partialSum = binomProduct.multiply(binom).multiply(powElement);

                if (lSum % 2 == 0)
					sum = sum.subtract(partialSum);
				else
					sum = sum.add(partialSum);
			}			
		}
		return sum;
	}

	public BigInteger enumerate2(int activeCellsNum) {
		if (activeCellsNum == 0) { 
			return enumerateAll2(alphabetSize - 1);
		}
		final List gcdPrimeDivisors = calcPrimeDivisors(ArithmeticUtils.gcd(size, activeCellsNum));
		if (gcdPrimeDivisors.isEmpty())
			return BigInteger.valueOf(0);

		final int omega = gcdPrimeDivisors.size();
		final ListEnumerator kCombEnumerator = enumerator.createInstance(true, 0, 2);

		BigInteger alphabetMinusOne = BigInteger.valueOf(alphabetSize - 1);
		BigInteger sum = BigInteger.valueOf(0);
		for (List k : kCombEnumerator.enumerate(omega)) {
			int primeProduct = 1;
			long kSum = 0;

			for (int i = 0; i < omega; i++) {
				primeProduct *= Math.pow(gcdPrimeDivisors.get(i), k.get(i));
				kSum += k.get(i);
			}
			if (kSum != 0 && activeCellsNum % primeProduct == 0) {
				final BigInteger powElement = alphabetMinusOne.pow((size * size - activeCellsNum) / primeProduct);
				final BigInteger binomCommon = binomialCoefficientBigInteger(size * size / primeProduct, activeCellsNum / primeProduct);

				BigInteger commonCoef = binomCommon.multiply(powElement);

				List rangeFrom = new ArrayList();
				List rangeTo = new ArrayList();
				for (int i = 0; i < omega; i++) {
					int ki = k.get(i);
					rangeFrom.add(ki);
					rangeTo.add((ki < 2) ? ki : gcdPrimeDivisors.get(i) + 1);					
				}
				final ListEnumerator lCombEnumerator = enumerator.createInstance(true, rangeFrom, rangeTo);

				BigInteger partialSum = BigInteger.ZERO;
				for (List l : lCombEnumerator.enumerate(omega)) {
					BigInteger binomProduct = BigInteger.ONE;
					long lSum = 0;

					for (int i = 0; i < omega; i++) {
						final BigInteger binom = binomialCoefficientBigInteger((gcdPrimeDivisors.get(i) + 1), l.get(i));
						binomProduct = binomProduct.multiply(binom);
						lSum += l.get(i);
					}

					if (lSum % 2 == 0)
						partialSum = partialSum.subtract(binomProduct);
					else
						partialSum = partialSum.add(binomProduct);
				}
				sum = sum.add(commonCoef.multiply(partialSum));
			}
		}
		return sum;
	}

	public BigInteger enumerate3(int activeCellsNum) {
		if (activeCellsNum == 0) {
			return enumerateAll3(alphabetSize - 1);
		}
		final List gcdPrimeDivisors = calcPrimeDivisors(ArithmeticUtils.gcd(size, activeCellsNum));
		if (gcdPrimeDivisors.isEmpty())
			return BigInteger.valueOf(0);

		final int omega = gcdPrimeDivisors.size();
		final ListEnumerator kCombEnumerator = enumerator.createInstance(true, 0, 2);

		BigInteger alphabetMinusOne = BigInteger.valueOf(alphabetSize - 1);
		BigInteger sum = BigInteger.valueOf(0);
		for (List k : kCombEnumerator.enumerate(omega)) {
            int primeProduct = 1;
            int combProduct = 1;
            long kSum = 0;

            for (int i = 0; i < omega; i++) {
                int prime = gcdPrimeDivisors.get(i);
                int exp = k.get(i);

                if (exp != 0) {
                    primeProduct *= Math.pow(prime, exp);

                    if (exp == 1)
                        combProduct *= (prime + 1);
                    else if (exp == 2)
                        combProduct *= prime;
                }
                kSum += exp;
            }

            if (kSum != 0 && activeCellsNum % primeProduct == 0) {
                final BigInteger powElement = alphabetMinusOne.pow((size * size - activeCellsNum) / primeProduct);
                final BigInteger binomCommon = binomialCoefficientBigInteger(size * size / primeProduct, activeCellsNum / primeProduct);

                BigInteger partial = binomCommon.multiply(powElement).multiply(BigInteger.valueOf(combProduct));

                if (kSum % 2 == 1)
                    sum = sum.add(partial);
                else
                    sum = sum.subtract(partial);
            }
		}
		return sum;
	}

    public static BigInteger binomialCoefficientBigInteger(int n, int k) {
        if (n < k || k < 0)
            return BigInteger.ZERO;

        if (n == k && k == 0)
            return BigInteger.ONE;

        if (k == 1 || k == n - 1)
            return BigInteger.valueOf(n);

        if (k > n / 2)
            return binomialCoefficientBigInteger(n, n - k);

        BigInteger result = BigInteger.ONE;

        for (int i = n - k + 1; i <= n; i++) {
            result = result.multiply(BigInteger.valueOf(i));
        }
        for (int j = 1; j <= k; j++) {
            result = result.divide(BigInteger.valueOf(j));
        }

//        for (int i = 1; i <= k; ++i)
//            result = result.multiply(BigInteger.valueOf((n - k + i) / i));

        return result;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy