diff --git a/.Rbuildignore b/.Rbuildignore index 993be48..e3fded5 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -10,3 +10,4 @@ ^doc$ ^Meta$ ^data-raw$ +^\./tests/testthat/dataForTests/generate_weeklyTestData\.R$ diff --git a/DESCRIPTION b/DESCRIPTION index abd5295..4e08c4a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: bayesRecon Type: Package -Date: 2023-12-19 +Date: 2024-05-29 Title: Probabilistic Reconciliation via Conditioning -Version: 0.2.0 +Version: 0.3.0 Authors@R: c(person(given = "Dario", family = "Azzimonti", role = c("aut","cre"), @@ -24,7 +24,15 @@ Authors@R: c(person(given = "Dario", email = "giorgio.corani@idsia.ch", comment = c(ORCID = "0000-0002-1541-8384"))) Maintainer: Dario Azzimonti -Description: Provides methods for probabilistic reconciliation of hierarchical forecasts of time series. The available methods include analytical Gaussian reconciliation (Corani et al., 2021) , MCMC reconciliation of count time series (Corani et al., 2022) , Bottom-Up Importance Sampling (Zambon et al., 2022) . +Description: Provides methods for probabilistic reconciliation of hierarchical forecasts of time series. + The available methods include analytical Gaussian reconciliation (Corani et al., 2021) + , + MCMC reconciliation of count time series (Corani et al., 2024) + , + Bottom-Up Importance Sampling (Zambon et al., 2024) + , + methods for the reconciliation of mixed hierarchies (Mix-Cond and TD-cond) + (Zambon et al., 2024. The 40th Conference on Uncertainty in Artificial Intelligence, accepted). License: LGPL (>= 3) Depends: R (>= 4.1.0) Imports: @@ -34,7 +42,7 @@ Imports: Encoding: UTF-8 LazyData: true Roxygen: list(markdown=TRUE) -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1 Suggests: knitr, rmarkdown, diff --git a/NAMESPACE b/NAMESPACE index e2a7930..0253736 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,8 +1,15 @@ # Generated by roxygen2: do not edit by hand +export(PMF.get_mean) +export(PMF.get_quantile) +export(PMF.get_var) +export(PMF.sample) +export(PMF.summary) export(get_reconc_matrices) export(reconc_BUIS) export(reconc_MCMC) +export(reconc_MixCond) +export(reconc_TDcond) export(reconc_gaussian) export(schaferStrimmer_cov) export(temporal_aggregation) diff --git a/NEWS.md b/NEWS.md index 4cb856a..d1cbfdd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,20 @@ +# bayesRecon 0.3.0 + +* Added `reconc_MixCond`, the implementation of Mixed conditioning for the reconciliation of mixed-type hierarchical forecasts. + +* Added `reconc_TDcond`, the implementation of Top-down conditioning for the reconciliation of mixed-type hierarchical forecasts. + +* Vignette "Reconciliation of M5 hierarchy with mixed-type forecasts". + +* Added functions `PMF.get_mean`, `PMF.get_quantile`, `PMF.get_var`, `PMF.sample`, `PMF.summary` that return point estimates and samples from a probability mass function object. + +* Added the dataset `M5_CA1_basefc` which contains the base forecasts for the store "CA1" of the hierarchical time series in the M5 competition. + # bayesRecon 0.2.0 -* Vignette "Properties of the reconciled distribution via conditioning" +* Vignette "Properties of the reconciled distribution via conditioning". -* Added option in `reconc_BUIS` to pass some base forecast as parameters and some as samples +* Added option in `reconc_BUIS` to pass some base forecast as parameters and some as samples. * Added option in `reconc_BUIS` to input a list of distributions instead of a string. diff --git a/R/M3_example.R b/R/M3_example.R deleted file mode 100644 index 1acd0d8..0000000 --- a/R/M3_example.R +++ /dev/null @@ -1,10 +0,0 @@ -#' Example of a time series from the M3 forecasting competition -#' -#' A monthly time series, from the M3 forecasting competition ("N1485"). -#' -#' @format -#' List of time series of class \link[stats]{ts}. -#' -#' -#' @source [https://forecasters.org/resources/time-series-data/m3-competition/](https://forecasters.org/resources/time-series-data/m3-competition/) -"M3_example" \ No newline at end of file diff --git a/R/PMF.R b/R/PMF.R new file mode 100644 index 0000000..2995d79 --- /dev/null +++ b/R/PMF.R @@ -0,0 +1,329 @@ +# A pmf is represented as normalized numeric vector v: +# for each j = 0, ..., M, the probability of j is the value v[[j+1]] + +### + +# Compute the empirical pmf from a vector of samples +PMF.from_samples = function(v) { + .check_discrete_samples(v) + pmf = tabulate(v+1) / length(v) # the support starts from 0 + # Tabulate only counts values above 1: if sum(tabulate(v+1)) > length(v), + # it means that there were negative samples + if (!isTRUE(all.equal(sum(pmf), 1))) { + stop("Input error: same samples are negative") + } + return(pmf) +} + +# Compute the pmf from a parametric distribution +PMF.from_params = function(params, distr, Rtoll = .RTOLL) { + # Check that the distribution is implemented, and that the params are ok + if (!(distr %in% .DISCR_DISTR)) { + stop(paste0("Input error: distr must be one of {", + paste(.DISCR_DISTR, collapse = ', '), "}")) + } + .check_distr_params(distr, params) + # Compute the pmf + switch( + distr, + "poisson" = { + lambda = params$lambda + M = stats::qpois(1-Rtoll, lambda) + pmf = stats::dpois(0:M, lambda)}, + "nbinom" = { + size = params$size + prob = params$prob + mu = params$mu + if (!is.null(prob)) { + M = stats::qnbinom(1-Rtoll, size=size, prob=prob) + pmf = stats::dnbinom(0:M, size=size, prob=prob) + } else if (!is.null(mu)) { + M = stats::qnbinom(1-Rtoll, size=size, mu=mu) + pmf = stats::dnbinom(0:M, size=size, mu=mu) + } + }, + ) + pmf = pmf / sum(pmf) + return(pmf) +} + +#' @title Sample from the distribution given as a PMF object +#' +#' @description +#' +#' Samples (with replacement) from the probability distribution specified by `pmf`. +#' +#' @param pmf the PMF object. +#' @param N_samples number of samples. +#' +#' @return Samples drawn from the distribution specified by `pmf`. +#' @seealso [PMF.get_mean()], [PMF.get_var()], [PMF.get_quantile()], [PMF.summary()] +#' +#' @examples +#' library(bayesRecon) +#' +#' # Let's build the pmf of a Binomial distribution with parameters n and p +#' n <- 10 +#' p <- 0.6 +#' pmf_binomial <- apply(matrix(seq(0,n)),MARGIN=1,FUN=function(x) dbinom(x,size=n,prob=p)) +#' +#' # Draw samples from the PMF object +#' set.seed(1) +#' samples <- PMF.sample(pmf=pmf_binomial,N_samples = 1e4) +#' +#' # Plot the histogram computed with the samples and the true value of the PMF +#' hist(samples,breaks=seq(0,n),freq=FALSE) +#' points(seq(0,n)-0.5,pmf_binomial,pch=16) +#' +#' @export +PMF.sample = function(pmf, N_samples) { + s = sample(0:(length(pmf)-1), prob = pmf, replace = TRUE, size = N_samples) + return(s) +} + +#' @title Get the mean of the distribution from a PMF object +#' +#' @description +#' +#' Returns the mean from the PMF specified by `pmf`. +#' +#' @param pmf the PMF object. +#' +#' @examples +#' library(bayesRecon) +#' +#' # Let's build the pmf of a Binomial distribution with parameters n and p +#' n <- 10 +#' p <- 0.6 +#' pmf_binomial <- apply(matrix(seq(0,10)),MARGIN=1,FUN=function(x) dbinom(x,size=n,prob=p)) +#' +#' +#' # The true mean corresponds to n*p +#' true_mean <- n*p +#' mean_from_PMF <- PMF.get_mean(pmf=pmf_binomial) +#' cat("True mean:", true_mean, "\nMean from PMF:", mean_from_PMF) +#' +#' @return A numerical value for mean of the distribution. +#' @seealso [PMF.get_var()], [PMF.get_quantile()], [PMF.sample()], [PMF.summary()] +#' @export +PMF.get_mean = function(pmf) { + supp = 0:(length(pmf)-1) + m = pmf %*% supp + return(m) +} + +#' @title Get the variance of the distribution from a PMF object +#' +#' @description +#' +#' Returns the variance from the PMF specified by `pmf`. +#' +#' @param pmf the PMF object. +#' +#' @examples +#' library(bayesRecon) +#' +#' # Let's build the pmf of a Binomial distribution with parameters n and p +#' n <- 10 +#' p <- 0.6 +#' pmf_binomial <- apply(matrix(seq(0,10)),MARGIN=1,FUN=function(x) dbinom(x,size=n,prob=p)) +#' +#' # The true variance corresponds to n*p*(1-p) +#' true_var <- n*p*(1-p) +#' var_from_PMF <- PMF.get_var(pmf=pmf_binomial) +#' cat("True variance:", true_var, "\nVariance from PMF:", var_from_PMF) +#' +#' @return A numerical value for variance. +#' @seealso [PMF.get_mean()], [PMF.get_quantile()], [PMF.sample()], [PMF.summary()] +#' @export +PMF.get_var = function(pmf) { + supp = 0:(length(pmf)-1) + v = pmf %*% supp^2 - PMF.get_mean(pmf)^2 + return(v) +} + + +#' @title Get quantile from a PMF object +#' +#' @description +#' +#' Returns the `p` quantile from the PMF specified by `pmf`. +#' +#' @param pmf the PMF object. +#' @param p the probability of the required quantile. +#' +#' @examples +#' library(bayesRecon) +#' +#' # Let's build the pmf of a Binomial distribution with parameters n and p +#' n <- 10 +#' p <- 0.6 +#' pmf_binomial <- apply(matrix(seq(0,10)),MARGIN=1,FUN=function(x) dbinom(x,size=n,prob=p)) +#' +#' # The true median is ceiling(n*p) +#' quant_50 <- PMF.get_quantile(pmf=pmf_binomial,p=0.5) +#' cat("True median:", ceiling(n*p), "\nMedian from PMF:", quant_50) +#' +#' +#' @return A numeric value for the quantile. +#' @seealso [PMF.get_mean()], [PMF.get_var()], [PMF.sample()], [PMF.summary()] +#' @export +PMF.get_quantile = function(pmf, p) { + if (p <= 0 | p >= 1) { + stop("Input error: probability p must be between 0 and 1") + } + cdf = cumsum(pmf) + x = min(which(cdf >= p)) + return(x-1) +} + + +#' @title Returns summary of a PMF object +#' +#' @description +#' +#' Returns the summary (min, max, IQR, median, mean) of the PMF specified by `pmf`. +#' +#' @param pmf the PMF object. +#' @param Ltoll used for computing the min of the PMF: the min is the smallest value +#' with probability greater than Ltoll (default: 1e-15) +#' @param Rtoll used for computing the max of the PMF: the max is the largest value +#' with probability greater than Rtoll (default: 1e-9) +#' +#' @examples +#' library(bayesRecon) +#' +#' # Let's build the pmf of a Binomial distribution with parameters n and p +#' n <- 10 +#' p <- 0.6 +#' pmf_binomial <- apply(matrix(seq(0,10)),MARGIN=1,FUN=function(x) dbinom(x,size=n,prob=p)) +#' +#' # Print the summary of this distribution +#' PMF.summary(pmf=pmf_binomial) +#' +#' +#' @return A summary data.frame +#' @seealso [PMF.get_mean()], [PMF.get_var()], [PMF.get_quantile()], [PMF.sample()] +#' @export +PMF.summary = function(pmf, Ltoll=.TOLL, Rtoll=.RTOLL) { + min_pmf = min(which(pmf > Ltoll)) - 1 + max_pmf = max(which(pmf > Rtoll)) - 1 + all_summaries <- data.frame("Min." = min_pmf, + `1st Qu.` = PMF.get_quantile(pmf,0.25), + "Median" = PMF.get_quantile(pmf,0.5), + "Mean" = PMF.get_mean(pmf), + `3rd Qu.` = PMF.get_quantile(pmf,0.75), + "Max" = max_pmf, + check.names = FALSE) + return(all_summaries) +} + +# Apply smoothing to a pmf to "cover the holes" in the support. +# If there is no hole, it doesn't do anything. +# If the smoothing parameter alpha is not specified, it is set to the min of pmf. +# If laplace is set to TRUE, add alpha to all the points. +# Otherwise, add alpha only to points with zero mass. +PMF.smoothing = function(pmf, alpha = 1e-9, laplace=FALSE) { + + if (is.null(alpha)) alpha = min(pmf[pmf!=0]) + + # apply smoothing only if there are holes + if (sum(pmf==0)) { + if (laplace) { pmf = pmf + rep(alpha, length(pmf)) + } else pmf[pmf==0] = alpha + } + + return(pmf / sum(pmf)) +} + + + +# Compute convolution between 2 pmfs. Then, for numerical reasons: +# -removes small values at the end of the vector (< Rtoll) +# -set to zero all the values to the left of the support +# -set to zero small values (< toll) +PMF.conv = function(pmf1, pmf2, toll=.TOLL, Rtoll=.RTOLL) { + pmf = stats::convolve(pmf1, rev(pmf2), type="open") + # Look for last value > Rtoll and remove all the elements after it: + last_pos = max(which(pmf > Rtoll)) + pmf = pmf[1:last_pos] + # Set to zero values smaller than toll: + pmf[pmf0)) + m2 = min(which(pmf2>0)) + m = m1 + m2 -1 + if (m>1) pmf[1:(m-1)] = 0 + pmf = pmf / sum(pmf) # re-normalize + return(pmf) +} + +# Computes the pmf of the bottom-up distribution analytically +# l_pmf: list of bottom pmfs +# toll and Rtoll: used during convolution (see PMF.conv) +# smoothing: whether to apply smoothing to the bottom pmfs to "cover the holes" +# al_smooth, lap_smooth: smoothing parameters (see PMF.smoothing) +# Returns: +# -the bottom-up pmf, if return_all=FALSE +# -otherwise, a list of lists of pmfs for all the steps of the algorithm; +# they correspond to the variables of the "auxiliary binary tree" +PMF.bottom_up = function(l_pmf, toll=.TOLL, Rtoll=.RTOLL, return_all=FALSE, + smoothing=TRUE, al_smooth=.ALPHA_SMOOTHING, lap_smooth=.LAP_SMOOTHING) { + + # Smoothing to "cover the holes" in the supports of the bottom pmfs + if (smoothing) l_pmf = lapply(l_pmf, PMF.smoothing, + alpha=al_smooth, laplace=lap_smooth) + + # Doesn't do convolutions sequentially + # Instead, for each iteration (while) it creates a new list of vectors + # by doing convolution between 1 and 2, 3 and 4, ... + # Then, the new list has length halved (if L is odd, just copy the last element) + # Ends when the list has length 1: contains just 1 vector that is the convolution + # of all the vectors of the list + old_v = l_pmf + l_l_v = list(old_v) # list with all the step-by-step lists of pmf + L = length(old_v) + while (L > 1) { + new_v = c() + for (j in 1:(L%/%2)) { + new_v = c(new_v, list(PMF.conv(old_v[[2*j-1]], old_v[[2*j]], + toll=toll, Rtoll=Rtoll))) + } + if (L%%2 == 1) new_v = c(new_v, list(old_v[[L]])) + old_v = new_v + l_l_v = c(l_l_v, list(old_v)) + L = length(old_v) + } + + if (return_all) { + return(l_l_v) + } else { + return(new_v[[1]]) + } +} + +# Given a vector v_u and a list of bottom pmf l_pmf, +# checks if the elements of v_u are contained in the support of the bottom-up distr +# Returns a vector with the same length of v_u with TRUE if it is contained and FALSE otherwise +PMF.check_support = function(v_u, l_pmf, toll=.TOLL, Rtoll=.RTOLL, + smoothing=TRUE, al_smooth=.ALPHA_SMOOTHING, lap_smooth=.LAP_SMOOTHING) { + pmf_u = PMF.bottom_up(l_pmf, toll=toll, Rtoll=Rtoll, return_all=FALSE, + smoothing=smoothing, al_smooth=al_smooth, lap_smooth=lap_smooth) + # The elements of v_u must be in the support of pmf_u + supp_u = which(pmf_u > 0) - 1 + mask = v_u %in% supp_u + return(mask) +} + +# Compute the tempered pmf +# The pmf is raised to the power of 1/temp, and then normalized +# temp must be a positive number +PMF.tempering = function(pmf, temp) { + + if (temp <= 0) stop("temp must be positive") + if (temp == 1) return(pmf) + + temp_pmf = pmf**(1/temp) + return(temp_pmf / sum(temp_pmf)) +} diff --git a/R/bayesRecon-package.R b/R/bayesRecon-package.R index a62ba47..880590e 100644 --- a/R/bayesRecon-package.R +++ b/R/bayesRecon-package.R @@ -4,28 +4,53 @@ #' #' @section Main functions: #' -#' The package implements reconciliation via conditioning for probabilistic forecasts of hierarchical time series. The main functions are -#' -#' * [reconc_gaussian()]: analytical reconciliation of Gaussian base forecasts; -#' * [reconc_BUIS()]: reconciliation of any probabilistic base forecast via importance sampling; -#' this is the recommended option for non-Gaussian base forecasts; -#' * [reconc_MCMC()]: reconciliation of probabilistic discrete base forecasts via Markov Chain Monte Carlo. -#' +#' The package implements reconciliation via conditioning for probabilistic forecasts +#' of hierarchical time series. The main functions are: +#' +#' * [reconc_gaussian()]: reconciliation via conditioning of multivariate Gaussian +#' base forecasts; this is done analytically; +#' * [reconc_BUIS()]: reconciliation via conditioning of any probabilistic forecast +#' via importance sampling; this is the recommended option for non-Gaussian base forecasts; +#' * [reconc_MCMC()]: reconciliation via conditioning of discrete probabilistic +#' forecasts via Markov Chain Monte Carlo; +#' * [reconc_MixCond()]: reconciliation via conditioning of mixed hierarchies, where +#' the upper forecasts are multivariate Gaussian and the bottom forecasts are discrete distributions; +#' * [reconc_TDcond()]: reconciliation via top-down conditioning of mixed hierarchies, where +#' the upper forecasts are multivariate Gaussian and the bottom forecasts are discrete distributions. +#' #' @section Utility functions: #' #' * [temporal_aggregation()]: temporal aggregation of a given time series object of class \link[stats]{ts}; -#' * [get_reconc_matrices()]: aggregation and summing matrices for a temporal hierarchy of time series from user-selected list of aggregation levels. +#' * [get_reconc_matrices()]: aggregation and summing matrices for a temporal hierarchy +#' of time series from user-selected list of aggregation levels; +#' * [schaferStrimmer_cov()]: computes the Schäfer-Strimmer shrinkage estimator for the covariance matrix; +#' * [PMF.get_mean()], [PMF.get_var()], [PMF.get_quantile()], [PMF.summary()], [PMF.sample()]: +#' functions for handling PMF objects. #' #' @references -#' Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). *Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule*. In: Hutter, F., Kersting, K., Lijffijt, J., Valera, I. (eds) Machine Learning and Knowledge Discovery in Databases. ECML PKDD 2020. Lecture Notes in Computer Science(), vol 12459. Springer, Cham. \doi{10.1007/978-3-030-67664-3_13}. -#' -#' Corani, G., Azzimonti, D., Rubattu, N. (2023). *Probabilistic reconciliation of count time series*. \doi{10.1016/j.ijforecast.2023.04.003}. -#' -#' Zambon, L., Azzimonti, D. & Corani, G. (2024). *Efficient probabilistic reconciliation of forecasts for real-valued and count time series*. \doi{10.1007/s11222-023-10343-y}. -#' -#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). *Properties of the reconciled distributions for Gaussian and count forecasts*. \doi{10.48550/arXiv.2303.15135}. -#' -#' +#' Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). +#' *Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule*. +#' ECML PKDD 2020. Lecture Notes in Computer Science, vol 12459. +#' \doi{10.1007/978-3-030-67664-3_13}. +#' +#' Corani, G., Azzimonti, D., Rubattu, N. (2024). +#' *Probabilistic reconciliation of count time series*. +#' International Journal of Forecasting 40 (2), 457-469. +#' \doi{10.1016/j.ijforecast.2023.04.003}. +#' +#' Zambon, L., Azzimonti, D. & Corani, G. (2024). +#' *Efficient probabilistic reconciliation of forecasts for real-valued and count time series*. +#' Statistics and Computing 34 (1), 21. +#' \doi{10.1007/s11222-023-10343-y}. +#' +#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +#' *Properties of the reconciled distributions for Gaussian and count forecasts*. +#' International Journal of Forecasting (in press). +#' \doi{10.1016/j.ijforecast.2023.12.004}. +#' +#' Zambon, L., Azzimonti, D., Rubattu, N., Corani, G. (2024). +#' *Probabilistic reconciliation of mixed-type hierarchical time series*. +#' The 40th Conference on Uncertainty in Artificial Intelligence, accepted. #' #' @keywords internal "_PACKAGE" diff --git a/R/carparts_example.R b/R/carparts_example.R deleted file mode 100644 index 6c70c59..0000000 --- a/R/carparts_example.R +++ /dev/null @@ -1,16 +0,0 @@ -#' Example of a time series from carparts -#' -#' A monthly time series from the `carparts` dataset, 51 observations, Jan 1998 - Mar 2002. -#' -#' @format -#' Univariate time series of class \link[stats]{ts}. -#' -#' @references -#' Hyndman, R.J., Koehler, A.B., Ord, J.K., and Snyder, R.D., (2008) Forecasting with exponential -#' smoothing: the state space approach, Springer -#' -#' Godahewa, Rakshitha, Bergmeir, Christoph, Webb, Geoff, Hyndman, Rob, & Montero-Manso, Pablo. (2020). Car Parts Dataset (without Missing Values) (Version 2) \doi{10.5281/zenodo.4656021} -#' -#' @source -#' Godahewa, Rakshitha, Bergmeir, Christoph, Webb, Geoff, Hyndman, Rob, & Montero-Manso, Pablo. (2020). Car Parts Dataset (without Missing Values) (Version 2) \doi{10.5281/zenodo.4656021} -"carparts_example" \ No newline at end of file diff --git a/R/data.R b/R/data.R new file mode 100644 index 0000000..d3667de --- /dev/null +++ b/R/data.R @@ -0,0 +1,162 @@ +#' Example of a time series from carparts +#' +#' A monthly time series from the `carparts` dataset, 51 observations, Jan 1998 - Mar 2002. +#' +#' @format +#' Univariate time series of class \link[stats]{ts}. +#' +#' @references +#' Hyndman, R.J., Koehler, A.B., Ord, J.K., and Snyder, R.D., (2008). +#' Forecasting with exponential smoothing: the state space approach. +#' Springer Science & Business Media. +#' +#' Godahewa, R., Bergmeir, C., Webb, G., Hyndman, R., & Montero-Manso, P. (2020). +#' Car Parts Dataset (without Missing Values) (Version 2) +#' \doi{10.5281/zenodo.4656021} +#' +#' @source +#' Godahewa, R., Bergmeir, C., Webb, G., Hyndman, R.J., & Montero-Manso, P. (2020). +#' Car Parts Dataset (without Missing Values) (Version 2) +#' \doi{10.5281/zenodo.4656021} +"carparts_example" + + +#' Infant Mortality grouped time series dataset +#' +#' A yearly grouped time series dataset, from 1901 to 2003, of infant mortality counts (deaths) in Australia; +#' disaggregated by state (see below), and sex (male and female). +#' +#' States: New South Wales (NSW), Victoria (VIC), Queensland (QLD), South Australia (SA), Western Australia +#' (WA), Northern Territory (NT), Australian Capital Territory (ACT), and Tasmania (TAS). +#' +#' @format +#' List of time series of class \link[stats]{ts}. +#' +#' @source +#' hts package [CRAN](https://cran.r-project.org/package=hts) +#' +#' @references +#' Hyndman, R.J., Ahmed, R.A., Athanasopoulos, G., Shang, H.L. (2011). +#' Optimal combination forecasts for hierarchical time series. +#' Computational Statistics and Data Analysis, 55(9), 2579-2589. +"infantMortality" + + +#' Example of a time series from the M3 forecasting competition +#' +#' A monthly time series, from the M3 forecasting competition ("N1485"). +#' +#' @format +#' List of time series of class \link[stats]{ts}. +#' +#' +#' @source [https://forecasters.org/resources/time-series-data/m3-competition/](https://forecasters.org/resources/time-series-data/m3-competition/) +"M3_example" + + +#' Extreme market events dataset +#' +#' Count time series of extreme market events in five economic sectors. +#' The data refer to the trading days between 2004/12/31 and 2018/12/19 (3508 trading days in total). +#' +#' The counts are computed by considering 29 companies included in the Euro Stoxx +#' 50 index and observing if the value of the CDS spread on a given day exceeds +#' the 90-th percentile of its distribution in the last trading year. +#' The companies are divided in the following sectors: Financial (FIN), Information +#' and Communication Technology (ICT), Manufacturing (MFG), Energy (ENG), and Trade (TRD). +#' +#' There are 6 time series: +#' - 5 bottom time series, corresponding to the daily counts for each sector +#' - 1 upper time series, which is the sum of all the bottom (ALL) +#' +#' @format +#' A multivariate time series of class \link[stats]{ts}. +#' +#' @source +#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +#' *Properties of the reconciled distributions for Gaussian and count forecasts*. +#' International Journal of Forecasting (in press). +#' \doi{10.1016/j.ijforecast.2023.12.004}. +#' +#' @references +#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +#' *Properties of the reconciled distributions for Gaussian and count forecasts*. +#' International Journal of Forecasting (in press). +#' \doi{10.1016/j.ijforecast.2023.12.004}. +#' +#' Agosto, A. (2022). +#' *Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion*. +#' \doi{10.2139/ssrn.4119895} +"extr_mkt_events" + + +#' Base forecasts for the extreme market events dataset +#' +#' Base forecasts for the `extr_mkt_events` dataset, computed using the model by +#' Agosto, A. (2022). +#' *Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion*. +#' \doi{10.2139/ssrn.4119895}. +#' +#' The predictive distribution for the bottom time series is a multivariate negative +#' binomial with a static vector of dispersion parameters and a time-varying vector +#' of location parameters following a score-driven dynamics. +#' The base forecasts for the upper time series are computed using a univariate version of this model. +#' They are in-sample forecasts: for each training instant, they are computed for +#' time t+1 by conditioning on the counts observed up to time t. +#' +#' @format +#' A list `extr_mkt_events_basefc` containing +#' \describe{ +#' \item{`extr_mkt_events_basefc$mu`}{data frame of the base forecast means, for each day} +#' \item{`extr_mkt_events_basefc$size`}{data frame of the static base forecast size parameters} +#' } +#' +#' @source +#' Agosto, A. (2022). +#' *Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion*. +#' \doi{10.2139/ssrn.4119895} +#' +#' @references +#' Agosto, A. (2022). +#' *Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion*. +#' \doi{10.2139/ssrn.4119895} +#' +#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +#' *Properties of the reconciled distributions for Gaussian and count forecasts*. +#' International Journal of Forecasting (in press). +#' \doi{10.1016/j.ijforecast.2023.12.004}. +"extr_mkt_events_basefc" + + +#' Example of hierarchical forecasts for a store from the M5 competition +#' +#' This dataset contains forecasts for the hierarchy of time series related to the store `CA_1` from the M5 competition. +#' +#' The store `CA_1` contains 3049 item level time series and 11 aggregate time series: +#' * Store level aggregation (`CA_1`) +#' * Category level aggregations (`HOBBIES`, `HOUSEHOLD`, `FOODS`) +#' * Department level aggregations (`HOBBIES_1`, `HOBBIES_2`, `HOUSEHOLD_1`, `HOUSEHOLD_2`, `FOODS_1`, `FOODS_2`, `FOODS_3`) +#' +#' Forecasts are generated with the function \link[smooth]{forecast} and the model \link[smooth]{adam} from the package `smooth`. +#' * The models for the bottom time series are selected with multiplicative Gamma error term (`MNN`); +#' * The models for the upper time series (`AXZ`) is selected with Gaussian additive error term, seasonality selected based on information criterion. +#' +#' The raw data was downloaded with the package \link[m5]{m5-package}. +#' +#' @format +#' A list containing: +#' * `upper`: a list of 11 elements each representing an aggregation level. Each element contains: `mu`, `sigma` the mean and standard deviation of the Gaussian forecast, `actual` the actual value, `residuals` the residuals of the model used to estimate forecasts covariance. +#' * `lower`: a list of 3049 elements each representing a forecast for each item. Each element contains `pmf` the probability mass function of the item level forecast, `actual` the actual value. +#' * `A`: the aggregation matrix for A. +#' * `S`: the S matrix for the hierarchy. +#' * `Q_u`: scaling factors for computing MASE on the upper forecasts. +#' * `Q_b`: scaling factors for computing MASE on the bottom forecasts. +#' +#' @references +#' Joachimiak K (2022). *m5: 'M5 Forecasting' Challenges Data*. R package version 0.1.1, . +#' +#' Makridakis, Spyros & Spiliotis, Evangelos & Assimakopoulos, Vassilis. (2020). *The M5 Accuracy competition: Results, findings and conclusions.* International Journal of Forecasting 38(4) 1346-1364. \doi{10.1016/j.ijforecast.2021.10.009} +#' +#' @source +#' Makridakis, Spyros & Spiliotis, Evangelos & Assimakopoulos, Vassilis. (2020). *The M5 Accuracy competition: Results, findings and conclusions.* International Journal of Forecasting 38(4) 1346-1364. \doi{10.1016/j.ijforecast.2021.10.009} +"M5_CA1_basefc" \ No newline at end of file diff --git a/R/extr_mkt_events.R b/R/extr_mkt_events.R deleted file mode 100644 index 71ef9bf..0000000 --- a/R/extr_mkt_events.R +++ /dev/null @@ -1,26 +0,0 @@ -#' Extreme market events dataset -#' -#' Count time series of extreme market events in five economic sectors. -#' The data refer to the trading days between 2004/12/31 and 2018/12/19 (3508 trading days in total). -#' -#' The counts are computed by considering 29 companies included in the Euro Stoxx -#' 50 index and observing if the value of the CDS spread on a given day exceeds -#' the 90-th percentile of its distribution in the last trading year. -#' The companies are divided in the following sectors: Financial (FIN), Information -#' and Communication Technology (ICT), Manufacturing (MFG), Energy (ENG), and Trade (TRD). -#' -#' There are 6 time series: -#' - 5 bottom time series, corresponding to the daily counts for each sector -#' - 1 upper time series, which is the sum of all the bottom (ALL) -#' -#' @format -#' A multivariate time series of class \link[stats]{ts}. -#' -#' @source -#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). *Properties of the reconciled distributions for Gaussian and count forecasts*. \doi{10.48550/arXiv.2303.15135}. -#' -#' @references -#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). *Properties of the reconciled distributions for Gaussian and count forecasts*. \doi{10.48550/arXiv.2303.15135}. -#' -#' Agosto, A. (2022). *Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion*. \doi{10.2139/ssrn.4119895} -"extr_mkt_events" diff --git a/R/extr_mkt_events_basefc.R b/R/extr_mkt_events_basefc.R deleted file mode 100644 index 7cbfd7c..0000000 --- a/R/extr_mkt_events_basefc.R +++ /dev/null @@ -1,27 +0,0 @@ -#' Base forecasts for the extreme market events dataset -#' -#' Base forecasts for the `extr_mkt_events` dataset, computed using the model by -#' Agosto, A. (2022). *Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion*. \doi{10.2139/ssrn.4119895}. -#' -#' The predictive distribution for the bottom time series is a multivariate negative -#' binomial with a static vector of dispersion parameters and a time-varying vector -#' of location parameters following a score-driven dynamics. -#' The base forecasts for the upper time series are computed using a univariate version of this model. -#' They are in-sample forecasts: for each training instant, they are computed for -#' time t+1 by conditioning on the counts observed up to time t. -#' -#' @format -#' A list `extr_mkt_events_basefc` containing -#' \describe{ -#' \item{`extr_mkt_events_basefc$mu`}{data frame of the base forecast means, for each day} -#' \item{`extr_mkt_events_basefc$size`}{data frame of the static base forecast size parameters} -#' } -#' -#' @source -#' Agosto, A. (2022). *Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion*. \doi{10.2139/ssrn.4119895} -#' -#' @references -#' Agosto, A. (2022). *Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion*. \doi{10.2139/ssrn.4119895} -#' -#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). *Properties of the reconciled distributions for Gaussian and count forecasts*. \doi{10.48550/arXiv.2303.15135}. -"extr_mkt_events_basefc" diff --git a/R/hierarchy.R b/R/hierarchy.R index e253b57..b86d222 100644 --- a/R/hierarchy.R +++ b/R/hierarchy.R @@ -1,4 +1,6 @@ -# Function to find the best hierarchy contained in A +# Function to find the best hierarchy contained in A; +# "best" means that minimizes the number of IS steps required by BUIS. +# It is not the maximal hierarchy contained in A! # Returns a vector with length equal to the number of rows of A # Each entry is 1 if the corresponding row has to be picked, and 0 otherwise .get_hier_rows <- function(A, scale = 196) { @@ -85,9 +87,9 @@ return(indices_sol) } -# Function that extract the "best hierarchy rows" from A, and sorts them in -# the correct order (i.e. bottom-up) -# Also sorts accordingly the vector v (e.g. of parameters) +# Function that extract the "best hierarchy rows" from A (see .get_hier_rows), +# and sorts them in the correct order (i.e. bottom-up) +# Also sorts accordingly the vectors v, d, it (e.g. of parameters) .get_HG <- function(A, v, d, it) { #get the indices of the "hierarchy rows" of A indices_sol <- .get_hier_rows(A) @@ -319,3 +321,120 @@ get_reconc_matrices <- function(agg_levels, h) { ) return(out) } + +# Returns TRUE if A is a hierarchy matrix +.check_hierarchical <- function(A) { + + k <- nrow(A) + m <- ncol(A) + + for (i in 1:k) { + for (j in 1:k) { + if (i < j) { + cond1 = A[i,] %*% A[j,] != 0 # Upper i and j have some common descendants + cond2 = any(A[j,] > A[i,]) # Upper j is not a descendant of upper i + cond3 = any(A[i,] > A[j,]) # Upper i is not a descendant of upper j + if (cond1 & cond2 & cond3) { + return(FALSE) + } + } + } + } + + return(TRUE) + +} + +# Check if A is a hierarchical matrix and if the rows are in bottom-up order +.check_BU_matr <- function(A) { + + k <- nrow(A) + m <- ncol(A) + + for (i in 1:k) { + for (j in 1:k) { + if (i < j) { + cond1 = A[i,] %*% A[j,] != 0 # Upper i and j have some common descendants + cond2 = any(A[i,] > A[j,]) # Upper i is not a descendant of upper j + if (cond1 & cond2) { + return(FALSE) + } + } + } + } + + return(TRUE) +} + +# Find the rows of A corresponding to the lowest level +.lowest_lev <- function(A) { + + if (!.check_hierarchical(A)) stop("Matrix A is not hierarchical") + + k = nrow(A) + m = ncol(A) + + rows = c() + for (i in 1:k) { + rows = c(rows, i) + for (j in 1:k) { + if (i != j) { + # If upper j is a descendant of upper i, remove i and exit loop + if (all(A[j,] <= A[i,])) { + rows = rows[-length(rows)] + break + } + } + } + } + # keep all rows except those that have no descendants among the uppers + + # The sum of the rows corresponding to the lowest level should be a vector of 1 + if (any(colSums(A[rows,,drop=FALSE])!=1)) { + stop("The hierarchy is not balanced") + } + + return(rows) +} + + +# Get the aggregating matrix Au of the sub-hierarchy composed just by the uppers +.get_Au <- function(A, lowest_rows=NULL) { + + if (is.null(lowest_rows)) lowest_rows = .lowest_lev(A) + + if (length(lowest_rows) == nrow(A)) { + warning("All the upper are lowest-upper. Return NULL") + return(NULL) + } + + A_ = A[-lowest_rows,,drop=FALSE] + n_bott = ncol(A_) + n_upp_u = nrow(A_) + n_bott_u = length(lowest_rows) + A_u = matrix(nrow=n_upp_u, ncol=n_bott_u) + for (j in 1:n_bott_u) { + l = lowest_rows[[j]] + mask = A[l,]==1 + for (i in 1:n_upp_u) { + A_u[i,j] = sum(A_[i, mask]==1) == sum(mask) # check that is a vector of 1 + } + } + + return(1*A_u) # to get numerical values instead of TRUE / FALSE +} + +# Check if the rows of A are ordered +.check_ordered_A <- function(A){ + aggregates_sum <- rowSums(A) + ordered_aggreg <- order(aggregates_sum,decreasing = TRUE) + if(all(aggregates_sum == aggregates_sum[ordered_aggreg]) ){ + return(list(value=TRUE)) + }else{ + return(list(value=FALSE, order=ordered_aggreg)) + } + +} + + + diff --git a/R/infantMortality.R b/R/infantMortality.R deleted file mode 100644 index 79a0580..0000000 --- a/R/infantMortality.R +++ /dev/null @@ -1,17 +0,0 @@ -#' Infant Mortality grouped time series dataset -#' -#' A yearly grouped time series dataset, from 1901 to 2003, of infant mortality counts (deaths) in Australia; -#' disaggregated by state (see below), and sex (male and female). -#' -#' States: New South Wales (NSW), Victoria (VIC), Queensland (QLD), South Australia (SA), Western Australia -#' (WA), Northern Territory (NT), Australian Capital Territory (ACT), and Tasmania (TAS). -#' -#' @format -#' List of time series of class \link[stats]{ts}. -#' -#' @source -#' hts package [CRAN](https://cran.r-project.org/package=hts) -#' -#' @references -#' R. J. Hyndman, R. A. Ahmed, G. Athanasopoulos and H.L. Shang (2011) Optimal combination forecasts for hierarchical time series. Computational Statistics and Data Analysis, 55(9), 2579-2589. -"infantMortality" \ No newline at end of file diff --git a/R/reconc.R b/R/reconc_BUIS.R similarity index 54% rename from R/reconc.R rename to R/reconc_BUIS.R index 9659c95..4c7b495 100644 --- a/R/reconc.R +++ b/R/reconc_BUIS.R @@ -1,88 +1,35 @@ ############################################################################### # Reconciliation with Bottom-Up Importance Sampling (BUIS) +############################################################################### -.distr_sample <- function(params, distr_, n) { - switch( - distr_, - "gaussian" = { - samples = stats::rnorm(n=n, mean = params[[1]], sd = params[[2]]) }, - "poisson" = { - samples = stats::rpois(n=n, lambda = params[[1]]) }, - "nbinom" = { - samples <-if (params[[2]] == 0) { - stop("Parameter size=0 in nbinom, this is not a valid distribution.") - stats::rpois(n=n, lambda = params[[1]]) - } else { - stats::rnbinom(n=n, mu = params[[1]], size = params[[2]]) - } }, - ) - return(samples) -} - -.distr_pmf <- function(x, params, distr_) { - switch( - distr_, - "gaussian" = { - pmf = stats::dnorm(x=x, mean = params[[1]], sd = params[[2]]) }, - "poisson" = { - pmf = stats::dpois(x=x, lambda = params[[1]]) }, - "nbinom" = { - pmf = stats::dnbinom(x=x, mu = params[[1]], size = params[[2]]) }, - ) - return(pmf) +# Checks that there is no bottom continuous variable child of a +# discrete upper variable +.check_hierfamily_rel <- function(sh.res, distr, debug=FALSE) { + for (bi in seq_along(distr[sh.res$bottom_idxs])) { + distr_bottom = distr[sh.res$bottom_idxs][[bi]] + rel_upper_i = sh.res$A[,bi] + rel_distr_upper = unlist(distr[sh.res$upper_idxs])[rel_upper_i == 1] + err_message = "A continuous bottom distribution cannot be child of a discrete one." + if (distr_bottom == "continuous") { + if (sum(rel_distr_upper == "discrete") | sum(rel_distr_upper %in% .DISCR_DISTR)) { + if (debug) { return(-1) } else { stop(err_message) } + } + } + if (distr_bottom %in% .CONT_DISTR) { + if (sum(rel_distr_upper == "discrete") | sum(rel_distr_upper %in% .DISCR_DISTR)) { + if (debug) { return(-1) } else { stop(err_message) } + } + } + } + if (debug) { return(0) } } .emp_pmf <- function(l, density_samples) { - empirical_pmf = sapply(0:max(density_samples), function(i) - sum(density_samples == i) / length(density_samples)) + empirical_pmf = PMF.from_samples(density_samples) w = sapply(l, function(i) empirical_pmf[i + 1]) return(w) } -.check_weigths <- function(w, n_eff_min=200, p_n_eff=0.01) { - warning = FALSE - warning_code = c() - warning_msg = c() - - n = length(w) - n_eff = n - - - # 1. w==0 - if (all(w==0)) { - warning = TRUE - warning_code = c(warning_code, 1) - warning_msg = c(warning_msg, - "Importance Sampling: all the weights are zeros. This is probably caused by a strong incoherence between bottom and upper base forecasts.") - }else{ - - # Effective sample size - n_eff = (sum(w)^2) / sum(w^2) - - # 2. n_eff < threshold - if (n_eff < n_eff_min) { - warning = TRUE - warning_code = c(warning_code, 2) - warning_msg = c(warning_msg, - paste0("Importance Sampling: effective_sample_size= ", round(n_eff,2), " (< ", n_eff_min,").")) - } - - # 3. n_eff < p*n, e.g. p = 0.05 - if (n_eff < p_n_eff*n) { - warning = TRUE - warning_code = c(warning_code, 3) - warning_msg = c(warning_msg, - paste0("Importance Sampling: effective_sample_size= ", round(n_eff,2), " (< ", round(p_n_eff * 100, 2),"%).")) - } - } - res = list(warning = warning, - warning_code = warning_code, - warning_msg = warning_msg, - n_eff = n_eff) - - return(res) -} - .compute_weights <- function(b, u, in_type_, distr_) { if (in_type_ == "samples") { if (distr_ == "discrete") { @@ -106,20 +53,12 @@ return(w) } -.resample <- function(S_, weights, num_samples = NA) { - if (is.na(num_samples)) { - num_samples = length(weights) - } - tmp_idx = sample(x = 1:num_samples, num_samples, replace = TRUE, prob = weights) - return(S_[tmp_idx, ]) -} - #' @title BUIS for Probabilistic Reconciliation of forecasts via conditioning #' #' @description #' #' Uses the Bottom-Up Importance Sampling algorithm to draw samples from the reconciled -#' forecast distribution, which is obtained via conditioning. +#' forecast distribution, obtained via conditioning. #' #' @details #' @@ -128,11 +67,11 @@ #' #' If `in_type[[i]]`='samples', then `base_forecast[[i]]` is a vector containing samples from the base forecast distribution. #' -#' If `in_type[[i]]`='params', then `base_forecast[[i]]` is a vector containing the estimated: +#' If `in_type[[i]]`='params', then `base_forecast[[i]]` is a list containing the estimated: #' #' * mean and sd for the Gaussian base forecast if `distr[[i]]`='gaussian', see \link[stats]{Normal}; #' * lambda for the Poisson base forecast if `distr[[i]]`='poisson', see \link[stats]{Poisson}; -#' * mu and size for the negative binomial base forecast if `distr[[i]]`='nbinom', see \link[stats]{NegBinomial}. +#' * size and prob (or mu) for the negative binomial base forecast if `distr[[i]]`='nbinom', see \link[stats]{NegBinomial}. #' #' See the description of the parameters `in_type` and `distr` for more details. #' @@ -144,7 +83,8 @@ #' * the effective sample size is < 200; #' * the effective sample size is < 1% of the sample size (`num_samples` if `in_type` is 'params' or the size of the base forecast if if `in_type` is 'samples'). #' -#' Note that warnings are an indication that the base forecasts might have issues. Please check the base forecasts in case of warnings. +#' Note that warnings are an indication that the base forecasts might have issues. +#' Please check the base forecasts in case of warnings. #' #' @param S Summing matrix (n x n_bottom). #' @param base_forecasts A list containing the base_forecasts, see details. @@ -155,14 +95,18 @@ #' #' If it `in_type` is a string it is assumed that all base forecasts are of the same type. #' -#' @param distr A string or a list of length n describing the type of base forecasts. If it is a list the i-th element is a string with two possible values: +#' @param distr A string or a list of length n describing the type of base forecasts. +#' If it is a list the i-th element is a string with two possible values: #' #' * 'continuous' or 'discrete' if `in_type[[i]]`='samples'; #' * 'gaussian', 'poisson' or 'nbinom' if `in_type[[i]]`='params'. #' #' If `distr` is a string it is assumed that all distributions are of the same type. #' -#' @param num_samples Number of samples drawn from the reconciled distribution. +#' @param num_samples Number of samples drawn from the reconciled distribution. +#' This is ignored if `bottom_in_type='samples'`; in this case, the number of reconciled samples is equal to +#' the number of samples of the base forecasts. +#' #' @param suppress_warnings Logical. If \code{TRUE}, no warnings about effective sample size #' are triggered. If \code{FALSE}, warnings are generated. Default is \code{FALSE}. See Details. #' @param seed Seed for reproducibility. @@ -197,7 +141,7 @@ #' #'base_forecasts = list() #'for (i in 1:nrow(S)) { -#' base_forecasts[[i]] = c(mus[[i]], sigmas[[i]]) +#' base_forecasts[[i]] = list(mean = mus[[i]], sd = sigmas[[i]]) #'} #' #' @@ -228,7 +172,7 @@ #' #'base_forecasts <- list() #'for (i in 1:nrow(S)) { -#' base_forecasts[[i]] = lambdas[i] +#' base_forecasts[[i]] = list(lambda = lambdas[i]) #'} #' #'#Sample from the reconciled forecast distribution using the BUIS algorithm @@ -240,7 +184,10 @@ #'print(rowMeans(samples_buis)) #' #' @references -#' Zambon, L., Azzimonti, D. & Corani, G. (2024). *Efficient probabilistic reconciliation of forecasts for real-valued and count time series*. \doi{10.1007/s11222-023-10343-y}. +#' Zambon, L., Azzimonti, D. & Corani, G. (2024). +#' *Efficient probabilistic reconciliation of forecasts for real-valued and count time series*. +#' Statistics and Computing 34 (1), 21. +#' \doi{10.1007/s11222-023-10343-y}. #' #' #' @seealso @@ -254,17 +201,19 @@ reconc_BUIS <- function(S, num_samples = 2e4, suppress_warnings = FALSE, seed = NULL) { - set.seed(seed) + + if (!is.null(seed)) set.seed(seed) - # Ensure that data inputs are valid - .check_input(S, base_forecasts, in_type, distr) + # Transform distr and in_type into lists if (!is.list(distr)) { distr = rep(list(distr), nrow(S)) } - if (!is.list(in_type)) { in_type = rep(list(in_type), nrow(S)) } + + # Ensure that data inputs are valid + .check_input_BUIS(S, base_forecasts, in_type, distr) # Split bottoms, uppers split_hierarchy.res = .split_hierarchy(S, base_forecasts) @@ -276,7 +225,8 @@ reconc_BUIS <- function(S, .check_hierfamily_rel(split_hierarchy.res, distr) # H, G - is.hier = .check_hierarchical(A) + is.hier = .check_hierarchical(A) + # If A is hierarchical we do not solve the integer linear programming problem if(is.hier) { H = A G = NULL @@ -322,7 +272,7 @@ reconc_BUIS <- function(S, weights = .compute_weights( b = (B %*% c), # (num_samples x 1) - u = unlist(upper_base_forecasts_H[[hi]]), + u = upper_base_forecasts_H[[hi]], in_type_ = in_typeH[[hi]], distr_ = distr_H[[hi]] ) @@ -349,7 +299,7 @@ reconc_BUIS <- function(S, c = G[gi, ] weights = weights * .compute_weights( b = (B %*% c), - u = unlist(upper_base_forecasts_G[[gi]]), + u = upper_base_forecasts_G[[gi]], in_type_ = in_typeG[[gi]], distr_ = distr_G[[gi]] ) @@ -387,121 +337,3 @@ reconc_BUIS <- function(S, return(out) } - - -#' @title Analytical reconciliation of Gaussian base forecasts -#' -#' @description -#' Closed form computation of the reconciled forecasts in case of Gaussian base forecasts. -#' -#' @param S summing matrix (n x n_bottom). -#' @param base_forecasts.mu a vector containing the means of the base forecasts. -#' @param base_forecasts.Sigma a matrix containing the covariance matrix of the base forecasts. -#' -#' @details -#' The order of the base forecast means and covariance is given by the order of the time series in the summing matrix. -#' -#' The function returns only the reconciled parameters of the bottom variables. -#' The reconciled upper parameters and the reconciled samples for the entire hierarchy can be obtained from the reconciled bottom parameters. -#' See the example section. -#' -#' -#' @return A list containing the bottom reconciled forecasts. The list has the following named elements: -#' -#' * `bottom_reconciled_mean`: reconciled mean for the bottom forecasts; -#' * `bottom_reconciled_covariance`: reconciled covariance for the bottom forecasts. -#' -#' -#' @examples -#' -#'library(bayesRecon) -#' -#'# Create a minimal hierarchy with 2 bottom and 1 upper variable -#'rec_mat <- get_reconc_matrices(agg_levels=c(1,2), h=2) -#'S <- rec_mat$S -#'A <- rec_mat$A -#' -#'#Set the parameters of the Gaussian base forecast distributions -#'mu1 <- 2 -#'mu2 <- 4 -#'muY <- 9 -#'mus <- c(muY,mu1,mu2) -#' -#'sigma1 <- 2 -#'sigma2 <- 2 -#'sigmaY <- 3 -#'sigmas <- c(sigmaY,sigma1,sigma2) -#' -#'Sigma <- diag(sigmas^2) #need to transform into covariance matrix -#'analytic_rec <- reconc_gaussian(S, base_forecasts.mu = mus, -#' base_forecasts.Sigma = Sigma) -#' -#'bottom_mu_reconc <- analytic_rec$bottom_reconciled_mean -#'bottom_Sigma_reconc <- analytic_rec$bottom_reconciled_covariance -#' -#'# Obtain reconciled mu and Sigma for the upper variable -#'upper_mu_reconc <- A %*% bottom_mu_reconc -#'upper_Sigma_reconc <- A %*% bottom_Sigma_reconc %*% t(A) -#' -#'# Obtain reconciled mu and Sigma for the entire hierarchy -#'Y_mu_reconc <- S %*% bottom_mu_reconc -#'Y_Sigma_reconc <- S %*% bottom_Sigma_reconc %*% t(S) # note: singular matrix -#' -#'# Obtain reconciled samples for the entire hierarchy: -#'# i.e., sample from the reconciled bottoms and multiply by S -#'chol_decomp = chol(bottom_Sigma_reconc) # Compute the Cholesky Decomposition -#'Z = matrix(rnorm(n = 2000), nrow = 2) # Sample from standard normal -#'B = chol_decomp %*% Z + matrix(rep(bottom_mu_reconc, 1000), nrow=2) # Apply the transformation -#' -#'U = S %*% B -#'Y_reconc = rbind(U, B) -#' -#' @references -#' Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). *Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule*. In: Hutter, F., Kersting, K., Lijffijt, J., Valera, I. (eds) Machine Learning and Knowledge Discovery in Databases. ECML PKDD 2020. Lecture Notes in Computer Science(), vol 12459. Springer, Cham. \doi{10.1007/978-3-030-67664-3_13}. -#' -#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). *Properties of the reconciled distributions for Gaussian and count forecasts*. \doi{10.48550/arXiv.2303.15135}. -#' -#' -#' @seealso [reconc_BUIS()] -#' -#' @export -reconc_gaussian <- function(S, base_forecasts.mu, - base_forecasts.Sigma) { - # Check if S contains only 0s and 1s. - .check_S(S) - hier = .get_A_from_S(S) - A = hier$A - k = nrow(A) #number of upper TS - m = ncol(A) #number of bottom TS - n = length(base_forecasts.mu) #total number of TS - - # Ensure that data inputs are valid - .check_cov(base_forecasts.Sigma) - if (!(nrow(base_forecasts.Sigma) == n)) { - stop("Input error: nrow(base_forecasts.Sigma) != length(base_forecasts.mu)") - } - if (!(k + m == n)) { - stop("Input error: the shape of S is not correct") - } - - Sigma_u = base_forecasts.Sigma[hier$upper_idxs, hier$upper_idxs] - Sigma_b = base_forecasts.Sigma[hier$bottom_idxs, hier$bottom_idxs] - Sigma_ub = matrix(base_forecasts.Sigma[hier$upper_idxs, hier$bottom_idxs], - nrow = length(hier$upper_idxs)) - mu_u = base_forecasts.mu[hier$upper_idxs] - mu_b = base_forecasts.mu[hier$bottom_idxs] - - # Formulation from: - # Zambon, L., et al. "Properties of the reconciled distributions for - # Gaussian and count forecasts." (2023) - Q = Sigma_u - Sigma_ub %*% t(A) - A %*% t(Sigma_ub) + A %*% Sigma_b %*% t(A) - invQ = solve(Q) - mu_b_tilde = mu_b + (t(Sigma_ub) - Sigma_b %*% t(A)) %*% invQ %*% (A %*% mu_b - mu_u) - Sigma_b_tilde = Sigma_b - (t(Sigma_ub) - Sigma_b %*% t(A)) %*% invQ %*% t(t(Sigma_ub) - Sigma_b %*% t(A)) - - out = list( - bottom_reconciled_mean = mu_b_tilde, - bottom_reconciled_covariance = Sigma_b_tilde - ) - return(out) -} diff --git a/R/reconc_MH.R b/R/reconc_MCMC.R similarity index 90% rename from R/reconc_MH.R rename to R/reconc_MCMC.R index 2a73096..7fc7c24 100644 --- a/R/reconc_MH.R +++ b/R/reconc_MCMC.R @@ -6,7 +6,8 @@ #' Uses Markov Chain Monte Carlo algorithm to draw samples from the reconciled #' forecast distribution, which is obtained via conditioning. #' -#' This is a bare-bones implementation of the Metropolis-Hastings algorithm, we suggest the usage of tools to check the convergence. +#' This is a bare-bones implementation of the Metropolis-Hastings algorithm, +#' we suggest the usage of tools to check the convergence. #' The function only works with Poisson or Negative Binomial base forecasts. #' #' The function [reconc_BUIS()] is generally faster on most hierarchies. @@ -25,11 +26,11 @@ #' @details #' #' The parameter `base_forecast` is a list containing n elements. -#' Each element is a vector containing the estimated: +#' Each element is a list containing the estimated: #' #' * mean and sd for the Gaussian base forecast, see \link[stats]{Normal}, if `distr`='gaussian'; #' * lambda for the Poisson base forecast, see \link[stats]{Poisson}, if `distr`='poisson'; -#' * mu and size for the negative binomial base forecast, see \link[stats]{NegBinomial}, if `distr`='nbinom'. +#' * size and prob (or mu) for the negative binomial base forecast, see \link[stats]{NegBinomial}, if `distr`='nbinom'. #' #' The order of the `base_forecast` list is given by the order of the time series in the summing matrix. #' @@ -55,12 +56,12 @@ #' #'base_forecasts = list() #'for (i in 1:nrow(S)) { -#' base_forecasts[[i]] = lambdas[i] +#' base_forecasts[[i]] = list(lambda = lambdas[i]) #'} #' #'#Sample from the reconciled forecast distribution using MCMC -#'mcmc = reconc_MCMC(S,base_forecasts=lambdas,distr="poisson", -#' num_samples=30000, seed=42) +#'mcmc = reconc_MCMC(S, base_forecasts, distr = "poisson", +#' num_samples = 30000, seed = 42) #'samples_mcmc <- mcmc$reconciled_samples #' #'#Compare the reconciled means with those obtained via BUIS @@ -72,8 +73,10 @@ #'print(rowMeans(samples_buis)) #' #' @references -#' Corani, G., Azzimonti, D., Rubattu, N. (2023). *Probabilistic reconciliation of count time series*. \doi{10.1016/j.ijforecast.2023.04.003}. -#' +#' Corani, G., Azzimonti, D., Rubattu, N. (2024). +#' *Probabilistic reconciliation of count time series*. +#' International Journal of Forecasting 40 (2), 457-469. +#' \doi{10.1016/j.ijforecast.2023.04.003}. #' #' @seealso #' [reconc_BUIS()] @@ -88,16 +91,18 @@ reconc_MCMC <- function(S, burn_in = 1000, seed = NULL) { - set.seed(seed) + if (!is.null(seed)) set.seed(seed) # Ensure that data inputs are valid if (distr == "gaussian") { stop("MCMC for Gaussian distributions is not implemented") } - .check_input(S, base_forecasts, in_type = "params", distr = distr) + # Transform distr into list if (!is.list(distr)) { distr = rep(list(distr), nrow(S)) } + # Check input + .check_input_BUIS(S, base_forecasts, in_type = as.list(rep("params", nrow(S))), distr = distr) n_bottom <- ncol(S) n_ts <- nrow(S) diff --git a/R/reconc_MixCond.R b/R/reconc_MixCond.R new file mode 100644 index 0000000..dbccc65 --- /dev/null +++ b/R/reconc_MixCond.R @@ -0,0 +1,210 @@ +############################################################################### +# Reconciliation with mixed-conditioning (Mix-Cond) +############################################################################### + + + +#' @title Probabilistic forecast reconciliation of mixed hierarchies via conditioning +#' +#' @description +#' +#' Uses importance sampling to draw samples from the reconciled +#' forecast distribution, obtained via conditioning, in the case of a mixed hierarchy. +#' +#' @details +#' +#' The base bottom forecasts `fc_bottom` must be a list of length n_bottom, where each element is either +#' * a PMF object (see details below), if `bottom_in_type='pmf'`; +#' * a vector of samples, if `bottom_in_type='samples'`; +#' * a list of parameters, if `bottom_in_type='params'`: +#' * lambda for the Poisson base forecast if `distr`='poisson', see \link[stats]{Poisson}; +#' * size and prob (or mu) for the negative binomial base forecast if `distr`='nbinom', +#' see \link[stats]{NegBinomial}. +#' +#' The base upper forecasts `fc_upper` must be a list containing the parameters of +#' the multivariate Gaussian distribution of the upper forecasts. +#' The list must contain only the named elements `mu` (vector of length n_upper) +#' and `Sigma` (n_upper x n_upper matrix) +#' +#' A PMF object is a numerical vector containing the probability mass function of a discrete distribution. +#' Each element corresponds to the probability of the integers from 0 to the last value of the support. +#' See also \link{PMF.get_mean}, \link{PMF.get_var}, \link{PMF.sample}, \link{PMF.get_quantile}, +#' \link{PMF.summary} for functions that handle PMF objects. +#' +#' Warnings are triggered from the Importance Sampling step if: +#' +#' * weights are all zeros, then the upper forecast is ignored during reconciliation; +#' * the effective sample size is < 200; +#' * the effective sample size is < 1% of the sample size. +#' +#' Note that warnings are an indication that the base forecasts might have issues. +#' Please check the base forecasts in case of warnings. +#' +#' @param S Summing matrix (n x n_bottom). +#' @param fc_bottom A list containing the bottom base forecasts, see details. +#' @param fc_upper A list containing the upper base forecasts, see details. +#' @param bottom_in_type A string with three possible values: +#' +#' * 'pmf' if the bottom base forecasts are in the form of pmf, see details; +#' * 'samples' if the bottom base forecasts are in the form of samples; +#' * 'params' if the bottom base forecasts are in the form of estimated parameters. +#' +#' @param distr A string describing the type of bottom base forecasts ('poisson' or 'nbinom'). +#' +#' This is only used if `bottom_in_type='params'`. +#' +#' @param num_samples Number of samples drawn from the reconciled distribution. +#' This is ignored if `bottom_in_type='samples'`; in this case, the number of +#' reconciled samples is equal to the number of samples of the base forecasts. +#' +#' @param return_type The return type of the reconciled distributions. +#' A string with three possible values: +#' +#' * 'pmf' returns a list containing the reconciled marginal pmf objects; +#' * 'samples' returns a list containing the reconciled multivariate samples; +#' * 'all' returns a list with both pmf objects and samples. +#' +#' @param suppress_warnings Logical. If \code{TRUE}, no warnings about samples +#' are triggered. If \code{FALSE}, warnings are generated. Default is \code{FALSE}. See Details. +#' @param seed Seed for reproducibility. +#' +#' @return A list containing the reconciled forecasts. The list has the following named elements: +#' +#' * `bottom_reconciled`: a list containing the pmf, the samples (matrix n_bottom x `num_samples`) or both, +#' depending on the value of `return_type`; +#' * `upper_reconciled`: a list containing the pmf, the samples (matrix n_upper x `num_samples`) or both, +#' depending on the value of `return_type`. +#' +#' @examples +#' +#' library(bayesRecon) +#' +#' # Consider a simple hierarchy with two bottom and one upper +#' A <- matrix(c(1,1),nrow=1) +#' S <- rbind(A,diag(nrow=2)) +#' # The bottom forecasts are Poisson with lambda=15 +#' lambda <- 15 +#' n_tot <- 60 +#' fc_bottom <- list() +#' fc_bottom[[1]] <- apply(matrix(seq(0,n_tot)),MARGIN=1,FUN=function(x) dpois(x,lambda=lambda)) +#' fc_bottom[[2]] <- apply(matrix(seq(0,n_tot)),MARGIN=1,FUN=function(x) dpois(x,lambda=lambda)) +#' +#' # The upper forecast is a Normal with mean 40 and std 5 +#' fc_upper<- list(mu=40, Sigma=matrix(5^2)) +#' +#' # We can reconcile with reconc_MixCond +#' res.mixCond <- reconc_MixCond(S, fc_bottom, fc_upper) +#' +#' # Note that the bottom distributions are slightly shifted to the right +#' PMF.summary(res.mixCond$bottom_reconciled$pmf[[1]]) +#' PMF.summary(fc_bottom[[1]]) +#' +#' PMF.summary(res.mixCond$bottom_reconciled$pmf[[2]]) +#' PMF.summary(fc_bottom[[2]]) +#' +#' # The upper distribution is slightly shifted to the left +#' PMF.summary(res.mixCond$upper_reconciled$pmf[[1]]) +#' PMF.get_var(res.mixCond$upper_reconciled$pmf[[1]]) +#' +#' @references +#' Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). +#' *Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule*. +#' ECML PKDD 2020. Lecture Notes in Computer Science, vol 12459. +#' \doi{10.1007/978-3-030-67664-3_13}. +#' +#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +#' *Properties of the reconciled distributions for Gaussian and count forecasts*. +#' International Journal of Forecasting (in press). +#' \doi{10.1016/j.ijforecast.2023.12.004}. +#' +#' Zambon, L., Azzimonti, D., Rubattu, N., Corani, G. (2024). +#' *Probabilistic reconciliation of mixed-type hierarchical time series*. +#' The 40th Conference on Uncertainty in Artificial Intelligence, accepted. +#' +#' @seealso [reconc_TDcond()], [reconc_BUIS()] +#' +#' @export +reconc_MixCond = function(S, fc_bottom, fc_upper, + bottom_in_type = "pmf", distr = NULL, + num_samples = 2e4, return_type = "pmf", + suppress_warnings = FALSE, seed = NULL) { + + if (!is.null(seed)) set.seed(seed) + + # Parameters for convolution + # toll=1e-16 + # Rtoll=1e-7 + # smooth_bottom=TRUE + # al_smooth=NULL + # lap_smooth=FALSE + + # After testing the convolution parameters: + # remove dots, remove comment above, and set the "best parameters" as default in + # PMF.check_support and .TD_sampling + + # Check inputs + .check_input_TD(S, fc_bottom, fc_upper, + bottom_in_type, distr, + return_type) + + # Get aggr. matrix A + A = .get_A_from_S(S)$A + n_u = nrow(A) + n_b = ncol(A) + + # Prepare samples from the base bottom distribution + if (bottom_in_type == "pmf") { + B = lapply(fc_bottom, PMF.sample, N_samples=num_samples) + B = do.call("cbind", B) # matrix of bottom samples (N_samples x n_bottom) + } else if (bottom_in_type == "samples") { + B = do.call("cbind", fc_bottom) + num_samples = nrow(B) + } else if (bottom_in_type == "params") { + L_pmf = lapply(fc_bottom, PMF.from_params, distr = distr) + B = lapply(L_pmf, PMF.sample, N_samples=num_samples) + B = do.call("cbind", B) # matrix of bottom samples (N_samples x n_bottom) + } + + # Get mean and covariance matrix of the MVN upper base forecasts + mu_u = fc_upper$mu + Sigma_u = as.matrix(fc_upper$Sigma) + + # IS using MVN + U = B %*% t(A) + weights = .MVN_density(x=U, mu = mu_u, Sigma = Sigma_u) + + + check_weights.res = .check_weigths(weights) + if (check_weights.res$warning & !suppress_warnings) { + warning_msg = check_weights.res$warning_msg + warning(warning_msg) + } + if(!(check_weights.res$warning & (1 %in% check_weights.res$warning_code))){ + B = .resample(B, weights, num_samples) + } + + ESS = sum(weights)**2/sum(weights**2) + + B = t(B) + U = A %*% B + + + # Prepare output: include the marginal pmfs and/or the samples (depending on "return" inputs) + out = list(bottom_reconciled=list(), upper_reconciled=list(), ESS = ESS) + if (return_type %in% c('pmf', 'all')) { + upper_pmf = lapply(1:n_u, function(i) PMF.from_samples(U[i,])) + bottom_pmf = lapply(1:n_b, function(i) PMF.from_samples(B[i,])) + + out$bottom_reconciled$pmf = bottom_pmf + out$upper_reconciled$pmf = upper_pmf + + } + if (return_type %in% c('samples','all')) { + + out$bottom_reconciled$samples = B + out$upper_reconciled$samples = U + + } + + return(out) +} diff --git a/R/reconc_TDcond.R b/R/reconc_TDcond.R new file mode 100644 index 0000000..2553e9b --- /dev/null +++ b/R/reconc_TDcond.R @@ -0,0 +1,312 @@ +# Sample from the distribution p(B_1, B_2 | B_1 + B_2 = u), +# where B_1 and B_2 are distributed as pmf1 and pmf2. +# u is a vector +.cond_biv_sampling = function(u, pmf1, pmf2) { + + # In this way then we iterate over the one with shorter support: + sw = FALSE + if (length(pmf1) > length(pmf2)) { + pmf_ = pmf1 + pmf1 = pmf2 + pmf2 = pmf_ + sw = TRUE + } + + b1 = rep(NA, length(u)) # initialize empty vector + + for (u_uniq in unique(u)) { # loop over different values of u + + len_supp1 = length(pmf1) + supp1 = 0:(len_supp1-1) + p1 = pmf1 + + supp2 = u_uniq - supp1 + supp2[supp2<0] = Inf # trick to get NA when we access pmf2 outside the support + p2 = pmf2[supp2+1] # +1 because support starts from 0, but vector indexing from 1 + p2[is.na(p2)] = 0 # set NA to zero + + p = p1 * p2 + p = p / sum(p) + + u_posit = (u == u_uniq) + b1[u_posit] = sample(supp1, size = sum(u_posit), replace = TRUE, prob = p) + } + + if (sw) b1 = u - b1 # if we have switched, switch back + + return(list(b1, u-b1)) +} + +# Given a vector u of the upper values and a list of the bottom distr pmfs, +# returns samples (dim: n_bottom x length(u)) from the conditional distr +# of the bottom given the upper values +.TD_sampling = function(u, bott_pmf, + toll=.TOLL, Rtoll=.RTOLL, smoothing=TRUE, + al_smooth=.ALPHA_SMOOTHING, lap_smooth=.LAP_SMOOTHING) { + + l_l_pmf = rev(PMF.bottom_up(bott_pmf, toll = toll, Rtoll = Rtoll, return_all = TRUE, + smoothing=smoothing, al_smooth=al_smooth, lap_smooth=lap_smooth)) + + b_old = matrix(u, nrow = 1) + for (l_pmf in l_l_pmf[2:length(l_l_pmf)]) { + L = length(l_pmf) + b_new = matrix(ncol = length(u), nrow = L) + for (j in 1:(L%/%2)) { + b = .cond_biv_sampling(b_old[j,], l_pmf[[2*j-1]], l_pmf[[2*j]]) + b_new[2*j-1,] = b[[1]] + b_new[2*j,] = b[[2]] + } + if (L%%2 == 1) b_new[L,] = b_old[L%/%2 + 1,] + b_old = b_new + } + + return(b_new) +} + + + +#' @title Probabilistic forecast reconciliation of mixed hierarchies via top-down conditioning +#' +#' @description +#' +#' Uses the top-down conditioning algorithm to draw samples from the reconciled +#' forecast distribution. Reconciliation is performed in two steps: +#' first, the upper base forecasts are reconciled via conditioning, +#' using only the hierarchical constraints between the upper variables; then, +#' the bottom distributions are updated via a probabilistic top-down procedure. +#' +#' @details +#' +#' The base bottom forecasts `fc_bottom` must be a list of length n_bottom, where each element is either +#' * a PMF object (see details below), if `bottom_in_type='pmf'`; +#' * a vector of samples, if `bottom_in_type='samples'`; +#' * a list of parameters, if `bottom_in_type='params'`: +#' * lambda for the Poisson base forecast if `distr`='poisson', see \link[stats]{Poisson}; +#' * size and prob (or mu) for the negative binomial base forecast if `distr`='nbinom', +#' see \link[stats]{NegBinomial}. +#' +#' The base upper forecasts `fc_upper` must be a list containing the parameters of +#' the multivariate Gaussian distribution of the upper forecasts. +#' The list must contain only the named elements `mu` (vector of length n_upper) +#' and `Sigma` (n_upper x n_upper matrix) +#' +#' A PMF object is a numerical vector containing the probability mass function of a discrete distribution. +#' Each element corresponds to the probability of the integers from 0 to the last value of the support. +#' See also \link{PMF.get_mean}, \link{PMF.get_var}, \link{PMF.sample}, \link{PMF.get_quantile}, +#' \link{PMF.summary} for functions that handle PMF objects. +#' +#' If some of the reconciled upper samples lie outside the support of the bottom-up distribution, +#' those samples are discarded and a warning is triggered. +#' The warning reports the percentage of samples kept. +#' +#' @param S Summing matrix (n x n_bottom). +#' @param fc_bottom A list containing the bottom base forecasts, see details. +#' @param fc_upper A list containing the upper base forecasts, see details. +#' @param bottom_in_type A string with three possible values: +#' +#' * 'pmf' if the bottom base forecasts are in the form of pmf, see details; +#' * 'samples' if the bottom base forecasts are in the form of samples; +#' * 'params' if the bottom base forecasts are in the form of estimated parameters. +#' +#' @param distr A string describing the type of bottom base forecasts ('poisson' or 'nbinom'). +#' +#' This is only used if `bottom_in_type=='params'`. +#' +#' @param num_samples Number of samples drawn from the reconciled distribution. +#' This is ignored if `bottom_in_type='samples'`; in this case, the number of +#' reconciled samples is equal to the number of samples of the base forecasts. +#' +#' @param return_type The return type of the reconciled distributions. +#' A string with three possible values: +#' +#' * 'pmf' returns a list containing the reconciled marginal pmf objects; +#' * 'samples' returns a list containing the reconciled multivariate samples; +#' * 'all' returns a list with both pmf objects and samples. +#' +#' @param suppress_warnings Logical. If \code{TRUE}, no warnings about samples +#' are triggered. If \code{FALSE}, warnings are generated. Default is \code{FALSE}. See Details. +#' @param seed Seed for reproducibility. +#' +#' @return A list containing the reconciled forecasts. The list has the following named elements: +#' +#' * `bottom_reconciled`: a list containing the pmf, the samples (matrix n_bottom x `num_samples`) or both, +#' depending on the value of `return_type`; +#' * `upper_reconciled`: a list containing the pmf, the samples (matrix n_upper x `num_samples`) or both, +#' depending on the value of `return_type`. +#' +#' @examples +#' +#' library(bayesRecon) +#' +#' # Consider a simple hierarchy with two bottom and one upper +#' A <- matrix(c(1,1),nrow=1) +#' S <- rbind(A,diag(nrow=2)) +#' # The bottom forecasts are Poisson with lambda=15 +#' lambda <- 15 +#' n_tot <- 60 +#' fc_bottom <- list() +#' fc_bottom[[1]] <- apply(matrix(seq(0,n_tot)),MARGIN=1,FUN=function(x) dpois(x,lambda=lambda)) +#' fc_bottom[[2]] <- apply(matrix(seq(0,n_tot)),MARGIN=1,FUN=function(x) dpois(x,lambda=lambda)) +#' +#' # The upper forecast is a Normal with mean 40 and std 5 +#' fc_upper<- list(mu=40, Sigma=matrix(c(5^2))) +#' +#' # We can reconcile with reconc_TDcond +#' res.TDcond <- reconc_TDcond(S, fc_bottom, fc_upper) +#' +#' # Note that the bottom distributions are shifted to the right +#' PMF.summary(res.TDcond$bottom_reconciled$pmf[[1]]) +#' PMF.summary(fc_bottom[[1]]) +#' +#' PMF.summary(res.TDcond$bottom_reconciled$pmf[[2]]) +#' PMF.summary(fc_bottom[[2]]) +#' +#' # The upper distribution remains similar +#' PMF.summary(res.TDcond$upper_reconciled$pmf[[1]]) +#' PMF.get_var(res.TDcond$upper_reconciled$pmf[[1]]) +#' +#' @references +#' Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). +#' *Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule*. +#' ECML PKDD 2020. Lecture Notes in Computer Science, vol 12459. +#' \doi{10.1007/978-3-030-67664-3_13}. +#' +#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +#' *Properties of the reconciled distributions for Gaussian and count forecasts*. +#' International Journal of Forecasting (in press). +#' \doi{10.1016/j.ijforecast.2023.12.004}. +#' +#' Zambon, L., Azzimonti, D., Rubattu, N., Corani, G. (2024). +#' *Probabilistic reconciliation of mixed-type hierarchical time series*. +#' The 40th Conference on Uncertainty in Artificial Intelligence, accepted. +#' +#' @seealso [reconc_MixCond()], [reconc_BUIS()] +#' +#' @export +reconc_TDcond = function(S, fc_bottom, fc_upper, + bottom_in_type = "pmf", distr = NULL, + num_samples = 2e4, return_type = "pmf", + suppress_warnings = FALSE, seed = NULL) { + + if (!is.null(seed)) set.seed(seed) + + # Check inputs + .check_input_TD(S, fc_bottom, fc_upper, + bottom_in_type, distr, + return_type) + + # Get aggr. matrix A and find the "lowest upper" + A = .get_A_from_S(S)$A + n_u = nrow(A) + n_b = ncol(A) + lowest_rows = .lowest_lev(A) + n_u_low = length(lowest_rows) # number of lowest upper + + # Get mean and covariance matrix of the MVN upper base forecasts + mu_u = fc_upper$mu + Sigma_u = as.matrix(fc_upper$Sigma) + + ### Get upper samples + if (n_u == n_u_low) { + # If all the upper are lowest-upper, just sample from the base distribution + U = .MVN_sample(num_samples, mu_u, Sigma_u) # (dim: num_samples x n_u_low) + U = round(U) # round to integer + U_js = asplit(U, MARGIN = 2) # split into list of column vectors + + } else { + # Else, analytically reconcile the upper and then sample from the lowest-uppers + + # Get the aggregation matrix A_u and the summing matrix S_u for the upper sub-hierarchy + A_u = .get_Au(A, lowest_rows) + S_u = matrix(nrow = n_u, ncol = n_u_low) + S_u[-lowest_rows,] = A_u + S_u[lowest_rows,] = diag(n_u_low) + + # Analytically reconcile the upper + rec_gauss_u = reconc_gaussian(S_u, mu_u, Sigma_u) + + # Sample from reconciled MVN on the lowest level of the upper (dim: num_samples x n_u_low) + U = .MVN_sample(n_samples = num_samples, + mu = rec_gauss_u$bottom_reconciled_mean, + Sigma = rec_gauss_u$bottom_reconciled_covariance) + U = round(U) # round to integer + U_js = asplit(U, MARGIN = 2) # split into list of column vectors + } + + # Prepare list of bottom pmf + if (bottom_in_type == "pmf") { + L_pmf = fc_bottom + } else if (bottom_in_type == "samples") { + L_pmf = lapply(fc_bottom, PMF.from_samples) + } else if (bottom_in_type == "params") { + L_pmf = lapply(fc_bottom, PMF.from_params, distr = distr) + } + + # Prepare list of lists of bottom pmf relative to each lowest upper + L_pmf_js = list() + for (j in lowest_rows) { + Aj = A[j,] + L_pmf_js = c(L_pmf_js, list(L_pmf[as.logical(Aj)])) + } + + # Check that each multiv. sample of U is contained in the supp of the bottom-up distr + samp_ok = mapply(PMF.check_support, U_js, L_pmf_js) + samp_ok = rowSums(samp_ok) == n_u_low + # Only keep the "good" upper samples, and throw a warning if some samples are discarded: + U_js = lapply(U_js, "[", samp_ok) + if (sum(samp_ok) != num_samples & !suppress_warnings) { + # We round down to the nearest decimal + warning(paste0("Only ", floor(sum(samp_ok)/num_samples*1000)/10, "% of the upper samples ", + "are in the support of the bottom-up distribution; ", + "the others are discarded.")) + } + + # Get bottom samples via the prob top-down + B = list() + for (j in 1:n_u_low) { + B[[j]] = .TD_sampling(U_js[[j]], L_pmf_js[[j]]) + } + B = do.call("rbind", B) # dim: n_bottom x num_samples + U = A %*% B # dim: n_upper x num_samples + + # Prepare output: include the marginal pmfs and/or the samples (depending on "return" inputs) + out = list(bottom_reconciled=list(), upper_reconciled=list()) + if (return_type %in% c('pmf', 'all')) { + upper_pmf = lapply(1:n_u, function(i) PMF.from_samples(U[i,])) + bottom_pmf = lapply(1:n_b, function(i) PMF.from_samples(B[i,])) + + out$bottom_reconciled$pmf = bottom_pmf + out$upper_reconciled$pmf = upper_pmf + + } + if (return_type %in% c('samples','all')) { + + out$bottom_reconciled$samples = B + out$upper_reconciled$samples = U + + } + + return(out) +} + + + + + + + + + + + + + + + + + + + + + + diff --git a/R/reconc_gaussian.R b/R/reconc_gaussian.R new file mode 100644 index 0000000..a9f1fe3 --- /dev/null +++ b/R/reconc_gaussian.R @@ -0,0 +1,123 @@ +#' +#' @title Analytical reconciliation of Gaussian base forecasts +#' +#' @description +#' Closed form computation of the reconciled forecasts in case of Gaussian base forecasts. +#' +#' @param S summing matrix (n x n_bottom). +#' @param base_forecasts.mu a vector containing the means of the base forecasts. +#' @param base_forecasts.Sigma a matrix containing the covariance matrix of the base forecasts. +#' +#' @details +#' The order of the base forecast means and covariance is given by the order of the time series in the summing matrix. +#' +#' The function returns only the reconciled parameters of the bottom variables. +#' The reconciled upper parameters and the reconciled samples for the entire hierarchy can be obtained from the reconciled bottom parameters. +#' See the example section. +#' +#' +#' @return A list containing the bottom reconciled forecasts. The list has the following named elements: +#' +#' * `bottom_reconciled_mean`: reconciled mean for the bottom forecasts; +#' * `bottom_reconciled_covariance`: reconciled covariance for the bottom forecasts. +#' +#' +#' @examples +#' +#'library(bayesRecon) +#' +#'# Create a minimal hierarchy with 2 bottom and 1 upper variable +#'rec_mat <- get_reconc_matrices(agg_levels=c(1,2), h=2) +#'S <- rec_mat$S +#'A <- rec_mat$A +#' +#'#Set the parameters of the Gaussian base forecast distributions +#'mu1 <- 2 +#'mu2 <- 4 +#'muY <- 9 +#'mus <- c(muY,mu1,mu2) +#' +#'sigma1 <- 2 +#'sigma2 <- 2 +#'sigmaY <- 3 +#'sigmas <- c(sigmaY,sigma1,sigma2) +#' +#'Sigma <- diag(sigmas^2) #need to transform into covariance matrix +#'analytic_rec <- reconc_gaussian(S, base_forecasts.mu = mus, +#' base_forecasts.Sigma = Sigma) +#' +#'bottom_mu_reconc <- analytic_rec$bottom_reconciled_mean +#'bottom_Sigma_reconc <- analytic_rec$bottom_reconciled_covariance +#' +#'# Obtain reconciled mu and Sigma for the upper variable +#'upper_mu_reconc <- A %*% bottom_mu_reconc +#'upper_Sigma_reconc <- A %*% bottom_Sigma_reconc %*% t(A) +#' +#'# Obtain reconciled mu and Sigma for the entire hierarchy +#'Y_mu_reconc <- S %*% bottom_mu_reconc +#'Y_Sigma_reconc <- S %*% bottom_Sigma_reconc %*% t(S) # note: singular matrix +#' +#'# Obtain reconciled samples for the entire hierarchy: +#'# i.e., sample from the reconciled bottoms and multiply by S +#'chol_decomp = chol(bottom_Sigma_reconc) # Compute the Cholesky Decomposition +#'Z = matrix(stats::rnorm(n = 2000), nrow = 2) # Sample from standard normal +#'B = t(chol_decomp) %*% Z + matrix(rep(bottom_mu_reconc, 1000), nrow=2) # Apply the transformation +#' +#'U = S %*% B +#'Y_reconc = rbind(U, B) +#' +#' @references +#' Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). +#' *Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule*. +#' ECML PKDD 2020. Lecture Notes in Computer Science, vol 12459. +#' \doi{10.1007/978-3-030-67664-3_13}. +#' +#' Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +#' *Properties of the reconciled distributions for Gaussian and count forecasts*. +#' International Journal of Forecasting (in press). +#' \doi{10.1016/j.ijforecast.2023.12.004}. +#' +#' @seealso [reconc_BUIS()] +#' +#' @export +reconc_gaussian <- function(S, base_forecasts.mu, + base_forecasts.Sigma) { + # Check if S contains only 0s and 1s. + .check_S(S) + hier = .get_A_from_S(S) + A = hier$A + k = nrow(A) #number of upper TS + m = ncol(A) #number of bottom TS + n = length(base_forecasts.mu) #total number of TS + + # Ensure that data inputs are valid + if (!(nrow(base_forecasts.Sigma) == n)) { + stop("Input error: nrow(base_forecasts.Sigma) != length(base_forecasts.mu)") + } + if (!(k + m == n)) { + stop("Input error: the shape of S is not correct") + } + .check_cov(base_forecasts.Sigma, "Sigma", pd_check=FALSE, symm_check=TRUE) + Sigma_u = base_forecasts.Sigma[hier$upper_idxs, hier$upper_idxs] + Sigma_b = base_forecasts.Sigma[hier$bottom_idxs, hier$bottom_idxs] + Sigma_ub = matrix(base_forecasts.Sigma[hier$upper_idxs, hier$bottom_idxs], + nrow = length(hier$upper_idxs)) + mu_u = base_forecasts.mu[hier$upper_idxs] + mu_b = base_forecasts.mu[hier$bottom_idxs] + + # Formulation from: + # Zambon, L., et al. "Properties of the reconciled distributions for + # Gaussian and count forecasts." (2023) + Q = Sigma_u - Sigma_ub %*% t(A) - A %*% t(Sigma_ub) + A %*% Sigma_b %*% t(A) + # we only need to check if Q is p.d. + .check_cov(Q, "Q", pd_check=TRUE, symm_check=FALSE) + invQ = solve(Q) + mu_b_tilde = mu_b + (t(Sigma_ub) - Sigma_b %*% t(A)) %*% invQ %*% (A %*% mu_b - mu_u) + Sigma_b_tilde = Sigma_b - (t(Sigma_ub) - Sigma_b %*% t(A)) %*% invQ %*% t(t(Sigma_ub) - Sigma_b %*% t(A)) + + out = list( + bottom_reconciled_mean = mu_b_tilde, + bottom_reconciled_covariance = Sigma_b_tilde + ) + return(out) +} diff --git a/R/shrink_cov.R b/R/shrink_cov.R index 2dd1149..8f65b7b 100644 --- a/R/shrink_cov.R +++ b/R/shrink_cov.R @@ -32,8 +32,9 @@ #' #' # Generate samples #' set.seed(42) -#' x <- replicate(nSamples, trueMean) + t(chol_trueSigma)%*%matrix(rnorm(pTrue*nSamples), -#' nrow=pTrue,ncol=nSamples) +#' x <- replicate(nSamples, trueMean) + +#' t(chol_trueSigma)%*%matrix(stats::rnorm(pTrue*nSamples), +#' nrow = pTrue, ncol = nSamples) #' x <- t(x) #' res_shrinkage <- schaferStrimmer_cov(x) #' res_shrinkage$lambda_star # should be 0.01287923 diff --git a/R/utils.R b/R/utils.R index 4feeb00..f99cab0 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,182 +1,472 @@ -# Input checks -.DISTR_SET = c("gaussian", "poisson", "nbinom") -.DISTR_SET2 = c("continuous", "discrete") -.check_input <- function(S, base_forecasts, in_type, distr) { +################################################################################ +# IMPLEMENTED DISTRIBUTIONS + +.DISTR_TYPES = c("continuous", "discrete") +.DISCR_DISTR = c("poisson", "nbinom") +.CONT_DISTR = c("gaussian") + +################################################################################ +# PARAMETERS FOR PMF CONVOLUTION AND SMOOTHING + +.TOLL = 1e-15 +.RTOLL = 1e-9 +.ALPHA_SMOOTHING = 1e-9 +.LAP_SMOOTHING = FALSE + +################################################################################ +# CHECK INPUT + +# Function to check values allowed in S. +.check_S <- function(S) { + if(!identical(sort(unique(as.vector(S))), c(0,1)) ){ + stop("Input error in S: S must be a matrix containing only 0s and 1s.") + } - .check_S(S) - if (!(nrow(S) == length(base_forecasts))) { - stop("Input error: nrow(S) != length(base_forecasts)") + if(!all(colSums(S)>1)){ + stop("Input error in S: all bottom level forecasts must aggregate into an upper.") } - if (is.character(in_type)) { - if (!(in_type %in% c("params", "samples"))) { - stop("Input error: in_type must be either 'samples' or 'params'") - } - flag_list_intype = FALSE - }else if (is.list(in_type)) { - if (!(nrow(S) == length(in_type))) { - stop("Input error: nrow(S) != length(in_type)") - } - for(i in 1:nrow(S)){ - if (!(in_type[[i]] %in% c("params", "samples"))) { - stop("Input error: in_type[[",i,"]] must be either 'samples' or 'params'") - } - } - flag_list_intype = TRUE - }else{ - stop("Input error: in_type must be either a string or a list, check documentation") + + if(nrow(unique(S))!=nrow(S)){ + stop("Input error in S: S has a repeated row.") } - if (is.character(distr) & - length(distr) == 1) { - # if distr is a string... - if (flag_list_intype){ - for(i in 1:nrow(S)){ - .check_distr(in_type[[i]], distr) - } - }else{ - .check_distr(in_type, distr) - } - }else if (is.list(distr)) { - if (!(nrow(S) == length(distr))) { - stop("Input error: nrow(S) != length(distr)") - } - for(i in 1:nrow(S)){ - if (flag_list_intype){ - .check_distr(in_type[[i]], distr[[i]],i) - }else{ - .check_distr(in_type, distr[[i]],i) - } - - } - }else{ - stop("Input error: distr must be either a string or a list, check documentation") + # Check that each bottom has a corresponding row with with one 1 and the rest 0s. + if(sum(rowSums(S) ==1) != ncol(S)){ + stop("Input error in S: there is at least one bottom that does not have a row with one 1 and the rest 0s.") } - - # Eventually: - # TODO if in_type=='samples' check sample sizes - # TODO if in_type=='params' check that: - # - gaussian: 2 parameters, (mu, sd) - # - poisson: 1 parameter, (lambda) - # - nbinom: 2 parameters, (n, p) - # TODO if distr is a list, check that entries are coherent + + } - -# Checks if a matrix is a covariance matrix (i.e. symmetric p.d.) -.check_cov <- function(cov_matrix) { +# Check if it is a covariance matrix (i.e. symmetric p.d.) +.check_cov <- function(cov_matrix, Sigma_str,pd_check=FALSE,symm_check=FALSE) { # Check if the matrix is square if (!is.matrix(cov_matrix) || nrow(cov_matrix) != ncol(cov_matrix)) { - stop("base_forecasts.Sigma not square") + stop(paste0(Sigma_str, " is not square")) } + # Check if the matrix is positive semi-definite - eigen_values <- eigen(cov_matrix, symmetric = TRUE)$values - if (any(eigen_values <= 0)) { - stop("base_forecasts.Sigma not positive semi-definite") + if(pd_check){ + eigen_values <- eigen(cov_matrix, symmetric = TRUE)$values + if (any(eigen_values <= 0)) { + stop(paste0(Sigma_str, " is not positive semi-definite")) + } } - # Check if the matrix is symmetric - if (!isSymmetric(cov_matrix)) { - stop("base_forecasts.Sigma not symmetric") + if(symm_check){ + # Check if the matrix is symmetric + if (!isSymmetric(cov_matrix)) { + stop(paste0(Sigma_str, " is not symmetric")) + } } # Check if the diagonal elements are non-negative if (any(diag(cov_matrix) < 0)) { - stop("base_forecasts.Sigma, diagonal elements are non-positive") + stop(paste0(Sigma_str, ": some elements on the diagonal are negative")) } # If all checks pass, return TRUE return(TRUE) } +# Checks if the input is a real number +.check_real_number <- function(x) { + return(length(x)==1 & is.numeric(x)) +} -# Function to check values allowed in S. -.check_S <- function(S) { - if(!identical(sort(unique(as.vector(S))), c(0,1)) ){ - stop("Input error: S must be a matrix containing only 0s and 1s.") +# Checks if the input is a positive number +.check_positive_number <- function(x) { + return(length(x)==1 && is.numeric(x) && x > 0) +} + +# Check that the distr is implemented +.check_implemented_distr <- function(distr) { + if (!(distr %in% c(.DISCR_DISTR, .CONT_DISTR))) { + stop(paste( + "Input error: the distribution must be one of {", + paste(c(.DISCR_DISTR, .CONT_DISTR), collapse = ', '), "}")) } } -# Individual check on the parameter distr -.check_distr <- function(in_type, distr, i=NULL) { +# Check the parameters of distr +.check_distr_params <- function(distr, params) { + .check_implemented_distr(distr) + if (!is.list(params)) { + stop("Input error: the parameters of the distribution must be given as a list.") + } + switch( + distr, + "gaussian" = { + mean = params$mean + sd = params$sd + if (!.check_real_number(mean)) { + stop("Input error: mean of Gaussian must be a real number") + } + if (!.check_positive_number(sd)) { + stop("Input error: sd of Gaussian must be a positive number") + } + }, + "poisson" = { + lambda = params$lambda + if (!.check_positive_number(lambda)) { + stop("Input error: lambda of Poisson must be a positive number") + } + }, + "nbinom" = { + size = params$size + prob = params$prob + mu = params$mu + # Check that size is specified, and that is a positive number + if (is.null(size)) { + stop("Input error: size parameter for the nbinom distribution must be specified") + } + if (!.check_positive_number(size)) { + stop("Input error: size of nbinom must be a positive number") + } + # Check that exactly one of prob, mu is specified + if (!is.null(prob) & !is.null(mu)) { + stop("Input error: prob and mu for the nbinom distribution are both specified ") + } else if (is.null(prob) & is.null(mu)) { + stop("Input error: either prob or mu must be specified") + } else { + if (!is.null(prob)) { + if (!.check_positive_number(prob) | prob > 1) { + stop("Input error: prob of nbinom must be positive and <= 1") + } + } else if (!is.null(mu)) { + if (!.check_positive_number(mu)) { + stop("Input error: mu of nbinom must be positive") + } + } + } + }, + ) +} + +# Check that the samples are discrete +.check_discrete_samples <- function(samples) { + if (!isTRUE(all.equal(unname(samples), as.integer(samples)))) { + stop("Input error: samples are not all discrete") + } +} + +# Check input for BUIS (and for MH) +# base_forecasts, in_type, and distr must be list +.check_input_BUIS <- function(S, base_forecasts, in_type, distr) { + + .check_S(S) - add_string = "" - if(!is.null(i)){ - add_string = paste("[[",i,"]]") + # Check in_type + if (!is.list(in_type)) { + stop("Input error: in_type must be a list") + } + if (!(nrow(S) == length(in_type))) { + stop("Input error: nrow(S) != length(in_type)") + } + for(i in 1:nrow(S)){ + if (!(in_type[[i]] %in% c("params", "samples"))) { + stop("Input error: in_type[[",i,"]] must be either 'samples' or 'params'") + } } - if (in_type == "params" & !(distr %in% .DISTR_SET)) { - stop(paste( - "Input error: if in_type='params', distr", add_string, " must be {", - paste(.DISTR_SET, collapse = ', '), - "}" - )) + # Check distr and base forecasts + if (!is.list(distr)) { + stop("Input error: distr must be a list") } - if (in_type == "samples" & !(distr %in% .DISTR_SET2)) { - stop(paste( - "Input error: if in_type='samples', distr", add_string, " must be {", - paste(.DISTR_SET2, collapse = ', '), - "}" - )) + if (!(nrow(S) == length(distr))) { + stop("Input error: nrow(S) != length(distr)") + } + if (!is.list(base_forecasts)) { + stop("Input error: base_forecasts must be a list") + } + if (!(nrow(S) == length(base_forecasts))) { + stop("Input error: nrow(S) != length(base_forecasts)") + } + for(i in 1:nrow(S)){ + if (in_type[[i]] == "params") { + .check_distr_params(distr[[i]], base_forecasts[[i]]) + } else if (in_type[[i]] == "samples") { + if (!(distr[[i]] %in% .DISTR_TYPES)) { + stop(paste( + "Input error: the distribution must be one of {", + paste(.DISTR_TYPES, collapse = ', '), "}")) + } + if (distr[[i]] == "discrete") { + .check_discrete_samples(base_forecasts[[i]]) + } + # TODO: check sample size? + } else { + stop("Input error: in_type[[",i,"]] must be either 'samples' or 'params'") + } } } -# Returns TRUE if A is a hierarchy matrix -# (according to Definition 1 in "Find Maximal Hierarchy") -# If this returns TRUE we avoid solving the integer linear programming problem -.check_hierarchical <- function(A) { +# Check input for TDcond +.check_input_TD <- function(S, fc_bottom, fc_upper, + bottom_in_type, distr, + return_type) { - k <- nrow(A) - m <- ncol(A) + .check_S(S) - for (i in 1:k) { - for (j in 1:k) { - if (i < j) { - cond1 = A[i,] %*% A[j,] != 0 # Upper i and j have some common descendants - cond2 = sum(A[i,] - A[j,] >= 0) < m # Upper j is not a descendant of upper i - cond3 = sum(A[i,] - A[j,] <= 0) < m # Upper i is not a descendant of upper j - if (cond1 & cond2 & cond3) { - return(FALSE) - } - } + n_b = ncol(S) # number of bottom TS + n_u = nrow(S) - n_b # number of upper TS + + if (!(bottom_in_type %in% c("pmf", "samples", "params"))) { + stop("Input error: bottom_in_type must be either 'pmf', 'samples', or 'params'") + } + if (!(return_type %in% c("pmf", "samples", "all"))) { + stop("Input error: return_type must be either 'pmf', 'samples', or 'all'") + } + if (length(fc_bottom) != n_b) { + stop("Input error: length of fc_bottom does not match with S") + } + # If Sigma is a number, transform into a matrix + if (length(fc_upper$Sigma) == 1) { + fc_upper$Sigma = as.matrix(fc_upper$Sigma) + } + # Check the dimensions of mu and Sigma + if (length(fc_upper$mu) != n_u | any(dim(fc_upper$Sigma) != c(n_u, n_u))) { + stop("Input error: the dimensions of the upper parameters do not match with S") + } + # Check that Sigma is a covariance matrix (symmetric positive semi-definite) + .check_cov(fc_upper$Sigma, "Upper covariance matrix", symm_check=TRUE) + + # If bottom_in_type is not "params" but distr is specified, throw a warning + if (bottom_in_type %in% c("pmf", "samples") & !is.null(distr)) { + warning(paste0("Since bottom_in_type = '", bottom_in_type, "', the input distr is ignored")) + } + # If bottom_in_type is params, distr must be one of the implemented discrete distr. + # Also, check the parameters + if (bottom_in_type == "params") { + if (is.null(distr)) { + stop("Input error: if bottom_in_type = 'params', distr must be specified") + } + if (!(distr %in% .DISCR_DISTR)) { + stop(paste0("Input error: distr must be one of {", + paste(.DISCR_DISTR, collapse = ', '), "}")) + } + for (i in 1:n_b) { + .check_distr_params(distr, fc_bottom[[i]]) } } +} + +# Check importance sampling weights +.check_weigths <- function(w, n_eff_min=200, p_n_eff=0.01) { + warning = FALSE + warning_code = c() + warning_msg = c() - return(TRUE) + n = length(w) + n_eff = n + + # 1. w==0 + if (all(w==0)) { + warning = TRUE + warning_code = c(warning_code, 1) + warning_msg = c(warning_msg, + "Importance Sampling: all the weights are zeros. This is probably caused by a strong incoherence between bottom and upper base forecasts.") + }else{ + + # Effective sample size + n_eff = (sum(w)^2) / sum(w^2) + + # 2. n_eff < threshold + if (n_eff < n_eff_min) { + warning = TRUE + warning_code = c(warning_code, 2) + warning_msg = c(warning_msg, + paste0("Importance Sampling: effective_sample_size= ", round(n_eff,2), " (< ", n_eff_min,").")) + } + + # 3. n_eff < p*n, e.g. p = 0.05 + if (n_eff < p_n_eff*n) { + warning = TRUE + warning_code = c(warning_code, 3) + warning_msg = c(warning_msg, + paste0("Importance Sampling: effective_sample_size= ", round(n_eff,2), " (< ", round(p_n_eff * 100, 2),"%).")) + } + } + res = list(warning = warning, + warning_code = warning_code, + warning_msg = warning_msg, + n_eff = n_eff) + return(res) } -# Checks that there is no bottom continuous variable child of a -# discrete upper variable -.check_hierfamily_rel <- function(sh.res, distr, debug=FALSE) { - for (bi in seq_along(distr[sh.res$bottom_idxs])) { - distr_bottom = distr[sh.res$bottom_idxs][[bi]] - rel_upper_i = sh.res$A[,bi] - rel_distr_upper = unlist(distr[sh.res$upper_idxs])[rel_upper_i == 1] - err_message = "A continuous bottom distribution is child of a discrete one." - if (distr_bottom == .DISTR_SET2[1]) { - if (sum(rel_distr_upper == .DISTR_SET2[2]) | - sum(rel_distr_upper == .DISTR_SET[2]) | sum(rel_distr_upper == .DISTR_SET[3])) { - if (debug) { return(-1) } else { stop(err_message) } - } +################################################################################ +# SAMPLE + +# Sample from one of the implemented distributions +.distr_sample <- function(params, distr, n) { + .check_distr_params(distr, params) + switch( + distr, + "gaussian" = { + mean = params$mean + sd = params$sd + samples = stats::rnorm(n = n, mean = mean, sd = sd) }, + "poisson" = { + lambda = params$lambda + samples = stats::rpois(n = n, lambda = lambda) }, + "nbinom" = { + size = params$size + prob = params$prob + mu = params$mu + if (!is.null(prob)) { + samples = stats::rnbinom(n = n, size = size, prob = prob) + } else if (!is.null(mu)) { + samples = stats::rnbinom(n = n, size = size, mu = mu) + } + }, + ) + return(samples) +} + +# Sample from a multivariate Gaussian distribution with specified mean and cov. matrix +.MVN_sample <- function(n_samples, mu, Sigma) { + n = length(mu) + if (any(dim(Sigma) != c(n,n))) { + stop("Dimension of mu and Sigma are not compatible!") + } + .check_cov(Sigma, "Sigma", pd_check = FALSE, symm_check = FALSE) + + Z = matrix(stats::rnorm(n*n_samples), ncol = n) + + Ch <- tryCatch(base::chol(Sigma), + error = function(e) stop(paste0(e,"check the covariance in .MVN_sample, the Cholesky fails."))) + + samples = Z %*% Ch + matrix(mu, nrow = n_samples, ncol = n, byrow = TRUE) + return(samples) +} + +# Compute the MVN density +.MVN_density <- function(x, mu, Sigma, max_size_x=5e3, suppress_warnings=TRUE) { + + # save dimension of mu + n = length(mu) + + # Check Sigma + if (any(dim(Sigma) != c(n,n))) { + stop("Dimension of mu and Sigma are not compatible!") + } + .check_cov(Sigma, "Sigma", pd_check = FALSE, symm_check = FALSE) + + # x must be a matrix with ncol = n (nrow is the number of points to evaluate) + # or a vector with length n (in which case it is transformed into a matrix) + if(is.vector(x)){ + if (length(x)!=n) stop("Length of x must be the same of mu") + x <- matrix(x, ncol=length(x)) + } else if (is.matrix(x)) { + if (ncol(x)!=n) stop("The number of columns of x must be equal to the length of mu") + } else { + stop("x must be either a vector or a matrix") + } + + # Compute Cholesky of Sigma + chol_S <- tryCatch(base::chol(Sigma), + error = function(e) stop(paste0(e,"check the covariance in .MVN_density, the Cholesky fails."))) + + # Constant of the loglikelihood (computed here because it is always the same) + const <- -sum(log(diag(chol_S))) - 0.5 * n * log(2 *pi) + + # This part breaks down the evaluation of the density eval into batches, for memory + rows_x <- nrow(x) + + if(rows_x > max_size_x){ + + logval <- rep(0, rows_x) + + # Compute how many batches we need + num_backsolves <- rows_x %/% max_size_x + + if(!suppress_warnings){ + warning_msg <- paste0("x has ",rows_x," rows, the density evaluation is broken down into ",num_backsolves," pieces for memory preservation.") + warning(warning_msg) } - if (distr_bottom == .DISTR_SET[1]) { - if (sum(rel_distr_upper == .DISTR_SET2[2]) | - sum(rel_distr_upper == .DISTR_SET[2]) | sum(rel_distr_upper == .DISTR_SET[3])) { - if (debug) { return(-1) } else { stop(err_message) } - } + + for(j in seq(num_backsolves)){ + idx_to_select <- (1+(j-1)*max_size_x):((j)*max_size_x) + # Do one backsolve for each batch + tmp <- backsolve(chol_S, t(x[idx_to_select,]) - mu, transpose = TRUE) + rss <- colSums(tmp^2) + + # Update the logval for those indices + logval[idx_to_select] <- const - 0.5 * rss + } + + # Last indices: if the number of rows of x is not exactly divided by the size of the batches + remainder <- rows_x %% max_size_x + if(remainder !=0){ + idx_to_select <- (1+(num_backsolves)*max_size_x):(remainder+(num_backsolves)*max_size_x) + # Do backsolve on the remaining indices + tmp <- backsolve(chol_S, t(x[idx_to_select,]) - mu, transpose = TRUE) + rss <- colSums(tmp^2) + + logval[idx_to_select] <- const - 0.5 * rss } + + }else{ + tmp <- backsolve(chol_S, t(x) - mu, transpose = TRUE) + rss <- colSums(tmp^2) + + logval <- const - 0.5 * rss + } + + return(exp(logval)) +} + +# Resample from weighted sample +.resample <- function(S_, weights, num_samples = NA) { + if (is.na(num_samples)) { + num_samples = length(weights) } - if (debug) { return(0) } + + if(nrow(S_)!=length(weights)) + stop("Error in .resample: nrow(S_) != length(weights)") + + tmp_idx = sample(x = 1:nrow(S_), num_samples, replace = TRUE, prob = weights) + return(S_[tmp_idx, ]) } +################################################################################ +# Miscellaneous + +# Compute the pmf of the distribution specified by distr and params at the points x +.distr_pmf <- function(x, params, distr) { + .check_distr_params(distr, params) + switch( + distr, + "gaussian" = { + mean = params$mean + sd = params$sd + pmf = stats::dnorm(x = x, mean = mean, sd = sd) }, + "poisson" = { + lambda = params$lambda + pmf = stats::dpois(x = x, lambda = lambda) }, + "nbinom" = { + size = params$size + prob = params$prob + mu = params$mu + if (!is.null(prob)) { + pmf = stats::dnbinom(x = x, size = size, prob = prob) + } else if (!is.null(mu)) { + pmf = stats::dnbinom(x = x, size = size, mu = mu) + } + }, + ) + return(pmf) +} -# Misc .shape <- function(m) { print(paste0("(", nrow(m), ",", ncol(m), ")")) } +################################################################################ # Functions for tests + .gen_gaussian <- function(params_file, seed=NULL) { - set.seed(seed) + if (!is.null(seed)) set.seed(seed) params = utils::read.csv(file = params_file, header = FALSE) out = list() for (i in 1:nrow(params)) { @@ -186,7 +476,7 @@ } .gen_poisson <- function(params_file, seed=NULL) { - set.seed(seed) + if (!is.null(seed)) set.seed(seed) params = utils::read.csv(file = params_file, header = FALSE) out = list() for (i in 1:nrow(params)) { diff --git a/README.Rmd b/README.Rmd index 9d3e8cd..759620f 100644 --- a/README.Rmd +++ b/README.Rmd @@ -26,16 +26,23 @@ knitr::opts_chunk$set( [![License: LGPL (>= 3)](https://img.shields.io/badge/license-LGPL (>= 3)-yellow.svg)](https://www.gnu.org/licences/lgpl-3.0) -The package `bayesRecon` implements probabilistic reconciliation of hierarchical time series forecasts via conditioning. +The package `bayesRecon` implements several methods for probabilistic reconciliation of hierarchical time series forecasts. The main functions are: - * `reconc_gaussian`: implements analytic formulae for the reconciliation of Gaussian base forecasts; - * `reconc_BUIS`: a generic tool for the reconciliation of any probabilistic time series forecast via importance sampling; + * `reconc_gaussian`: reconciliation via conditioning of multivariate Gaussian base forecasts; + this is done analytically; + * `reconc_BUIS`: reconciliation via conditioning of any probabilistic forecast via importance sampling; this is the recommended option for non-Gaussian base forecasts; - * `reconc_MCMC`: a generic tool for the reconciliation of probabilistic count time series forecasts via Markov Chain Monte Carlo. + * `reconc_MCMC`: reconciliation via conditioning of discrete probabilistic forecasts via Markov Chain Monte Carlo; + * `reconc_MixCond`: reconciliation via conditioning of mixed hierarchies, where + the upper forecasts are multivariate Gaussian and the bottom forecasts are discrete distributions; + * `reconc_TDcond`: reconciliation via top-down conditioning of mixed hierarchies, where the upper forecasts are + multivariate Gaussian and the bottom forecasts are discrete distributions. ## News +:boom: [2024-05-29] Added `reconc_MixCond` and `reconc_TDcond` and the vignette "Reconciliation of M5 hierarchy with mixed-type forecasts". + :boom: [2023-12-19] Added the vignette "Properties of the reconciled distribution via conditioning". :boom: [2023-08-23] Added the vignette "Probabilistic Reconciliation via Conditioning with bayesRecon". Added the `schaferStrimmer_cov` function. @@ -92,11 +99,11 @@ lambdas <- c(lambdaY, lambdaS1, lambdaS2) base_forecasts = list() for (i in 1:nrow(S)) { - base_forecasts[[i]] = lambdas[i] + base_forecasts[[i]] = list(lambda = lambdas[i]) } ``` -We recommend using the BUIS algorithm (Zambon et al., 2022) to sample from the reconciled distribution. +We recommend using the BUIS algorithm (Zambon et al., 2024) to sample from the reconciled distribution. ```{r} buis <- reconc_BUIS( @@ -157,7 +164,7 @@ plot( ``` -We also provide a function for sampling using Markov Chain Monte Carlo (Corani et al., 2022). +We also provide a function for sampling using Markov Chain Monte Carlo (Corani et al., 2023). ```{r} mcmc = reconc_MCMC( @@ -192,7 +199,7 @@ sigmas <- c(sigmaY, sigmaS1, sigmaS2) base_forecasts = list() for (i in 1:nrow(S)) { - base_forecasts[[i]] = c(mus[[i]], sigmas[[i]]) + base_forecasts[[i]] = list(mean = mus[[i]], sd = sigmas[[i]]) } ``` @@ -211,7 +218,7 @@ samples_buis <- buis$reconciled_samples buis_means <- rowMeans(samples_buis) ``` -In the base forecasts are Gaussian, the reconciled distribution is still Gaussian and can be computed in closed form: +If the base forecasts are Gaussian, the reconciled distribution is still Gaussian and can be computed in closed form: ```{r} Sigma <- diag(sigmas ^ 2) #transform into covariance matrix @@ -233,15 +240,29 @@ while the reconciled means obtained via BUIS are ## References -Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). *Probabilistic Reconciliation of Hierarchical Forecast via Bayes’ Rule*. In: Hutter, F., Kersting, K., Lijffijt, J., Valera, I. (eds) Machine Learning and Knowledge Discovery in Databases. ECML PKDD 2020. Lecture Notes in Computer Science(), vol 12459. Springer, Cham. [DOI](https://doi.org/10.1007/978-3-030-67664-3_13) - -Corani, G., Azzimonti, D., Rubattu, N. (2023). *Probabilistic reconciliation of count -time series*. [DOI](https://doi.org/10.1016/j.ijforecast.2023.04.003) - -Zambon, L., Azzimonti, D. & Corani, G. (2024). *Efficient probabilistic reconciliation of forecasts -for real-valued and count time series*. [DOI](https://doi.org/10.1007/s11222-023-10343-y) - -Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). *Properties of the reconciled distributions for Gaussian and count forecasts*. [DOI](https://doi.org/10.48550/arXiv.2303.15135) +Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). +*Probabilistic Reconciliation of Hierarchical Forecast via Bayes’ Rule*. +ECML PKDD 2020. Lecture Notes in Computer Science, vol 12459. +[DOI](https://doi.org/10.1007/978-3-030-67664-3_13) + +Corani, G., Azzimonti, D., Rubattu, N. (2024). +*Probabilistic reconciliation of count time series*. +International Journal of Forecasting 40 (2), 457-469. +[DOI](https://doi.org/10.1016/j.ijforecast.2023.04.003) + +Zambon, L., Azzimonti, D. & Corani, G. (2024). +*Efficient probabilistic reconciliation of forecasts for real-valued and count time series*. +Statistics and Computing 34 (1), 21. +[DOI](https://doi.org/10.1007/s11222-023-10343-y) + +Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +*Properties of the reconciled distributions for Gaussian and count forecasts*. +International Journal of Forecasting (in press). +[DOI](https://doi.org/10.1016/j.ijforecast.2023.12.004) + +Zambon, L., Azzimonti, D., Rubattu, N., Corani, G. (2024). +*Probabilistic reconciliation of mixed-type hierarchical time series*. +The 40th Conference on Uncertainty in Artificial Intelligence, accepted. ## Contributors diff --git a/README.md b/README.md index 44d789f..ea2b080 100644 --- a/README.md +++ b/README.md @@ -18,21 +18,30 @@ experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](h 3)](https://img.shields.io/badge/license-LGPL%20(%3E=%203)-yellow.svg)](https://www.gnu.org/licences/lgpl-3.0) -The package `bayesRecon` implements probabilistic reconciliation of -hierarchical time series forecasts via conditioning. +The package `bayesRecon` implements several methods for probabilistic +reconciliation of hierarchical time series forecasts. The main functions are: -- `reconc_gaussian`: implements analytic formulae for the reconciliation - of Gaussian base forecasts; -- `reconc_BUIS`: a generic tool for the reconciliation of any - probabilistic time series forecast via importance sampling; this is - the recommended option for non-Gaussian base forecasts; -- `reconc_MCMC`: a generic tool for the reconciliation of probabilistic - count time series forecasts via Markov Chain Monte Carlo. +- `reconc_gaussian`: reconciliation via conditioning of multivariate + Gaussian base forecasts; this is done analytically; +- `reconc_BUIS`: reconciliation via conditioning of any probabilistic + forecast via importance sampling; this is the recommended option for + non-Gaussian base forecasts; +- `reconc_MCMC`: reconciliation via conditioning of discrete + probabilistic forecasts via Markov Chain Monte Carlo; +- `reconc_MixCond`: reconciliation via conditioning of mixed + hierarchies, where the upper forecasts are multivariate Gaussian and + the bottom forecasts are discrete distributions; +- `reconc_TDcond`: reconciliation via top-down conditioning of mixed + hierarchies, where the upper forecasts are multivariate Gaussian and + the bottom forecasts are discrete distributions. ## News +:boom: \[2024-05-29\] Added `reconc_MixCond` and `reconc_TDcond` and the +vignette “Reconciliation of M5 hierarchy with mixed-type forecasts”. + :boom: \[2023-12-19\] Added the vignette “Properties of the reconciled distribution via conditioning”. @@ -97,11 +106,11 @@ lambdas <- c(lambdaY, lambdaS1, lambdaS2) base_forecasts = list() for (i in 1:nrow(S)) { - base_forecasts[[i]] = lambdas[i] + base_forecasts[[i]] = list(lambda = lambdas[i]) } ``` -We recommend using the BUIS algorithm (Zambon et al., 2022) to sample +We recommend using the BUIS algorithm (Zambon et al., 2024) to sample from the reconciled distribution. ``` r @@ -175,7 +184,7 @@ plot( We also provide a function for sampling using Markov Chain Monte Carlo -(Corani et al., 2022). +(Corani et al., 2023). ``` r mcmc = reconc_MCMC( @@ -210,7 +219,7 @@ sigmas <- c(sigmaY, sigmaS1, sigmaS2) base_forecasts = list() for (i in 1:nrow(S)) { - base_forecasts[[i]] = c(mus[[i]], sigmas[[i]]) + base_forecasts[[i]] = list(mean = mus[[i]], sd = sigmas[[i]]) } ``` @@ -229,7 +238,7 @@ samples_buis <- buis$reconciled_samples buis_means <- rowMeans(samples_buis) ``` -In the base forecasts are Gaussian, the reconciled distribution is still +If the base forecasts are Gaussian, the reconciled distribution is still Gaussian and can be computed in closed form: ``` r @@ -250,22 +259,27 @@ the reconciled means obtained via BUIS are 7.41, 2.71, 4.71. Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). *Probabilistic Reconciliation of Hierarchical Forecast via Bayes’ Rule*. -In: Hutter, F., Kersting, K., Lijffijt, J., Valera, I. (eds) Machine -Learning and Knowledge Discovery in Databases. ECML PKDD 2020. Lecture -Notes in Computer Science(), vol 12459. Springer, Cham. +ECML PKDD 2020. Lecture Notes in Computer Science, vol 12459. [DOI](https://doi.org/10.1007/978-3-030-67664-3_13) -Corani, G., Azzimonti, D., Rubattu, N. (2023). *Probabilistic -reconciliation of count time series*. +Corani, G., Azzimonti, D., Rubattu, N. (2024). *Probabilistic +reconciliation of count time series*. International Journal of +Forecasting 40 (2), 457-469. [DOI](https://doi.org/10.1016/j.ijforecast.2023.04.003) Zambon, L., Azzimonti, D. & Corani, G. (2024). *Efficient probabilistic reconciliation of forecasts for real-valued and count time series*. +Statistics and Computing 34 (1), 21. [DOI](https://doi.org/10.1007/s11222-023-10343-y) -Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). *Properties of +Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). *Properties of the reconciled distributions for Gaussian and count forecasts*. -[DOI](https://doi.org/10.48550/arXiv.2303.15135) +International Journal of Forecasting (in press). +[DOI](https://doi.org/10.1016/j.ijforecast.2023.12.004) + +Zambon, L., Azzimonti, D., Rubattu, N., Corani, G. (2024). +*Probabilistic reconciliation of mixed-type hierarchical time series*. +The 40th Conference on Uncertainty in Artificial Intelligence, accepted. ## Contributors diff --git a/data-raw/CA_1_h_1_base_fc.rds b/data-raw/CA_1_h_1_base_fc.rds new file mode 100644 index 0000000..f0b5915 Binary files /dev/null and b/data-raw/CA_1_h_1_base_fc.rds differ diff --git a/data-raw/M5_utils.R b/data-raw/M5_utils.R new file mode 100644 index 0000000..199c950 --- /dev/null +++ b/data-raw/M5_utils.R @@ -0,0 +1,74 @@ +get_hier_M5 = function(save_ = FALSE, save_path = "../../../results/") { + + n_b = 3049 + n_u = 11 + n = n_u + n_b + + A = matrix(0, nrow = n_u, ncol = n_b) + A[1,] = 1 # store + A[2,1:565] = 1 # categories + A[3,566:1612] = 1 + A[4,1613:3049] = 1 + A[5,1:416] = 1 # departments + A[6,417:565] = 1 + A[7,566:1097] = 1 + A[8,1098:1612] = 1 + A[9,1613:1828] = 1 + A[10,1829:2226] = 1 + A[11,2227:3049] = 1 + + S = rbind(A, diag(rep(1, n_b))) + + if (save_) { + saveRDS(S, paste0(save_path, "S.rds")) + saveRDS(A, paste0(save_path, "A.rds")) + } + + return(list(A = A, S = S)) +} + +get_upp_ts = function(dset.store.train, dset.store.test, lev, + name, h, len = 1941) { + + if (!(lev %in% c("store_id", "cat_id", "dept_id"))) stop("Wrong lev name") + + df1 = dset.store.train[dset.store.train[[lev]] == name] + df2 = dset.store.test[dset.store.test[[lev]] == name] + st = which(colnames(df1)=="d_1") + + serie = cbind( + df1[,st:(st+len-1)], + df2[,st:(st+h-1)] ) + data.train = serie[,1:(len+h-1)] + data.test = serie[,(len+h):(len+h)] + train.agg = colSums(data.train) + test.agg = colSums(data.test) + return(list(train = train.agg, test = test.agg)) +} + +get_bott_ts = function(dset.store.train, dset.store.test, + item_id, h, len = 1941) { + + df1 = dset.store.train[dset.store.train$item_id == item.id] + df2 = dset.store.test[dset.store.test$item_id == item.id] + st = which(colnames(df1)=="d_1") + + serie = c(df1[,st:(st+len-1)], df2[,st:(st+h-1)] ) + train = as.numeric(serie)[1:(len+h-1)] + test = as.numeric(serie)[[len+h]] + return(list(train = train, test = test)) +} + +model_upper = function(data, mod = "AXX") { + model = auto.adam(data, mod, lags = c(7), distribution = "dnorm", + occurrence = "none") + # uses: orders = list(ar = c(3, 3), i = c(2, 1), ma = c(3, 3), select = TRUE) + return(model) +} + +model_bottom = function(data, model_str = "MNN", occ_str = "auto", distr = c("dgamma")) { + # distr = c("dnorm","dlaplace","ds","dgnorm", "dlnorm", "dinvgauss", "dgamma") + model = adam(data, model_str, lags = c(7), + occurrence = occ_str, distribution = distr) + return(model) +} \ No newline at end of file diff --git a/data-raw/M5data_forecasts.R b/data-raw/M5data_forecasts.R new file mode 100644 index 0000000..e9d6277 --- /dev/null +++ b/data-raw/M5data_forecasts.R @@ -0,0 +1,164 @@ +rm(list = ls()) +library(m5) +library(smooth) + + +source("./data-raw/M5_utils.R") + +################################## + +seed=42 + +set.seed(seed) +STORE="CA_1" +n_samples_b = 2e4 +round_up = FALSE + +path_m5_data <- "./data-raw/M5_data" +m5_forecast_path <- "./data-raw/" + +m5::m5_download(path_m5_data) + +dset = m5::m5_get_raw_evaluation(path = path_m5_data) +names(dset) = c("sales_train_evaluation", "sales_test_evaluation", 'sell_prices', + "calendar","weights_evaluation") +dset.store.train = dset$sales_train_evaluation +dset.store.train = dset.store.train[dset.store.train$store_id == STORE] +dset.store.test = dset$sales_test_evaluation +dset.store.test = dset.store.test[dset.store.test$store_id == STORE] + +CAT = c("HOBBIES", "HOUSEHOLD", "FOODS") +DEPT = c("HOBBIES_1", "HOBBIES_2", "HOUSEHOLD_1", "HOUSEHOLD_2", + "FOODS_1", "FOODS_2", "FOODS_3") + +store_path = paste0(m5_forecast_path) +len = 1941 +h=1 + +############### +### Base forecasts upper time series + +if (!dir.exists(store_path)) dir.create(store_path,recursive = TRUE) + +str_base_fc = paste0(store_path,"/CA_1_h_",h,"_base_fc.rds") + +if(file.exists(str_base_fc)){ + print("Loading base forecasts of upper time series...") + M5_CA1_basefc <- readRDS(str_base_fc) +}else{ + + print("Computing base forecasts of upper time series...") + + + + M5_CA1_basefc = list() + + train_u <- list() + + # Store + ts.agg = get_upp_ts(dset.store.train, dset.store.test, "store_id", + STORE, h = h, len = len) + train.agg = ts.agg$train + test.agg = ts.agg$test + + model = model_upper(train.agg) + fc.model = forecast(model, h = 1) + M5_CA1_basefc$upper[[STORE]] = list( + mu = as.numeric(fc.model$mean), + sigma = model$scale, + actual = test.agg, + residuals = model$residuals + ) + train_u[[STORE]] <- train.agg + + # Category + for (cat.id in CAT) { + ts.agg = get_upp_ts(dset.store.train, dset.store.test, "cat_id", + cat.id, h = h, len = len) + train.agg = ts.agg$train + test.agg = ts.agg$test + + model = model_upper(train.agg) + fc.model = forecast(model, h = 1) + M5_CA1_basefc$upper[[cat.id]] = list( + mu = as.numeric(fc.model$mean), + sigma = model$scale, + actual = test.agg, + residuals = model$residuals + ) + train_u[[cat.id]] <- train.agg + } + + # Department + for (dept.id in DEPT) { + ts.agg = get_upp_ts(dset.store.train, dset.store.test, "dept_id", + dept.id, h = h, len = len) + train.agg = ts.agg$train + test.agg = ts.agg$test + + model = model_upper(train.agg) + fc.model = forecast(model, h = 1) + M5_CA1_basefc$upper[[dept.id]] = list( + mu = as.numeric(fc.model$mean), + sigma = model$scale, + actual = test.agg, + residuals = model$residuals + ) + train_u[[dept.id]] <- train.agg + } + + + saveRDS(M5_CA1_basefc, str_base_fc) + + + train_b <- list() + + for (item.id in unique(dset.store.train$item_id)) { + + print(paste0("Doing ",item.id,"...")) + bts = get_bott_ts(dset.store.train, dset.store.test, + item_id, h, len = 1941) + train = bts$train + test = bts$test + + model = model_bottom(train, model_str = "MNN", + occ_str = "auto", #"odds-ratio", + distr = "dgamma") + fc.model = forecast(model, h = 1, interval="simulated", + scenarios=TRUE, nsim = n_samples_b) + + # round to integer (up or to the closest integer, depending on round_up) + samples = if (round_up) ceiling(fc.model$scenarios[1,]) else round(fc.model$scenarios[1,]) + samples[samples<0] = 0 # set negative to zero + samples <- as.integer(samples) + pmf = PMF.from_samples(samples) # empirical pmf + + M5_CA1_basefc$bottom[[item.id]] = list( + pmf = pmf, + actual = test + #residuals = model$residuals + ) + train_b[[item.id]] <- train + print("Done.\n") + } + + + hier = get_hier_M5(save_ = FALSE) + + M5_CA1_basefc$A <- hier$A + M5_CA1_basefc$S <- hier$S + + + Q_u = unlist(lapply(train_u, function(x) mean(abs(x[-1] - x[-length(x)])))) + Q_b = unlist(lapply(train_b, function(x) mean(abs(x[-1] - x[-length(x)])))) + + M5_CA1_basefc$Q_u <- Q_u + M5_CA1_basefc$Q_b <- Q_b + + saveRDS(M5_CA1_basefc, str_base_fc) +} + + +usethis::use_data(M5_CA1_basefc, overwrite = TRUE) + +unlink("./data-raw/M5_data/",recursive=TRUE) diff --git a/data/M5_CA1_basefc.rda b/data/M5_CA1_basefc.rda new file mode 100644 index 0000000..9dba5be Binary files /dev/null and b/data/M5_CA1_basefc.rda differ diff --git a/man/M3_example.Rd b/man/M3_example.Rd index b28d993..cdfa103 100644 --- a/man/M3_example.Rd +++ b/man/M3_example.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/M3_example.R +% Please edit documentation in R/data.R \docType{data} \name{M3_example} \alias{M3_example} diff --git a/man/M5_CA1_basefc.Rd b/man/M5_CA1_basefc.Rd new file mode 100644 index 0000000..dcea6ec --- /dev/null +++ b/man/M5_CA1_basefc.Rd @@ -0,0 +1,48 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{M5_CA1_basefc} +\alias{M5_CA1_basefc} +\title{Example of hierarchical forecasts for a store from the M5 competition} +\format{ +A list containing: +\itemize{ +\item \code{upper}: a list of 11 elements each representing an aggregation level. Each element contains: \code{mu}, \code{sigma} the mean and standard deviation of the Gaussian forecast, \code{actual} the actual value, \code{residuals} the residuals of the model used to estimate forecasts covariance. +\item \code{lower}: a list of 3049 elements each representing a forecast for each item. Each element contains \code{pmf} the probability mass function of the item level forecast, \code{actual} the actual value. +\item \code{A}: the aggregation matrix for A. +\item \code{S}: the S matrix for the hierarchy. +\item \code{Q_u}: scaling factors for computing MASE on the upper forecasts. +\item \code{Q_b}: scaling factors for computing MASE on the bottom forecasts. +} +} +\source{ +Makridakis, Spyros & Spiliotis, Evangelos & Assimakopoulos, Vassilis. (2020). \emph{The M5 Accuracy competition: Results, findings and conclusions.} International Journal of Forecasting 38(4) 1346-1364. \doi{10.1016/j.ijforecast.2021.10.009} +} +\usage{ +M5_CA1_basefc +} +\description{ +This dataset contains forecasts for the hierarchy of time series related to the store \code{CA_1} from the M5 competition. +} +\details{ +The store \code{CA_1} contains 3049 item level time series and 11 aggregate time series: +\itemize{ +\item Store level aggregation (\code{CA_1}) +\item Category level aggregations (\code{HOBBIES}, \code{HOUSEHOLD}, \code{FOODS}) +\item Department level aggregations (\code{HOBBIES_1}, \code{HOBBIES_2}, \code{HOUSEHOLD_1}, \code{HOUSEHOLD_2}, \code{FOODS_1}, \code{FOODS_2}, \code{FOODS_3}) +} + +Forecasts are generated with the function \link[smooth]{forecast} and the model \link[smooth]{adam} from the package \code{smooth}. +\itemize{ +\item The models for the bottom time series are selected with multiplicative Gamma error term (\code{MNN}); +\item The models for the upper time series (\code{AXZ}) is selected with Gaussian additive error term, seasonality selected based on information criterion. +} + +The raw data was downloaded with the package \link[m5]{m5-package}. +} +\references{ +Joachimiak K (2022). \emph{m5: 'M5 Forecasting' Challenges Data}. R package version 0.1.1, \url{https://CRAN.R-project.org/package=m5}. + +Makridakis, Spyros & Spiliotis, Evangelos & Assimakopoulos, Vassilis. (2020). \emph{The M5 Accuracy competition: Results, findings and conclusions.} International Journal of Forecasting 38(4) 1346-1364. \doi{10.1016/j.ijforecast.2021.10.009} +} +\keyword{datasets} diff --git a/man/PMF.get_mean.Rd b/man/PMF.get_mean.Rd new file mode 100644 index 0000000..452d609 --- /dev/null +++ b/man/PMF.get_mean.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/PMF.R +\name{PMF.get_mean} +\alias{PMF.get_mean} +\title{Get the mean of the distribution from a PMF object} +\usage{ +PMF.get_mean(pmf) +} +\arguments{ +\item{pmf}{the PMF object.} +} +\value{ +A numerical value for mean of the distribution. +} +\description{ +Returns the mean from the PMF specified by \code{pmf}. +} +\examples{ +library(bayesRecon) + +# Let's build the pmf of a Binomial distribution with parameters n and p +n <- 10 +p <- 0.6 +pmf_binomial <- apply(matrix(seq(0,10)),MARGIN=1,FUN=function(x) dbinom(x,size=n,prob=p)) + + +# The true mean corresponds to n*p +true_mean <- n*p +mean_from_PMF <- PMF.get_mean(pmf=pmf_binomial) +cat("True mean:", true_mean, "\nMean from PMF:", mean_from_PMF) + +} +\seealso{ +\code{\link[=PMF.get_var]{PMF.get_var()}}, \code{\link[=PMF.get_quantile]{PMF.get_quantile()}}, \code{\link[=PMF.sample]{PMF.sample()}}, \code{\link[=PMF.summary]{PMF.summary()}} +} diff --git a/man/PMF.get_quantile.Rd b/man/PMF.get_quantile.Rd new file mode 100644 index 0000000..9058622 --- /dev/null +++ b/man/PMF.get_quantile.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/PMF.R +\name{PMF.get_quantile} +\alias{PMF.get_quantile} +\title{Get quantile from a PMF object} +\usage{ +PMF.get_quantile(pmf, p) +} +\arguments{ +\item{pmf}{the PMF object.} + +\item{p}{the probability of the required quantile.} +} +\value{ +A numeric value for the quantile. +} +\description{ +Returns the \code{p} quantile from the PMF specified by \code{pmf}. +} +\examples{ +library(bayesRecon) + +# Let's build the pmf of a Binomial distribution with parameters n and p +n <- 10 +p <- 0.6 +pmf_binomial <- apply(matrix(seq(0,10)),MARGIN=1,FUN=function(x) dbinom(x,size=n,prob=p)) + +# The true median is ceiling(n*p) +quant_50 <- PMF.get_quantile(pmf=pmf_binomial,p=0.5) +cat("True median:", ceiling(n*p), "\nMedian from PMF:", quant_50) + + +} +\seealso{ +\code{\link[=PMF.get_mean]{PMF.get_mean()}}, \code{\link[=PMF.get_var]{PMF.get_var()}}, \code{\link[=PMF.sample]{PMF.sample()}}, \code{\link[=PMF.summary]{PMF.summary()}} +} diff --git a/man/PMF.get_var.Rd b/man/PMF.get_var.Rd new file mode 100644 index 0000000..9422c28 --- /dev/null +++ b/man/PMF.get_var.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/PMF.R +\name{PMF.get_var} +\alias{PMF.get_var} +\title{Get the variance of the distribution from a PMF object} +\usage{ +PMF.get_var(pmf) +} +\arguments{ +\item{pmf}{the PMF object.} +} +\value{ +A numerical value for variance. +} +\description{ +Returns the variance from the PMF specified by \code{pmf}. +} +\examples{ +library(bayesRecon) + +# Let's build the pmf of a Binomial distribution with parameters n and p +n <- 10 +p <- 0.6 +pmf_binomial <- apply(matrix(seq(0,10)),MARGIN=1,FUN=function(x) dbinom(x,size=n,prob=p)) + +# The true variance corresponds to n*p*(1-p) +true_var <- n*p*(1-p) +var_from_PMF <- PMF.get_var(pmf=pmf_binomial) +cat("True variance:", true_var, "\nVariance from PMF:", var_from_PMF) + +} +\seealso{ +\code{\link[=PMF.get_mean]{PMF.get_mean()}}, \code{\link[=PMF.get_quantile]{PMF.get_quantile()}}, \code{\link[=PMF.sample]{PMF.sample()}}, \code{\link[=PMF.summary]{PMF.summary()}} +} diff --git a/man/PMF.sample.Rd b/man/PMF.sample.Rd new file mode 100644 index 0000000..2ba4aa2 --- /dev/null +++ b/man/PMF.sample.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/PMF.R +\name{PMF.sample} +\alias{PMF.sample} +\title{Sample from the distribution given as a PMF object} +\usage{ +PMF.sample(pmf, N_samples) +} +\arguments{ +\item{pmf}{the PMF object.} + +\item{N_samples}{number of samples.} +} +\value{ +Samples drawn from the distribution specified by \code{pmf}. +} +\description{ +Samples (with replacement) from the probability distribution specified by \code{pmf}. +} +\examples{ +library(bayesRecon) + +# Let's build the pmf of a Binomial distribution with parameters n and p +n <- 10 +p <- 0.6 +pmf_binomial <- apply(matrix(seq(0,n)),MARGIN=1,FUN=function(x) dbinom(x,size=n,prob=p)) + +# Draw samples from the PMF object +set.seed(1) +samples <- PMF.sample(pmf=pmf_binomial,N_samples = 1e4) + +# Plot the histogram computed with the samples and the true value of the PMF +hist(samples,breaks=seq(0,n),freq=FALSE) +points(seq(0,n)-0.5,pmf_binomial,pch=16) + +} +\seealso{ +\code{\link[=PMF.get_mean]{PMF.get_mean()}}, \code{\link[=PMF.get_var]{PMF.get_var()}}, \code{\link[=PMF.get_quantile]{PMF.get_quantile()}}, \code{\link[=PMF.summary]{PMF.summary()}} +} diff --git a/man/PMF.summary.Rd b/man/PMF.summary.Rd new file mode 100644 index 0000000..de31220 --- /dev/null +++ b/man/PMF.summary.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/PMF.R +\name{PMF.summary} +\alias{PMF.summary} +\title{Returns summary of a PMF object} +\usage{ +PMF.summary(pmf, Ltoll = .TOLL, Rtoll = .RTOLL) +} +\arguments{ +\item{pmf}{the PMF object.} + +\item{Ltoll}{used for computing the min of the PMF: the min is the smallest value +with probability greater than Ltoll (default: 1e-15)} + +\item{Rtoll}{used for computing the max of the PMF: the max is the largest value +with probability greater than Rtoll (default: 1e-9)} +} +\value{ +A summary data.frame +} +\description{ +Returns the summary (min, max, IQR, median, mean) of the PMF specified by \code{pmf}. +} +\examples{ +library(bayesRecon) + +# Let's build the pmf of a Binomial distribution with parameters n and p +n <- 10 +p <- 0.6 +pmf_binomial <- apply(matrix(seq(0,10)),MARGIN=1,FUN=function(x) dbinom(x,size=n,prob=p)) + +# Print the summary of this distribution +PMF.summary(pmf=pmf_binomial) + + +} +\seealso{ +\code{\link[=PMF.get_mean]{PMF.get_mean()}}, \code{\link[=PMF.get_var]{PMF.get_var()}}, \code{\link[=PMF.get_quantile]{PMF.get_quantile()}}, \code{\link[=PMF.sample]{PMF.sample()}} +} diff --git a/man/bayesRecon-package.Rd b/man/bayesRecon-package.Rd index f2b1a79..80d73eb 100644 --- a/man/bayesRecon-package.Rd +++ b/man/bayesRecon-package.Rd @@ -6,7 +6,7 @@ \alias{bayesRecon-package} \title{bayesRecon: Probabilistic Reconciliation via Conditioning} \description{ -Provides methods for probabilistic reconciliation of hierarchical forecasts of time series. The available methods include analytical Gaussian reconciliation (Corani et al., 2021) \doi{10.1007/978-3-030-67664-3_13}, MCMC reconciliation of count time series (Corani et al., 2022) \doi{10.48550/arXiv.2207.09322}, Bottom-Up Importance Sampling (Zambon et al., 2022) \doi{10.48550/arXiv.2210.02286}. +Provides methods for probabilistic reconciliation of hierarchical forecasts of time series. The available methods include analytical Gaussian reconciliation (Corani et al., 2021) \doi{10.1007/978-3-030-67664-3_13}, MCMC reconciliation of count time series (Corani et al., 2024) \doi{10.1016/j.ijforecast.2023.04.003}, Bottom-Up Importance Sampling (Zambon et al., 2024) \doi{10.1007/s11222-023-10343-y}, methods for the reconciliation of mixed hierarchies (Mix-Cond and TD-cond) (Zambon et al., 2024. The 40th Conference on Uncertainty in Artificial Intelligence, accepted). } \section{Learn more}{ @@ -17,12 +17,19 @@ To learn more about \code{bayesRecon}, start with the vignettes: \code{browseVig \section{Main functions}{ -The package implements reconciliation via conditioning for probabilistic forecasts of hierarchical time series. The main functions are +The package implements reconciliation via conditioning for probabilistic forecasts +of hierarchical time series. The main functions are: \itemize{ -\item \code{\link[=reconc_gaussian]{reconc_gaussian()}}: analytical reconciliation of Gaussian base forecasts; -\item \code{\link[=reconc_BUIS]{reconc_BUIS()}}: reconciliation of any probabilistic base forecast via importance sampling; -this is the recommended option for non-Gaussian base forecasts; -\item \code{\link[=reconc_MCMC]{reconc_MCMC()}}: reconciliation of probabilistic discrete base forecasts via Markov Chain Monte Carlo. +\item \code{\link[=reconc_gaussian]{reconc_gaussian()}}: reconciliation via conditioning of multivariate Gaussian +base forecasts; this is done analytically; +\item \code{\link[=reconc_BUIS]{reconc_BUIS()}}: reconciliation via conditioning of any probabilistic forecast +via importance sampling; this is the recommended option for non-Gaussian base forecasts; +\item \code{\link[=reconc_MCMC]{reconc_MCMC()}}: reconciliation via conditioning of discrete probabilistic +forecasts via Markov Chain Monte Carlo; +\item \code{\link[=reconc_MixCond]{reconc_MixCond()}}: reconciliation via conditioning of mixed hierarchies, where +the upper forecasts are multivariate Gaussian and the bottom forecasts are discrete distributions; +\item \code{\link[=reconc_TDcond]{reconc_TDcond()}}: reconciliation via top-down conditioning of mixed hierarchies, where +the upper forecasts are multivariate Gaussian and the bottom forecasts are discrete distributions. } } @@ -30,18 +37,38 @@ this is the recommended option for non-Gaussian base forecasts; \itemize{ \item \code{\link[=temporal_aggregation]{temporal_aggregation()}}: temporal aggregation of a given time series object of class \link[stats]{ts}; -\item \code{\link[=get_reconc_matrices]{get_reconc_matrices()}}: aggregation and summing matrices for a temporal hierarchy of time series from user-selected list of aggregation levels. +\item \code{\link[=get_reconc_matrices]{get_reconc_matrices()}}: aggregation and summing matrices for a temporal hierarchy +of time series from user-selected list of aggregation levels; +\item \code{\link[=schaferStrimmer_cov]{schaferStrimmer_cov()}}: computes the Schäfer-Strimmer shrinkage estimator for the covariance matrix; +\item \code{\link[=PMF.get_mean]{PMF.get_mean()}}, \code{\link[=PMF.get_var]{PMF.get_var()}}, \code{\link[=PMF.get_quantile]{PMF.get_quantile()}}, \code{\link[=PMF.summary]{PMF.summary()}}, \code{\link[=PMF.sample]{PMF.sample()}}: +functions for handling PMF objects. } } \references{ -Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). \emph{Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule}. In: Hutter, F., Kersting, K., Lijffijt, J., Valera, I. (eds) Machine Learning and Knowledge Discovery in Databases. ECML PKDD 2020. Lecture Notes in Computer Science(), vol 12459. Springer, Cham. \doi{10.1007/978-3-030-67664-3_13}. +Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). +\emph{Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule}. +ECML PKDD 2020. Lecture Notes in Computer Science, vol 12459. +\doi{10.1007/978-3-030-67664-3_13}. -Corani, G., Azzimonti, D., Rubattu, N. (2023). \emph{Probabilistic reconciliation of count time series}. \doi{10.1016/j.ijforecast.2023.04.003}. +Corani, G., Azzimonti, D., Rubattu, N. (2024). +\emph{Probabilistic reconciliation of count time series}. +International Journal of Forecasting 40 (2), 457-469. +\doi{10.1016/j.ijforecast.2023.04.003}. -Zambon, L., Azzimonti, D. & Corani, G. (2024). \emph{Efficient probabilistic reconciliation of forecasts for real-valued and count time series}. \doi{10.1007/s11222-023-10343-y}. +Zambon, L., Azzimonti, D. & Corani, G. (2024). +\emph{Efficient probabilistic reconciliation of forecasts for real-valued and count time series}. +Statistics and Computing 34 (1), 21. +\doi{10.1007/s11222-023-10343-y}. -Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). \emph{Properties of the reconciled distributions for Gaussian and count forecasts}. \doi{10.48550/arXiv.2303.15135}. +Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +\emph{Properties of the reconciled distributions for Gaussian and count forecasts}. +International Journal of Forecasting (in press). +\doi{10.1016/j.ijforecast.2023.12.004}. + +Zambon, L., Azzimonti, D., Rubattu, N., Corani, G. (2024). +\emph{Probabilistic reconciliation of mixed-type hierarchical time series}. +The 40th Conference on Uncertainty in Artificial Intelligence, accepted. } \author{ \strong{Maintainer}: Dario Azzimonti \email{dario.azzimonti@gmail.com} (\href{https://orcid.org/0000-0001-5080-3061}{ORCID}) diff --git a/man/carparts_example.Rd b/man/carparts_example.Rd index 0b84b5c..8c01289 100644 --- a/man/carparts_example.Rd +++ b/man/carparts_example.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/carparts_example.R +% Please edit documentation in R/data.R \docType{data} \name{carparts_example} \alias{carparts_example} @@ -8,7 +8,9 @@ Univariate time series of class \link[stats]{ts}. } \source{ -Godahewa, Rakshitha, Bergmeir, Christoph, Webb, Geoff, Hyndman, Rob, & Montero-Manso, Pablo. (2020). Car Parts Dataset (without Missing Values) (Version 2) \doi{10.5281/zenodo.4656021} +Godahewa, R., Bergmeir, C., Webb, G., Hyndman, R.J., & Montero-Manso, P. (2020). +Car Parts Dataset (without Missing Values) (Version 2) +\doi{10.5281/zenodo.4656021} } \usage{ carparts_example @@ -17,9 +19,12 @@ carparts_example A monthly time series from the \code{carparts} dataset, 51 observations, Jan 1998 - Mar 2002. } \references{ -Hyndman, R.J., Koehler, A.B., Ord, J.K., and Snyder, R.D., (2008) Forecasting with exponential -smoothing: the state space approach, Springer +Hyndman, R.J., Koehler, A.B., Ord, J.K., and Snyder, R.D., (2008). +Forecasting with exponential smoothing: the state space approach. +Springer Science & Business Media. -Godahewa, Rakshitha, Bergmeir, Christoph, Webb, Geoff, Hyndman, Rob, & Montero-Manso, Pablo. (2020). Car Parts Dataset (without Missing Values) (Version 2) \doi{10.5281/zenodo.4656021} +Godahewa, R., Bergmeir, C., Webb, G., Hyndman, R., & Montero-Manso, P. (2020). +Car Parts Dataset (without Missing Values) (Version 2) +\doi{10.5281/zenodo.4656021} } \keyword{datasets} diff --git a/man/extr_mkt_events.Rd b/man/extr_mkt_events.Rd index 14c88f1..5567e07 100644 --- a/man/extr_mkt_events.Rd +++ b/man/extr_mkt_events.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/extr_mkt_events.R +% Please edit documentation in R/data.R \docType{data} \name{extr_mkt_events} \alias{extr_mkt_events} @@ -8,7 +8,10 @@ A multivariate time series of class \link[stats]{ts}. } \source{ -Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). \emph{Properties of the reconciled distributions for Gaussian and count forecasts}. \doi{10.48550/arXiv.2303.15135}. +Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +\emph{Properties of the reconciled distributions for Gaussian and count forecasts}. +International Journal of Forecasting (in press). +\doi{10.1016/j.ijforecast.2023.12.004}. } \usage{ extr_mkt_events @@ -31,8 +34,13 @@ There are 6 time series: } } \references{ -Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). \emph{Properties of the reconciled distributions for Gaussian and count forecasts}. \doi{10.48550/arXiv.2303.15135}. +Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +\emph{Properties of the reconciled distributions for Gaussian and count forecasts}. +International Journal of Forecasting (in press). +\doi{10.1016/j.ijforecast.2023.12.004}. -Agosto, A. (2022). \emph{Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion}. \doi{10.2139/ssrn.4119895} +Agosto, A. (2022). +\emph{Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion}. +\doi{10.2139/ssrn.4119895} } \keyword{datasets} diff --git a/man/extr_mkt_events_basefc.Rd b/man/extr_mkt_events_basefc.Rd index 7de3b76..a608b54 100644 --- a/man/extr_mkt_events_basefc.Rd +++ b/man/extr_mkt_events_basefc.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/extr_mkt_events_basefc.R +% Please edit documentation in R/data.R \docType{data} \name{extr_mkt_events_basefc} \alias{extr_mkt_events_basefc} @@ -12,14 +12,18 @@ A list \code{extr_mkt_events_basefc} containing } } \source{ -Agosto, A. (2022). \emph{Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion}. \doi{10.2139/ssrn.4119895} +Agosto, A. (2022). +\emph{Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion}. +\doi{10.2139/ssrn.4119895} } \usage{ extr_mkt_events_basefc } \description{ Base forecasts for the \code{extr_mkt_events} dataset, computed using the model by -Agosto, A. (2022). \emph{Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion}. \doi{10.2139/ssrn.4119895}. +Agosto, A. (2022). +\emph{Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion}. +\doi{10.2139/ssrn.4119895}. } \details{ The predictive distribution for the bottom time series is a multivariate negative @@ -30,8 +34,13 @@ They are in-sample forecasts: for each training instant, they are computed for time t+1 by conditioning on the counts observed up to time t. } \references{ -Agosto, A. (2022). \emph{Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion}. \doi{10.2139/ssrn.4119895} +Agosto, A. (2022). +\emph{Multivariate Score-Driven Models for Count Time Series to Assess Financial Contagion}. +\doi{10.2139/ssrn.4119895} -Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). \emph{Properties of the reconciled distributions for Gaussian and count forecasts}. \doi{10.48550/arXiv.2303.15135}. +Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +\emph{Properties of the reconciled distributions for Gaussian and count forecasts}. +International Journal of Forecasting (in press). +\doi{10.1016/j.ijforecast.2023.12.004}. } \keyword{datasets} diff --git a/man/infantMortality.Rd b/man/infantMortality.Rd index b88bd78..990a8fa 100644 --- a/man/infantMortality.Rd +++ b/man/infantMortality.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/infantMortality.R +% Please edit documentation in R/data.R \docType{data} \name{infantMortality} \alias{infantMortality} @@ -22,6 +22,8 @@ States: New South Wales (NSW), Victoria (VIC), Queensland (QLD), South Australia (WA), Northern Territory (NT), Australian Capital Territory (ACT), and Tasmania (TAS). } \references{ -R. J. Hyndman, R. A. Ahmed, G. Athanasopoulos and H.L. Shang (2011) Optimal combination forecasts for hierarchical time series. Computational Statistics and Data Analysis, 55(9), 2579-2589. +Hyndman, R.J., Ahmed, R.A., Athanasopoulos, G., Shang, H.L. (2011). +Optimal combination forecasts for hierarchical time series. +Computational Statistics and Data Analysis, 55(9), 2579-2589. } \keyword{datasets} diff --git a/man/reconc_BUIS.Rd b/man/reconc_BUIS.Rd index 909303f..751282b 100644 --- a/man/reconc_BUIS.Rd +++ b/man/reconc_BUIS.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/reconc.R +% Please edit documentation in R/reconc_BUIS.R \name{reconc_BUIS} \alias{reconc_BUIS} \title{BUIS for Probabilistic Reconciliation of forecasts via conditioning} @@ -27,7 +27,8 @@ reconc_BUIS( If it \code{in_type} is a string it is assumed that all base forecasts are of the same type.} -\item{distr}{A string or a list of length n describing the type of base forecasts. If it is a list the i-th element is a string with two possible values: +\item{distr}{A string or a list of length n describing the type of base forecasts. +If it is a list the i-th element is a string with two possible values: \itemize{ \item 'continuous' or 'discrete' if \code{in_type[[i]]}='samples'; \item 'gaussian', 'poisson' or 'nbinom' if \code{in_type[[i]]}='params'. @@ -35,7 +36,9 @@ If it \code{in_type} is a string it is assumed that all base forecasts are of th If \code{distr} is a string it is assumed that all distributions are of the same type.} -\item{num_samples}{Number of samples drawn from the reconciled distribution.} +\item{num_samples}{Number of samples drawn from the reconciled distribution. +This is ignored if \code{bottom_in_type='samples'}; in this case, the number of reconciled samples is equal to +the number of samples of the base forecasts.} \item{suppress_warnings}{Logical. If \code{TRUE}, no warnings about effective sample size are triggered. If \code{FALSE}, warnings are generated. Default is \code{FALSE}. See Details.} @@ -52,7 +55,7 @@ A list containing the reconciled forecasts. The list has the following named ele } \description{ Uses the Bottom-Up Importance Sampling algorithm to draw samples from the reconciled -forecast distribution, which is obtained via conditioning. +forecast distribution, obtained via conditioning. } \details{ The parameter \code{base_forecast} is a list containing n elements where the i-th element depends on @@ -60,11 +63,11 @@ the values of \code{in_type[[i]]} and \code{distr[[i]]}. If \code{in_type[[i]]}='samples', then \code{base_forecast[[i]]} is a vector containing samples from the base forecast distribution. -If \code{in_type[[i]]}='params', then \code{base_forecast[[i]]} is a vector containing the estimated: +If \code{in_type[[i]]}='params', then \code{base_forecast[[i]]} is a list containing the estimated: \itemize{ \item mean and sd for the Gaussian base forecast if \code{distr[[i]]}='gaussian', see \link[stats]{Normal}; \item lambda for the Poisson base forecast if \code{distr[[i]]}='poisson', see \link[stats]{Poisson}; -\item mu and size for the negative binomial base forecast if \code{distr[[i]]}='nbinom', see \link[stats]{NegBinomial}. +\item size and prob (or mu) for the negative binomial base forecast if \code{distr[[i]]}='nbinom', see \link[stats]{NegBinomial}. } See the description of the parameters \code{in_type} and \code{distr} for more details. @@ -78,7 +81,8 @@ Warnings are triggered from the Importance Sampling step if: \item the effective sample size is < 1\% of the sample size (\code{num_samples} if \code{in_type} is 'params' or the size of the base forecast if if \code{in_type} is 'samples'). } -Note that warnings are an indication that the base forecasts might have issues. Please check the base forecasts in case of warnings. +Note that warnings are an indication that the base forecasts might have issues. +Please check the base forecasts in case of warnings. } \examples{ @@ -104,7 +108,7 @@ sigmas <- c(sigmaY,sigma1,sigma2) base_forecasts = list() for (i in 1:nrow(S)) { -base_forecasts[[i]] = c(mus[[i]], sigmas[[i]]) +base_forecasts[[i]] = list(mean = mus[[i]], sd = sigmas[[i]]) } @@ -135,7 +139,7 @@ lambdas <- c(lambdaY,lambda1,lambda2) base_forecasts <- list() for (i in 1:nrow(S)) { - base_forecasts[[i]] = lambdas[i] + base_forecasts[[i]] = list(lambda = lambdas[i]) } #Sample from the reconciled forecast distribution using the BUIS algorithm @@ -148,7 +152,10 @@ print(rowMeans(samples_buis)) } \references{ -Zambon, L., Azzimonti, D. & Corani, G. (2024). \emph{Efficient probabilistic reconciliation of forecasts for real-valued and count time series}. \doi{10.1007/s11222-023-10343-y}. +Zambon, L., Azzimonti, D. & Corani, G. (2024). +\emph{Efficient probabilistic reconciliation of forecasts for real-valued and count time series}. +Statistics and Computing 34 (1), 21. +\doi{10.1007/s11222-023-10343-y}. } \seealso{ \code{\link[=reconc_gaussian]{reconc_gaussian()}} diff --git a/man/reconc_MCMC.Rd b/man/reconc_MCMC.Rd index 5fb13e2..8efd524 100644 --- a/man/reconc_MCMC.Rd +++ b/man/reconc_MCMC.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/reconc_MH.R +% Please edit documentation in R/reconc_MCMC.R \name{reconc_MCMC} \alias{reconc_MCMC} \title{MCMC for Probabilistic Reconciliation of forecasts via conditioning} @@ -44,18 +44,19 @@ A list containing the reconciled forecasts. The list has the following named ele Uses Markov Chain Monte Carlo algorithm to draw samples from the reconciled forecast distribution, which is obtained via conditioning. -This is a bare-bones implementation of the Metropolis-Hastings algorithm, we suggest the usage of tools to check the convergence. +This is a bare-bones implementation of the Metropolis-Hastings algorithm, +we suggest the usage of tools to check the convergence. The function only works with Poisson or Negative Binomial base forecasts. The function \code{\link[=reconc_BUIS]{reconc_BUIS()}} is generally faster on most hierarchies. } \details{ The parameter \code{base_forecast} is a list containing n elements. -Each element is a vector containing the estimated: +Each element is a list containing the estimated: \itemize{ \item mean and sd for the Gaussian base forecast, see \link[stats]{Normal}, if \code{distr}='gaussian'; \item lambda for the Poisson base forecast, see \link[stats]{Poisson}, if \code{distr}='poisson'; -\item mu and size for the negative binomial base forecast, see \link[stats]{NegBinomial}, if \code{distr}='nbinom'. +\item size and prob (or mu) for the negative binomial base forecast, see \link[stats]{NegBinomial}, if \code{distr}='nbinom'. } The order of the \code{base_forecast} list is given by the order of the time series in the summing matrix. @@ -76,12 +77,12 @@ lambdas <- c(lambdaY,lambda1,lambda2) base_forecasts = list() for (i in 1:nrow(S)) { - base_forecasts[[i]] = lambdas[i] + base_forecasts[[i]] = list(lambda = lambdas[i]) } #Sample from the reconciled forecast distribution using MCMC -mcmc = reconc_MCMC(S,base_forecasts=lambdas,distr="poisson", - num_samples=30000, seed=42) +mcmc = reconc_MCMC(S, base_forecasts, distr = "poisson", + num_samples = 30000, seed = 42) samples_mcmc <- mcmc$reconciled_samples #Compare the reconciled means with those obtained via BUIS @@ -94,7 +95,10 @@ print(rowMeans(samples_buis)) } \references{ -Corani, G., Azzimonti, D., Rubattu, N. (2023). \emph{Probabilistic reconciliation of count time series}. \doi{10.1016/j.ijforecast.2023.04.003}. +Corani, G., Azzimonti, D., Rubattu, N. (2024). +\emph{Probabilistic reconciliation of count time series}. +International Journal of Forecasting 40 (2), 457-469. +\doi{10.1016/j.ijforecast.2023.04.003}. } \seealso{ \code{\link[=reconc_BUIS]{reconc_BUIS()}} diff --git a/man/reconc_MixCond.Rd b/man/reconc_MixCond.Rd new file mode 100644 index 0000000..af0d9dd --- /dev/null +++ b/man/reconc_MixCond.Rd @@ -0,0 +1,149 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/reconc_MixCond.R +\name{reconc_MixCond} +\alias{reconc_MixCond} +\title{Probabilistic forecast reconciliation of mixed hierarchies via conditioning} +\usage{ +reconc_MixCond( + S, + fc_bottom, + fc_upper, + bottom_in_type = "pmf", + distr = NULL, + num_samples = 20000, + return_type = "pmf", + suppress_warnings = FALSE, + seed = NULL +) +} +\arguments{ +\item{S}{Summing matrix (n x n_bottom).} + +\item{fc_bottom}{A list containing the bottom base forecasts, see details.} + +\item{fc_upper}{A list containing the upper base forecasts, see details.} + +\item{bottom_in_type}{A string with three possible values: +\itemize{ +\item 'pmf' if the bottom base forecasts are in the form of pmf, see details; +\item 'samples' if the bottom base forecasts are in the form of samples; +\item 'params' if the bottom base forecasts are in the form of estimated parameters. +}} + +\item{distr}{A string describing the type of bottom base forecasts ('poisson' or 'nbinom'). + +This is only used if \code{bottom_in_type='params'}.} + +\item{num_samples}{Number of samples drawn from the reconciled distribution. +This is ignored if \code{bottom_in_type='samples'}; in this case, the number of +reconciled samples is equal to the number of samples of the base forecasts.} + +\item{return_type}{The return type of the reconciled distributions. +A string with three possible values: +\itemize{ +\item 'pmf' returns a list containing the reconciled marginal pmf objects; +\item 'samples' returns a list containing the reconciled multivariate samples; +\item 'all' returns a list with both pmf objects and samples. +}} + +\item{suppress_warnings}{Logical. If \code{TRUE}, no warnings about samples +are triggered. If \code{FALSE}, warnings are generated. Default is \code{FALSE}. See Details.} + +\item{seed}{Seed for reproducibility.} +} +\value{ +A list containing the reconciled forecasts. The list has the following named elements: +\itemize{ +\item \code{bottom_reconciled}: a list containing the pmf, the samples (matrix n_bottom x \code{num_samples}) or both, +depending on the value of \code{return_type}; +\item \code{upper_reconciled}: a list containing the pmf, the samples (matrix n_upper x \code{num_samples}) or both, +depending on the value of \code{return_type}. +} +} +\description{ +Uses importance sampling to draw samples from the reconciled +forecast distribution, obtained via conditioning, in the case of a mixed hierarchy. +} +\details{ +The base bottom forecasts \code{fc_bottom} must be a list of length n_bottom, where each element is either +\itemize{ +\item a PMF object (see details below), if \code{bottom_in_type='pmf'}; +\item a vector of samples, if \code{bottom_in_type='samples'}; +\item a list of parameters, if \code{bottom_in_type='params'}: +\itemize{ +\item lambda for the Poisson base forecast if \code{distr}='poisson', see \link[stats]{Poisson}; +\item size and prob (or mu) for the negative binomial base forecast if \code{distr}='nbinom', +see \link[stats]{NegBinomial}. +} +} + +The base upper forecasts \code{fc_upper} must be a list containing the parameters of +the multivariate Gaussian distribution of the upper forecasts. +The list must contain only the named elements \code{mu} (vector of length n_upper) +and \code{Sigma} (n_upper x n_upper matrix) + +A PMF object is a numerical vector containing the probability mass function of a discrete distribution. +Each element corresponds to the probability of the integers from 0 to the last value of the support. +See also \link{PMF.get_mean}, \link{PMF.get_var}, \link{PMF.sample}, \link{PMF.get_quantile}, +\link{PMF.summary} for functions that handle PMF objects. + +Warnings are triggered from the Importance Sampling step if: +\itemize{ +\item weights are all zeros, then the upper forecast is ignored during reconciliation; +\item the effective sample size is < 200; +\item the effective sample size is < 1\% of the sample size. +} + +Note that warnings are an indication that the base forecasts might have issues. +Please check the base forecasts in case of warnings. +} +\examples{ + +library(bayesRecon) + +# Consider a simple hierarchy with two bottom and one upper +A <- matrix(c(1,1),nrow=1) +S <- rbind(A,diag(nrow=2)) +# The bottom forecasts are Poisson with lambda=15 +lambda <- 15 +n_tot <- 60 +fc_bottom <- list() +fc_bottom[[1]] <- apply(matrix(seq(0,n_tot)),MARGIN=1,FUN=function(x) dpois(x,lambda=lambda)) +fc_bottom[[2]] <- apply(matrix(seq(0,n_tot)),MARGIN=1,FUN=function(x) dpois(x,lambda=lambda)) + +# The upper forecast is a Normal with mean 40 and std 5 +fc_upper<- list(mu=40, Sigma=matrix(5^2)) + +# We can reconcile with reconc_MixCond +res.mixCond <- reconc_MixCond(S, fc_bottom, fc_upper) + +# Note that the bottom distributions are slightly shifted to the right +PMF.summary(res.mixCond$bottom_reconciled$pmf[[1]]) +PMF.summary(fc_bottom[[1]]) + +PMF.summary(res.mixCond$bottom_reconciled$pmf[[2]]) +PMF.summary(fc_bottom[[2]]) + +# The upper distribution is slightly shifted to the left +PMF.summary(res.mixCond$upper_reconciled$pmf[[1]]) +PMF.get_var(res.mixCond$upper_reconciled$pmf[[1]]) + +} +\references{ +Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). +\emph{Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule}. +ECML PKDD 2020. Lecture Notes in Computer Science, vol 12459. +\doi{10.1007/978-3-030-67664-3_13}. + +Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +\emph{Properties of the reconciled distributions for Gaussian and count forecasts}. +International Journal of Forecasting (in press). +\doi{10.1016/j.ijforecast.2023.12.004}. + +Zambon, L., Azzimonti, D., Rubattu, N., Corani, G. (2024). +\emph{Probabilistic reconciliation of mixed-type hierarchical time series}. +The 40th Conference on Uncertainty in Artificial Intelligence, accepted. +} +\seealso{ +\code{\link[=reconc_TDcond]{reconc_TDcond()}}, \code{\link[=reconc_BUIS]{reconc_BUIS()}} +} diff --git a/man/reconc_TDcond.Rd b/man/reconc_TDcond.Rd new file mode 100644 index 0000000..eb2cafb --- /dev/null +++ b/man/reconc_TDcond.Rd @@ -0,0 +1,146 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/reconc_TDcond.R +\name{reconc_TDcond} +\alias{reconc_TDcond} +\title{Probabilistic forecast reconciliation of mixed hierarchies via top-down conditioning} +\usage{ +reconc_TDcond( + S, + fc_bottom, + fc_upper, + bottom_in_type = "pmf", + distr = NULL, + num_samples = 20000, + return_type = "pmf", + suppress_warnings = FALSE, + seed = NULL +) +} +\arguments{ +\item{S}{Summing matrix (n x n_bottom).} + +\item{fc_bottom}{A list containing the bottom base forecasts, see details.} + +\item{fc_upper}{A list containing the upper base forecasts, see details.} + +\item{bottom_in_type}{A string with three possible values: +\itemize{ +\item 'pmf' if the bottom base forecasts are in the form of pmf, see details; +\item 'samples' if the bottom base forecasts are in the form of samples; +\item 'params' if the bottom base forecasts are in the form of estimated parameters. +}} + +\item{distr}{A string describing the type of bottom base forecasts ('poisson' or 'nbinom'). + +This is only used if \code{bottom_in_type=='params'}.} + +\item{num_samples}{Number of samples drawn from the reconciled distribution. +This is ignored if \code{bottom_in_type='samples'}; in this case, the number of +reconciled samples is equal to the number of samples of the base forecasts.} + +\item{return_type}{The return type of the reconciled distributions. +A string with three possible values: +\itemize{ +\item 'pmf' returns a list containing the reconciled marginal pmf objects; +\item 'samples' returns a list containing the reconciled multivariate samples; +\item 'all' returns a list with both pmf objects and samples. +}} + +\item{suppress_warnings}{Logical. If \code{TRUE}, no warnings about samples +are triggered. If \code{FALSE}, warnings are generated. Default is \code{FALSE}. See Details.} + +\item{seed}{Seed for reproducibility.} +} +\value{ +A list containing the reconciled forecasts. The list has the following named elements: +\itemize{ +\item \code{bottom_reconciled}: a list containing the pmf, the samples (matrix n_bottom x \code{num_samples}) or both, +depending on the value of \code{return_type}; +\item \code{upper_reconciled}: a list containing the pmf, the samples (matrix n_upper x \code{num_samples}) or both, +depending on the value of \code{return_type}. +} +} +\description{ +Uses the top-down conditioning algorithm to draw samples from the reconciled +forecast distribution. Reconciliation is performed in two steps: +first, the upper base forecasts are reconciled via conditioning, +using only the hierarchical constraints between the upper variables; then, +the bottom distributions are updated via a probabilistic top-down procedure. +} +\details{ +The base bottom forecasts \code{fc_bottom} must be a list of length n_bottom, where each element is either +\itemize{ +\item a PMF object (see details below), if \code{bottom_in_type='pmf'}; +\item a vector of samples, if \code{bottom_in_type='samples'}; +\item a list of parameters, if \code{bottom_in_type='params'}: +\itemize{ +\item lambda for the Poisson base forecast if \code{distr}='poisson', see \link[stats]{Poisson}; +\item size and prob (or mu) for the negative binomial base forecast if \code{distr}='nbinom', +see \link[stats]{NegBinomial}. +} +} + +The base upper forecasts \code{fc_upper} must be a list containing the parameters of +the multivariate Gaussian distribution of the upper forecasts. +The list must contain only the named elements \code{mu} (vector of length n_upper) +and \code{Sigma} (n_upper x n_upper matrix) + +A PMF object is a numerical vector containing the probability mass function of a discrete distribution. +Each element corresponds to the probability of the integers from 0 to the last value of the support. +See also \link{PMF.get_mean}, \link{PMF.get_var}, \link{PMF.sample}, \link{PMF.get_quantile}, +\link{PMF.summary} for functions that handle PMF objects. + +If some of the reconciled upper samples lie outside the support of the bottom-up distribution, +those samples are discarded and a warning is triggered. +The warning reports the percentage of samples kept. +} +\examples{ + +library(bayesRecon) + +# Consider a simple hierarchy with two bottom and one upper +A <- matrix(c(1,1),nrow=1) +S <- rbind(A,diag(nrow=2)) +# The bottom forecasts are Poisson with lambda=15 +lambda <- 15 +n_tot <- 60 +fc_bottom <- list() +fc_bottom[[1]] <- apply(matrix(seq(0,n_tot)),MARGIN=1,FUN=function(x) dpois(x,lambda=lambda)) +fc_bottom[[2]] <- apply(matrix(seq(0,n_tot)),MARGIN=1,FUN=function(x) dpois(x,lambda=lambda)) + +# The upper forecast is a Normal with mean 40 and std 5 +fc_upper<- list(mu=40, Sigma=matrix(c(5^2))) + +# We can reconcile with reconc_TDcond +res.TDcond <- reconc_TDcond(S, fc_bottom, fc_upper) + +# Note that the bottom distributions are shifted to the right +PMF.summary(res.TDcond$bottom_reconciled$pmf[[1]]) +PMF.summary(fc_bottom[[1]]) + +PMF.summary(res.TDcond$bottom_reconciled$pmf[[2]]) +PMF.summary(fc_bottom[[2]]) + +# The upper distribution remains similar +PMF.summary(res.TDcond$upper_reconciled$pmf[[1]]) +PMF.get_var(res.TDcond$upper_reconciled$pmf[[1]]) + +} +\references{ +Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). +\emph{Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule}. +ECML PKDD 2020. Lecture Notes in Computer Science, vol 12459. +\doi{10.1007/978-3-030-67664-3_13}. + +Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +\emph{Properties of the reconciled distributions for Gaussian and count forecasts}. +International Journal of Forecasting (in press). +\doi{10.1016/j.ijforecast.2023.12.004}. + +Zambon, L., Azzimonti, D., Rubattu, N., Corani, G. (2024). +\emph{Probabilistic reconciliation of mixed-type hierarchical time series}. +The 40th Conference on Uncertainty in Artificial Intelligence, accepted. +} +\seealso{ +\code{\link[=reconc_MixCond]{reconc_MixCond()}}, \code{\link[=reconc_BUIS]{reconc_BUIS()}} +} diff --git a/man/reconc_gaussian.Rd b/man/reconc_gaussian.Rd index e4f70ee..0cf16f1 100644 --- a/man/reconc_gaussian.Rd +++ b/man/reconc_gaussian.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/reconc.R +% Please edit documentation in R/reconc_gaussian.R \name{reconc_gaussian} \alias{reconc_gaussian} \title{Analytical reconciliation of Gaussian base forecasts} @@ -68,17 +68,23 @@ Y_Sigma_reconc <- S \%*\% bottom_Sigma_reconc \%*\% t(S) # note: singular matri # Obtain reconciled samples for the entire hierarchy: # i.e., sample from the reconciled bottoms and multiply by S chol_decomp = chol(bottom_Sigma_reconc) # Compute the Cholesky Decomposition -Z = matrix(rnorm(n = 2000), nrow = 2) # Sample from standard normal -B = chol_decomp \%*\% Z + matrix(rep(bottom_mu_reconc, 1000), nrow=2) # Apply the transformation +Z = matrix(stats::rnorm(n = 2000), nrow = 2) # Sample from standard normal +B = t(chol_decomp) \%*\% Z + matrix(rep(bottom_mu_reconc, 1000), nrow=2) # Apply the transformation U = S \%*\% B Y_reconc = rbind(U, B) } \references{ -Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). \emph{Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule}. In: Hutter, F., Kersting, K., Lijffijt, J., Valera, I. (eds) Machine Learning and Knowledge Discovery in Databases. ECML PKDD 2020. Lecture Notes in Computer Science(), vol 12459. Springer, Cham. \doi{10.1007/978-3-030-67664-3_13}. +Corani, G., Azzimonti, D., Augusto, J.P.S.C., Zaffalon, M. (2021). +\emph{Probabilistic Reconciliation of Hierarchical Forecast via Bayes' Rule}. +ECML PKDD 2020. Lecture Notes in Computer Science, vol 12459. +\doi{10.1007/978-3-030-67664-3_13}. -Zambon, L., Agosto, A., Giudici, P., Corani, G. (2023). \emph{Properties of the reconciled distributions for Gaussian and count forecasts}. \doi{10.48550/arXiv.2303.15135}. +Zambon, L., Agosto, A., Giudici, P., Corani, G. (2024). +\emph{Properties of the reconciled distributions for Gaussian and count forecasts}. +International Journal of Forecasting (in press). +\doi{10.1016/j.ijforecast.2023.12.004}. } \seealso{ \code{\link[=reconc_BUIS]{reconc_BUIS()}} diff --git a/man/schaferStrimmer_cov.Rd b/man/schaferStrimmer_cov.Rd index 8b37e7b..39b12d7 100644 --- a/man/schaferStrimmer_cov.Rd +++ b/man/schaferStrimmer_cov.Rd @@ -39,8 +39,9 @@ trueMean <- c(0,0) # Generate samples set.seed(42) -x <- replicate(nSamples, trueMean) + t(chol_trueSigma)\%*\%matrix(rnorm(pTrue*nSamples), - nrow=pTrue,ncol=nSamples) +x <- replicate(nSamples, trueMean) + + t(chol_trueSigma)\%*\%matrix(stats::rnorm(pTrue*nSamples), + nrow = pTrue, ncol = nSamples) x <- t(x) res_shrinkage <- schaferStrimmer_cov(x) res_shrinkage$lambda_star # should be 0.01287923 diff --git a/tests/testthat/dataForTests/Weekly-Gaussian_S.csv b/tests/testthat/dataForTests/Weekly-Gaussian_S.csv index 463e342..307348e 100644 --- a/tests/testthat/dataForTests/Weekly-Gaussian_S.csv +++ b/tests/testthat/dataForTests/Weekly-Gaussian_S.csv @@ -1,98 +1,98 @@ -1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 -1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 -1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 -1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00 -0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00 +1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1 +1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1 +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1 +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 diff --git a/tests/testthat/dataForTests/Weekly-Gaussian_basef.csv b/tests/testthat/dataForTests/Weekly-Gaussian_basef.csv index 2c6b0df..fa84bac 100644 --- a/tests/testthat/dataForTests/Weekly-Gaussian_basef.csv +++ b/tests/testthat/dataForTests/Weekly-Gaussian_basef.csv @@ -1,98 +1,98 @@ -20.108969864880674,3.0 -20.525131446497316,3.0 -17.63431449340681,3.0 -21.395605099289075,3.0 -17.329834251180998,3.0 -18.336558824397933,3.0 -60.06467732231163,3.0 -59.65079195743517,3.0 -55.20325493196959,3.0 -57.81163982498749,3.0 -57.371700491743745,3.0 -37.85927122253677,3.0 -35.56187413891096,3.0 -59.26870034702594,3.0 -62.978476874408216,3.0 -54.85445468850228,3.0 -64.74366349736533,3.0 -54.1140274895275,3.0 -53.27204187913661,3.0 -18.955680905576735,3.0 -21.66921892177268,3.0 -19.576176697800335,3.0 -18.33098468909278,3.0 -17.916462703495345,3.0 -18.172632297761073,3.0 -18.423164399451156,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -0.0,3.0 -498.0216322947625,3.0 -122.67177839781664,3.0 -124.99573977831378,3.0 -127.98062361046973,3.0 -122.37349050816236,3.0 -247.66751817613041,3.0 -250.3541141186321,3.0 -5.634849165190505,2.0 -9.833589192410015,2.0 -6.3023800293289165,2.0 -9.486182621822866,2.0 -6.883748580948357,2.0 -6.681108721672265,2.0 -7.256882352376998,2.0 -9.201275416306906,2.0 -5.615510721442498,2.0 -7.715131010235192,2.0 -6.865061126107154,2.0 -7.239984123429718,2.0 -5.647203398587565,2.0 -9.299393532899847,2.0 -9.101941815597787,2.0 -6.760267695740124,2.0 -6.144436521608066,2.0 -8.883918752538587,2.0 -7.973917947425619,2.0 -5.687767782816352,2.0 -9.264498904744308,2.0 -6.177537392208406,2.0 -5.731136162983294,2.0 -7.949343865092274,2.0 -7.870058874736866,2.0 -5.30634981184984,2.0 -7.95213001666309,2.0 -6.226749095912479,2.0 -6.702224687173487,2.0 -9.923643697193079,2.0 -9.597702024695398,2.0 -5.188858437613185,2.0 -9.307746448546265,2.0 -8.767844226678585,2.0 -7.02589377510444,2.0 -6.717629376387389,2.0 -5.85458586036048,2.0 -6.973295048812124,2.0 -8.208330851375177,2.0 -6.372962152914619,2.0 -7.311771671479159,2.0 -9.356858268345977,2.0 -7.005656109237162,2.0 -8.05294135060925,2.0 -5.589835648245561,2.0 -8.51092180490273,2.0 -7.070168323089434,2.0 -6.711726064214677,2.0 -7.9796266057216805,2.0 -5.99932131563299,2.0 -5.498683813002075,2.0 -8.67298110965266,2.0 +14.5069790952839,3 +19.1458363434067,3 +17.0503938880283,3 +19.8301018360071,3 +14.7999517290154,3 +13.1039223008556,3 +16.8911961067934,3 +17.9714736414608,3 +20.402385317022,3 +17.3661422041478,3 +17.3076626381371,3 +15.2747587412596,3 +14.5933411869919,3 +13.1767805962591,3 +17.6552191332448,3 +16.9490526749287,3 +14.7386739965295,3 +19.2271203123964,3 +15.9620091763791,3 +17.2424195662607,3 +19.0740356836468,3 +18.3478299066192,3 +18.2549169653794,3 +13.753086970537,3 +18.8377491233405,3 +18.3635600443231,3 +33.6528154386906,3 +36.8804957240354,3 +27.9038740298711,3 +34.8626697482541,3 +37.7685275211697,3 +32.5824213793967,3 +27.7701217832509,3 +34.6042718081735,3 +33.965794308926,3 +33.2044287426397,3 +37.421865590266,3 +32.0080039359163,3 +37.2013091676636,3 +439.826599178254,3 +107.715810849215,3 +110.528334179195,3 +107.189266092959,3 +114.393188056885,3 +218.24414502841,3 +221.582454149844,3 +6.3275433157105,2 +6.86061949818395,2 +7.86426681675948,2 +9.54103894997388,2 +6.00840965518728,2 +9.49194842483848,2 +9.72337634302676,2 +8.30398896243423,2 +8.1455702194944,2 +5.30893135233782,2 +6.0298728744965,2 +5.88278376264498,2 +8.43511423328891,2 +6.92051859106869,2 +8.84920709999278,2 +7.48849621042609,2 +8.58809254132211,2 +9.95953047415242,2 +6.90017589717172,2 +8.88722610659897,2 +9.67352615552954,2 +6.06071260641329,2 +8.25836883042939,2 +5.62777547980659,2 +6.33610334363766,2 +6.93057046271861,2 +5.06695166579448,2 +6.91193978535011,2 +9.34845422860235,2 +6.7017449834384,2 +7.41040057735518,2 +7.99782912712544,2 +7.46770653524436,2 +5.93108800705522,2 +9.13686659303494,2 +8.34233369096182,2 +8.9711993036326,2 +5.53971812943928,2 +8.61855473020114,2 +7.05637214821763,2 +9.10473147057928,2 +8.23530096909963,2 +8.9146638114471,2 +7.76518155820668,2 +7.64859790098853,2 +8.94678115844727,2 +5.11665601166897,2 +7.38615032518283,2 +8.661568693351,2 +8.46365778241307,2 +7.38809811067767,2 +9.3060473841615,2 diff --git a/tests/testthat/dataForTests/generate_weeklyTestData.R b/tests/testthat/dataForTests/generate_weeklyTestData.R new file mode 100644 index 0000000..cd521a6 --- /dev/null +++ b/tests/testthat/dataForTests/generate_weeklyTestData.R @@ -0,0 +1,26 @@ +# Generate the weekly base forecasts parameters +# CHANGE THE WORKING DIRECTORY BEFORE RUNNING +rm(list=ls()) +library(bayesRecon) + +# Generate A matrix for weekly hierarchy +A <- .gen_weekly() +S <- rbind(A, diag(nrow=52,ncol=52))+0e-3 +# Save matrix to file +write.table(S,file="./Weekly-Gaussian_S.csv",row.names = FALSE,sep=',',col.names = FALSE,quote = FALSE) + +# Generate randomly bottom means +set.seed(1) +bottom_means <- runif(52,min=5,max=10) + +# The upper means are generated by +# aggregating the bottom means (according to A) with an epsilon of incoherence +eps = 0.1 +upper_means <- (1+eps)*A%*%bottom_means +upper_means <- as.vector(upper_means) + +# Create the matrix to save to csv +base_forecasts_out <- cbind(c(upper_means,bottom_means),c(rep(3,length(upper_means)),rep(2,length(bottom_means)))) +write.table(base_forecasts_out,file="./Weekly-Gaussian_basef.csv",row.names = FALSE,sep=',',col.names = FALSE,quote = FALSE) + + diff --git a/tests/testthat/test-PMF.R b/tests/testthat/test-PMF.R new file mode 100644 index 0000000..c4023fe --- /dev/null +++ b/tests/testthat/test-PMF.R @@ -0,0 +1,70 @@ +test_that("PMF.conv", { + + # Generate a size and a prob each binomial + s1 <- 20; p1 <- 0.6 + s2 <- 30; p2 <- 0.7 + + # Compute the pmf for the two binomials + pmf1 <- dbinom(seq(0,s1),size=s1,prob=p1) + pmf2 <- dbinom(seq(0,s2),size=s2,prob=p2) + + # True mean of the convolution + expected_conv_mean = s1*p1+s2*p2 + expected_conv_var = s1*p1*(1-p1)+s2*p2*(1-p2) + + # Compute the PMF of the convolution + pmf_conv <- PMF.conv(pmf1 = pmf1,pmf2 = pmf2) + + abs(PMF.get_mean(pmf_conv)-expected_conv_mean) + abs(PMF.get_var(pmf_conv)-expected_conv_var) + + # Check if the convolution mean is equal to the truth + expect_lt(abs(PMF.get_mean(pmf_conv)-expected_conv_mean),1e-6) + + # Check if the convolution var is equal to the truth + expect_lt(abs(PMF.get_var(pmf_conv)-expected_conv_var),8e-5) +}) + +test_that("PMF.bottom_up", { + + # Test with 10 bottom + n_bottom <- 10 + + # Create sizes and probs for nbinom bottom distributions + sizes <- c(seq(11,15),seq(19,15)) + probs <- c(rep(0.4,5),rep(0.7,5)) + distr <- "nbinom" + + # Compute true BU params (mean/var) and bottom pmfs + true_bu_mean <- 0 + true_bu_var <- 0 + bott_pmfs <- list() + for(i in seq(n_bottom)){ + true_bu_mean <- true_bu_mean + sizes[i]*(1-probs[i])/probs[i] + true_bu_var <- true_bu_var + sizes[i]*(1-probs[i])/probs[i]^2 + params <- list(size=sizes[i],prob=probs[i]) + bott_pmfs[[i]] <- PMF.from_params(params=params,distr = distr) + } + # Run PMF.bottom_up to get the bottom up pmf + bottom_up_pmf <- PMF.bottom_up(l_pmf=bott_pmfs) + + # Check if true mean is close enough to bottom up pmf mean + expect_lt(abs(PMF.get_mean(bottom_up_pmf)-true_bu_mean)/true_bu_mean,2e-6) + + # Check if true var is close enough to bottom up pmf var + expect_lt(abs(PMF.get_var(bottom_up_pmf)-true_bu_var)/true_bu_var,6e-5) +}) + +test_that("PMF.quantile",{ + n_samples = 1e5 + size = 10 + prob = 0.6 + p = 0.01 + + x = rnbinom(n_samples, size = size, prob = prob) + pmf = PMF.from_samples(x) + q = PMF.get_quantile(pmf, p) + qq = qnbinom(p, size = size, prob = prob) + + expect_equal(q,qq) +}) diff --git a/tests/testthat/test-hierarchy.R b/tests/testthat/test-hierarchy.R index fa0e20c..11b1c82 100644 --- a/tests/testthat/test-hierarchy.R +++ b/tests/testthat/test-hierarchy.R @@ -12,3 +12,45 @@ test_that("get_reconc_matrices produces expected aggregation and summing matrice diff <- max(abs(expected_rowSumsA-rowSums(out$A)))+max(abs(expected_rowSumsS-rowSums(out$S))) expect_equal(diff, 0) }) + +test_that(".get_Au and .lowest_lev produce expected outcomes", { + + A <- matrix( + data=c(1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 1),nrow=4,byrow = TRUE) + + + expect_equal(.get_Au(A),matrix(c(1,1,1),ncol=3)) + expect_equal(.lowest_lev(A),c(2,3,4)) + +}) + +test_that(".get_Au behaves identically on A with different row order.",{ + A <- matrix(data=c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1), + nrow=10,byrow = TRUE) + + A1 <- matrix(data=c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1), + nrow=10,byrow = TRUE) + + expect_equal(.get_Au(A),.get_Au(A1)) +}) diff --git a/tests/testthat/test-examples.R b/tests/testthat/test-reconc_BUIS_gaussian.R similarity index 76% rename from tests/testthat/test-examples.R rename to tests/testthat/test-reconc_BUIS_gaussian.R index 5ae3894..161a87d 100644 --- a/tests/testthat/test-examples.R +++ b/tests/testthat/test-reconc_BUIS_gaussian.R @@ -5,7 +5,8 @@ test_that("Monthly, in_type=='params', distr='gaussian'",{ base_forecasts_in = read.csv(file = "dataForTests/Monthly-Gaussian_basef.csv", header = FALSE) base_forecasts = list() for (i in 1:nrow(base_forecasts_in)) { - base_forecasts[[i]] = list(as.numeric(base_forecasts_in[i,]))[[1]] + base_forecasts[[i]] = list(mean = base_forecasts_in[i,1], + sd = base_forecasts_in[i,2]) } res.buis = reconc_BUIS(S, base_forecasts, in_type = "params", distr = "gaussian", num_samples = 100000, seed=42) @@ -19,20 +20,22 @@ test_that("Monthly, in_type=='params', distr='gaussian'",{ test_that("Weekly, in_type=='params', distr='gaussian'",{ # Run IS Reconc - S = read.csv(file = "dataForTests/Weekly-Gaussian_S.csv", header = FALSE) - S = as.matrix(S) - base_forecasts_in = read.csv(file = "dataForTests/Weekly-Gaussian_basef.csv", header = FALSE) - base_forecasts = list() + S <- read.csv(file = "dataForTests/Weekly-Gaussian_S.csv", header = FALSE) + S <- as.matrix(S) + mode(S) <- "numeric" + base_forecasts_in <- read.csv(file = "dataForTests/Weekly-Gaussian_basef.csv", header = FALSE) + base_forecasts <- list() for (i in 1:nrow(base_forecasts_in)) { - base_forecasts[[i]] = list(as.numeric(base_forecasts_in[i,]))[[1]] + base_forecasts[[i]] <- list(mean = base_forecasts_in[i,1], + sd = base_forecasts_in[i,2]) } - res.buis = reconc_BUIS(S, base_forecasts, + res.buis <- reconc_BUIS(S, base_forecasts, in_type = "params", distr = "gaussian", num_samples = 100000, seed=42) # Run Gauss Reconc - res.gauss = reconc_gaussian(S, base_forecasts_in[[1]], diag(base_forecasts_in[[2]]^2)) + res.gauss <- reconc_gaussian(S, base_forecasts_in[[1]], diag(base_forecasts_in[[2]]^2)) # Test - b_mask = rowSums(S) == 1 - m = mean(rowMeans(res.buis$reconciled_samples)[b_mask] - as.numeric(res.gauss$bottom_reconciled_mean)) + b_mask <- rowSums(S) == 1 + m <- mean(rowMeans(res.buis$reconciled_samples)[b_mask] - as.numeric(res.gauss$bottom_reconciled_mean)) expect_equal(abs(m) < 2e-2, TRUE) }) @@ -42,7 +45,7 @@ test_that("Monthly, in_type=='params', distr='poisson'",{ base_forecasts_in = read.csv(file = "dataForTests/Monthly-Poisson_basef.csv", header = FALSE) base_forecasts = list() for (i in 1:nrow(base_forecasts_in)) { - base_forecasts[[i]] = list(as.numeric(base_forecasts_in[i,]))[[1]] + base_forecasts[[i]] = list(lambda = base_forecasts_in[i,1]) } res.buis = reconc_BUIS(S, base_forecasts, in_type = "params", distr = "poisson", num_samples = 100000, seed=42) @@ -56,7 +59,8 @@ test_that("Monthly, in_type=='params', distr='nbinom'",{ base_forecasts_in = read.csv(file = "dataForTests/Monthly-NegBin_basef.csv", header = FALSE) base_forecasts = list() for (i in 1:nrow(base_forecasts_in)) { - base_forecasts[[i]] = list(as.numeric(base_forecasts_in[i,]))[[1]] + base_forecasts[[i]] = list(size = base_forecasts_in[i,2], + mu = base_forecasts_in[i,1]) } res.buis = reconc_BUIS(S, base_forecasts, in_type = "params", distr = "nbinom", num_samples = 10000, seed=42) @@ -75,7 +79,8 @@ test_that("Monthly, in_type=='samples', distr='continuous'",{ base_forecasts_in = read.csv(file = "dataForTests/Monthly-Gaussian_basef.csv", header = FALSE) base_forecasts = list() for (i in 1:nrow(base_forecasts_in)) { - base_forecasts[[i]] = list(as.numeric(base_forecasts_in[i,]))[[1]] + base_forecasts[[i]] = list(mean = base_forecasts_in[i,1], + sd = base_forecasts_in[i,2]) } res.buis = reconc_BUIS(S, base_forecasts, in_type = "params", distr = "gaussian", num_samples = 100000, seed=42) m = mean(rowMeans(res.buis$reconciled_samples) - rowMeans(res.buis_samples$reconciled_samples)) @@ -92,7 +97,7 @@ test_that("Monthly, in_type=='samples', distr='discrete'",{ base_forecasts_in = read.csv(file = "dataForTests/Monthly-Poisson_basef.csv", header = FALSE) base_forecasts = list() for (i in 1:nrow(base_forecasts_in)) { - base_forecasts[[i]] = list(as.numeric(base_forecasts_in[i,]))[[1]] + base_forecasts[[i]] = list(lambda = base_forecasts_in[i,1]) } res.buis = reconc_BUIS(S, base_forecasts, in_type = "params", distr = "poisson", num_samples = 100000, seed=42) m = mean(rowMeans(res.buis$reconciled_samples) - rowMeans(res.buis_samples$reconciled_samples)) diff --git a/tests/testthat/test-reconc_MCMC.R b/tests/testthat/test-reconc_MCMC.R index cbcd5b3..e16fce8 100644 --- a/tests/testthat/test-reconc_MCMC.R +++ b/tests/testthat/test-reconc_MCMC.R @@ -4,7 +4,7 @@ test_that("MCMC Monthly, in_type=='params', distr='poisson'", { base_forecasts_in = read.csv(file = "dataForTests/Monthly-Poisson_basef.csv", header = FALSE) base_forecasts = list() for (i in 1:nrow(base_forecasts_in)) { - base_forecasts[[i]] = list(as.numeric(base_forecasts_in[i,]))[[1]] + base_forecasts[[i]] = list(lambda = base_forecasts_in[i,1]) } res.buis = reconc_BUIS(S, base_forecasts, in_type = "params", distr = "poisson", num_samples = 100000,seed=42) diff --git a/tests/testthat/test-reconc_MixCond.R b/tests/testthat/test-reconc_MixCond.R new file mode 100644 index 0000000..edc95a5 --- /dev/null +++ b/tests/testthat/test-reconc_MixCond.R @@ -0,0 +1,59 @@ +test_that("reconc_MixCond simple example", { + + # Simple example with + # - 12 bottom + # - 10 upper: year, 6 bi-monthly, 3 quarterly + A <- matrix(data=c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1), + nrow=10,byrow = TRUE) + + + S <- rbind(A,diag(nrow=12)) + + # Define means and vars for the forecasts + means <- c(90,62,63,64,31,32,31,33,31,32,rep(15,12)) + vars <- c(20,8,8,8,4,4,4,4,4,4,rep(2,12))^2 + + # create the lists for reconciliation + ## upper + fc_upper <- list(mu = means[1:10], + Sigma = diag(vars[1:10])) + + ## bottom + fc_bottom <- list() + for(i in seq(ncol(S))){ + fc_bottom[[i]] <-as.integer(.distr_sample(list(mean=means[i+10],sd = vars[i+10]), "gaussian", 2e4)) + fc_bottom[[i]][which(fc_bottom[[i]]<0)] <- 0 # set-negative-to-zero + } + + + res.MixCond <- reconc_MixCond(S,fc_bottom,fc_upper,bottom_in_type = "samples",seed=42) + + bott_rec_means <- unlist(lapply(res.MixCond$bottom_reconciled$pmf,PMF.get_mean)) + bott_rec_vars <- unlist(lapply(res.MixCond$bottom_reconciled$pmf,PMF.get_var)) + + + # Create PMF from samples + fc_bottom_pmf <- list() + for(i in seq(ncol(S))){ + fc_bottom_pmf[[i]] <-PMF.from_samples(fc_bottom[[i]]) + } + + # Reconcile from bottom PMF + res.MixCond_pmf <- reconc_MixCond(S,fc_bottom_pmf,fc_upper,seed=42) + + bott_rec_means_pmf <- unlist(lapply(res.MixCond_pmf$bottom_reconciled$pmf,PMF.get_mean)) + bott_rec_vars_pmf <- unlist(lapply(res.MixCond_pmf$bottom_reconciled$pmf,PMF.get_var)) + + expect_equal(bott_rec_means,bott_rec_means_pmf,tolerance = "3e") + expect_equal(bott_rec_vars,bott_rec_vars_pmf,tolerance = "3e") + +}) diff --git a/tests/testthat/test-reconc_TDcond.R b/tests/testthat/test-reconc_TDcond.R new file mode 100644 index 0000000..2d6cb31 --- /dev/null +++ b/tests/testthat/test-reconc_TDcond.R @@ -0,0 +1,86 @@ +test_that("reconc_TDcond simple example", { + + # Simple example with + # - 12 bottom + # - 10 upper: year, 6 bi-monthly, 3 quarterly + A <- matrix(data=c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1), + nrow=10,byrow = TRUE) + + + S <- rbind(A,diag(nrow=12)) + + # Define means and vars for the forecasts + means <- c(90,31,32,31,33,31,32,62,63,64,rep(15,12)) + vars <- c(20,4,4,4,4,4,4,8,8,8,rep(2,12))^2 + + # create the lists for reconciliation + ## upper + fc_upper <- list(mu = means[1:10], + Sigma = diag(vars[1:10])) + + ## bottom + fc_bottom <- list() + for(i in seq(ncol(S))){ + fc_bottom[[i]] <-as.integer(.distr_sample(list(mean=means[i+10],sd = vars[i+10]), "gaussian", 2e4)) + fc_bottom[[i]][which(fc_bottom[[i]]<0)] <- 0 # set-negative-to-zero + } + + + # reconciliation with TDcond + res.TDcond <- reconc_TDcond(S, fc_bottom, fc_upper, + bottom_in_type = "samples", + num_samples = 2e4, return_type = "pmf", + seed = 42) + + res.TDcond2 <- reconc_TDcond(S, fc_bottom, fc_upper, + bottom_in_type = "samples", + num_samples = 2e4, return_type = "samples", + seed = 42) + + res.TDcond3 <- reconc_TDcond(S, fc_bottom, fc_upper, + bottom_in_type = "samples", + num_samples = 2e4, return_type = "all", + seed = 42) + + # Check if all return_type return identical results + expect_identical(res.TDcond$bottom_reconciled$pmf,res.TDcond3$bottom_reconciled$pmf) + expect_identical(res.TDcond2$bottom_reconciled$samples,res.TDcond3$bottom_reconciled$samples) + + # Compute the reconciliation analytically (everything Gaussian) + ## Save bottom forecast parameters + fc_bott_gauss <- list(mu = means[11:22], + Sigma = diag(vars[11:22])) + + # Compute the reconciled precision + inv_B <- diag(1/diag(fc_bott_gauss$Sigma)) + inv_U <- diag(1/diag(fc_upper$Sigma)) + At_inv_U_A <- crossprod(A,inv_U)%*%A + # Here we use the reduced A with only the lowest level + Au <- A[.lowest_lev(A),] + inv_A_B_At <- solve(Au%*%tcrossprod(fc_bott_gauss$Sigma,Au)) + + # formulas for the reconciled precision, covariance and mean + bott_reconc_Prec <- inv_B+At_inv_U_A-crossprod(Au,inv_A_B_At)%*%Au + bott_reconc_cov <- solve(bott_reconc_Prec) + bott_reconc_mean <- fc_bott_gauss$mu + tcrossprod(bott_reconc_cov,A)%*%inv_U%*%(fc_upper$mu-A%*%fc_bott_gauss$mu) + + # compute the difference between empirical and analytical + m_diff <- unlist(lapply(res.TDcond$bottom_reconciled$pmf,PMF.get_mean)) - bott_reconc_mean + + expect_true(all(abs(m_diff/bott_reconc_mean)<8e-3)) + + + # The variances are different + #unlist(lapply(res.TDcond$pmf$bottom,PMF.get_var)) + #diag(bott_reconc_cov) + +}) diff --git a/tests/testthat/test-sample_funs.R b/tests/testthat/test-sample_funs.R new file mode 100644 index 0000000..f465270 --- /dev/null +++ b/tests/testthat/test-sample_funs.R @@ -0,0 +1,131 @@ +test_that("sampling from univariate normal", { + + # Generate 1e4 samples from univariate Gaussian + params <- list(mean=42, sd=1) + distr <- "gaussian" + n <- 1e4 + samples <- .distr_sample(params, distr, n) + + # Compute empirical mean and sd + sam_mean <- mean(samples) + sam_sd <- sd(samples) + + # Check how close empirical values are to the truth + m <- abs(sam_mean-42)/42 + s <- abs(sam_sd-1) + + expect_equal(m < 2e-3, TRUE) + expect_equal(s < 4e-2, TRUE) +}) + +test_that("sampling from univariate nbinom", { + + # Generate 1e4 samples from negative binomial (size, prob) + params <- list(size=12,prob=0.8) + distr <- "nbinom" + n <- 1e4 + samples <- .distr_sample(params, distr, n) + + # Compute empirical mean + sam_mean <- mean(samples) + true_mean <- params$size*(1-params$prob)/params$prob + + # Check how close empirical values are to the truth + m <- abs(sam_mean-true_mean)/true_mean + + expect_equal(m < 3e-2, TRUE) + + # Generate 1e4 samples from negative binomial (size, mu) + params <- list(size=12,mu=true_mean) + distr <- "nbinom" + n <- 1e4 + samples <- .distr_sample(params, distr, n) + + # Compute empirical mean + sam_mean <- mean(samples) + + # Check how close empirical values are to the truth + m <- abs(sam_mean-params$mu)/params$mu + + expect_equal(m < 3e-2, TRUE) + + # Check if it returns an error when all 3 parameters are specified + params <- list(size=12,mu=true_mean,prob=0.8) + distr <- "nbinom" + n <- 1e4 + expect_error(.distr_sample(params, distr, n)) + + # Check if it returns an error when size is not specified + params <- list(mu=true_mean,prob=0.8) + distr <- "nbinom" + n <- 1e4 + expect_error(.distr_sample(params, distr, n)) + + + +}) + +test_that("sampling from univariate poisson", { + + # Generate 1e4 samples from poisson + params <- list(lambda=10) + distr <- "poisson" + n <- 1e4 + samples <- .distr_sample(params, distr, n) + + # Compute empirical mean + sam_mean <- mean(samples) + + # Check how close empirical values are to the truth + m <- abs(sam_mean-10)/10 + + expect_equal(m < 3e-2, TRUE) +}) + +test_that("sampling from multivariate normal", { + + # Generate 1e4 samples from bivariate normal + mu=c(10,10) + Sigma= matrix(c(1,0.7,0.7,1),nrow = 2) + n <- 1e4 + samples <- .MVN_sample(n, mu, Sigma) + + # Compute empirical mean + sam_mean <- colMeans(samples) + + # Check how close empirical values are to the truth + m <- abs(sam_mean-10)/10 + + expect_equal(all(m < 8e-3), TRUE) +}) + +test_that("MVN density works", { + + # Create 3x3 covariance matrix + L <- matrix(0,nrow=3,ncol=3) + L[lower.tri(L,diag=TRUE)] <- c(0.9,0.8,0.5,0.9,0.2,0.6) + Sigma <- L%*%t(L) + + # create mean vector + mu <- c(0,1,-1) + + # matrix where to evaluate the MVN + xx <- matrix(c(0,2,1, + 2,3,4, + 0.5,0.5,0.5, + 0,1,-1), ncol=3,byrow=TRUE) + + res <- .MVN_density(x=xx,mu=mu,Sigma=Sigma) + + true_val <- c(8.742644e-04, 1.375497e-11, 3.739985e-03, 1.306453e-01) + expect_equal(res,true_val,tolerance = "3e") + + # Check if block-evaluation works + xx <- matrix(runif(3*1e4),ncol=3,byrow=TRUE) + + res_chuncks <- .MVN_density(x=xx,mu=mu,Sigma=Sigma) + res_all <- .MVN_density(x=xx,mu=mu,Sigma=Sigma,max_size_x = 1e4) + + expect_equal(res_chuncks,res_all) + +}) diff --git a/tests/testthat/test-schaferStrimmer.R b/tests/testthat/test-schaferStrimmer.R index 6399bb9..19cad7e 100644 --- a/tests/testthat/test-schaferStrimmer.R +++ b/tests/testthat/test-schaferStrimmer.R @@ -11,7 +11,8 @@ test_that("Test shrinkage estimator", { # we run 100 shrinkage estimators lambdas <- rep(0, 100) for(i in seq(100)){ - rr <- replicate(nSamples, trueMean) + t(chol_trueSigma)%*%matrix(rnorm(pTrue*nSamples), nrow=pTrue,ncol=nSamples) + rr <- replicate(nSamples, trueMean) + + t(chol_trueSigma)%*%matrix(stats::rnorm(pTrue*nSamples), nrow=pTrue,ncol=nSamples) # Estimate mean and covariance from samples mean_est <- rowMeans(rr) Sigma_est <- cov(t(rr)) diff --git a/tests/testthat/test-weightswarn.R b/tests/testthat/test-weightswarn.R index 1724c77..a12e248 100644 --- a/tests/testthat/test-weightswarn.R +++ b/tests/testthat/test-weightswarn.R @@ -3,9 +3,9 @@ test_that("Test effective sample size", { # ----------- n = 200 - b1 = rpois(n=n, lambda = 3) - b2 = rpois(n=n, lambda = 4) - u = rnorm(n=n, mean = 30, sd = 1) + b1 = stats::rpois(n=n, lambda = 3) + b2 = stats::rpois(n=n, lambda = 4) + u = stats::rnorm(n=n, mean = 30, sd = 1) B = cbind(b1,b2) c = matrix(S[1,]) b = (B %*% c) @@ -23,9 +23,9 @@ test_that("Test effective sample size", { # ----------- n = 199 - b1 = rpois(n=n, lambda = 3) - b2 = rpois(n=n, lambda = 4) - u = rnorm(n=n, mean = 30, sd = 1) + b1 = stats::rpois(n=n, lambda = 3) + b2 = stats::rpois(n=n, lambda = 4) + u = stats::rnorm(n=n, mean = 30, sd = 1) B = cbind(b1,b2) c = matrix(S[1,]) b = (B %*% c) @@ -43,9 +43,9 @@ test_that("Test effective sample size", { # ----------- n = 2000 - b1 = rpois(n=n, lambda = 3) - b2 = rpois(n=n, lambda = 4) - u = rnorm(n=n, mean = 18, sd = 1) + b1 = stats::rpois(n=n, lambda = 3) + b2 = stats::rpois(n=n, lambda = 4) + u = stats::rnorm(n=n, mean = 18, sd = 1) B = cbind(b1,b2) c = matrix(S[1,]) b = (B %*% c) diff --git a/vignettes/bayesRecon.Rmd b/vignettes/bayesRecon.Rmd index 25ff595..d4ccc53 100644 --- a/vignettes/bayesRecon.Rmd +++ b/vignettes/bayesRecon.Rmd @@ -271,8 +271,8 @@ for (level in train.agg) { level.fc <- forecast(model, h = h) # save mean and sd of the gaussian predictive distribution for (i in 1:h) { - fc[[fc.idx]] <- c(level.fc$mean[[i]], - (level.fc$upper[, "95%"][[i]] - level.fc$mean[[i]]) / qnorm(0.975)) + fc[[fc.idx]] <- list(mean = level.fc$mean[[i]], + sd = (level.fc$upper[, "95%"][[i]] - level.fc$mean[[i]]) / qnorm(0.975)) fc.idx <- fc.idx + 1 } level.idx <- level.idx + 1 diff --git a/vignettes/bayesRecon_cache/html/__packages b/vignettes/bayesRecon_cache/html/__packages new file mode 100644 index 0000000..0b55a29 --- /dev/null +++ b/vignettes/bayesRecon_cache/html/__packages @@ -0,0 +1 @@ +bayesRecon diff --git a/vignettes/bayesRecon_cache/html/hier-fore_82d4e86c107d9c29f78d1bc6446b9f40.RData b/vignettes/bayesRecon_cache/html/hier-fore_82d4e86c107d9c29f78d1bc6446b9f40.RData new file mode 100644 index 0000000..7e21316 Binary files /dev/null and b/vignettes/bayesRecon_cache/html/hier-fore_82d4e86c107d9c29f78d1bc6446b9f40.RData differ diff --git a/vignettes/bayesRecon_cache/html/hier-fore_82d4e86c107d9c29f78d1bc6446b9f40.rdb b/vignettes/bayesRecon_cache/html/hier-fore_82d4e86c107d9c29f78d1bc6446b9f40.rdb new file mode 100644 index 0000000..a03f66d Binary files /dev/null and b/vignettes/bayesRecon_cache/html/hier-fore_82d4e86c107d9c29f78d1bc6446b9f40.rdb differ diff --git a/vignettes/bayesRecon_cache/html/hier-fore_82d4e86c107d9c29f78d1bc6446b9f40.rdx b/vignettes/bayesRecon_cache/html/hier-fore_82d4e86c107d9c29f78d1bc6446b9f40.rdx new file mode 100644 index 0000000..4a35338 Binary files /dev/null and b/vignettes/bayesRecon_cache/html/hier-fore_82d4e86c107d9c29f78d1bc6446b9f40.rdx differ diff --git a/vignettes/img/M5store_hier.png b/vignettes/img/M5store_hier.png new file mode 100644 index 0000000..026a1c1 Binary files /dev/null and b/vignettes/img/M5store_hier.png differ diff --git a/vignettes/mixed_reconciliation.Rmd b/vignettes/mixed_reconciliation.Rmd new file mode 100644 index 0000000..fbfbcc8 --- /dev/null +++ b/vignettes/mixed_reconciliation.Rmd @@ -0,0 +1,454 @@ +--- +title: "Reconciliation of M5 hierarchy with mixed-type forecasts" +author: "Dario Azzimonti, Lorenzo Zambon, Nicolò Rubattu, Giorgio Corani" +date: "2024-05-29" +lang: "en" +bibliography: references.bib +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Reconciliation of M5 hierarchy with mixed-type forecasts} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} +library(bayesRecon) +``` + +# Introduction + +This vignette partially reproduces the results of *Probabilistic reconciliation of mixed-type hierarchical time series* [@zambon2024mixed], +published at UAI 2024 (the 40th Conference on Uncertainty in Artificial Intelligence). + +In particular, we replicate the reconciliation of the one-step ahead (h=1) forecasts of one store of the M5 competition [@MAKRIDAKIS20221325]. +Sect. 5 of the paper presents the results for 10 stores, each reconciled +14 times using rolling one-step ahead forecasts. + + +# Data and base forecasts + +The M5 competition [@MAKRIDAKIS20221325] is about daily time series of sales data referring to 10 different stores. +Each store has the same hierarchy: 3049 bottom time series (single items) and 11 upper time series, obtained by aggregating the items by department, product category, and store; see the figure below. + +```{r out.width = '100%', echo = FALSE} +knitr::include_graphics("img/M5store_hier.png") +``` + +We reproduce the results of the store "CA_1". The base forecasts (for h=1) of the bottom and upper time series are stored in `M5_CA1_basefc`, available as data in the package. +The base forecast are computed using ADAM [@svetunkov2023iets], implemented in the R package smooth [@smooth_pkg]. + + +```{r} +# Hierarchy composed by 3060 time series: 3049 bottom and 11 upper +n_b <- 3049 +n_u <- 11 +n <- n_b + n_u + +# Load matrix A and S +A <- M5_CA1_basefc$A +S <- M5_CA1_basefc$S + +# Load base forecasts: +base_fc_upper <- M5_CA1_basefc$upper +base_fc_bottom <- M5_CA1_basefc$bottom + +# We will save all the results in the list rec_fc +rec_fc <- list( + Gauss = list(), + Mixed_cond = list(), + TD_cond = list() + ) +``` + +# Gaussian reconciliation + +We first perform Gaussian reconciliation (`Gauss`, @corani2021probabilistic). +It assumes all forecasts to be Gaussian, even though the bottom base forecasts are not Gaussian. + +We assume the upper base forecasts to be a multivariate Gaussian and we estimate their covariance matrix from the in-sample residuals. We assume also the bottom base forecasts to be independent Gaussians. + + +```{r} +# Parameters of the upper base forecast distributions +mu_u <- unlist(lapply(base_fc_upper, "[[", "mu")) # upper means +# Compute the (shrinked) covariance matrix of the residuals +residuals.upper <- lapply(base_fc_upper, "[[", "residuals") +residuals.upper <- t(do.call("rbind", residuals.upper)) +Sigma_u <- schaferStrimmer_cov(residuals.upper)$shrink_cov + +# Parameters of the bottom base forecast distributions +mu_b <- c() +sd_b <- c() +for (fc_b in base_fc_bottom) { + pmf <- fc_b$pmf + mu_b <- c(mu_b, PMF.get_mean(pmf)) + sd_b <- c(sd_b, PMF.get_var(pmf)**0.5) +} +Sigma_b <- diag(sd_b**2) + +# Mean and covariance matrix of the base forecasts +base_forecasts.mu <- c(mu_u,mu_b) +base_forecasts.Sigma <- matrix(0, nrow = n, ncol = n) +base_forecasts.Sigma[1:n_u,1:n_u] <- Sigma_u +base_forecasts.Sigma[(n_u+1):n,(n_u+1):n] <- Sigma_b +``` + +We reconcile using the function `reconc_gaussian()`, which takes as input: + +* the summing matrix `S`; +* the means of the base forecast, `base_forecasts.mu`; +* the covariance of the base forecast, `base_forecasts.Sigma`. + +The function returns the reconciled mean and covariance for the bottom time series. + +```{r} +# Gaussian reconciliation +start <- Sys.time() +gauss <- reconc_gaussian(S, base_forecasts.mu, base_forecasts.Sigma) +stop <- Sys.time() + +rec_fc$Gauss <- list(mu_b = gauss$bottom_reconciled_mean, + Sigma_b = gauss$bottom_reconciled_covariance, + mu_u = A %*% gauss$bottom_reconciled_mean, + Sigma_u = A %*% gauss$bottom_reconciled_covariance %*% t(A)) + +Gauss_time <- as.double(round(difftime(stop, start, units = "secs"), 2)) +cat("Time taken by Gaussian reconciliation: ", Gauss_time, "s") +``` + + +# Reconciliation with mixed-conditioning + +We now reconcile the forecasts using the mixed-conditioning +approach of @zambon2024mixed, Sect. 3. +The algorithm is implemented in the function `reconc_MixCond()`. The function takes as input: + +* the summing matrix `S`; +* the probability mass functions of the bottom base forecasts, stored in the list `fc_bottom_4rec`; +* the parameters of the multivariate Gaussian distribution for the upper variables, `fc_upper_4rec`; +* additional function parameters; among those note that `num_samples` specifies the number of samples used in the internal importance sampling (IS) algorithm. + +The function returns the reconciled forecasts in the form of probability mass functions for both the upper and bottom time series. The function parameter `return_type` can be changed to `samples` or `all` to obtain the IS samples. + +```{r} +seed <- 1 +N_samples_IS <- 5e4 + +# Base forecasts +fc_upper_4rec <- list(mu=mu_u, Sigma=Sigma_u) +fc_bottom_4rec <- lapply(base_fc_bottom, "[[", "pmf") # list of PMFs + +# MixCond reconciliation +start <- Sys.time() +mix_cond <- reconc_MixCond(S, fc_bottom_4rec, fc_upper_4rec, bottom_in_type = "pmf", + num_samples = N_samples_IS, return_type = "pmf", seed = seed) +stop <- Sys.time() + +rec_fc$Mixed_cond <- list( + bottom = mix_cond$bottom_reconciled$pmf, + upper = mix_cond$upper_reconciled$pmf, + ESS = mix_cond$ESS + ) + +MixCond_time <- as.double(round(difftime(stop, start, units = "secs"), 2)) +cat("Computational time for Mix-cond reconciliation: ", MixCond_time, "s") +``` + +As discussed in @zambon2024mixed, Sect. 3, conditioning with mixed variables performs poorly in high dimensions. +This is because the bottom-up distribution, built by assuming the bottom forecasts to be independent, is untenable +in high dimensions. +Moreover, forecasts for count time series are usually biased and their sum tends to be strongly biased; see @zambon2024mixed, Fig. 3, for a graphical example. + +# Top down conditioning +Top down conditioning (TD-cond; see @zambon2024mixed, Sect. 4) is a more reliable approach for reconciling mixed variables in high dimensions. +The algorithm is implemented in the function `reconc_TDcond()`; it takes the same arguments as `reconc_MixCond()` and returns reconciled forecasts in the same format. + +```{r} +N_samples_TD <- 1e4 + +# TDcond reconciliation +start <- Sys.time() +td <- reconc_TDcond(S, fc_bottom_4rec, fc_upper_4rec, + bottom_in_type = "pmf", num_samples = N_samples_TD, + return_type = "pmf", seed = seed) +stop <- Sys.time() +``` +The algorithm TD-cond raises a warning regarding the incoherence between the joint bottom-up and the upper base forecasts. +We will see that this warning does not impact the performances of TD-cond. + +```{r} +rec_fc$TD_cond <- list( + bottom = td$bottom_reconciled$pmf, + upper = td$upper_reconciled$pmf + ) + +TDCond_time <- as.double(round(difftime(stop, start, units = "secs"), 2)) +cat("Computational time for TD-cond reconciliation: ", TDCond_time, "s") +``` + + + +# Comparison + +The computational time required for the Gaussian reconciliation is `r Gauss_time` seconds, Mix-cond requires `r MixCond_time` seconds and TD-cond requires `r TDCond_time` seconds. + +For each time series in the hierarchy, we compute the following scores for each method: + +- MASE: Mean Absolute Scaled Error + +- MIS: Mean Interval Score + +- RPS: Ranked Probability Score + +```{r} +# Parameters for computing the scores +alpha <- 0.1 # MIS uses 90% coverage intervals +jitt <- 1e-9 # jitter for numerical stability + +# Save actual values +actuals_u <- unlist(lapply(base_fc_upper, "[[", "actual")) +actuals_b <- unlist(lapply(base_fc_bottom, "[[", "actual")) +actuals <- c(actuals_u, actuals_b) + +# Scaling factor for computing MASE +Q_u <- M5_CA1_basefc$Q_u +Q_b <- M5_CA1_basefc$Q_b +Q <- c(Q_u, Q_b) + +# Initialize lists to save the results +mase <- list() +mis <- list() +rps <- list() +``` + +The following functions are used for computing the scores: + +* `AE_pmf`: compute the absolute error for a PMF; +* `MIS_pmf`: compute interval score for a PMF; +* `RPS_pmf`: compute RPS for a PMF; +* `MIS_gauss`: compute MIS for a Gaussian distribution. + +The implementation of these functions is available in the source code of the vignette but not shown here. + +```{r,include=FALSE} +# Functions for computing the scores of a PMF +AE_pmf <- function(pmf, actual) { + return(abs(PMF.get_quantile(pmf,p=0.5) - actual)) +} +MIS_pmf <- function(pmf, actual, alpha) { + u <- PMF.get_quantile(pmf, p=1-(alpha/2)) + l <- PMF.get_quantile(pmf, p=alpha/2) + return(u - l + (2/alpha)*(l - actual)*(actual < l) + + (2/alpha)*(actual - u)*(actual > u) ) +} +RPS_pmf <- function(pmf, actual) { + cdf <- cumsum(pmf) / sum(pmf) + M <- length(cdf) + # if actual is outside the supp of pmf, add ones to the end of the cdf: + if (actual >= M) { + cdf <- c(cdf, rep(1, (actual-M+1))) + M <- length(cdf) + } + cdf_act <- (0:(M-1)) >= actual # unit step function in actual + crps_ <- sum((cdf - cdf_act)**2) + return(crps_) +} + +# Function for computing the MIS of (possibly truncated) Gaussian forecasts +MIS_gauss <- function(mus, sds, actuals, alpha, trunc=FALSE) { + z <- qnorm(1-(alpha/2)) + u <- mus + z * sds + l <- mus - z * sds + # If it is truncated, set negative quantiles to zero + if (trunc) { + l[l<0] <- 0 + u[u<0] <- 0 + } + return(u - l + (2/alpha)*(l - actuals)*(actuals < l) + + (2/alpha)*(actuals - u)*(actuals > u) ) +} +``` + + + + +```{r} +# Compute scores for the base forecasts +# Upper +mu_u <- unlist(lapply(base_fc_upper, "[[", "mu")) +sd_u <- unlist(lapply(base_fc_upper, "[[", "sigma")) +mase$base[1:n_u] <- abs(mu_u - actuals_u) / Q_u +mis$base[1:n_u] <- MIS_gauss(mu_u, sd_u, actuals_u, alpha) +rps$base[1:n_u] <- scoringRules::crps(actuals_u, "norm", mean=mu_u, sd=sd_u) +# Bottom +pmfs = lapply(base_fc_bottom, "[[", "pmf") +mase$base[(n_u+1):n] <- mapply(AE_pmf, pmfs, actuals_b) / Q_b +mis$base[(n_u+1):n] <- mapply(MIS_pmf, pmfs, actuals_b, MoreArgs = list(alpha=alpha)) +rps$base[(n_u+1):n] <- mapply(RPS_pmf, pmfs, actuals_b) + +# Compute scores for Gauss reconciliation +mu <- c(rec_fc$Gauss$mu_u, rec_fc$Gauss$mu_b) +sd <- c(diag(rec_fc$Gauss$Sigma_u), diag(rec_fc$Gauss$Sigma_b))**0.5 +sd <- sd + jitt +mase$Gauss <- abs(mu - actuals) / Q +mis$Gauss <- MIS_gauss(mu, sd, actuals, alpha) +rps$Gauss <- scoringRules::crps(actuals, "norm", mean=mu, sd=sd) + +# Compute scores for Mix-cond reconciliation +pmfs <- c(rec_fc$Mixed_cond$upper, rec_fc$Mixed_cond$bottom) +mase$MixCond <- mapply(AE_pmf, pmfs, actuals) / Q +mis$MixCond <- mapply(MIS_pmf, pmfs, actuals, MoreArgs = list(alpha=alpha)) +rps$MixCond <- mapply(RPS_pmf, pmfs, actuals) + +# Compute scores for TD-cond reconciliation +pmfs <- c(rec_fc$TD_cond$upper, rec_fc$TD_cond$bottom) +mase$TDcond <- mapply(AE_pmf, pmfs, actuals) / Q +mis$TDcond <- mapply(MIS_pmf, pmfs, actuals, MoreArgs = list(alpha=alpha)) +rps$TDcond <- mapply(RPS_pmf, pmfs, actuals) +``` + + +## Skill scores +We report the improvement over the base forecasts using the skill score values and averaging them across experiments. +For instance, the skill score of Gauss on RPS is: + +$$ \text{Skill}_{\%}\,(\text{RPS, }Gauss) = 100 \cdot +\frac{\text{RPS}(base) - \text{RPS}(Gauss)} +{(\text{RPS}(base) + \text{RPS}(Gauss))/2}$$ + +This formula is implemented in the function `skill.score`, available in the source code of the vignette but not shown here. + +```{r,include=FALSE} +# Function for computing the skill score +skill.score <- function(ref, met) { + s <- (2 * (ref - met) / (ref + met)) * 100 + s[is.na(s)] <- 0 # if both numerator and denominator are 0, set skill score to 0 + return(s) +} +``` + + +```{r} +scores <- list( + mase = mase, + mis = mis, + rps = rps + ) +scores_ = names(scores) + +ref_met <- "base" +methods_ <- c("Gauss", "MixCond", "TDcond") + +# For each score and method we compute the skill score with respect to the base forecasts +skill_scores <- list() +for (s in scores_) { + skill_scores[[s]] <- list() + for (met in methods_) { + skill_scores[[s]][["upper"]][[met]] <- skill.score(scores[[s]][[ref_met]][1:n_u], + scores[[s]][[met]][1:n_u]) + skill_scores[[s]][["bottom"]][[met]] <- skill.score(scores[[s]][[ref_met]][(n_u+1):n], + scores[[s]][[met]][(n_u+1):n]) + } +} +``` + +We report in the tables below the mean values for each skill score. + + +```{r} +mean_skill_scores <- list() + +for (s in scores_) { + mean_skill_scores[[s]] <- rbind(data.frame(lapply(skill_scores[[s]][["upper"]], mean)), + data.frame(lapply(skill_scores[[s]][["bottom"]], mean)) + ) + rownames(mean_skill_scores[[s]]) <- c("upper","bottom") +} +``` + +```{r} +knitr::kable(mean_skill_scores$mase,digits = 2,caption = "Mean skill score on MASE.",align = 'lccc') +``` +The mean MASE skill score is positive only for the TD-cond reconciliation. Both Mix-cond and Gauss achieve scores lower than the base forecasts, even if Mix-cond degrades less the base forecasts compared to Gauss. + +```{r} +knitr::kable(mean_skill_scores$mis,digits = 2,caption = "Mean skill score on MIS.") +``` +The mean MIS score of TD-cond is slightly above that of the base forecasts. Mix-cond achieves slightly higher scores than the base forecasts only on the bottom variables. Gauss strongly degrades the base forecasts according to this metric. + +```{r} +knitr::kable(mean_skill_scores$rps,digits = 2,caption = "Mean skill score on RPS.") +``` +The mean RPS skill score for TD-cond is positive for both upper and bottom time series. Mix-cond slightly improves the base forecasts on the bottom variables, however it degrades the upper base forecasts. Gauss strongly degrades both upper and bottom base forecasts. + +## Boxplots + +Finally, we show the boxplots of the skill scores for each method divided in upper and bottom levels. + +```{r,fig.width=7,fig.height=8} +custom_colors <- c("#a8a8e4", + "#a9c7e4", + "#aae4df") + +# Boxplots of MASE skill scores +par(mfrow = c(2, 1)) +boxplot(skill_scores$mase$upper, main = "MASE upper time series", + col = custom_colors, ylim = c(-80,80)) +abline(h=0,lty=3) +boxplot(skill_scores$mase$bottom, main = "MASE bottom time series", + col = custom_colors, ylim = c(-200,200)) +abline(h=0,lty=3) +``` +```{r,eval=TRUE,include=FALSE} +par(mfrow = c(1, 1)) +``` + +Both Mix-cond and TD-cond do not improve the bottom MASE over the base forecasts (boxplot flattened on the value zero), however TD-cond provides a slight improvement over the upper base forecasts (boxplot over the zero line). + +```{r,fig.width=7,fig.height=8} +# Boxplots of MIS skill scores +par(mfrow = c(2, 1)) +boxplot(skill_scores$mis$upper, main = "MIS upper time series", + col = custom_colors, ylim = c(-150,150)) +abline(h=0,lty=3) +boxplot(skill_scores$mis$bottom, main = "MIS bottom time series", + col = custom_colors, ylim = c(-200,200)) +abline(h=0,lty=3) +``` +```{r,eval=TRUE,include=FALSE} +par(mfrow = c(1, 1)) +``` + +Both Mix-cond and TD-cond do not improve nor degrade the bottom base forecasts in MIS score as shown by the small boxplots centered around zero. On the upper variables instead only TD-cond does not degrade the MIS score of the base forecasts. + + +```{r,fig.width=7,fig.height=8} +# Boxplots of RPS skill scores +par(mfrow = c(2,1)) +boxplot(skill_scores$rps$upper, main = "RPS upper time series", + col = custom_colors, ylim = c(-80,80)) +abline(h=0,lty=3) +boxplot(skill_scores$rps$bottom, main = "RPS bottom time series", + col = custom_colors, ylim = c(-200,200)) +abline(h=0,lty=3) +``` +```{r,eval=TRUE,include=FALSE} +par(mfrow = c(1, 1)) +``` + +According to RPS, TD-cond does not degrade the bottom base forecasts and improves the upper base forecasts. On the other hand both Gauss and Mix-cond strongly degrade the upper base forecasts. + + +# Full reproducibility + +The full experiment described in [@zambon2024mixed] can be reproduced by using the code available [here](https://github.com/LorenzoZambon/M5_MixedReconc). + +# References +
diff --git a/vignettes/reconciliation_properties.Rmd b/vignettes/reconciliation_properties.Rmd index b9c43bf..9e5f222 100644 --- a/vignettes/reconciliation_properties.Rmd +++ b/vignettes/reconciliation_properties.Rmd @@ -21,9 +21,9 @@ knitr::opts_chunk$set( # Introduction -This vignette reproduces the results of the paper *Properties of the reconciled distributions for Gaussian and count forecasts* [@zambon2023properties], +This vignette reproduces the results of the paper *Properties of the reconciled distributions for Gaussian and count forecasts* [@zambon2024properties], accepted for publication in the International Journal of Forecasting. -We replicate here the main experiment of the paper (see sec. 3, @zambon2023properties) where we reconcile base forecasts constituted by negative binomial distributions. +We replicate here the main experiment of the paper (see sec. 3, @zambon2024properties) where we reconcile base forecasts constituted by negative binomial distributions. We use the R package `BayesRecon`. @@ -109,7 +109,7 @@ for (j in 1:N) { # Base forecasts: base_fc_j <- c() for (i in 1:n) { - base_fc_j[[i]] <- c(base_fc$mu[[j,i]], base_fc$size[[i]]) + base_fc_j[[i]] <- list(size = base_fc$size[[i]], mu = base_fc$mu[[j,i]]) } # Reconcile via importance sampling: @@ -214,8 +214,8 @@ N_samples <- 1e5 ### Example of concordant-shift effect j <- 124 base_fc_j <- c() -for (i in 1:n) base_fc_j[[i]] <- c(extr_mkt_events_basefc$mu[[j,i]], - extr_mkt_events_basefc$size[[i]]) +for (i in 1:n) base_fc_j[[i]] <- list(size = extr_mkt_events_basefc$size[[i]], + mu = extr_mkt_events_basefc$mu[[j,i]]) # Reconcile buis <- reconc_BUIS(S, base_fc_j, "params", "nbinom", num_samples = N_samples, seed = 42) @@ -231,8 +231,8 @@ knitr::kable(matrix(means, nrow=1), col.names = col_names) ### Example of combination effect j <- 1700 base_fc_j <- c() -for (i in 1:n) base_fc_j[[i]] <- c(extr_mkt_events_basefc$mu[[j,i]], - extr_mkt_events_basefc$size[[i]]) +for (i in 1:n) base_fc_j[[i]] <- list(size = extr_mkt_events_basefc$size[[i]], + mu = extr_mkt_events_basefc$mu[[j,i]]) # Reconcile buis <- reconc_BUIS(S, base_fc_j, "params", "nbinom", num_samples = N_samples, seed = 42) @@ -254,8 +254,8 @@ variance is always smaller than the base variance. ```{r} j <- 2308 base_fc_j <- c() -for (i in 1:n) base_fc_j[[i]] <- c(extr_mkt_events_basefc$mu[[j,i]], - extr_mkt_events_basefc$size[[i]]) +for (i in 1:n) base_fc_j[[i]] <- list(size = extr_mkt_events_basefc$size[[i]], + mu = extr_mkt_events_basefc$mu[[j,i]]) # Reconcile buis <- reconc_BUIS(S, base_fc_j, "params", "nbinom", num_samples = N_samples, seed = 42) samples_y <- buis$reconciled_samples diff --git a/vignettes/references.bib b/vignettes/references.bib index 3afd588..9aa27e4 100644 --- a/vignettes/references.bib +++ b/vignettes/references.bib @@ -130,7 +130,8 @@ @InProceedings{corani2021probabilistic booktitle="Machine Learning and Knowledge Discovery in Databases", year="2021", publisher="Springer International Publishing", - pages="211--226" + pages="211--226", + doi="10.1007/978-3-030-67664-3_13" } @article{zambon2022efficient, @@ -148,15 +149,12 @@ @article{zambon2022efficient -@article{zambon2023properties, - title={Properties of the reconciled distributions for Gaussian and count forecasts}, - author={Zambon, Lorenzo and Agosto, Arianna and Giudici, Paolo and Corani, Giorgio}, - journal={arXiv preprint arXiv:2303.15135}, - year={2023}, - eprint={2303.15135}, - archivePrefix={arXiv}, - primaryClass={stat.AP}, - doi={10.48550/arXiv.2303.15135} +@article{zambon2024properties, +title = {Properties of the reconciled distributions for Gaussian and count forecasts}, +journal = {International Journal of Forecasting}, +year = {2024}, +issn = {0169-2070}, +author = {Lorenzo Zambon and Arianna Agosto and Paolo Giudici and Giorgio Corani} } @@ -164,7 +162,12 @@ @article{corani2023probabilistic title={Probabilistic reconciliation of count time series}, author={Corani, Giorgio and Azzimonti, Dario and Rubattu, Nicol{\`o}}, journal={International Journal of Forecasting}, - year={2023}, + volume = {40}, + number = {2}, + pages = {457-469}, + year = {2024}, + issn = {0169-2070}, + doi = {https://doi.org/10.1016/j.ijforecast.2023.04.003}, publisher={Elsevier} } @@ -185,3 +188,41 @@ @article{agosto2022multivariate year={2022} } +@inproceedings{zambon2024mixed, + title={Probabilistic reconciliation of mixed-type hierarchical time series}, + author={Zambon, Lorenzo and Azzimonti, Dario and Rubattu, Nicolò and Corani, Giorgio}, + booktitle={The 40th Conference on Uncertainty in Artificial Intelligence}, + year={2024} +} + +@article{MAKRIDAKIS20221325, + title = {{The M5 competition: Background, organization, and implementation}}, + journal = {International Journal of Forecasting}, + volume = {38}, + number = {4}, + pages = {1325-1336}, + year = {2022}, + author = {Spyros Makridakis and Evangelos Spiliotis and Vassilios Assimakopoulos}, + keywords = {Forecasting competitions, M competitions, Accuracy, Uncertainty, Time series, Retail sales forecasting}, + doi = {10.1016/j.ijforecast.2021.07.007} +} + +@article{svetunkov2023iets, + title={{iETS: State space model for intermittent demand forecasting}}, + author={Svetunkov, Ivan and Boylan, John E}, + journal={International Journal of Production Economics}, + volume={265}, + pages={109013}, + year={2023}, + publisher={Elsevier}, + doi={10.1016/j.ijpe.2023.109013} +} + + +@Manual{smooth_pkg, + title = {smooth: Forecasting Using State Space Models}, + author = {Ivan Svetunkov}, + year = {2023}, + note = {R package version 4.0.0}, + url = {https://cran.r-project.org/package=smooth}, +}