/*
 * Copyright (C) 1996-2011 Daniel Waggoner and Tao Zha
 *
 * This free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * It is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * If you did not received a copy of the GNU General Public License
 * with this software, see <http://www.gnu.org/licenses/>.
 */

#include "dw_switch.h"
#include "dw_switchio.h"
#include "dw_histogram.h"
#include "VARio.h"
#include "VARbase.h"
#include "dw_sbvar_command_line.h"
#include "dw_parse_cmd.h"
#include "dw_ascii.h"
#include "dw_error.h"
#include "dw_math.h"
#include "dw_std.h"
#include "sbvar_impulse_responses.h"

#include <stdlib.h>
#include <string.h>
#include <math.h>

/*
   Assumes
     vd    : horizon x nvar*nvar matrix
     S     : integer array of length horizon
     A0_Xi : nvar x nvar matrix equal to A0[S[0]]*Xi[S[0]]
     B     : h dimensional array of nvar x nvar*nlags matrices or null pointer.
             See GetIRMatrices() for a description of B.  A null pointer implies
             that nlags is zero.

   Notes:
     The element in position (k,i+j*nvars) of vd is the cummulative contributions
     to the total variance of ith variable to the jth shock at horizon k. Horizon 
     zero is the contemporaneous contribution.
*/
void variance_decomposition(TMatrix vd, int *S, TMatrix A0_Xi, TMatrix* B)
{
  int horizon=RowM(vd), t, j;
  PRECISION tmp;

  impulse_response(vd,S,A0_Xi,B);

  for (j=ColM(vd)-1; j >= 0; j--)
    ElementM(vd,0,j)*=ElementM(vd,0,j);

  for (t=1; t < horizon; t++)
    for (j=ColM(vd)-1; j >= 0; j--)
      {
	tmp=ElementM(vd,t,j);
	ElementM(vd,t,j)=tmp*tmp+ElementM(vd,t-1,j);
      }
}



/*
   Normalizes variance decomposition.  Converts cummulative contributions to the 
   total variance into cummulative percentage contributions.  This routine must 
   be called before ReorderVarianceDecomposition().
*/
void NormalizeVarianceDecomposition(TMatrix vd, T_VAR_Parameters *p)
{
  PRECISION tmp;
  int n=p->nvars, i, j, t;

  // normalizes to percentages
  for (t=RowM(vd)-1; t >= 0; t--)
    for (i=0; i < n; i++)
      {
	for (tmp=0.0, j=0; j < n; j++) tmp+=ElementM(vd,t,j*n+i);
	for (tmp=1.0/tmp, j=0; j < n; j++) ElementM(vd,t,j*n+i)*=tmp;
      }
}

/*
   Reorders variance decomposition.  Reorders the matrix so that the element in 
   position (k,i+j*nvars) of tvd is moved to position (k,j+i*nvars).  If called 
   after NormalizeVarianceDecomposition(), the element in position (k,j_i*vnars) 
   is the cummulative percentage contributions to the total variance of ith 
   variable to the jth shock at horizon k.
*/
void ReorderVarianceDecomposition(TMatrix vd, T_VAR_Parameters *p)
{
  PRECISION tmp;
  int n=p->nvars, i, j, t;

  // reorders columns
  for (t=RowM(vd)-1; t >= 0; t--)
    for (i=0; i < n; i++)
      for (j=i+1; j < n; j++)
	{
	  tmp=ElementM(vd,t,i*n+j);
	  ElementM(vd,t,i*n+j)=ElementM(vd,t,j*n+i);
	  ElementM(vd,t,j*n+i)=tmp;
	}
}

/*
   Assumes
    draws : number of draws of the regime path to make for each posterior draw
    posterior_file : FILE pointer to file containing posterior draws.  If null, 
                     current parameters are used.
    thin : thinning factor to use if posterior_file is not null.
    horizon : non-negative integer
    ergodic : if non-zero, uses the ergodic distribution to draw the initial 
              regime, otherwise uses the filtered probabilities at time nobs.
    model : point to valid TStateModel structure
    flag : determines the type of posterior draws file passed.

   Results:
    Creates matrix containing the mean variance decompositions.

   Returns:
    Pointer to matrix upon success and null pointer on failure.

  Notes:
     The element in position (k,i+j*nvars) of tvd is the cummulative contributions
     to the total variance of ith variable to the jth shock at horizon k. Horizon 
     zero is the contemporaneous contribution.
*/
TMatrix variance_decomposition_mean(int draws, FILE *posterior_file, int thin, int ergodic, int horizon, TStateModel *model, int flag)
{
  T_VAR_Parameters *p;
  int done=0, *S, i, j, k, m, n=1000, T=model->nobs, count=0;
  TMatrix vd, tvd, *A0_Xi, *B;
  TVector init_prob, prob;

 // quick check of passed parameters
  if ((horizon <= 0) || !model) return 0;

  p=(T_VAR_Parameters*)(model->theta);

  // allocate memory
  S=(int*)dw_malloc(horizon*sizeof(int));
  vd=CreateMatrix(horizon,p->nvars*p->nvars);
  InitializeMatrix(tvd=CreateMatrix(horizon,p->nvars*p->nvars),0.0);
  A0_Xi=dw_CreateArray_matrix(model->sv->nstates);
  B=dw_CreateArray_matrix(model->sv->nstates);
  for (i=model->sv->nstates-1; i >= 0; i--)
    {
      A0_Xi[i]=CreateMatrix(p->nvars,p->nvars);
      B[i]=CreateMatrix(p->nvars*p->nlags,p->nvars);
    }
  init_prob=CreateVector(p->nstates);
  prob=CreateVector(p->nstates);

  i=0;
  while (!done)
    {
      // Read parameters and push them into model
      if (!posterior_file)
	done=1;
      else
	{
	  dw_NextLine(posterior_file,thin-1);
	  if (!GetPosteriorDraw(posterior_file,model,flag))
	    {
	      done=2;
	      printf("total posterior draws processed - %d\n",i);
	    }
	  else
	    if (i++ == n)
	      {
		printf("%d posterior draws processed\n",i);
		n+=1000;
	      }
	}

      if (done != 2)
	{
	  // Compute A0_Xi and B
	  GetIRMatrices(model->sv->nstates,A0_Xi,B,p);

	  // Use ergodic initial probability or filtered probability at time T
	  if (ergodic)
	    Ergodic(init_prob,model->sv->Q);
	  else
	    for (j=p->nstates-1; j >= 0; j--)
	      ElementV(init_prob,j)=ProbabilityStateConditionalCurrent(j,T,model);

	  for (k=draws; k > 0; k--)
	    {
	      // Draw time T regime
	      m=DrawDiscrete(init_prob);
              
	      // Draw regimes from time T+1 through T+h inclusive
	      for (j=0; j < horizon; j++)
		{
		  ColumnVector(prob,model->sv->Q,m);
		  S[j]=m=DrawDiscrete(prob);
		}

	      // Compute variance decomposition contributions
	      variance_decomposition(vd,S,A0_Xi[S[0]],B);

	      // Accumulate variance decomposition contributions
	      AddMM(tvd,tvd,vd);

	      count++;
	    }
	}
    }

  FreeMatrix(vd);
  dw_free(S);
  dw_FreeArray(A0_Xi);
  dw_FreeArray(B);
  FreeVector(prob);
  FreeVector(init_prob);

  ProductMS(tvd,tvd,1.0/(PRECISION)count);
  return tvd;
}

/*
   Assumes
    posterior_file : FILE pointer to file containing posterior draws.  If null, 
                     current parameters are used.
    thin : thinning factor to use if posterior_file is not null.
    s : fixed regime
    horizon : non-negative integer
    model : point to valid TStateModel structure
    flag : determines the type of posterior draws file passed.

   Results:
    Creates matrix containing the mean variance decompositions.

   Returns:
    Pointer to matrix upon success and null pointer on failure.

  Notes:
     The element in position (k,i+j*nvars) of tvd is the cummulative contributions
     to the total variance of ith variable to the jth shock at horizon k. Horizon 
     zero is the contemporaneous contribution.
*/
TMatrix variance_decomposition_mean_regime(FILE *posterior_file, int thin, int s, int horizon, TStateModel *model, int flag)
{
  T_VAR_Parameters *p;
  int done=0, *S, i, n=1000, count=0;
  TMatrix tvd, vd, *A0_Xi, *B;

 // quick check of passed parameters
  if ((horizon <= 0) || !model) return 0;

  p=(T_VAR_Parameters*)(model->theta);

  // allocate memory
  S=(int*)dw_malloc(horizon*sizeof(int));
  for (i=0; i < horizon; i++) S[i]=s;
  vd=CreateMatrix(horizon,p->nvars*p->nvars);
  InitializeMatrix(tvd=CreateMatrix(horizon,p->nvars*p->nvars),0.0);
  A0_Xi=dw_CreateArray_matrix(model->sv->nstates);
  B=dw_CreateArray_matrix(model->sv->nstates);
  for (i=model->sv->nstates-1; i >= 0; i--)
    {
      A0_Xi[i]=CreateMatrix(p->nvars,p->nvars);
      B[i]=CreateMatrix(p->nvars*p->nlags,p->nvars);
    }

  i=0;
  while (!done)
    {
      // Read parameters and push them into model
      if (!posterior_file)
	done=1;
      else
	{
	  dw_NextLine(posterior_file,thin-1);
	  if (!GetPosteriorDraw(posterior_file,model,flag))
	    {
	      done=2;
	      printf("total posterior draws processed - %d\n",i);
	    }
	  else
	    if (i++ == n)
	      {
		printf("%d posterior draws processed\n",i);
		n+=1000;
	      }
	}

      if (done != 2)
	{
	  // Compute A0_Xi and B
	  GetIRMatrices(model->sv->nstates,A0_Xi,B,p);

	  // Compute variance decomposition contributions
	  variance_decomposition(vd,S,A0_Xi[s],B);

	  // Accumulate variance decomposition contributions
	  AddMM(tvd,tvd,vd);

	  count++;
	}
    }

  FreeMatrix(vd);
  dw_free(S);
  dw_FreeArray(A0_Xi);
  dw_FreeArray(B);

  ProductMS(tvd,tvd,1.0/(PRECISION)count);
  return tvd;
}

/*
   Assumes
    draws : number of draws of the regime path to make for each posterior draw
    posterior_file : FILE pointer to file containing posterior draws.  If null, 
                     current parameters are used.
    thin : thinning factor to use if posterior_file is not null.
    horizon : non-negative integer
    ergodic : if non-zero, uses the ergodic distribution to draw the initial 
              regime, otherwise uses the filtered probabilities at time nobs.
    model : point to valid TStateModel structure
    flag : determines the type of posterior draws file passed.

   Results:
    Creates matrix histogram containing the cummulative percentage contributions 
    to the total variance.

   Returns:
    Pointer to histogram upon success and null pointer on failure.

   Notes:
     The element in position (k,i+j*nvars) is the cummulative contribution to the
     total variance of ith variable to the jth shock at horizon k. Horizon zero
     is the contemporaneous contribution.
*/
TMatrixHistogram *variance_decomposition_percentiles(int draws, FILE *posterior_file, int thin, int ergodic, int horizon, TStateModel *model, int flag)
{
  T_VAR_Parameters *p;
  int done=0, *S, i, j, k, m, n=1000, T=model->nobs;
  TMatrix vd, *A0_Xi, *B;
  TVector init_prob, prob;
  TMatrixHistogram *histogram;

 // quick check of passed parameters
  if ((horizon <= 0) || !model) return (TMatrixHistogram*)NULL;

  p=(T_VAR_Parameters*)(model->theta);

  // allocate memory
  S=(int*)dw_malloc(horizon*sizeof(int));
  vd=CreateMatrix(horizon,p->nvars*p->nvars);
  histogram=CreateMatrixHistogram(horizon,p->nvars*p->nvars,100,HISTOGRAM_VARIABLE);
  A0_Xi=dw_CreateArray_matrix(model->sv->nstates);
  B=dw_CreateArray_matrix(model->sv->nstates);
  for (i=model->sv->nstates-1; i >= 0; i--)
    {
      A0_Xi[i]=CreateMatrix(p->nvars,p->nvars);
      B[i]=CreateMatrix(p->nvars*p->nlags,p->nvars);
    }
  init_prob=CreateVector(p->nstates);
  prob=CreateVector(p->nstates);

  i=0;
  while (!done)
    {
      // Read parameters and push them into model
      if (!posterior_file)
	done=1;
      else
	{
	  dw_NextLine(posterior_file,thin-1);
	  if (!GetPosteriorDraw(posterior_file,model,flag))
	    {
	      done=2;
	      printf("total posterior draws processed - %d\n",i);
	    }
	  else
	    if (i++ == n)
	      {
		printf("%d posterior draws processed\n",i);
		n+=1000;
	      }
	}

      if (done != 2)
	{
	  // Compute A0_Xi and B
	  GetIRMatrices(model->sv->nstates,A0_Xi,B,p);

	  // Use ergodic initial probability or filtered probability at time T
	  if (ergodic)
	    Ergodic(init_prob,model->sv->Q);
	  else
	    for (j=p->nstates-1; j >= 0; j--)
	      ElementV(init_prob,j)=ProbabilityStateConditionalCurrent(j,T,model);

	  for (k=draws; k > 0; k--)
	    {
	      // Draw time T regime
	      m=DrawDiscrete(init_prob);
              
	      // Draw regimes from time T+1 through T+h inclusive
	      for (j=0; j < horizon; j++)
		{
		  ColumnVector(prob,model->sv->Q,m);
		  S[j]=m=DrawDiscrete(prob);
		}

	      // Compute variance decomposition contributions
	      variance_decomposition(vd,S,A0_Xi[S[0]],B);

	      // Convert to percentages
	      NormalizeVarianceDecomposition(vd,p);

	      // Accumulate variance decomposition percentages
	      AddMatrixObservation(vd,histogram);
	    }
	}
    }

  FreeMatrix(vd);
  dw_free(S);
  dw_FreeArray(A0_Xi);
  dw_FreeArray(B);
  FreeVector(prob);
  FreeVector(init_prob);

  return histogram;
}

/*
   Assumes
    posterior_file : FILE pointer to file containing posterior draws.  If null, 
                     current parameters are used.
    thin : thinning factor to use if posterior_file is not null.
    s : fixed regime
    horizon : non-negative integer
    model : point to valid TStateModel structure
    flag : determines the type of posterior draws file passed.

   Results:
    Creates matrix histogram containing the cummulative percentage contributions 
    to the total variance.

   Returns:
    Pointer to histogram upon success and null pointer on failure.

   Notes:
     The element in position (k,i+j*nvars) is the cummulative contribution to the
     total variance of ith variable to the jth shock at horizon k. Horizon zero
     is the contemporaneous contribution.
*/
TMatrixHistogram *variance_decomposition_percentiles_regime(FILE *posterior_file, int thin, int s, int horizon, TStateModel *model, int flag)
{
  T_VAR_Parameters *p;
  int done=0, *S, i, n=1000;
  TMatrix vd, *A0_Xi, *B;
  TMatrixHistogram *histogram;

 // quick check of passed parameters
  if ((horizon <= 0) || !model) return 0;

  p=(T_VAR_Parameters*)(model->theta);

  // allocate memory
  S=(int*)dw_malloc(horizon*sizeof(int));
  for (i=0; i < horizon; i++) S[i]=s;
  vd=CreateMatrix(horizon,p->nvars*p->nvars);
  histogram=CreateMatrixHistogram(horizon,p->nvars*p->nvars,100,HISTOGRAM_VARIABLE);
  A0_Xi=dw_CreateArray_matrix(model->sv->nstates);
  B=dw_CreateArray_matrix(model->sv->nstates);
  for (i=model->sv->nstates-1; i >= 0; i--)
    {
      A0_Xi[i]=CreateMatrix(p->nvars,p->nvars);
      B[i]=CreateMatrix(p->nvars*p->nlags,p->nvars);
    }

  i=0;
  while (!done)
    {
      // Read parameters and push them into model
      if (!posterior_file)
	done=1;
      else
	{
	  dw_NextLine(posterior_file,thin-1);
	  if (!GetPosteriorDraw(posterior_file,model,flag))
	    {
	      done=2;
	      printf("total posterior draws processed - %d\n",i);
	    }
	  else
	    if (i++ == n)
	      {
		printf("%d posterior draws processed\n",i);
		n+=1000;
	      }
	}

      if (done != 2)
	{
	  // Compute A0_Xi and B
	  GetIRMatrices(model->sv->nstates,A0_Xi,B,p);

	  // Compute variance decomposition contributions
	  variance_decomposition(vd,S,A0_Xi[S[0]],B);

	  // Convert to percentages
	  NormalizeVarianceDecomposition(vd,p);

	  // Accumulate variance decomposition percentages
	  AddMatrixObservation(vd,histogram);
	}
    }

  FreeMatrix(vd);
  dw_free(S);
  dw_FreeArray(A0_Xi);
  dw_FreeArray(B);

  return histogram;
}



/*
  Additional command line parameters

   -horrizon <integer>
      If this argument exists, then the forecast horizon is given by the passed 
      integer.  The default value is 12.

   -filtered
      Uses filtered probabilities at the end of the sample as initial conditions 
      for regime probabilities.  The default behavior is to us the erogdic 
      distribution for the initial conditions.  This flag only applies if neither 
      -regimes nor -regime is specified. 

   -parameter_uncertainty 
      Apply parameter uncertainty.

   -shocks_per_parameter <integer> 
      Number of regime paths to draw for each parameter draw.  The default value 
      is 1 if parameter_uncertainty is set and 10,000 otherwise.

   -error_bands 
      Output percentile error bands.  (default = off - mean is computed)

   -percentiles n p_1 p_2 ... p_n
      Percentiles to compute. The first parameter after percentiles must be the 
      number of percentiles and the following values are the actual percentiles. 
      (default = 3  0.16  0.50  0.84 - only meaningful if -error_bands is set)
     
   -thin 
      Thinning factor.  Only 1/thin of the draws in posterior draws file are 
      used. The default value is 1.

   -regimes 
      Produces forecasts as if each regime were permanent. (default = off)

   -regime <integer>
      Produces forecasts as if the given regime were permanent.  Regime numbers 
      are zero based.  (default = off)

   -flat
      Assumes that posterior draws is a flat file format.  The default is that 
      the posterior draws are in a free file format.  

*/
void dw_sbvar_variance_decomposition_command_line(int nargs, char **args)
{
  char *post=(char*)NULL, *out_filename, *fmt="%%svar_decomp_mean_regime_%d_%%s.out", *buffer;
  TStateModel *model;
  T_VAR_Parameters *p;
  int ergodic, type, s, horizon, thin, draws, i, j, n;
  FILE *f_out, *posterior_file=(FILE*)NULL;
  TMatrix tvd;
  TVector percentiles=(TVector)NULL;
  TMatrixHistogram *histogram;

  TVARCommandLine *cmd=(TVARCommandLine*)NULL;

  // Setup model and initial parameters
  if (!(cmd=CreateTStateModel_VARCommandLine(nargs,args,(TVARCommandLine*)NULL)))
    dw_Error(MEM_ERR);
  else
    if (!cmd->model)
      dw_UserError("Unable to setup SBVAR from command line parameters");
    else
      if (!cmd->parameters_filename_actual)
	dw_UserError("Unable to initialize parameters from command line parameters");
      else
	{
	  model=cmd->model;
	  p=(T_VAR_Parameters*)(model->theta);

	  // horizon
	  horizon=dw_ParseInteger_String(nargs,args,"horizon",12);

	  // Output tag
	  OutTag_VARCommandLine(cmd);

	  // Type
	  type=(dw_FindArgument_String(nargs,args,"flat") >= 0) ? F_FLAT : F_FREE;

	  // Ergodic distribution for initial value of shocks
	  ergodic=(dw_FindArgument_String(nargs,args,"filtered") >= 0) ? 0 : 1;

	  // Error bands and percentiles
	  if ((i=dw_FindArgument_String(nargs,args,"percentiles")) != -1)
	    {
	      if ((i+1 < nargs) && dw_IsInteger(args[i+1]) && ((n=atoi(args[i+1])) > 0) && (i+1+n < nargs))
		{
		  percentiles=CreateVector(n);
		  for (j=0; j < n; j++)
		    if (!dw_IsFloat(args[i+2+j])|| ((ElementV(percentiles,j)=atof(args[i+2+j])) <= 0.0) || (ElementV(percentiles,j) >= 1.0)) 
		      break;
		  if (j < n)
		    {
		      dw_UserError("sbvar_variance_decomposition_command_line():  Error parsing percentiles\n");
		      goto ERROR_EXIT;
		    }
		}
	      else
		{
		  dw_UserError("sbvar_variance_decomposition_command_line():  Error parsing percentiles\n");
		  goto ERROR_EXIT;
		}
	    }
	  else
	    if (dw_FindArgument_String(nargs,args,"error_bands") != -1)
	      {
		percentiles=CreateVector(3);
		ElementV(percentiles,0)=0.16; ElementV(percentiles,1)=0.5; ElementV(percentiles,2)=0.84;
	      }

	  // Parameter uncertainty
	  if (dw_FindArgument_String(nargs,args,"parameter_uncertainty") != -1)
	    {
	      // Open posterior draws file
	      post=CreateFilenameFromTag((type == F_FREE) ? "%ssimulation_%s.out" : "%sdraws_%s.out",cmd->in_tag ? cmd->in_tag : "notag",cmd->in_directory);
	      if (!(posterior_file=fopen(post,"rt")))
		{	  
		  printf("dw_sbvar_variance_decomposition_command line(): Unable to open posterior draws file: %s\n",post);
		  goto ERROR_EXIT;
		}

	      // Get thinning factor from command line
	      thin=dw_ParseInteger_String(nargs,args,"thin",1);
	      if (thin <= 0) thin=1;

	      // Get shocks_per_parameter from command line
	      draws=dw_ParseInteger_String(nargs,args,"shocks_per_parameter",1);
	    }
	  else
	    {
	      // thinning factor not used
	      thin=1;

	      // Get shocks_per_parameter from command line
	      draws=dw_ParseInteger_String(nargs,args,"shocks_per_parameter",10000);
	    }

	  fmt=percentiles ? "%%svar_decomp_percentiles_regime_%d_%%s.out" : "%%svar_decomp_mean_regime_%d_%%s.out";
	  if (dw_FindArgument_String(nargs,args,"regimes") != -1)
	    for (s=0; s < p->nstates; s++)
	      {
		if (posterior_file) rewind(posterior_file);
		// s must not contain more than 10 digits 
		sprintf(buffer=(char*)dw_malloc(strlen(fmt) + 10),fmt,s);
		out_filename=CreateFilenameFromTag(buffer,cmd->out_tag,cmd->out_directory);
		dw_free(buffer);
		if (f_out=fopen(out_filename,"wt"))
		  {		
		    printf("Constructing variance decomposition - regime %d\n",s);
		    if (percentiles)
		      {
			if (histogram=variance_decomposition_percentiles_regime(posterior_file,thin,s,horizon,model,type))
			  {
			    tvd=CreateMatrix(horizon,p->nvars*p->nvars);
			    for (i=0; i < DimV(percentiles); i++)
			      {
				MatrixPercentile(tvd,ElementV(percentiles,i),histogram);
				ReorderVarianceDecomposition(tvd,p);
				dw_PrintMatrix(f_out,tvd,"%lg ");
				fprintf(f_out,"\n");
			      }
			    FreeMatrix(tvd);
			    FreeMatrixHistogram(histogram);
			  }
		      }
		    else
		      {
			if (tvd=variance_decomposition_mean_regime(posterior_file,thin,s,horizon,model,type))
			  {
			    NormalizeVarianceDecomposition(tvd,p);
			    ReorderVarianceDecomposition(tvd,p);
			    dw_PrintMatrix(f_out,tvd,"%lg ");
			    FreeMatrix(tvd);
			  }
		      }
		    fclose(f_out);
		  }
		dw_free(out_filename);
	      }
	  else
	    if (dw_FindArgument_String(nargs,args,"regime") != -1)
	      if (((s=dw_ParseInteger_String(nargs,args,"regime",-1)) >= 0) && (s < p->nstates))
		{
		  // s must not contain more than 10 digits 
		  sprintf(buffer=(char*)dw_malloc(strlen(fmt) + 10),fmt,s);
		  out_filename=CreateFilenameFromTag(buffer,cmd->out_tag,cmd->out_directory);
		  dw_free(buffer);
		  if (f_out=fopen(out_filename,"wt"))
		    {		
		      printf("Constructing variance decomposition - regime %d\n",s);
		      if (percentiles)
			{
			  if (histogram=variance_decomposition_percentiles_regime(posterior_file,thin,s,horizon,model,type))
			    {
			      tvd=CreateMatrix(horizon,p->nvars*p->nvars);
			      for (i=0; i < DimV(percentiles); i++)
				{
				  MatrixPercentile(tvd,ElementV(percentiles,i),histogram);
				  ReorderVarianceDecomposition(tvd,p);
				  dw_PrintMatrix(f_out,tvd,"%lg ");
				  fprintf(f_out,"\n");
				}
			      FreeMatrix(tvd);
			      FreeMatrixHistogram(histogram);
			    }
			}
		      else
			{
			  if (tvd=variance_decomposition_mean_regime(posterior_file,thin,s,horizon,model,type))
			    {
			      NormalizeVarianceDecomposition(tvd,p);
			      ReorderVarianceDecomposition(tvd,p);
			      dw_PrintMatrix(f_out,tvd,"%lg ");
			      FreeMatrix(tvd);
			    }
			}
		      fclose(f_out);
		    }
		  dw_free(out_filename);
		}
	      else
		{
		  printf("dw_sbvar_variance_decomposition_command line(): regime number must be between 0 and %d inclusive\n",p->nstates-1);
		  return;
		}
	    else
	      { 
		if (percentiles)
		  if (ergodic)
		    fmt="%svar_decomp_percentiles_ergodic_%s.out";
		  else
		    fmt="%svar_decomp_percentiles_filtered_%s.out";
		else
		  if (ergodic)
		    fmt="%svar_decomp_mean_ergodic_%s.out";
		  else
		    fmt="%svar_decomp_mean_filtered_%s.out";
		out_filename=CreateFilenameFromTag(fmt,cmd->out_tag,cmd->out_directory);
		if (f_out=fopen(out_filename,"wt"))
		  {
		    printf("Constructing variance decomposition - %d draws of regimes per posterior value\n",draws);
		    if (percentiles)
		      {
			if (histogram=variance_decomposition_percentiles(draws,posterior_file,thin,ergodic,horizon,model,type))
			  {
			    tvd=CreateMatrix(horizon,p->nvars*p->nvars);
			    for (i=0; i < DimV(percentiles); i++)
			      {
				MatrixPercentile(tvd,ElementV(percentiles,i),histogram);
				ReorderVarianceDecomposition(tvd,p);
				dw_PrintMatrix(f_out,tvd,"%lg ");
				fprintf(f_out,"\n");
			      }
			    FreeMatrix(tvd);
			    FreeMatrixHistogram(histogram);
			  }
		      }
		    else
		      {
			if (tvd=variance_decomposition_mean(draws,posterior_file,thin,ergodic,horizon,model,type))
			  {
			    NormalizeVarianceDecomposition(tvd,p);
			    ReorderVarianceDecomposition(tvd,p);
			    dw_PrintMatrix(f_out,tvd,"%lg ");
			    FreeMatrix(tvd);
			  }
		      }
		    fclose(f_out);
		  }
		dw_free(out_filename);
	      }
	}

 ERROR_EXIT:
  if (post) dw_free(post);
  if (posterior_file) fclose(posterior_file);
  Free_VARCommandLine(cmd);
}
