Skip to content

OwenTree Scrambling [Owen1996]

Description

Perform Owen’s scrambling on a given Pointset.

Unlike Owen’s scramler, this scrambler partially stores the trees to allow user to specify bits. The key function is setBitPattern which allows to adress specific dyadic intervals and have multiple parameters:

  • Dimension: Which tree to modify
  • The pattern: A string of ‘0’, ‘1’ or ‘*’. First characters are the most significant bits !
  • Value: Sets the corresponding bits to True or False (swap or not).

For instance, the pattern ‘0*1’ addresses 2 dyadic intervals : [0.125, 0.250] and [0.375, 0.500]. Specfically :

  • ‘0’: Inside [0.000, 0.500]
  • ’*’: Either [0.000, 0.250] or [0.250, 0.500]
  • ‘1’: Inside [0.125, 0.250] or [0.375, 0.500]

Therefore, if value is set to true, it is guaranteed to swap points in the intervals:

  • [0.1250, 0.1875] with [0.1875, 0.2500]
  • [0.3750, 0.4375] with [0.4375, 0.5000]

To swap [0.0, 0.5] with [0.5, 1.0] use the pattern "" (ie. swap points independently of their first bit). Use it last as it is always included in the other non-empty pattern.

The trees are not grown unless necessary. By default, they starts with no leaves. Setting the pattern 0*1 will grow a FULL tree of height 3 (2^(3+1) - 1 elements). Setting afterwards 0*1* will expand the tree to be of height 4 (2^(4+1) elements).

The max_height parameter in the constructor allows the scrambling to go beyond the stored trees without memory overhead. Trees are then generated randomly in the same way Owen’s scrambler does.

  • By it’s very nature, it only operates on ‘integer pointsets’, meaning that points are not in [0, 1], but integers [[0, INT_MAX]]. There are no check on the type in the executable version and double are cast to integers (and will likely be converted to 0).

Files

include/utk/scrambling/ScramblingOwenTree.hpp

Usage


No CLI interface. 
#include <utk/utils/PointsetIO.hpp>
#include <utk/utils/Pointset.hpp>
#include <utk/samplers/SamplerSobol.hpp>
#include <utk/scrambling/ScramblingOwen.hpp>

int main()
{
    utk::Pointset<uint32_t> pts;

    utk::SamplerSobol sobol(2 /* dimension */);
    sobol.setRandomSeed(/* empty means random, can also pass a number */);

    // Check for no errors
    if (sobol.generateSamples(pts, 1024 /* Number of points */))
    {
        utk::ScramblingOwenTree owen(32 /* max depth : no tree stored yet */);
        owen.setBitPattern(
            0,      // Dimension 
            "0*1",  // Patterns. 
                    // '0': Inside [0.000, 0.500]
                    // '*': Either [0.000, 0.250] or [0.250, 0.500]
                    // '1': Inside [0.125, 0.250] or [0.375, 0.500]
                    // Therefore : Guarentees to swap or not  
                    //   [0.1250, 0.1875] with [0.1875, 0.2500]
                    //   [0.3750, 0.4375] with [0.4375, 0.5000]
            true    // True means 'swap' the intervals
        ); // Tree up to depth 3 alreay stores, so no allocation


        // In place:
        owen.Scramble(pts);
        owen.setRandomSeed();
        // Results in another pointset. If double, it is converted appropriatly
        utk::Pointset<double> pts2;
        owen.Scramble(pts, pts2);        
    }
}
import pyutk
samples = pyutk.Sobol(d=2, depth=0).isample(1024) # isample returns integers
sc = pyutk.OwenTree(
  depth = 32                      # max depth
)
sc.setBitPattern(
    0, 
    "0*1", 
    False
)

sc.scramble(samples) # This is a double array