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

ch.openchvote.utilities.algebra.ZZ Maven / Gradle / Ivy

Go to download

This module provides a collection of utility classes, especially for various mathematical concepts.

The newest version!
/*
 * Copyright (C) 2024 Berner Fachhochschule https://e-voting.bfh.ch
 *
 *  - This program is free software: you can redistribute it and/or modify                           -
 *  - it under the terms of the GNU Affero General Public License as published by                    -
 *  - the Free Software Foundation, either version 3 of the License, or                              -
 *  - (at your option) any later version.                                                            -
 *  -                                                                                                -
 *  - This program is distributed in the hope that it will be useful,                                -
 *  - but WITHOUT ANY WARRANTY; without even the implied warranty of                                 -
 *  - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                                   -
 *  - GNU General Public License for more details.                                                   -
 *  -                                                                                                -
 *  - You should have received a copy of the GNU Affero General Public License                       -
 *  - along with this program. If not, see .                           -
 */
package ch.openchvote.utilities.algebra;

import ch.openchvote.utilities.UtilityException;
import ch.openchvote.utilities.sequence.Vector;
import ch.openchvote.utilities.set.FiniteSet;
import ch.openchvote.utilities.tools.Streamable;
import ch.openchvote.utilities.tools.VMGJFassade;

import java.math.BigInteger;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;

import static ch.openchvote.utilities.UtilityException.Type.*;

/**
 * This class represents the ring of integers modulo {@code n}. The ring offers two binary operation (addition and
 * multiplication) from which other operations (subtraction, division, etc.) can be derived. The elements of the ring
 * are represented by objects of type {@link BigInteger}. The ring is a {@link FiniteSet} with a size of {@code n}.
 * Instances of this class are immutable.
 */
public final class ZZ implements FiniteSet, Streamable {

    // a cache of previously constructed instances
    static private final Map CACHE = Collections.synchronizedMap(new HashMap<>());

    // the modulus
    private final BigInteger n;

    // private constructor used by factory method
    private ZZ(BigInteger n) {
        this.n = n;
    }

    /**
     * Returns the ring {@code {0,...,n-1}} of integers modulo {@code n}.
     *
     * @param n The modulus
     * @return The ring of integers modulo {@code n}
     */
    static public ZZ of(BigInteger n) {
        if (n == null) {
            throw new UtilityException(NULL_POINTER, ZZ.class);
        }
        return CACHE.computeIfAbsent(n, key -> {
            if (n.signum() <= 0) {
                throw new UtilityException(INVALID_PARAMETERS, ZZ.class, "Value n must be positive");
            }
            return new ZZ(n);
        });
    }

    /**
     * Maps a given integer into the ring of integers modulo {@code n}.
     *
     * @param x The given integer
     * @return The corresponding element of the ring
     */
    public BigInteger mapToRing(BigInteger x) {
        return x.mod(this.n);
    }

    /**
     * Computes the modular sum of two integers {@code x} and {@code y}.
     *
     * @param x The first integer
     * @param y The second integer
     * @return The modular sum {@code x + y mod n}
     */
    public BigInteger add(BigInteger x, BigInteger y) {
        return x.add(y).mod(this.n);
    }

    /**
     * Computes the modular sum of a vector of integers. Returns 1 if the vector is empty.
     *
     * @param bold_x The vector of integers
     * @return The modular sum of the given vector of integers
     */
    public BigInteger sum(Vector bold_x) {
        return bold_x.toStream().reduce(BigInteger.ZERO, this::add);
    }

    /**
     * Computes the additive inverse of {@code x} modulo {@code p}.
     *
     * @param x The given integer
     * @return The additive inverse of {@code x} modulo {@code p}
     */
    public BigInteger minus(BigInteger x) {
        return this.n.subtract(x).mod(this.n);
    }

    /**
     * Computes the modular difference of two integers {@code x} and {@code y}.
     *
     * @param x The first integer
     * @param y The second integer
     * @return The modular difference {@code x - y mod n}
     */
    @SuppressWarnings("SuspiciousNameCombination")
    public BigInteger subtract(BigInteger x, BigInteger y) {
        return this.add(x, this.minus(y));
    }

    /**
     * Computes the modular product of two integers {@code x} and {@code y}.
     *
     * @param x The first integer
     * @param y The second integer
     * @return The modular product {@code x * y mod n}
     */
    public BigInteger multiply(BigInteger x, BigInteger y) {
        return x.multiply(y).mod(this.n);
    }

    /**
     * Computes the modular product of three integers {@code x}, {@code y}, and {@code z}.
     *
     * @param x The first integer
     * @param y The second integer
     * @param z The third integer
     * @return The modular product {@code x * y * y mod n}
     */
    public BigInteger multiply(BigInteger x, BigInteger y, BigInteger z) {
        return this.multiply(this.multiply(x, y), z);
    }

    /**
     * Computes the modular product of a vector of integers. Returns 1 if the vector is empty.
     *
     * @param bold_x The vector of integers
     * @return The modular product of the given vector of integers
     */
    public BigInteger prod(Vector bold_x) {
        return bold_x.toStream().reduce(BigInteger.ONE, this::multiply);
    }

    /**
     * Computes {@code x} to the power of {@code y}.
     *
     * @param x The base
     * @param y The exponent
     * @return {@code x} to the power of {@code y}
     */
    public BigInteger pow(BigInteger x, BigInteger y) {
        if (VMGJFassade.isLoaded()) {
            return VMGJFassade.modPow(x, y, this.n);
        } else {
            return x.modPow(y, this.n);
        }
    }

    /**
     * Computes the multiplicative inverse of {@code x} modulo {@code p}.
     *
     * @param x The given integer
     * @return The multiplicative inverse of {@code x} modulo {@code p}
     */
    public BigInteger invert(BigInteger x) {
        return x.modInverse(this.n);
    }

    /**
     * Computes the modular division of two integers {@code x} and {@code y}.
     *
     * @param x The first integer
     * @param y The second integer
     * @return The modular division {@code x / y mod n}
     */
    @SuppressWarnings("SuspiciousNameCombination")
    public BigInteger divide(BigInteger x, BigInteger y) {
        return this.multiply(x, this.invert(y));
    }

    /**
     * Computes the modular sum of products obtained from combining the values of two equally long vectors of integers.
     * Returns 0 if the vectors are empty.
     *
     * @param bold_x The first vector of integers
     * @param bold_y The second vector of integers
     * @return The resulting modular sum of products
     */
    public BigInteger sumProd(Vector bold_x, Vector bold_y) {
        return this.sum(bold_x.map(bold_y, this::multiply));
    }

    /**
     * Computes the modular product of the modular powers obtained from combining the values of two equally long vectors
     * of bases and exponents. Returns 1 if the vectors are empty. Tries to delegate the computation to the VMGJ
     * library.
     *
     * @param bold_x The first vector of integers
     * @param bold_y The second vector of integers
     * @return The modular product of powers
     */
    public BigInteger prodPow(Vector bold_x, Vector bold_y) {
        if (bold_x.getLength() != bold_y.getLength()) {
            throw new UtilityException(INCOMPATIBLE_LENGTHS, ZZ.class);
        }
        if (VMGJFassade.isLoaded()) {
            return VMGJFassade.modProdPow(bold_x.toArray(), bold_y.toArray(BigInteger[]::new), this.n);
        } else {
            return this.prod(bold_x.map(bold_y, this::pow));
        }
    }

    @Override
    public boolean contains(BigInteger x) {
        return x != null && x.signum() >= 0 && x.compareTo(this.n) < 0;
    }

    @Override
    public BigInteger getSize() {
        return this.n;
    }

    @Override
    public Stream toStream() {
        return Stream.iterate(BigInteger.ZERO, x -> x.compareTo(this.n) < 0, x -> x.add(BigInteger.ONE));
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy