Added RandomAllInclusiveSet (ideal algorithm for random testing)
parent
31b7fb8e44
commit
02db399e56
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Represents a set that randomizes all elements of an entire predicted set,
|
||||
* ensuring that repeat sets are less predictable.
|
||||
*
|
||||
* This algorithm works by first repeating the given set S the necessary number
|
||||
* of times in order to produce a new set S' that contains at least one element
|
||||
* for the requested sample size. S' is then randomized in its entirety.
|
||||
*
|
||||
* See also RandomGroupedSet.
|
||||
*/
|
||||
rectest.set.RandomAllInclusiveSet = Class( 'RandomAllInclusiveSet' )
|
||||
.extend( rectest.set.RandomGroupedSet,
|
||||
{
|
||||
/**
|
||||
* Randomizes an entire set large enough to encompass the requested sample
|
||||
* size
|
||||
*
|
||||
* The actual array randomization algorithm is inherited from the parent.
|
||||
*
|
||||
* @param {Array} set set to randomize
|
||||
*
|
||||
* @return {Array} randomized set
|
||||
*/
|
||||
'override protected randomizeSet': function( set )
|
||||
{
|
||||
var samples = this.getSampleSize();
|
||||
|
||||
// this algorithm will work only if we know how many samples are desired
|
||||
if ( samples < 1 )
|
||||
{
|
||||
throw Error(
|
||||
"RandomAllInclusiveSet can only be used with sets of " +
|
||||
"known length; desired sample size is unknown"
|
||||
);
|
||||
}
|
||||
|
||||
// nothing we can do with an empty set (avoid the division by 0 and just
|
||||
// bail out)
|
||||
if ( set.length === 0 )
|
||||
{
|
||||
return set;
|
||||
}
|
||||
|
||||
// call the super method with the set repeated N times, where N is the
|
||||
// minimum number of repeats required to satisfy the requested sample
|
||||
// size (may result in a set larger than the sample size, but that is
|
||||
// fine)
|
||||
return this.__super( this._repeatSet( set,
|
||||
Math.ceil( samples / set.length )
|
||||
) );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Recursively repeats the given set n times
|
||||
*
|
||||
* @param {Array} set set to repeat
|
||||
* @param {number} n number of times to repeat
|
||||
* @param {=Array} s2 destination array (defaults to [] on first iteration)
|
||||
*
|
||||
* @return {Array} s2 after operation is complete
|
||||
*/
|
||||
'private _repeatSet': function( set, n, s2 )
|
||||
{
|
||||
s2 = s2 || [];
|
||||
n = ( isNaN( n ) ) ? 0 : n; // failsafe
|
||||
|
||||
var i = set.length;
|
||||
|
||||
if ( n === 0 )
|
||||
{
|
||||
return s2;
|
||||
}
|
||||
|
||||
// does not matter that we're doing it in reverse, since the set
|
||||
// will be randomized later
|
||||
while ( i-- )
|
||||
{
|
||||
s2.push( set[ i ] );
|
||||
}
|
||||
|
||||
return this._repeatSet( set, --n, s2 );
|
||||
}
|
||||
} );
|
|
@ -2,6 +2,10 @@
|
|||
* Represents a set that is randomized each time the first element is reached.
|
||||
* The set will loop back to the first element until the required number of
|
||||
* samples are satisfied.
|
||||
*
|
||||
* Note that this means that, should the sample size be larger than the number
|
||||
* of elements in the set, the set will be randomized only for each iteration,
|
||||
* which may not be what you want for a truely random sample set.
|
||||
*/
|
||||
rectest.set.RandomGroupedSet = Class( 'RandomGroupedSet' )
|
||||
.implement( rectest.set.Set )
|
||||
|
@ -35,48 +39,25 @@ rectest.set.RandomGroupedSet = Class( 'RandomGroupedSet' )
|
|||
__construct: function( base_set, sample_size )
|
||||
{
|
||||
this._set = base_set;
|
||||
this._setLength = this._set.length;
|
||||
this._samplesRemain = +sample_size || -1;
|
||||
|
||||
this._reset();
|
||||
},
|
||||
|
||||
|
||||
'private _repeatSet': function( set, n, s2 )
|
||||
{
|
||||
s2 = s2 || [];
|
||||
|
||||
var i = set.length;
|
||||
|
||||
if ( n === 0 )
|
||||
{
|
||||
return s2;
|
||||
}
|
||||
|
||||
// does not matter that we're doing it in reverse, since the set
|
||||
// will be randomized later
|
||||
while ( i-- )
|
||||
{
|
||||
s2[ i ] = set[ i ];
|
||||
}
|
||||
|
||||
return this._repeatSet( set, --n, s2 );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Randomizes a set using the Fisher-Yates shuffle algorithm
|
||||
*
|
||||
* @param {Array} set set to sort
|
||||
*/
|
||||
'private _randomizeSet': function( set )
|
||||
'virtual protected randomizeSet': function( set )
|
||||
{
|
||||
var i = set.length;
|
||||
|
||||
// simply prevent an infinite loop below
|
||||
if ( i === 0 )
|
||||
{
|
||||
return;
|
||||
return set;
|
||||
}
|
||||
|
||||
// simply loop through each element in the set, swapping each with a
|
||||
|
@ -86,6 +67,8 @@ rectest.set.RandomGroupedSet = Class( 'RandomGroupedSet' )
|
|||
var r = Math.floor( Math.random() * ( i + 1 ) );
|
||||
set[ i ] = [ set[ r ], ( set[ r ] = set[ i ] ) ][ 0 ];
|
||||
}
|
||||
|
||||
return set;
|
||||
},
|
||||
|
||||
|
||||
|
@ -96,12 +79,6 @@ rectest.set.RandomGroupedSet = Class( 'RandomGroupedSet' )
|
|||
*/
|
||||
'public getNextElement': function()
|
||||
{
|
||||
// reset once we're at the end
|
||||
if ( this._setPos === this._setLength )
|
||||
{
|
||||
this._reset();
|
||||
}
|
||||
|
||||
// return null once we have returned all of the requested samples
|
||||
// (intentionally a 0 check, as this will be negative for an
|
||||
// infinite number of samples)
|
||||
|
@ -110,6 +87,12 @@ rectest.set.RandomGroupedSet = Class( 'RandomGroupedSet' )
|
|||
return null;
|
||||
}
|
||||
|
||||
// reset once we're at the end
|
||||
if ( this._setPos === this._setLength )
|
||||
{
|
||||
this._reset();
|
||||
}
|
||||
|
||||
// return element from set (do not shift/pop, since we may need to
|
||||
// repeatedly iterate through this list)
|
||||
return this._set[ this._setPos++ ];
|
||||
|
@ -118,7 +101,14 @@ rectest.set.RandomGroupedSet = Class( 'RandomGroupedSet' )
|
|||
|
||||
'private _reset': function()
|
||||
{
|
||||
this._setPos = 0;
|
||||
this._randomizeSet( this._set );
|
||||
this._setPos = 0;
|
||||
this._set = this.randomizeSet( this._set );
|
||||
this._setLength = this._set.length;
|
||||
},
|
||||
|
||||
|
||||
'protected getSampleSize': function()
|
||||
{
|
||||
return this._samplesRemain;
|
||||
}
|
||||
} );
|
||||
|
|
|
@ -8,7 +8,7 @@ rectest.set.SetFactory = Class( 'SetFactory',
|
|||
var sets = rectest.set;
|
||||
|
||||
return [
|
||||
null,
|
||||
sets.RandomAllInclusiveSet,
|
||||
sets.RandomGroupedSet,
|
||||
null,
|
||||
null
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
development purposes -->
|
||||
<script type="text/javascript" src="scripts/set/Set.js"></script>
|
||||
<script type="text/javascript" src="scripts/set/RandomGroupedSet.js"></script>
|
||||
<script type="text/javascript" src="scripts/set/RandomAllInclusiveSet.js"></script>
|
||||
<script type="text/javascript" src="scripts/set/SetFactory.js"></script>
|
||||
<script type="text/javascript" src="scripts/TestCase.js"></script>
|
||||
<script type="text/javascript" src="scripts/TestRun.js"></script>
|
||||
|
|
Loading…
Reference in New Issue