/*
 * Redberry: symbolic tensor computations.
 *
 * Copyright (c) 2010-2015:
 *   Stanislav Poslavsky   
 *   Bolotin Dmitriy       
 *
 * This file is part of Redberry.
 *
 * Redberry is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Redberry 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 General Public License
 * along with Redberry. If not, see .
 */
package cc.redberry.core.groups.permutations;

import cc.redberry.core.context.CC;
import org.apache.commons.math3.random.RandomGenerator;
import org.apache.commons.math3.random.Well19937a;

import java.util.List;

/**
 * Algorithms for generating uniform distributed random elements of permutation group.
 * 

Example:

* In the following example we use a two generators, which generates a group of order 5616 and choose 5616 random * elements of this group with uniform distribution *

 //primitive permutation group with 5616 elements
 * Permutation perm1 = new PermutationOneLineInt(9, 1, 2, 0, 4, 8, 5, 11, 6, 3, 10, 12, 7);
 * Permutation perm2 = new PermutationOneLineInt(2, 0, 1, 8, 3, 5, 7, 11, 4, 12, 9, 6, 10);
 * ArrayList<Permutation> generators = new ArrayList<>(Arrays.asList(perm1, perm2));
 * //we'll use a list of generators as a source of randomness
 * //this brings some randomization in generators list
 * RandomPermutation.randomness(generators);
 * Set<Permutation> set = new HashSet<>();
 * int k = 5616; //equal to order of group
 * //choosing 5616 random elements
 * for (; k > 0; --k)
 *     set.add(RandomPermutation.random(generators));
 * //uniform
 * System.out.println(set.size());//~3500
 * 
*

* * @author Dmitry Bolotin * @author Stanislav Poslavsky * @since 1.1.6 */ public final class RandomPermutation { private RandomPermutation() { } //------------------------------ RANDOM --------------------------------------------// /** * Default size of random source list of generators */ public static final int DEFAULT_RANDOMNESS_EXTEND_TO_SIZE = 10; /** * Default size of random refinements */ public static final int DEFAULT_NUMBER_OF_RANDOM_REFINEMENTS = 20; /** * Brings randomness to a list of generators: the source list will be extended and filled by an equivalent set * of generators generated randomly; commonly it should be used in a combination with * {@link #random(java.util.List, org.apache.commons.math3.random.RandomGenerator)} to produce almost uniform distributed permutations in a group defined * by corresponding set of generators. This method is a variant of PREINITIALIZE described * in Sec. 3.2.2 in [Holt05]. * * @param generators a list of generators * @see #random(java.util.List, org.apache.commons.math3.random.RandomGenerator) */ public static void randomness(List generators) { randomness(generators, DEFAULT_RANDOMNESS_EXTEND_TO_SIZE, DEFAULT_NUMBER_OF_RANDOM_REFINEMENTS, CC.getRandomGenerator()); } /** * Brings randomness to a list of generators: the source list will be extended and filled by an equivalent set * of generators generated randomly; commonly it should be used in a combination with * {@link #random(java.util.List, org.apache.commons.math3.random.RandomGenerator)} to produce almost uniform distributed permutations in a group defined * by corresponding set of generators. This method is a variant of PREINITIALIZE described * in Sec. 3.2.2 in [Holt05]. * * @param generators a list of generators * @param extendToSize extend specified list to this size with additional (equivalent) random elements * @param numberOfRefinements number of invocations of random procedure to refine the randomness * @param random random generator */ public static void randomness(List generators, int extendToSize, int numberOfRefinements, RandomGenerator random) { if (generators.size() < 2 && extendToSize < 2) throw new IllegalArgumentException("List should extended by at least one element."); if (generators.size() < extendToSize) { int delta = extendToSize - generators.size() + 1; int i = 0; while (--delta >= 0) generators.add(generators.get(i++)); } //hold identity for use in PRRANDOM if (!generators.get(generators.size() - 1).isIdentity()) generators.add(generators.get(0).getIdentity()); while (--numberOfRefinements >= 0) random(generators, random); } /** * Produces almost uniformly distributed elements of a group specified by specified generators (only if method * {@link #randomness(java.util.List, int, int, org.apache.commons.math3.random.RandomGenerator)} was invoked with specified generators); and brings additional * randomness in the specified list. See algorithm PRRANDOM in Sec. 3.2.2 in [Holt05]. * * @param generators generators (method {@link #randomness(java.util.List, int, int, org.apache.commons.math3.random.RandomGenerator)} should be invoked before) * @return random element of a group */ public static Permutation random(List generators) { return random(generators, CC.getRandomGenerator()); } /** * Produces almost uniformly distributed elements of a group specified by specified generators (only if method * {@link #randomness(java.util.List, int, int, org.apache.commons.math3.random.RandomGenerator)} was invoked with specified generators); and brings additional * randomness in the specified list. See algorithm PRRANDOM in Sec. 3.2.2 in [Holt05]. * * @param generators generators (method {@link #randomness(java.util.List, int, int, org.apache.commons.math3.random.RandomGenerator)} should be invoked before) * @param random random generator * @return random element of a group */ public static Permutation random(List generators, RandomGenerator random) { if (generators.size() < 3) throw new IllegalArgumentException("List size should be >= 3"); int generatorsSize = generators.size() - 1; //do not take last element int s = random.nextInt(generatorsSize); int t; do { t = random.nextInt(generatorsSize); } while (t == s); Permutation ps = generators.get(s), pt = generators.get(t), x0 = generators.get(generatorsSize); if (random.nextBoolean()) pt = pt.inverse(); if (random.nextBoolean()) { generators.set(s, ps = ps.composition(pt)); generators.set(generatorsSize, x0 = x0.composition(ps)); } else { generators.set(s, ps = pt.composition(ps)); generators.set(generatorsSize, x0 = ps.composition(x0)); } return x0; } }

Ads help maintain this website.