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

org.bouncycastle.pqc.math.linearalgebra.Permutation Maven / Gradle / Ivy

There is a newer version: 1.70_1
Show newest version
package org.bouncycastle.pqc.math.linearalgebra;

import java.security.SecureRandom;

import org.bouncycastle.util.Arrays;

/**
 * This class implements permutations of the set {0,1,...,n-1} for some given n
 * > 0, i.e., ordered sequences containing each number m (0 <=
 * m < n)
 * once and only once.
 */
public class Permutation
{

    /**
     * perm holds the elements of the permutation vector, i.e. [perm(0),
     * perm(1), ..., perm(n-1)]
     */
    private int[] perm;

    /**
     * Create the identity permutation of the given size.
     *
     * @param n the size of the permutation
     */
    public Permutation(int n)
    {
        if (n <= 0)
        {
            throw new IllegalArgumentException("invalid length");
        }

        perm = new int[n];
        for (int i = n - 1; i >= 0; i--)
        {
            perm[i] = i;
        }
    }

    /**
     * Create a permutation using the given permutation vector.
     *
     * @param perm the permutation vector
     */
    public Permutation(int[] perm)
    {
        if (!isPermutation(perm))
        {
            throw new IllegalArgumentException(
                "array is not a permutation vector");
        }

        this.perm = IntUtils.clone(perm);
    }

    /**
     * Create a permutation from an encoded permutation.
     *
     * @param enc the encoded permutation
     */
    public Permutation(byte[] enc)
    {
        if (enc.length <= 4)
        {
            throw new IllegalArgumentException("invalid encoding");
        }

        int n = LittleEndianConversions.OS2IP(enc, 0);
        int size = IntegerFunctions.ceilLog256(n - 1);

        if (enc.length != 4 + n * size)
        {
            throw new IllegalArgumentException("invalid encoding");
        }

        perm = new int[n];
        for (int i = 0; i < n; i++)
        {
            perm[i] = LittleEndianConversions.OS2IP(enc, 4 + i * size, size);
        }

        if (!isPermutation(perm))
        {
            throw new IllegalArgumentException("invalid encoding");
        }

    }

    /**
     * Create a random permutation of the given size.
     *
     * @param n  the size of the permutation
     * @param sr the source of randomness
     */
    public Permutation(int n, SecureRandom sr)
    {
        if (n <= 0)
        {
            throw new IllegalArgumentException("invalid length");
        }

        perm = new int[n];

        int[] help = new int[n];
        for (int i = 0; i < n; i++)
        {
            help[i] = i;
        }

        int k = n;
        for (int j = 0; j < n; j++)
        {
            int i = RandUtils.nextInt(sr, k);
            k--;
            perm[j] = help[i];
            help[i] = help[k];
        }
    }

    /**
     * Encode this permutation as byte array.
     *
     * @return the encoded permutation
     */
    public byte[] getEncoded()
    {
        int n = perm.length;
        int size = IntegerFunctions.ceilLog256(n - 1);
        byte[] result = new byte[4 + n * size];
        LittleEndianConversions.I2OSP(n, result, 0);
        for (int i = 0; i < n; i++)
        {
            LittleEndianConversions.I2OSP(perm[i], result, 4 + i * size, size);
        }
        return result;
    }

    /**
     * @return the permutation vector (perm(0),perm(1),...,perm(n-1))
     */
    public int[] getVector()
    {
        return IntUtils.clone(perm);
    }

    /**
     * Compute the inverse permutation P-1.
     *
     * @return this-1
     */
    public Permutation computeInverse()
    {
        Permutation result = new Permutation(perm.length);
        for (int i = perm.length - 1; i >= 0; i--)
        {
            result.perm[perm[i]] = i;
        }
        return result;
    }

    /**
     * Compute the product of this permutation and another permutation.
     *
     * @param p the other permutation
     * @return this * p
     */
    public Permutation rightMultiply(Permutation p)
    {
        if (p.perm.length != perm.length)
        {
            throw new IllegalArgumentException("length mismatch");
        }
        Permutation result = new Permutation(perm.length);
        for (int i = perm.length - 1; i >= 0; i--)
        {
            result.perm[i] = perm[p.perm[i]];
        }
        return result;
    }

    /**
     * checks if given object is equal to this permutation.
     * 

* The method returns false whenever the given object is not permutation. * * @param other - * permutation * @return true or false */ public boolean equals(Object other) { if (!(other instanceof Permutation)) { return false; } Permutation otherPerm = (Permutation)other; return IntUtils.equals(perm, otherPerm.perm); } /** * @return a human readable form of the permutation */ public String toString() { String result = "[" + perm[0]; for (int i = 1; i < perm.length; i++) { result += ", " + perm[i]; } result += "]"; return result; } /** * @return the hash code of this permutation */ public int hashCode() { return Arrays.hashCode(perm); } /** * Check that the given array corresponds to a permutation of the set * {0, 1, ..., n-1}. * * @param perm permutation vector * @return true if perm represents an n-permutation and false otherwise */ private boolean isPermutation(int[] perm) { int n = perm.length; boolean[] onlyOnce = new boolean[n]; for (int i = 0; i < n; i++) { if ((perm[i] < 0) || (perm[i] >= n) || onlyOnce[perm[i]]) { return false; } onlyOnce[perm[i]] = true; } return true; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy