Exemplo n.º 1
0
class BootstrapRunner(AbstractRunner):
    def __init__(self, runnerArgument):
        """
        Parameters
        ----------
        runnerArgument: RunnerArgument

        Notes
        -----
        1. Uses METHOD_LEASTSQ for fitModel iterations.
        """
        super().__init__()
        #
        self.lastErr = ""
        self.fitter = runnerArgument.fitter
        self.numIteration = runnerArgument.numIteration
        self.kwargs = runnerArgument.kwargs
        self.synthesizerClass = runnerArgument.synthesizerClass
        if "logger" in self.fitter.__dict__.keys():
            self.logger = self.fitter.logger
        else:
            self.logger = Logger()
        self._isDone = not self._fitInitial()
        self.columns = self.fitter.selectedColumns
        # Initializations for bootstrap loop
        if not self.isDone:
            fittedTS = self.fitter.fittedTS.subsetColumns(self.columns,
                                                          isCopy=False)
            self.synthesizer = self.synthesizerClass(
                observedTS=self.fitter.observedTS.subsetColumns(self.columns,
                                                                isCopy=False),
                fittedTS=fittedTS,
                **self.kwargs)
            self.numSuccessIteration = 0
            if self.fitter.minimizerResult is None:
                self.fitter.fitModel()
            self.baseChisq = self.fitter.minimizerResult.redchi
            self.curIteration = 0
            self.fd = self.logger.getFileDescriptor()
            self.baseFittedStatistic = TimeseriesStatistic(
                self.fitter.observedTS.subsetColumns(
                    self.fitter.selectedColumns, isCopy=False))

    def report(self, id=None):
        if True:
            return
        if id is None:
            self._startTime = time.time()
        else:
            elapsed = time.time() - self._startTime
            print("%s: %2.3f" % (id, elapsed))

    @property
    def numWorkUnit(self):
        return self.numIteration

    @property
    def isDone(self):
        return self._isDone

    def run(self):
        """
        Runs the bootstrap.

        Returns
        -------
        BootstrapResult
        """
        def mkNullResult():
            fittedStatistic = TimeseriesStatistic(
                self.fitter.observedTS[self.fitter.selectedColumns])
            return BootstrapResult(self.fitter, 0, {}, fittedStatistic)

        #
        if self.isDone:
            return
        # Set up logging for this run
        if self.fd is not None:
            sys.stderr = self.fd
            sys.stdout = self.fd
        isSuccess = False
        bootstrapError = 0
        self.report()
        for _ in range(ITERATION_MULTIPLIER):
            newObservedTS = self.synthesizer.calculate()
            self.report("newObservedTS")
            # Update fitter to use the new observed data
            _ = self.fitter._updateObservedTS(newObservedTS, isCheck=False)
            self.report("updated fitter")
            # Try fitting
            try:
                self.fitter.fitModel(params=self.fitter.params)
                self.report("fitter.fit")
            except Exception as err:
                # Problem with the fit.
                msg = "modelFitterBootstrap. Fit failed on iteration %d."  \
                      % iteration
                self.logger.error(msg, err)
                bootstrapError += 1
                continue
            # Verify that there is a result
            if self.fitter.minimizerResult is None:
                continue
            # Check if the fit is of sufficient quality
            if self.fitter.minimizerResult.redchi > MAX_CHISQ_MULT * self.baseChisq:
                continue
            if self.fitter.params is None:
                continue
            isSuccess = True
            self.report("break")
            break
        # Create the result
        if isSuccess:
            self.numSuccessIteration += 1
            parameterDct = {
                k: [v]
                for k, v in self.fitter.params.valuesdict().items()
            }
            fittedStatistic = self.baseFittedStatistic.copy()
            fittedStatistic.accumulate(
                self.fitter.fittedTS.subsetColumns(self.fitter.selectedColumns,
                                                   isCopy=False))
            bootstrapResult = BootstrapResult(self.fitter,
                                              self.numSuccessIteration,
                                              parameterDct,
                                              fittedStatistic,
                                              bootstrapError=bootstrapError)
        else:
            bootstrapResult = mkNullResult()
            self._isDone = True
        # Close the logging file
        if self.fd is not None:
            if not self.fd.closed:
                self.fd.close()
        # See if completed work
        if self.numSuccessIteration >= self.numIteration:
            self._isDone = True
        return bootstrapResult

    def _fitInitial(self):
        """
        Do the initial fit.

        Returns
        -------
        bool
            successful fit
        """
        isSuccess = False
        for _ in range(MAX_TRIES):
            try:
                self.fitter.fitModel()  # Initialize model
                isSuccess = True
                break
            except Exception as err:
                self.lastErr = err
                msg = "Could not do initial fit"
                self.logger.error(msg, err)
        return isSuccess
Exemplo n.º 2
0
class TestLogger(unittest.TestCase):
    def setUp(self):
        self.remove()
        self.logger = Logger(toFile=LOG_PATH,
                             logPerformance=True,
                             logLevel=logs.LEVEL_MAX)

    def tearDown(self):
        self.remove()

    def remove(self):
        for ffile in FILES:
            if os.path.isfile(ffile):
                os.remove(ffile)

    def isFile(self):
        return os.path.isfile(LOG_PATH)

    def read(self):
        if not self.isFile():
            raise RuntimeError("Missing log file.")
        with open(LOG_PATH, "r") as fd:
            lines = fd.readlines()
        return lines

    def testConstructor(self):
        if IGNORE_TEST:
            return
        self.assertFalse(self.isFile())
        self.assertEqual(self.logger.logLevel, logs.LEVEL_MAX)

    def testFileDescriptor(self):
        if IGNORE_TEST:
            return
        fd = self.logger.getFileDescriptor()
        self.assertIsInstance(fd, io.TextIOWrapper)
        fd.close()

    def _checkMsg(self, msg):
        lines = self.read()
        true = any([MSG in t for t in lines])
        self.assertTrue(true)
        return lines

    def testWrite(self):
        if IGNORE_TEST:
            return
        self.logger._write(MSG, 0)
        _ = self._checkMsg(MSG)

    def _testApi(self, method, logLevel):
        if IGNORE_TEST:
            return
        logger = Logger(toFile=LOG_PATH, logLevel=logLevel)
        stmt = "logger.%s(MSG)" % method
        exec(stmt)
        line1s = self._checkMsg(MSG)
        #
        logger = Logger(toFile=LOG_PATH, logLevel=0)
        stmt = "logger.%s(MSG)" % method
        exec(stmt)
        line2s = self.read()
        self.assertEqual(len(line1s), len(line2s))

    def testActivity(self):
        if IGNORE_TEST:
            return
        self._testApi("activity", logs.LEVEL_ACTIVITY)

    def testResult(self):
        if IGNORE_TEST:
            return
        self._testApi("result", logs.LEVEL_RESULT)

    def testStatus(self):
        if IGNORE_TEST:
            return
        self._testApi("status", logs.LEVEL_STATUS)

    def testException(self):
        if IGNORE_TEST:
            return
        self._testApi("status", logs.LEVEL_EXCEPTION)

    def testStartBlock(self):
        if IGNORE_TEST:
            return
        guid = self.logger.startBlock(BLOCK1)
        self.assertLess(guid, BlockSpecification.guid)
        self.assertEqual(len(self.logger.blockDct), 1)

    def testEndBlock(self):
        if IGNORE_TEST:
            return
        guid1 = self.logger.startBlock(BLOCK1)
        guid2 = self.logger.startBlock(BLOCK2)
        self.logger.endBlock(guid2)
        self.logger.endBlock(guid1)
        self.assertGreater(self.logger.statisticDct[BLOCK1].total,
                           self.logger.statisticDct[BLOCK2].total)

    def testNoLogPerformance(self):
        if IGNORE_TEST:
            return
        logger = Logger(toFile=LOG_PATH,
                        logPerformance=False,
                        logLevel=logs.LEVEL_MAX)
        guid = logger.startBlock(BLOCK1)
        self.assertEqual(len(self.logger.blockDct), 0)
        logger.endBlock(guid)
        self.assertEqual(len(self.logger.blockDct), 0)

    def testPerformanceReport(self):
        if IGNORE_TEST:
            return

        def test(numBlock, sleepTime):
            logger = Logger(logPerformance=True)
            for idx in range(numBlock):
                block = "blk_%d" % idx
                guid = logger.startBlock(block)
                time.sleep(sleepTime)
                logger.endBlock(guid)
            df = logger.performanceDF
            self.assertLess(np.abs(sleepTime - df["mean"].mean()), sleepTime)
            self.assertEqual(df["count"].mean(), 1.0)

        #
        test(3, 0.1)
        test(30, 0.1)

    def testJoin(self):
        if IGNORE_TEST:
            return
        NAMES = ["aa", "bbb", "z"]
        result = Logger.join(*NAMES)
        for name in NAMES:
            self.assertGreaterEqual(result.index(name), 0)

    def testCopy(self):
        if IGNORE_TEST:
            return
        newLogger = self.logger.copy()
        self.assertTrue(self.logger.equals(newLogger))