BreakingBytes / simkit

Model Simulation Framework
http://breakingbytes.github.io/simkit/
BSD 3-Clause "New" or "Revised" License
27 stars 16 forks source link

get_covariance is loops twice over arguments #107

Open mikofski opened 7 years ago

mikofski commented 7 years ago

during the first loop, it is just getting the dimensions, mainly of nobs which seems like this should already be known, but even still, this could be popped from a sequence on the 2nd loop which would eliminate redundant code and try-except blocks.

    def get_covariance(datargs, outargs, vargs, datvar, outvar):
        """
        Get covariance matrix.

        :param datargs: data arguments
        :param outargs: output arguments
        :param vargs: variable arguments
        :param datvar: variance of data arguments
        :param outvar: variance of output arguments
        :return: covariance
        """
        # number of formula arguments that are not constant
        argn = len(vargs)
        # number of observations must be the same for all vargs
        nobs = 1
        c = []
        for m in xrange(argn):
            a = vargs[m]
            try:
                a = datargs[a]
            except (KeyError, TypeError):
                a = outargs[a]
                avar = outvar[a]
            else:
                avar = datvar[a]
            c.append([])  # add a list
            for n in xrange(argn):
                b = vargs[n]
                try:
                    b = datargs[b]
                except (KeyError, TypeError):
                    b = outargs[b]
                c.append(avar.get(b, 0.0))  # add covariance to sequence
                try:
                    nobs = max(nobs, len(c))
                except (TypeError, ValueError):
                    LOGGER.debug('c of %s vs %s = %g', a, b, c)
        # covariance matrix is initially zeros
        cov = np.zeros((nobs, argn, argn))
        # loop over arguments in both directions, fill in covariance
        for m in xrange(argn):
            d = c.pop()
            for n in xrange(argn):
                cov[:, argn-1-m, argn-1-n] = d.pop()
        if nobs == 1:
            cov = cov.squeeze()  # squeeze out any extra dimensions
        LOGGER.debug('covariance:\n%r', cov)
        return cov