def testBinWithSum(self):
        one = Bin(5, -3.0, 7.0, named("xaxis", lambda x: x),
                  Sum(named("yaxis", lambda x: 10.0)), Sum(lambda x: 10.0),
                  Sum(lambda x: 10.0), Sum(lambda x: 10.0))
        for _ in self.simple:
            one.fill(_)
        self.assertEqual(list(map(lambda _: _.sum, one.values)),
                         [30.0, 20.0, 20.0, 10.0, 0.0])
        self.assertEqual(one.underflow.sum, 10.0)
        self.assertEqual(one.overflow.sum, 10.0)
        self.assertEqual(one.nanflow.sum, 0.0)

        two = Select(
            lambda x: x.bool,
            Bin(5, -3.0, 7.0, lambda x: x.double, Sum(lambda x: 10.0),
                Sum(lambda x: 10.0), Sum(lambda x: 10.0), Sum(lambda x: 10.0)))
        for _ in self.struct:
            two.fill(_)

        self.assertEqual(list(map(lambda _: _.sum, two.cut.values)),
                         [20.0, 10.0, 10.0, 10.0, 0.0])
        self.assertEqual(two.cut.underflow.sum, 0.0)
        self.assertEqual(two.cut.overflow.sum, 0.0)
        self.assertEqual(two.cut.nanflow.sum, 0.0)

        self.checkScaling(one)
        self.checkScaling(one.toImmutable())
        self.checkJson(one)
        self.checkPickle(one)
        self.checkName(one)
        self.checkScaling(two)
        self.checkScaling(two.toImmutable())
        self.checkJson(two)
        self.checkPickle(two)
        self.checkName(two)
    def testSumWithWeightingFactorStringFunctions(self):
        for i in xrange(11):
            left, right = self.struct[:i], self.struct[i:]

            leftSumming = Select("int", Sum("double * 2"))
            rightSumming = Select("int", Sum("double * 2"))

            for _ in left:
                leftSumming.fill(_)
            for _ in right:
                rightSumming.fill(_)

            self.assertAlmostEqual(
                leftSumming.cut.sum,
                sum(_.double * 2 * _.int for _ in left if _.int > 0))
            self.assertAlmostEqual(
                rightSumming.cut.sum,
                sum(_.double * 2 * _.int for _ in right if _.int > 0))

            finalResult = leftSumming + rightSumming

            self.assertAlmostEqual(
                finalResult.cut.sum,
                sum(_.double * 2 * _.int for _ in self.struct if _.int > 0))

            self.checkScaling(leftSumming)
            self.checkScaling(leftSumming.toImmutable())
            self.checkJson(leftSumming)
            self.checkPickle(leftSumming)
            self.checkName(leftSumming)
    def testBin(self):
        one = Bin(5, -3.0, 7.0, named("xaxis", lambda x: x))
        for _ in self.simple:
            one.fill(_)
        self.assertEqual(list(map(lambda _: _.entries, one.values)),
                         [3.0, 2.0, 2.0, 1.0, 0.0])
        self.assertEqual(one.underflow.entries, 1.0)
        self.assertEqual(one.overflow.entries, 1.0)
        self.assertEqual(one.nanflow.entries, 0.0)

        two = Select(lambda x: x.bool, Bin(5, -3.0, 7.0, lambda x: x.double))
        for _ in self.struct:
            two.fill(_)

        self.assertEqual(list(map(lambda _: _.entries, two.cut.values)),
                         [2.0, 1.0, 1.0, 1.0, 0.0])
        self.assertEqual(two.cut.underflow.entries, 0.0)
        self.assertEqual(two.cut.overflow.entries, 0.0)
        self.assertEqual(two.cut.nanflow.entries, 0.0)

        self.checkScaling(one)
        self.checkScaling(one.toImmutable())
        self.checkJson(one)
        self.checkPickle(one)
        self.checkName(one)
        self.checkScaling(two)
        self.checkScaling(two.toImmutable())
        self.checkJson(two)
        self.checkPickle(two)
        self.checkName(two)
    def testSumWithFilterStringFunctions(self):
        for i in xrange(11):
            left, right = self.struct[:i], self.struct[i:]

            leftSumming = Select("not bool", Sum("double + 1"))
            rightSumming = Select("not bool", Sum("double + 1"))

            for _ in left:
                leftSumming.fill(_)
            for _ in right:
                rightSumming.fill(_)

            self.assertAlmostEqual(
                leftSumming.cut.sum,
                sum(_.double + 1 for _ in left if not _.bool))
            self.assertAlmostEqual(
                rightSumming.cut.sum,
                sum(_.double + 1 for _ in right if not _.bool))

            finalResult = leftSumming + rightSumming

            self.assertAlmostEqual(
                finalResult.cut.sum,
                sum(_.double + 1 for _ in self.struct if not _.bool))

            self.checkScaling(leftSumming)
            self.checkScaling(leftSumming.toImmutable())
            self.checkJson(leftSumming)
            self.checkPickle(leftSumming)
            self.checkName(leftSumming)
    def testSumWithFilter(self):
        for i in xrange(11):
            left, right = self.struct[:i], self.struct[i:]

            leftSumming = Select(lambda x: x.bool, Sum(lambda x: x.double))
            rightSumming = Select(lambda x: x.bool, Sum(lambda x: x.double))

            for _ in left:
                leftSumming.fill(_)
            for _ in right:
                rightSumming.fill(_)

            self.assertAlmostEqual(leftSumming.cut.sum,
                                   sum(_.double for _ in left if _.bool))
            self.assertAlmostEqual(rightSumming.cut.sum,
                                   sum(_.double for _ in right if _.bool))

            finalResult = leftSumming + rightSumming

            self.assertAlmostEqual(
                finalResult.cut.sum,
                sum(_.double for _ in self.struct if _.bool))

            self.checkScaling(leftSumming)
            self.checkScaling(leftSumming.toImmutable())
            self.checkJson(leftSumming)
            self.checkPickle(leftSumming)
            self.checkName(leftSumming)
    def testCountWithFilter(self):
        for i in xrange(11):
            left, right = self.simple[:i], self.simple[i:]

            leftCounting = Select(named("something", lambda x: x > 0.0),
                                  Count())
            rightCounting = Select(named("something", lambda x: x > 0.0),
                                   Count())

            for _ in left:
                leftCounting.fill(_)
            for _ in right:
                rightCounting.fill(_)

            self.assertEqual(leftCounting.cut.entries,
                             len(list(filter(lambda x: x > 0.0, left))))
            self.assertEqual(rightCounting.cut.entries,
                             len(list(filter(lambda x: x > 0.0, right))))

            finalResult = leftCounting + rightCounting

            self.assertEqual(finalResult.cut.entries,
                             len(list(filter(lambda x: x > 0.0, self.simple))))

            self.checkScaling(leftCounting)
            self.checkScaling(leftCounting.toImmutable())
            self.checkJson(leftCounting)
            self.checkPickle(leftCounting)
            self.checkName(leftCounting)
    def testDeviateWithWeightingFactor(self):
        for i in xrange(11):
            left, right = self.struct[:i], self.struct[i:]

            leftDeviating = Select(lambda x: x.int,
                                   Deviate(lambda x: x.double))
            rightDeviating = Select(lambda x: x.int,
                                    Deviate(lambda x: x.double))

            for _ in left:
                leftDeviating.fill(_)
            for _ in right:
                rightDeviating.fill(_)

            if sum(map(lambda _: _.int if _.int > 0.0 else 0.0, left)) == 0.0:
                self.assertTrue(math.isnan(leftDeviating.cut.mean))
                self.assertTrue(math.isnan(leftDeviating.cut.variance))
            else:
                self.assertAlmostEqual(
                    leftDeviating.cut.mean,
                    self.meanWeighted(list(map(lambda _: _.double, left)),
                                      list(map(lambda _: _.int, left))))
                self.assertAlmostEqual(
                    leftDeviating.cut.variance,
                    self.varianceWeighted(list(map(lambda _: _.double, left)),
                                          list(map(lambda _: _.int, left))))

            if sum(map(lambda _: _.int if _.int > 0.0 else 0.0, right)) == 0.0:
                self.assertTrue(math.isnan(rightDeviating.cut.mean))
                self.assertTrue(math.isnan(rightDeviating.cut.variance))
            else:
                self.assertAlmostEqual(
                    rightDeviating.cut.mean,
                    self.meanWeighted(list(map(lambda _: _.double, right)),
                                      list(map(lambda _: _.int, right))))
                self.assertAlmostEqual(
                    rightDeviating.cut.variance,
                    self.varianceWeighted(list(map(lambda _: _.double, right)),
                                          list(map(lambda _: _.int, right))))

            finalResult = leftDeviating + rightDeviating

            self.assertAlmostEqual(
                finalResult.cut.variance,
                self.varianceWeighted(
                    list(map(lambda _: _.double, self.struct)),
                    list(map(lambda _: _.int, self.struct))))

            self.checkScaling(leftDeviating)
            self.checkScaling(leftDeviating.toImmutable())
            self.checkJson(leftDeviating)
            self.checkPickle(leftDeviating)
            self.checkName(leftDeviating)
    def testDeviateWithFilter(self):
        for i in xrange(11):
            left, right = self.struct[:i], self.struct[i:]

            leftDeviating = Select(lambda x: x.bool,
                                   Deviate(lambda x: x.double))
            rightDeviating = Select(lambda x: x.bool,
                                    Deviate(lambda x: x.double))

            for _ in left:
                leftDeviating.fill(_)
            for _ in right:
                rightDeviating.fill(_)

            if len([_.double for _ in left if _.bool]) == 0:
                self.assertTrue(math.isnan(leftDeviating.cut.mean))
                self.assertTrue(math.isnan(leftDeviating.cut.variance))
            else:
                self.assertAlmostEqual(
                    leftDeviating.cut.mean,
                    self.mean([_.double for _ in left if _.bool]))
                self.assertAlmostEqual(
                    leftDeviating.cut.variance,
                    self.variance([_.double for _ in left if _.bool]))

            if len([_.double for _ in right if _.bool]) == 0:
                self.assertTrue(math.isnan(rightDeviating.cut.mean))
                self.assertTrue(math.isnan(rightDeviating.cut.variance))
            else:
                self.assertAlmostEqual(
                    rightDeviating.cut.mean,
                    self.mean([_.double for _ in right if _.bool]))
                self.assertAlmostEqual(
                    rightDeviating.cut.variance,
                    self.variance([_.double for _ in right if _.bool]))

            finalResult = leftDeviating + rightDeviating

            self.assertAlmostEqual(
                finalResult.cut.variance,
                self.variance([_.double for _ in self.struct if _.bool]))

            self.checkScaling(leftDeviating)
            self.checkScaling(leftDeviating.toImmutable())
            self.checkJson(leftDeviating)
            self.checkPickle(leftDeviating)
            self.checkName(leftDeviating)