예제 #1
0
    def test_salts(self):
        """Test salting behavior"""
        i = 20
        a = Assignment('assign_salt_a')

        # assigning variables with different names and the same unit should yield
        # different randomizations, when salts are not explicitly specified
        a.x = RandomInteger(min=0, max=100000, unit=i)
        a.y = RandomInteger(min=0, max=100000, unit=i)
        self.assertTrue(a.x != a.y)

        # when salts are specified, they act the same way auto-salting does
        a.z = RandomInteger(min=0, max=100000, unit=i, salt='x')
        self.assertTrue(a.x == a.z)

        # when the Assignment-level salt is different, variables with the same
        # name (or salt) should generally be assigned to different values
        b = Assignment('assign_salt_b')
        b.x = RandomInteger(min=0, max=100000, unit=i)
        self.assertTrue(a.x != b.x)

        # when a full salt is specified, only the full salt is used to do
        # hashing
        a.f = RandomInteger(min=0, max=100000, unit=i, full_salt='fs')
        b.f = RandomInteger(min=0, max=100000, unit=i, full_salt='fs')
        self.assertTrue(a.f == b.f)
        a.f = RandomInteger(min=0, max=100000, unit=i, full_salt='fs2')
        b.f = RandomInteger(min=0, max=100000, unit=i, full_salt='fs2')
        self.assertTrue(a.f == b.f)
예제 #2
0
 def test_set_get_uniform(self):
     a = Assignment(self.tester_salt)
     a.foo = UniformChoice(choices=['a', 'b'], unit=self.tester_unit)
     a.bar = UniformChoice(choices=['a', 'b'], unit=self.tester_unit)
     a.baz = UniformChoice(choices=['a', 'b'], unit=self.tester_unit)
     self.assertEqual(a.foo, 'b')
     self.assertEqual(a.bar, 'a')
     self.assertEqual(a.baz, 'a')
예제 #3
0
    def test_sample(self):
        """Test random sampling without replacement"""

        # returns experiment function with x = sample(c, draws)
        # experiment salt is a string version of c
        def sample(choices, draws, fast_sample=False):
            @experiment_decorator(','.join(map(str, choices)))
            def exp_func(e, i):
                if fast_sample:
                    e.x = FastSample(choices=choices, draws=draws, unit=i)
                else:
                    e.x = Sample(choices=choices, draws=draws, unit=i)
                self.assertTrue(len(e.x) == draws)
                return e

            return exp_func

        def listDistributionTester(func, value_mass, N=1000):
            value_density = TestRandomOperators.valueMassToDensity(value_mass)

            # compute N trials
            xs_list = [func(i=i).get('x') for i in six.moves.range(N)]

            # each xs is a row of the transpose of xs_list.
            # this is expected to have the same distribution as value_density
            for xs in zip(*xs_list):
                self.assertProbs(xs, value_density, float(N))

        listDistributionTester(sample([1, 2, 3], draws=3),
                               ((1, 1), (2, 1), (3, 1)))
        listDistributionTester(sample([1, 2, 3], draws=2),
                               ((1, 1), (2, 1), (3, 1)))
        listDistributionTester(sample([1, 2, 3], draws=2, fast_sample=True),
                               ((1, 1), (2, 1), (3, 1)))
        listDistributionTester(sample(['a', 'a', 'b'], draws=3),
                               (('a', 2), ('b', 1)))

        a = Assignment('assign_salt_a')
        a.old_sample = Sample(choices=[1, 2, 3, 4], draws=1, unit=1)
        new_sample = a.old_sample
        a.old_sample = FastSample(choices=[1, 2, 3, 4], draws=1, unit=1)
        self.assertTrue(len(a.old_sample), 1)
        self.assertTrue(len(new_sample), 1)
        self.assertTrue(a.old_sample != new_sample)
예제 #4
0
    def test_sample(self):
        """Test random sampling without replacement"""

        # returns experiment function with x = sample(c, draws)
        # experiment salt is a string version of c
        def sample(choices, draws, fast_sample=False):
            @experiment_decorator(','.join(map(str, choices)))
            def exp_func(e, i):
                if fast_sample:
                    e.x = FastSample(choices=choices, draws=draws, unit=i)
                else:
                    e.x = Sample(choices=choices, draws=draws, unit=i)
                self.assertTrue(len(e.x) == draws)
                return e
            return exp_func

        def listDistributionTester(func, value_mass, N=1000):
            value_density = TestRandomOperators.valueMassToDensity(value_mass)

            # compute N trials
            xs_list = [func(i=i).get('x') for i in six.moves.range(N)]

            # each xs is a row of the transpose of xs_list.
            # this is expected to have the same distribution as value_density
            for xs in zip(*xs_list):
                self.assertProbs(xs, value_density, float(N))

        listDistributionTester(
            sample([1, 2, 3], draws=3), ((1, 1), (2, 1), (3, 1)))
        listDistributionTester(
            sample([1, 2, 3], draws=2), ((1, 1), (2, 1), (3, 1)))
        listDistributionTester(
            sample([1, 2, 3], draws=2, fast_sample=True), ((1, 1), (2, 1), (3, 1)))
        listDistributionTester(
            sample(['a', 'a', 'b'], draws=3), (('a', 2), ('b', 1)))

        a = Assignment('assign_salt_a')
        a.old_sample = Sample(choices=[1, 2, 3, 4], draws=1, unit=1)
        new_sample = a.old_sample
        a.old_sample = FastSample(choices=[1, 2, 3, 4], draws=1, unit=1)
        self.assertTrue(len(a.old_sample), 1)
        self.assertTrue(len(new_sample), 1)
        self.assertTrue(a.old_sample != new_sample)
예제 #5
0
 def test_overrides(self):
     a = Assignment(self.tester_salt)
     a.set_overrides({'x': 42, 'y': 43})
     a.x = 5
     a.y = 6
     self.assertEqual(a.x, 42)
     self.assertEqual(a.y, 43)
예제 #6
0
    def __init__(self, db_experiment, salt=None, **inputs):
        self.db_experiment = db_experiment

        self.inputs = inputs  # input data

        # True when assignments have been exposure logged
        self._exposure_logged = False
        self._salt = self.db_experiment.salt  # Experiment-level salt

        # Determines whether or not exposure should be logged
        self._in_experiment = True

        # use the name of the class as the default name
        self._name = self.db_experiment.name

        # auto-exposure logging is enabled by default
        self._auto_exposure_log = True

        self.setup()  # sets name, salt, etc.

        self._assignment = Assignment(self.salt)
        self._assigned = False
예제 #7
0
class SingleTrial(SimpleInterpretedExperiment):
    def __init__(self, db_experiment, salt=None, **inputs):
        self.db_experiment = db_experiment

        self.inputs = inputs  # input data

        # True when assignments have been exposure logged
        self._exposure_logged = False
        self._salt = self.db_experiment.salt  # Experiment-level salt

        # Determines whether or not exposure should be logged
        self._in_experiment = True

        # use the name of the class as the default name
        self._name = self.db_experiment.name

        # auto-exposure logging is enabled by default
        self._auto_exposure_log = True

        self.setup()  # sets name, salt, etc.

        self._assignment = Assignment(self.salt)
        self._assigned = False

    def __str__(self):
        return f"Trial {self._salt} of {self._name}"

    def loadScript(self):
        self.script = self.db_experiment.get_planout_dict()

    def setup(self):
        self.name = self.db_experiment.name

    def configure_logger(self):
        pass

    def log_exposure(self, extras=None):
        """Logs exposure to treatment"""
        if not self._in_experiment:
            return

        for key, value in self._assignment.items():
            variation, created = Variation.objects.get_or_create(
                experiment=self.db_experiment, key=key, value=value)

            user_identifier_type = self.inputs.get('user_identifier_type')

            if user_identifier_type is not None:
                exposure = Exposure(experiment=self.db_experiment,
                                    variation=variation)

                if user_identifier_type == DJANGO_USER_DB_ID:
                    user = get_user_model().objects.get(
                        id=self.inputs['user_id'])
                    exposure.event_user = user
                    exposure.event_user_identifier_type = DJANGO_USER_DB_ID
                else:
                    exposure.event_user_identifier = self.inputs['user_id']
                    exposure.event_user_identifier_type = user_identifier_type

                exposure.save()

        self._exposure_logged = True

    def log(self, data):
        ExperimentLog.objects.create(experiment=self.db_experiment, data=data)
예제 #8
0
 def test_set_get_constant(self):
     a = Assignment(self.tester_salt)
     a.foo = 12
     self.assertEqual(a.foo, 12)
예제 #9
0
    def test_salts(self):
        """Test salting behavior"""
        i = 20
        a = Assignment('assign_salt_a')

        # assigning variables with different names and the same unit should yield
        # different randomizations, when salts are not explicitly specified
        a.x = RandomInteger(min=0, max=100000, unit=i)
        a.y = RandomInteger(min=0, max=100000, unit=i)
        self.assertTrue(a.x != a.y)

        # when salts are specified, they act the same way auto-salting does
        a.z = RandomInteger(min=0, max=100000, unit=i, salt='x')
        self.assertTrue(a.x == a.z)

        # when the Assignment-level salt is different, variables with the same
        # name (or salt) should generally be assigned to different values
        b = Assignment('assign_salt_b')
        b.x = RandomInteger(min=0, max=100000, unit=i)
        self.assertTrue(a.x != b.x)

        # when a full salt is specified, only the full salt is used to do
        # hashing
        a.f = RandomInteger(min=0, max=100000, unit=i, full_salt='fs')
        b.f = RandomInteger(min=0, max=100000, unit=i, full_salt='fs')
        self.assertTrue(a.f == b.f)
        a.f = RandomInteger(min=0, max=100000, unit=i, full_salt='fs2')
        b.f = RandomInteger(min=0, max=100000, unit=i, full_salt='fs2')
        self.assertTrue(a.f == b.f)
예제 #10
0
 def wrapped_f(**kwargs):
     params = Assignment(name)
     return f(params, **kwargs)
예제 #11
0
def get_segment(name, num_segments, **units):
    # randomly assign primary unit to a segment
    ass = Assignment(name)
    ass.segment = RandomInteger(min=0, max=num_segments - 1, **units)
    return ass.segment
예제 #12
0
    def test_custom_salt(self):
        a = Assignment(self.tester_salt)
	custom_salt = lambda x,y: '%s-%s' % (x,y)
        a.foo = UniformChoice(choices=range(8), unit=self.tester_unit)
        self.assertEqual(a.foo, 7)
예제 #13
0
def get_segment(name, num_segments, **units):
    # randomly assign primary unit to a segment
    ass = Assignment(name)
    ass.segment = RandomInteger(min=0, max=num_segments - 1, **units)
    return ass.segment
예제 #14
0
 def test_custom_salt(self):
     a = Assignment(self.tester_salt)
     custom_salt = lambda x,y: '%s-%s' % (x,y)
     a.foo = UniformChoice(choices=list(range(8)), unit=self.tester_unit)
     self.assertEqual(a.foo, 7)