| # Copyright 2016 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import copy |
| import math |
| import numpy as np |
| |
| from analysis.linear.feature import ChangedFile |
| from analysis.linear.feature import FeatureValue |
| from analysis.linear.feature import WrapperMetaFeature |
| from analysis.linear.model import LogLinearModel |
| from analysis.linear.model import UnnormalizedLogLinearModel |
| from analysis.linear.weight import MetaWeight |
| from analysis.linear.weight import Weight |
| from analysis.linear.linear_testcase import LinearTestCase |
| from libs.meta_object import MetaDict |
| |
| |
| class UnnormalizedLogLinearModelTest(LinearTestCase): |
| |
| def setUp(self): |
| super(UnnormalizedLogLinearModelTest, self).setUp() |
| self.model = UnnormalizedLogLinearModel(self._meta_feature, |
| self._meta_weight, |
| 0.00001) |
| |
| def testLogZeroish(self): |
| self.assertTrue(self.model.LogZeroish(-float('inf'))) |
| self.assertFalse(self.model.LogZeroish(2.)) |
| |
| def testFilterReasonWithWeight(self): |
| meta_weight = MetaWeight({'f1': Weight(2.), 'f2': Weight(0.), |
| 'f3': Weight(1.)}) |
| reason = MetaDict({'f1': ['reason1', 'reason3'], 'f2': ['reason2']}) |
| |
| model = UnnormalizedLogLinearModel(None, meta_weight) |
| self.assertListEqual(model.FilterReasonWithWeight(reason), ['reason1', |
| 'reason3']) |
| |
| |
| class LoglinearTest(LinearTestCase): |
| |
| def testLogLinearModel(self): |
| """An arbitrary test to get 100% code coverage. |
| |
| Right now this test simply calls every method. The only assertions are |
| that log-domain and normal-domain things are related appropriately; |
| and similarly for the quadrance and l2-norm. Since the one is defined |
| in terms of the other in exactly the way written here, those should |
| be trivially true. However, if the implementation changes, then they |
| may become flaky due to floating point fuzz. Really this should be |
| replaced by a collection of semantically meaningful tests, i.e., |
| ones that actually look for bugs we might realistically need to |
| guard against. At least this test is good for detecting typo-style |
| errors where we try accessing fields/methods that don't exist. |
| """ |
| model = LogLinearModel(self._Y, self._meta_feature, self._meta_weight) |
| model.ClearAllMemos() |
| self.assertEqual(self._meta_weight, model.meta_weight) |
| self.assertEqual(math.sqrt(model.quadrance), model.l2) |
| |
| for x in self._X: |
| self.assertEqual(math.exp(model.LogZ(x)), model.Z(x)) |
| model.Expectation(x, lambda y: np.array([1.0])) |
| for y in self._Y(x): |
| model.Features(x)(y) |
| model.Score(x)(y) |
| self.assertEqual( |
| math.exp(model.LogProbability(x)(y)), |
| model.Probability(x)(y)) |
| |
| def testMetaWeightSetter(self): |
| model = LogLinearModel(self._Y, self._meta_feature, self._meta_weight) |
| new_meta_weight = copy.deepcopy(self._meta_weight) |
| new_meta_weight['Feature0'] = Weight(2.1) |
| model.meta_weight = new_meta_weight |
| self.assertTrue(model.meta_weight == new_meta_weight) |