예제 #1
0
    def test_adjudicate_combined_remove_unadj(self):
        """
        Test combining adjudication switching with un-adjudication.
        """
        iqrs = IqrSession()

        # Set initial state
        p0 = DescriptorMemoryElement('', 0).set_vector([0])
        p1 = DescriptorMemoryElement('', 1).set_vector([1])
        p2 = DescriptorMemoryElement('', 2).set_vector([2])
        n3 = DescriptorMemoryElement('', 3).set_vector([3])
        n4 = DescriptorMemoryElement('', 4).set_vector([4])

        # Set initial state
        iqrs.positive_descriptors = {p0, p1, p2}
        iqrs.negative_descriptors = {n3, n4}

        # Add p5, switch p1 to negative, unadj p2
        p5 = DescriptorMemoryElement('', 5).set_vector([5])
        iqrs.adjudicate(new_positives=[p5],
                        new_negatives=[p1],
                        un_positives=[p2])
        assert iqrs.positive_descriptors == {p0, p5}
        assert iqrs.negative_descriptors == {n3, n4, p1}

        # Add n6, switch n4 to positive, unadj n3
        n6 = DescriptorMemoryElement('', 6).set_vector([6])
        iqrs.adjudicate(new_positives=[n4],
                        new_negatives=[n6],
                        un_negatives=[n3])
        assert iqrs.positive_descriptors == {p0, p5, n4}
        assert iqrs.negative_descriptors == {p1, n6}
예제 #2
0
    def test_adjudicate_unadj_noeffect(self):
        """
        Test that an empty call, or un-adjudicating a descriptor that is not
        currently marked as a positive or negative, causes no state change.
        """
        iqrs = IqrSession()

        # Set initial state
        p0 = DescriptorMemoryElement('', 0).set_vector([0])
        p1 = DescriptorMemoryElement('', 1).set_vector([1])
        p2 = DescriptorMemoryElement('', 2).set_vector([2])
        n3 = DescriptorMemoryElement('', 3).set_vector([3])
        n4 = DescriptorMemoryElement('', 4).set_vector([4])

        # Set initial state
        iqrs.positive_descriptors = {p0, p1, p2}
        iqrs.negative_descriptors = {n3, n4}

        # Empty adjudication
        iqrs.adjudicate()
        assert iqrs.positive_descriptors == {p0, p1, p2}
        assert iqrs.negative_descriptors == {n3, n4}

        # Attempt un-adjudication of a non-adjudicated element.
        e = DescriptorMemoryElement('', 5).set_vector([5])
        iqrs.adjudicate(un_positives=[e], un_negatives=[e])
        assert iqrs.positive_descriptors == {p0, p1, p2}
        assert iqrs.negative_descriptors == {n3, n4}
예제 #3
0
    def test_adjudicate_cache_resetting_negative(self):
        """
        Test results view cache resetting functionality on adjudicating certain
        ways.
        """
        e = DescriptorMemoryElement('', 0).set_vector([0])

        iqrs = IqrSession()
        iqrs._ordered_pos = True
        iqrs._ordered_neg = True
        iqrs._ordered_non_adj = True

        # Check that adding a positive adjudication resets the positive and
        # non-adjudicated result caches.
        iqrs.adjudicate(new_negatives=[e])
        assert iqrs._ordered_pos is True  # NOT reset
        assert iqrs._ordered_neg is None  # reset
        assert iqrs._ordered_non_adj is None  # reset
예제 #4
0
    def test_adjudication_cache_not_reset(self):
        """
        Test that pos/neg/non-adj result caches are NOT reset when no state
        change occurs under different circumstances
        """
        # setup initial IQR session state.
        p0 = DescriptorMemoryElement('', 0).set_vector([0])
        p1 = DescriptorMemoryElement('', 1).set_vector([1])
        p2 = DescriptorMemoryElement('', 2).set_vector([2])
        n3 = DescriptorMemoryElement('', 3).set_vector([3])
        n4 = DescriptorMemoryElement('', 4).set_vector([4])
        iqrs = IqrSession()
        iqrs.positive_descriptors = {p0, p1, p2}
        iqrs.negative_descriptors = {n3, n4}
        iqrs._ordered_pos = iqrs._ordered_neg = iqrs._ordered_non_adj = True

        # Empty adjudication
        iqrs.adjudicate()
        assert iqrs._ordered_pos is True
        assert iqrs._ordered_neg is True
        assert iqrs._ordered_non_adj is True

        # Repeat positive/negative adjudication
        iqrs.adjudicate(new_positives=[p0])
        assert iqrs._ordered_pos is True
        assert iqrs._ordered_neg is True
        assert iqrs._ordered_non_adj is True
        iqrs.adjudicate(new_negatives=[n3])
        assert iqrs._ordered_pos is True
        assert iqrs._ordered_neg is True
        assert iqrs._ordered_non_adj is True
        iqrs.adjudicate(new_positives=[p1], new_negatives=[n4])
        assert iqrs._ordered_pos is True
        assert iqrs._ordered_neg is True
        assert iqrs._ordered_non_adj is True

        # No-op un-adjudication
        e = DescriptorMemoryElement('', 5).set_vector([5])
        iqrs.adjudicate(un_positives=[e], un_negatives=[e])
        assert iqrs._ordered_pos is True
        assert iqrs._ordered_neg is True
        assert iqrs._ordered_non_adj is True
예제 #5
0
    def test_adjudication_switch(self):
        """
        Test providing positives and negatives on top of an existing state such
        that the descriptor adjudications are reversed. (what was once positive
        is now negative, etc.)
        """
        iqrs = IqrSession()

        p0 = DescriptorMemoryElement('', 0).set_vector([0])
        p1 = DescriptorMemoryElement('', 1).set_vector([1])
        p2 = DescriptorMemoryElement('', 2).set_vector([2])
        n3 = DescriptorMemoryElement('', 3).set_vector([3])
        n4 = DescriptorMemoryElement('', 4).set_vector([4])

        # Set initial state
        iqrs.positive_descriptors = {p0, p1, p2}
        iqrs.negative_descriptors = {n3, n4}

        # Adjudicate, partially swapping adjudications individually
        iqrs.adjudicate(new_positives=[n3])
        assert iqrs.positive_descriptors == {p0, p1, p2, n3}
        assert iqrs.negative_descriptors == {n4}

        iqrs.adjudicate(new_negatives=[p1])
        assert iqrs.positive_descriptors == {p0, p2, n3}
        assert iqrs.negative_descriptors == {n4, p1}

        # Adjudicate swapping remaining at the same time
        iqrs.adjudicate(new_positives=[n4], new_negatives=[p0, p2])
        assert iqrs.positive_descriptors == {n3, n4}
        assert iqrs.negative_descriptors == {p0, p1, p2}
예제 #6
0
    def test_adjudicate_add_duplicates(self):
        """
        Test that adding duplicate descriptors as positive or negative
        adjudications has no effect as the behavior of sets should be observed.
        """
        iqrs = IqrSession()

        p0 = DescriptorMemoryElement('', 0).set_vector([0])
        p2 = DescriptorMemoryElement('', 2).set_vector([2])
        n1 = DescriptorMemoryElement('', 1).set_vector([1])
        p3 = DescriptorMemoryElement('', 3).set_vector([3])
        n4 = DescriptorMemoryElement('', 4).set_vector([4])

        # Partially add the above descriptors
        iqrs.adjudicate(new_positives=[p0], new_negatives=[n1])
        assert iqrs.positive_descriptors == {p0}
        assert iqrs.negative_descriptors == {n1}

        # Add all descriptors, observing that that already added descriptors
        # are ignored.
        iqrs.adjudicate(new_positives=[p0, p2, p3], new_negatives=[n1, n4])
        assert iqrs.positive_descriptors == {p0, p2, p3}
        assert iqrs.negative_descriptors == {n1, n4}

        # Duplicate previous call so no new descriptors are added. No change or
        # issue should be observed.
        iqrs.adjudicate(new_positives=[p0, p2, p3], new_negatives=[n1, n4])
        assert iqrs.positive_descriptors == {p0, p2, p3}
        assert iqrs.negative_descriptors == {n1, n4}
예제 #7
0
    def test_adjudicate_remove_pos_neg(self):
        """
        Test that we can remove positive and negative adjudications using
        "un_*" parameters.
        """
        iqrs = IqrSession()

        # Set initial state
        p0 = DescriptorMemoryElement('', 0).set_vector([0])
        p1 = DescriptorMemoryElement('', 1).set_vector([1])
        p2 = DescriptorMemoryElement('', 2).set_vector([2])
        n3 = DescriptorMemoryElement('', 3).set_vector([3])
        n4 = DescriptorMemoryElement('', 4).set_vector([4])

        # Set initial state
        iqrs.positive_descriptors = {p0, p1, p2}
        iqrs.negative_descriptors = {n3, n4}

        # "Un-Adjudicate" descriptors individually
        iqrs.adjudicate(un_positives=[p1])
        assert iqrs.positive_descriptors == {p0, p2}
        assert iqrs.negative_descriptors == {n3, n4}
        iqrs.adjudicate(un_negatives=[n3])
        assert iqrs.positive_descriptors == {p0, p2}
        assert iqrs.negative_descriptors == {n4}

        # "Un-Adjudicate" collectively
        iqrs.adjudicate(un_positives=[p0, p2], un_negatives=[n4])
        assert iqrs.positive_descriptors == set()
        assert iqrs.negative_descriptors == set()
예제 #8
0
    def test_add_iqr_state_classifier_simple(self):
        """
        Test calling IQR classifier add endpoint with a simple IQR Session
        serialization.
        """
        # Make a simple session with dummy adjudication descriptor elements
        iqrs = IqrSession(session_uid=str("0"))
        iqr_p1 = DescriptorMemoryElement('test', 0).set_vector([0])
        iqr_n1 = DescriptorMemoryElement('test', 1).set_vector([1])
        iqrs.adjudicate(new_positives=[iqr_p1], new_negatives=[iqr_n1])

        test_iqrs_b64 = base64.b64encode(iqrs.get_state_bytes())
        test_label = 'test-label-08976azsdv'

        with mock.patch(STUB_CLASSIFIER_MOD_PATH +
                        ".DummySupervisedClassifier._train") as m_cfier_train:

            with self.app.test_client() as cli:
                rv = cli.post('/iqr_classifier',
                              data={
                                  'bytes_b64': test_iqrs_b64,
                                  'label': test_label,
                              })
                self.assertStatus(rv, 201)
                self.assertResponseMessageRegex(
                    rv, "Finished training "
                    "IQR-session-based "
                    "classifier for label "
                    "'%s'." % test_label)

            m_cfier_train.assert_called_once_with({
                'positive': {iqr_p1},
                'negative': {iqr_n1}
            })
            # Collection should include initial dummy classifier and new iqr
            # classifier.
            self.assertEqual(len(self.app.classifier_collection.labels()), 2)
            self.assertIn(test_label, self.app.classifier_collection.labels())
예제 #9
0
    def test_adjudicate_both_labels(self):
        """
        Test that providing a descriptor element as both a positive AND
        negative adjudication causes no state change..
        """
        iqrs = IqrSession()

        # Set initial state
        p0 = DescriptorMemoryElement('', 0).set_vector([0])
        p1 = DescriptorMemoryElement('', 1).set_vector([1])
        p2 = DescriptorMemoryElement('', 2).set_vector([2])
        n3 = DescriptorMemoryElement('', 3).set_vector([3])
        n4 = DescriptorMemoryElement('', 4).set_vector([4])

        # Set initial state
        iqrs.positive_descriptors = {p0, p1, p2}
        iqrs.negative_descriptors = {n3, n4}

        # Attempt adjudicating a new element as both postive AND negative
        e = DescriptorMemoryElement('', 5).set_vector([5])
        iqrs.adjudicate(new_positives=[e], new_negatives=[e])
        assert iqrs.positive_descriptors == {p0, p1, p2}
        assert iqrs.negative_descriptors == {n3, n4}
예제 #10
0
    def test_add_iqr_state_classifier_simple(self):
        """
        Test calling IQR classifier add endpoint with a simple IQR Session
        serialization.
        """
        # Make a simple session with dummy adjudication descriptor elements
        iqrs = IqrSession(session_uid=str("0"))
        iqr_p1 = DescriptorMemoryElement('test', 0).set_vector([0])
        iqr_n1 = DescriptorMemoryElement('test', 1).set_vector([1])
        iqrs.adjudicate(
            new_positives=[iqr_p1], new_negatives=[iqr_n1]
        )

        test_iqrs_b64 = base64.b64encode(iqrs.get_state_bytes())
        test_label = 'test-label-08976azsdv'

        with mock.patch(STUB_CLASSIFIER_MOD_PATH +
                        ".DummySupervisedClassifier._train") as m_cfier_train:

            with self.app.test_client() as cli:
                rv = cli.post('/iqr_classifier', data={
                    'bytes_b64': test_iqrs_b64,
                    'label': test_label,
                })
                self.assertStatus(rv, 201)
                self.assertResponseMessageRegex(rv, "Finished training "
                                                    "IQR-session-based "
                                                    "classifier for label "
                                                    "'%s'." % test_label)

            m_cfier_train.assert_called_once_with(
                {'positive': {iqr_p1}, 'negative': {iqr_n1}}
            )
            # Collection should include initial dummy classifier and new iqr
            # classifier.
            self.assertEqual(len(self.app.classifier_collection.labels()), 2)
            self.assertIn(test_label, self.app.classifier_collection.labels())
예제 #11
0
    def test_adjudicate_new_pos_neg(self):
        """
        Test that providing iterables to ``new_positives`` and
        ``new_negatives`` parameters result in additions to the positive and
        negative sets respectively.
        """
        iqrs = IqrSession()

        p0 = DescriptorMemoryElement('', 0).set_vector([0])
        iqrs.adjudicate(new_positives=[p0])
        assert iqrs.positive_descriptors == {p0}
        assert iqrs.negative_descriptors == set()

        n1 = DescriptorMemoryElement('', 1).set_vector([1])
        iqrs.adjudicate(new_negatives=[n1])
        assert iqrs.positive_descriptors == {p0}
        assert iqrs.negative_descriptors == {n1}

        p2 = DescriptorMemoryElement('', 2).set_vector([2])
        p3 = DescriptorMemoryElement('', 3).set_vector([3])
        n4 = DescriptorMemoryElement('', 4).set_vector([4])
        iqrs.adjudicate(new_positives=[p2, p3], new_negatives=[n4])
        assert iqrs.positive_descriptors == {p0, p2, p3}
        assert iqrs.negative_descriptors == {n1, n4}
예제 #12
0
    def test_refine_with_prev_results(self):
        """
        Test that the results of RelevancyIndex ranking are directly reflected
        in an existing results dictionary of probability values.
        """
        # IqrSession instance. No config for rel_index because we will mock
        # that.
        iqrs = IqrSession()
        # Mock relevancy index in order to check how its called and mock return
        # value.
        iqrs.rel_index = mock.MagicMock(spec=RelevancyIndex)
        # Mock length to be non-zero to simulate it having contents
        iqrs.rel_index.__len__.return_value = 1

        test_in_pos_elem = DescriptorMemoryElement('t', 0).set_vector([0])
        test_in_neg_elem = DescriptorMemoryElement('t', 1).set_vector([1])
        test_ex_pos_elem = DescriptorMemoryElement('t', 2).set_vector([2])
        test_ex_neg_elem = DescriptorMemoryElement('t', 3).set_vector([3])
        test_other_elem = DescriptorMemoryElement('t', 4).set_vector([4])

        # Mock return dictionary, probabilities don't matter much other than
        # they are not 1.0 or 0.0.
        iqrs.rel_index.rank.return_value = \
            {e: 0.5 for e in [test_in_pos_elem, test_in_neg_elem,
                              test_other_elem]}

        # Create a "previous state" of the results dictionary containing
        # results from our "working set" of descriptor elements.
        iqrs.results = {
            test_in_pos_elem: 0.2,
            test_in_neg_elem: 0.2,
            test_other_elem: 0.2,
            # ``refine`` replaces the previous dict, so disjoint keys are
            # NOT retained.
            'something else': 0.3,
        }

        # Prepare IQR state for refinement
        # - set dummy internal/external positive negatives.
        iqrs.external_descriptors(positive=[test_ex_pos_elem],
                                  negative=[test_ex_neg_elem])
        iqrs.adjudicate(new_positives=[test_in_pos_elem],
                        new_negatives=[test_in_neg_elem])

        # Test calling refine method
        iqrs.refine()

        # We test that:
        # - ``rel_index.rank`` called with the combination of
        #   external/adjudicated descriptor elements.
        # - ``results`` attribute now has an dict value
        # - value of ``results`` attribute is what we expect.
        iqrs.rel_index.rank.assert_called_once_with(
            {test_in_pos_elem, test_ex_pos_elem},
            {test_in_neg_elem, test_ex_neg_elem},
        )
        assert iqrs.results is not None
        assert len(iqrs.results) == 3
        assert test_other_elem in iqrs.results
        assert test_in_pos_elem in iqrs.results
        assert test_in_neg_elem in iqrs.results
        assert 'something else' not in iqrs.results

        assert iqrs.results[test_other_elem] == 0.5
        assert iqrs.results[test_in_pos_elem] == 0.5
        assert iqrs.results[test_in_neg_elem] == 0.5
예제 #13
0
    def test_refine_no_prev_results(self):
        """
        Test that the results of RelevancyIndex ranking are directly reflected
        in a new results dictionary of probability values, even for elements
        that were also used in adjudication.

        This test is useful because a previous state of the IQR Session
        structure would force return probabilities for some descriptor elements
        to certain values if they were also present in the positive or negative
        adjudicate (internal or external) sets.
        """
        # IqrSession instance. No config for rel_index because we will mock
        # that.
        iqrs = IqrSession()
        # Mock relevancy index in order to check how its called and mock return
        # value.
        iqrs.rel_index = mock.MagicMock(spec=RelevancyIndex)
        # Mock length to be non-zero to simulate it having contents
        iqrs.rel_index.__len__.return_value = 1

        test_in_pos_elem = DescriptorMemoryElement('t', 0).set_vector([0])
        test_in_neg_elem = DescriptorMemoryElement('t', 1).set_vector([1])
        test_ex_pos_elem = DescriptorMemoryElement('t', 2).set_vector([2])
        test_ex_neg_elem = DescriptorMemoryElement('t', 3).set_vector([3])
        test_other_elem = DescriptorMemoryElement('t', 4).set_vector([4])

        # Mock return dictionary, probabilities don't matter much other than
        # they are not 1.0 or 0.0.
        iqrs.rel_index.rank.return_value = \
            {e: 0.5 for e in [test_in_pos_elem, test_in_neg_elem,
                              test_other_elem]}

        # Asserting expected pre-condition where there are no results yet.
        assert iqrs.results is None

        # Prepare IQR state for refinement
        # - set dummy internal/external positive negatives.
        iqrs.external_descriptors(positive=[test_ex_pos_elem],
                                  negative=[test_ex_neg_elem])
        iqrs.adjudicate(new_positives=[test_in_pos_elem],
                        new_negatives=[test_in_neg_elem])

        # Test calling refine method
        iqrs.refine()

        # We test that:
        # - ``rel_index.rank`` called with the combination of
        #   external/adjudicated descriptor elements.
        # - ``results`` attribute now has a dict value
        # - value of ``results`` attribute is what we expect.
        iqrs.rel_index.rank.assert_called_once_with(
            {test_in_pos_elem, test_ex_pos_elem},
            {test_in_neg_elem, test_ex_neg_elem},
        )
        assert iqrs.results is not None
        assert len(iqrs.results) == 3
        assert test_other_elem in iqrs.results
        assert test_in_pos_elem in iqrs.results
        assert test_in_neg_elem in iqrs.results

        assert iqrs.results[test_other_elem] == 0.5
        assert iqrs.results[test_in_pos_elem] == 0.5
        assert iqrs.results[test_in_neg_elem] == 0.5