fill_covariance_list <- function(need, covariance_list, matsqrt_tol, solve_tol){
    # This function is used by compare.default() to fill in required but missing
    # elements from the covariance list (that is, the list that contains up to
    # four equivalent specifications of a covariance structure).  The function
    # that generates the errors can have any of these as an argument, and this
    # function fills in any gaps.
    #
    # The order of the conditional clauses is determined by trying to find an
    # "optimal" route to the desired matrix given what is already present in the
    # list.  Preference is given to operations on the "square root" level (that
    # is, SqrtSigma and Q) when a direct route from a given matrix to the
    # desired one is not available.

    stopifnot(all(need %in% c("Sigma", "SqrtSigma", "P", "Q")),
              is.list(covariance_list))

    # First, calculate Sigma if necessary.
    if("Sigma" %in% need && is.null(covariance_list[["Sigma"]])){
        if(!is.null(covariance_list[["SqrtSigma"]])){
            covariance_list[["Sigma"]] <- covsquare(covariance_list[["SqrtSigma"]])
        } else {
            if(is.null(covariance_list[["P"]])){
                covariance_list[["SqrtSigma"]] <- covinv(covariance_list[["Q"]], tol = solve_tol)
                covariance_list[["Sigma"]] <- covsquare(covariance_list[["SqrtSigma"]])
            } else {
                covariance_list[["Sigma"]] <- covinv(covariance_list[["P"]], tol = solve_tol)
            }
        }
    }

    # Next, SqrtSigma.
    if("SqrtSigma" %in% need && is.null(covariance_list[["SqrtSigma"]])){
        if(!is.null(covariance_list[["Q"]])){
            covariance_list[["SqrtSigma"]] <- covinv(covariance_list[["Q"]], tol = solve_tol)
        } else {
            if(is.null(covariance_list[["Sigma"]])){
                covariance_list[["Q"]] <- covsqrt(covariance_list[["P"]], tol = matsqrt_tol)
                covariance_list[["SqrtSigma"]] <- covinv(covariance_list[["Q"]], tol = solve_tol)
            } else {
                covariance_list[["SqrtSigma"]] <- covsqrt(covariance_list[["Sigma"]], tol = matsqrt_tol)
            }
        }
    }

    # Now P.
    if("P" %in% need && is.null(covariance_list[["P"]])){
        if(!is.null(covariance_list[["Q"]])){
            covariance_list[["P"]] <- covsquare(covariance_list[["Q"]])
        } else {
            if(is.null(covariance_list[["Sigma"]])){
                covariance_list[["Q"]] <- covinv(covariance_list[["SqrtSigma"]], tol = solve_tol)
                covariance_list[["P"]] <- covsquare(covariance_list[["Q"]])
            } else {
                covariance_list[["P"]] <- covinv(covariance_list[["Sigma"]], tol = solve_tol)
            }
        }
    }

    # Finally, Q.
    if("Q" %in% need && is.null(covariance_list[["Q"]])){
        if(!is.null(covariance_list[["SqrtSigma"]])){
            covariance_list[["Q"]] <- covinv(covariance_list[["SqrtSigma"]], tol = solve_tol)
        } else {
            if(!is.null(covariance_list[["P"]])){
                covariance_list[["Q"]] <- covsqrt(covariance_list[["P"]], tol = matsqrt_tol)
            } else {
                covariance_list[["SqrtSigma"]] <-
                    covsqrt(covariance_list[["Sigma"]], tol = matsqrt_tol)
                covariance_list[["Q"]] <- covinv(covariance_list[["SqrtSigma"]], tol = solve_tol)
            }
        }
    }

    return(covariance_list)
}
