net.sf.tweety.commons.util.RandomSubsetIterator Maven / Gradle / Ivy
/*
* This file is part of "Tweety", a collection of Java libraries for
* logical aspects of artificial intelligence and knowledge representation.
*
* Tweety is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3 as
* published by the Free Software Foundation.
*
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
* Copyright 2016 The Tweety Project Team
*/
package net.sf.tweety.commons.util;
import java.util.*;
/**
* Iterates over all subsets of a given sets in a random order.
*
* @author Matthias Thimm
*
* @param The element class which is iterated.
*/
public class RandomSubsetIterator extends SubsetIterator {
/** The set over which subsets are iterated. */
private List set;
/** Whether to avoid duplicates in the iteration. */
private boolean avoidDuplicates;
/** The random number generator. */
private Random random;
/** Only used when avoidDuplicats is set to true. Then
* this set contains all (representations of) subsets
* already generated (if those are less than half the number
* of all subsets) or the subsets not generated yet (otherwise). */
private Set temp;
/** Only used when avoidDuplicats is set to true. The number
* of already generated subsets. */
private long generatedSubsets;
/** Only used when avoidDuplicats is set to true. The number
* of all subsets. */
private double allSubsets;
/** Only used when avoidDuplicats is set to true. Whether
* the mode of using this.temp has been switched. */
private boolean switched;
/** Creates a new subset iterator for the given set.
* @param set some set.
* @param avoidDuplicates whether to avoid duplicates in the iteration.
* NOTE: setting this value to true might increase computation time
* and needed space drastically.
*/
public RandomSubsetIterator(Set set, boolean avoidDuplicates){
super(set);
this.set = new ArrayList(set);
this.avoidDuplicates = avoidDuplicates;
this.random = new Random();
if(this.avoidDuplicates){
this.temp = new HashSet();
this.generatedSubsets = 0;
this.allSubsets = Math.pow(2, this.set.size());
this.switched = false;
}
}
/* (non-Javadoc)
* @see java.util.Iterator#hasNext()
*/
@Override
public boolean hasNext() {
return !this.avoidDuplicates || this.generatedSubsets < this.allSubsets;
}
/* (non-Javadoc)
* @see java.util.Iterator#next()
*/
@Override
public Set next() {
if(!this.avoidDuplicates){
Set result = new HashSet();
for(T elem: this.set)
if(this.random.nextBoolean())
result.add(elem);
return result;
}else{
boolean firstHalf = this.generatedSubsets == 0 || this.allSubsets / this.generatedSubsets > 2;
BitSet bitSet = this.generate(this.set.size(), firstHalf);
Set result = new HashSet();
for(int i = 0; i < this.set.size(); i++)
if(bitSet.length() > i && bitSet.get(i))
result.add(this.set.get(i));
this.generatedSubsets++;
if(!this.switched && this.allSubsets / this.generatedSubsets <= 2){
this.switched = true;
Set temp2 = new HashSet();
bitSet = new BitSet();
BitSet tmp;
double numberOfBitSets = Math.pow(2, this.set.size());
for(long i = 0; i < numberOfBitSets; i++){
if(!this.temp.contains(bitSet)){
tmp = new BitSet();
tmp.or(bitSet);
temp2.add(tmp);
}
this.increment(bitSet);
}
this.temp = temp2;
}
return result;
}
}
/** Increments the given bit set
* @param bitSet some bit set.
*/
private void increment(BitSet bitSet){
boolean carry = true, tmp;
int i = 0;
while(carry){
tmp = carry;
carry = carry && bitSet.get(i);
bitSet.set(i, tmp ^ bitSet.get(i));
i++;
}
}
/**
* Generates a new bit set of the given length. If checkForDuplicates
* is true then the all bit sets in this.temp are regarded as already
* being generated and the new one will be different from all of those.
* Furthermore, the new bit set is added to this.temp. If checkForDuplicates
* is false, the new bit set will be chosen from this.temp and removed there.
* @param length the length of the bit set.
* @param checkForDuplicates whether to check for duplicates (see above).
* @return a bit set.
*/
private BitSet generate(int length, boolean checkForDuplicates){
BitSet result;
if(checkForDuplicates){
do{
result = this.generateRandomly(length);
}while(this.temp.contains(result));
this.temp.add(result);
return result;
}else{
long idx = this.random.nextInt(this.temp.size());
for(BitSet elem: this.temp){
if(idx == 0){
this.temp.remove(elem);
return elem;
}
idx--;
}
}
//this should not happen
throw new RuntimeException("this should not happen");
}
/** Generates a random bit set of the given length.
* @param length some length.
* @return a random bit set.
*/
private BitSet generateRandomly(int length){
BitSet result = new BitSet();
for(int i = 0; i < length; i++)
if(this.random.nextBoolean())
result.set(i);
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy