com.meliorbis.economics.infrastructure.AbstractModel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ModelSolver Show documentation
Show all versions of ModelSolver Show documentation
A library for solving economic models, particularly
macroeconomic models with heterogeneous agents who have model-consistent
expectations
/**
*
*/
package com.meliorbis.economics.infrastructure;
import static com.meliorbis.numerics.DoubleArrayFactories.createArrayOfSize;
import static com.meliorbis.numerics.generic.primitives.impl.Interpolation.interp;
import static com.meliorbis.numerics.generic.primitives.impl.Interpolation.interpolateFunction;
import static com.meliorbis.numerics.generic.primitives.impl.Interpolation.spec;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.NotImplementedException;
import com.meliorbis.economics.aggregate.AggregateProblemSolver;
import com.meliorbis.economics.individual.IndividualProblemSolver;
import com.meliorbis.economics.infrastructure.notifications.ArrayObserver;
import com.meliorbis.economics.infrastructure.notifications.Notifier;
import com.meliorbis.economics.infrastructure.simulation.DiscretisedDistribution;
import com.meliorbis.economics.infrastructure.simulation.DiscretisedDistributionSimulatorImpl;
import com.meliorbis.economics.infrastructure.simulation.SimState;
import com.meliorbis.economics.model.AggregateFixedPointState;
import com.meliorbis.economics.model.Model;
import com.meliorbis.economics.model.ModelConfig;
import com.meliorbis.economics.model.ModelException;
import com.meliorbis.economics.model.State;
import com.meliorbis.economics.model.StateWithControls;
import com.meliorbis.numerics.fixedpoint.FixedPointValueDelegate;
import com.meliorbis.numerics.function.primitives.DoubleRectangularGridDomain;
import com.meliorbis.numerics.generic.MultiDimensionalArray;
import com.meliorbis.numerics.generic.impl.IndexedReduction;
import com.meliorbis.numerics.generic.impl.IntegerArray;
import com.meliorbis.numerics.generic.primitives.DoubleArray;
import com.meliorbis.numerics.generic.primitives.DoubleSubspaceSplitIterator;
import com.meliorbis.numerics.generic.primitives.impl.Interpolation.Params;
import com.meliorbis.numerics.generic.primitives.impl.Interpolation.Specification;
import com.meliorbis.numerics.index.IndexIterator;
import com.meliorbis.numerics.index.impl.Index;
import com.meliorbis.numerics.io.NumericsReader;
import com.meliorbis.numerics.io.NumericsWriter;
import com.meliorbis.numerics.threading.ComputableRecursiveAction;
import com.meliorbis.utils.Utils;
/**
* An abstract base class for models which provides some of the common data
* structures.
*
* @author Tobias Grasl
*
* @param The Config type
* @param The State type
*/
public abstract class AbstractModel> extends Base implements Model
{
protected C _config;
public DoubleRectangularGridDomain _individualVarDomain;
protected int[] _individualVarDimensions;
protected int[] _aggregateVarDimensions;
protected int[] _individualTransitionDimensions;
protected int[] _aggregateExpectationDimensions;
protected int[] _individualExpectationDimensions;
protected int[] _simulationGridDimensions;
private int[] _aggVarAtDimensions;
private int[] _transitionArrangeDimensions;
private int[] _expectationFillDimensions;
private DiscretisedDistributionSimulatorImpl _simulator;
private IndividualProblemSolver _indSolver;
private AggregateProblemSolver _aggSolver;
private final Notifier _aggExpNotifier = new Notifier();
private int _aggDetStateStart;
private int _aggStochStateStart;
/**
* Sets up grid dimensions etc
*/
public void initialise()
{
/* NOTE: These ignore lifecycle dimension, since many arrays don't have that
*/
setAggDetStateStart(_config.getIndividualEndogenousStateCount() + _config.getIndividualExogenousStateCount());
int stochStateStart = getAggDetStateStart() +
_config.getAggregateEndogenousStateCount();
stochStateStart += _config.getAggregateControlCount();
setAggStochStateStart(stochStateStart);
_individualVarDimensions = initIndividualVarDimensions();
_aggregateVarDimensions = initAggregateVarDimensions();
_individualTransitionDimensions = initIndividualTransitionDimensions();
_aggregateExpectationDimensions = initAggregateExpectationDimensions();
_individualExpectationDimensions = initIndividualExpectationDimensions();
_simulationGridDimensions = initSimulationGridDimensions();
// The transition transpose dimensions to swap the order of endogenous and exogenous states
// For filling expecations
final int nAggStates = _config.getAggregateEndogenousStateCount();
final int nAggShocks = _config.getAggregateExogenousStateCount();
_aggVarAtDimensions = Utils.repeatArray(-1,_aggregateVarDimensions.length);
for (int i = 0; i < _config.getAggregateControlCount(); i++)
{
// should be constant across controls not affecting expectations, so select a slice
if(!ArrayUtils.contains(_config.getControlsAffectingExpectations(), i)) {
_aggVarAtDimensions[_config.getAggregateEndogenousStateCount() + i] = 0;
}
}
int nExpnAffectingControls = _config.getControlsAffectingExpectations().length;
/* NOTE: By the time the arrange happens, only expectation-affecting control dimensions
* apply due to the prior at operation
*/
_transitionArrangeDimensions = ArrayUtils.add(ArrayUtils.addAll(
// Current shocks come first
Utils.sequence(nAggStates + nExpnAffectingControls,nAggStates + nExpnAffectingControls + nAggShocks),
// After that, current states and expectation affecting controls
Utils.sequence(0, nAggStates + nExpnAffectingControls)),
// Finally, the last dimension, with the number of states
nAggStates+nExpnAffectingControls+nAggShocks);
// The dimensions in the expected states across which to fill the transposed transition
_expectationFillDimensions = ArrayUtils.addAll(
// Current Shocks
Utils.sequence(0, nAggShocks),
// States, controls and the number-of-states dimension
Utils.sequence(2*nAggShocks+_config.getAggregateNormalisingStateCount(),
2*nAggShocks+_config.getAggregateNormalisingStateCount()+nAggStates
+ nExpnAffectingControls + 1));
_individualVarDomain = individualVariableDomain();
}
@Override
final public int getAggStochStateStart()
{
return _aggStochStateStart;
}
@Override
final public int getAggDetStateStart()
{
return _aggDetStateStart;
}
final void setAggStochStateStart(int val_)
{
_aggStochStateStart = val_;
}
final void setAggDetStateStart(int val_)
{
_aggDetStateStart = val_;
}
final public void setConfig(C config_)
{
_config = config_;
}
final public void initIndividualSolverInstance(IndividualProblemSolver indSolver_)
{
_indSolver = indSolver_;
}
@Override
final public IndividualProblemSolver getIndividualSolverInstance()
{
return _indSolver;
}
final public void initAggregateSolverInstance(AggregateProblemSolver aggSolver_)
{
_aggSolver = aggSolver_;
}
@Override
final public AggregateProblemSolver getAggregateSolverInstance()
{
return _aggSolver;
}
public DiscretisedDistributionSimulatorImpl getSimulator()
{
return _simulator;
}
public void setSimulator(DiscretisedDistributionSimulatorImpl simulator_)
{
_simulator = simulator_;
}
private int[] initSimulationGridDimensions()
{
List dimensions = new ArrayList();
// Endogenous States
Utils.addLengthsToList(dimensions, _config.getIndividualEndogenousStatesForSimulation());
// Exogenous States
Utils.addLengthsToList(dimensions, _config.getIndividualExogenousStates());
return toIntArray(dimensions);
}
protected int[] initAggregateExpectationDimensions()
{
List dimensions = new ArrayList();
addAggregateExpectationDimensions(dimensions);
// The primary expectations are over aggregate states, so initialise it for that size
dimensions.add(_config.getAggregateEndogenousStateCount());
return toIntArray(dimensions);
}
/**
* @param dimensions
*/
private void addAggregateExpectationDimensions(List dimensions)
{
// Current Shocks
Utils.addLengthsToList(dimensions, _config.getAggregateExogenousStates());
// Future temporary Shocks
Utils.addLengthsToList(dimensions, _config.getAggregateExogenousStates());
// Future persistent Shocks
Utils.addLengthsToList(dimensions, _config.getAggregateNormalisingExogenousStates());
// Current endogenous States
Utils.addLengthsToList(dimensions, _config.getAggregateEndogenousStates());
/* Only include those controls specified as affecting expectations
*/
for(int idx : _config.getControlsAffectingExpectations())
{
dimensions.add(_config.getAggregateControls().get(idx).numberOfElements());
}
}
protected int[] initIndividualExpectationDimensions()
{
List dimensions = new ArrayList();
addAggregateExpectationDimensions(dimensions);
// Individual endogenous states
Utils.addLengthsToList(dimensions, _config.getIndividualEndogenousStates());
// Individual Shocks
Utils.addLengthsToList(dimensions, _config.getIndividualExogenousStates());
// The primary expectations are over individual states, so initialise it for that size
dimensions.add(_config.getIndividualEndogenousStateCount());
return toIntArray(dimensions);
}
protected int[] initIndividualTransitionDimensions()
{
List dimensions = individualDimensionsList();
Utils.addLengthsToList(dimensions, _config.getAggregateNormalisingExogenousStates());
dimensions.add(1);
return toIntArray(dimensions);
}
@Override
public DoubleArray> createIndividualTransitionGrid()
{
return createIndividualTransitionGrid(1);
}
@Override
public DoubleArray> createIndividualTransitionGrid(int numVars_)
{
return createVariableGrid(_individualTransitionDimensions, numVars_);
}
@Override
public DoubleArray> createIndividualVariableGrid()
{
return createIndividualVariableGrid(1);
}
@Override
public DoubleArray> createIndividualVariableGrid(int numVars_)
{
return createVariableGrid(_individualVarDimensions, numVars_);
}
@Override
public DoubleArray> createAggregateVariableGrid()
{
return createAggregateVariableGrid(1);
}
@Override
public DoubleArray> createAggregateVariableGrid(int numVars_)
{
return createVariableGrid(_aggregateVarDimensions, numVars_);
}
@Override
public DoubleArray> createAggregateExpectationGrid()
{
return createAggregateExpectationGrid(_config.getAggregateEndogenousStateCount());
}
@Override
public DoubleArray> createAggregateExpectationGrid(int numVars_)
{
return createVariableGrid(_aggregateExpectationDimensions, numVars_);
}
@Override
public DoubleArray> createIndividualExpectationGrid()
{
return createIndividualExpectationGrid(_config.getIndividualEndogenousStateCount());
}
@Override
public DoubleArray> createIndividualExpectationGrid(int numVars_)
{
return createVariableGrid(_individualExpectationDimensions, numVars_);
}
@Override
public DoubleArray> createSimulationGrid()
{
// Note that because the simulation grid only has one variable (density),
// it is not necessary to use createVariableGrid here
return createArrayOfSize(_simulationGridDimensions);
}
/**
* Creates a grid with the specfied dimensions for the specified number of variables,
* which is used in place of the last dimension
*
* @param dimensions_ The dimensions of the grid, with an additional place for the number of variables
* @param numVars_ The number of variables
*
* @return A grid with the specified dimensions
*/
private DoubleArray> createVariableGrid(int[] dimensions_, int numVars_)
{
if(numVars_ == dimensions_[dimensions_.length-1])
{
return createArrayOfSize(dimensions_);
}
else
{
// Have to copy so as not to pollute state!
int[] dims = Arrays.copyOf(dimensions_,dimensions_.length);
dims[dims.length-1] = numVars_;
return createArrayOfSize(dims);
}
}
protected int[] initIndividualVarDimensions()
{
List dimensions = individualDimensionsList();
// By default, the grid is for a single variable
dimensions.add(1);
return toIntArray(dimensions);
}
protected DoubleRectangularGridDomain individualVariableDomain()
{
List> dimensions = new ArrayList>();
dimensions.addAll(_config.getIndividualEndogenousStates());
dimensions.addAll(_config.getIndividualExogenousStates());
addAggregateGridPoints(dimensions);
return _functionFactory.createDomain(dimensions);
}
private final void addAggregateGridPoints(List> dimensions)
{
/* The aggregate deterministic state dims
*/
dimensions.addAll(_config.getAggregateEndogenousStates());
dimensions.addAll(_config.getAggregateControls());
/* Finally, the aggregate stochastic state dims
*/
dimensions.addAll(_config.getAggregateExogenousStates());
}
/**
* @return A list containing individual variable dimensions for a grid
*/
protected List individualDimensionsList()
{
List dimensions = new ArrayList();
/* First the individual deterministic state dims
*/
Utils.addLengthsToList(dimensions, _config.getIndividualEndogenousStates());
/* Then the individual stochastic state dims
*/
Utils.addLengthsToList(dimensions, _config.getIndividualExogenousStates());
/* Add the aggregate dimensions
*/
addAggregateDimensions(dimensions);
return dimensions;
}
private int[] initAggregateVarDimensions()
{
List dimensions = new ArrayList();
addAggregateDimensions(dimensions);
dimensions.add(1);
return toIntArray(dimensions);
}
/**
* @param dimensions The list of integers to convert to an int array
*
* @return A primitive array containing the values from the List
*/
protected int[] toIntArray(List dimensions)
{
return ArrayUtils.toPrimitive(dimensions.toArray(new Integer[dimensions.size()]));
}
protected void addAggregateDimensions(List dimensions)
{
/* The aggregate deterministic state dims
*/
Utils.addLengthsToList(dimensions, _config.getAggregateEndogenousStates());
Utils.addLengthsToList(dimensions, _config.getAggregateControls());
/* Finally, the aggregate stochastic state dims
*/
Utils.addLengthsToList(dimensions, _config.getAggregateExogenousStates());
}
/**
* Default does nothing
*/
@Override
public void writeAdditional(S state_, NumericsWriter writer_) throws IOException
{
}
/**
* Default does nothing
*/
@Override
public void readAdditional(S state_, NumericsReader reader_) throws IOException
{
}
/**
* The implementation checks whether an IDoubleArray is passed for the shocks and, if so, delegates to the
* double-specific method. Otherwise, it assumes integer shocks and delegates to the integer specific method
*
* @param simState_ The simulation state for which to calculate aggregates
* @param currentAggShock_ The aggregate shock for which to calculate aggregates
* @param calcState_ The calculation state
*
* @return The aggregate state values given the inputs
*
* @throws ModelException If there are errors performing the calculation
*
* @param The type of shock, should be either Double or Integer
*/
@Override
final public double[] calculateAggregateStates(SimState simState_, MultiDimensionalArray currentAggShock_, S calcState_) throws ModelException
{
if(currentAggShock_ instanceof DoubleArray>) {
return calculateAggregateStates(simState_, (DoubleArray>)currentAggShock_, calcState_);
}
return calculateAggregateStates(simState_, (IntegerArray)currentAggShock_, calcState_);
}
/**
* Calculates aggregate states when continuous shocks are being simulated.
*
* The implementation in this class throws an expectation if called. Subclasses to be used with continuous shocks must override
* it.
*
* @param simState_ The simulation state for which to calculate aggregates
* @param currentAggShock_ The aggregate shock for which to calculate aggregates
* @param calcState_ The calculation state
*
* @return The aggregate state values given the inputs
*
* @throws ModelException If there are errors performing the calculation
*/
public double[] calculateAggregateStates(SimState simState_, DoubleArray> currentAggShock_, S calcState_) throws ModelException
{
throw new NotImplementedException("This method must be implemented in Models that are simulated with continuous shocks");
}
/**
* Calculates aggregate states when discrete shocks are being simulated.
*
* The implementation in this class throws an expectation if called. Subclasses to be used with discrete shocks must override
* it.
*
* @param simState_ The simulation state for which to calculate aggregates
* @param currentAggShock_ The aggregate shock for which to calculate aggregates
* @param calcState_ The calculation state
*
* @return The aggregate state values given the inputs
*
* @throws ModelException If there are errors performing the calculation
*/
public double[] calculateAggregateStates(SimState simState_, IntegerArray currentAggShock_, S calcState_) throws ModelException
{
throw new NotImplementedException("This method must be implemented in Models that are simulated with discrete shocks");
}
/**
* Default does nothing
*/
@Override
public void beginIteration(S state_) throws ModelException
{
}
/**
* @return The current configuration applied to this model
*/
@Override
public C getConfig()
{
return _config;
}
// @Override
// public void postProcessAggregateTransition(IDoubleArray>
// currentAggState_, Integer[] priorShockIndex_,
// Integer[] currentShockIndex_, ICalcState state_) throws
// MultiDimensionalArrayException
// {
//
// }
public int[] initialShocks()
{
int[] shocks = Utils.repeatArray(0, _config.getAggregateExogenousStateCount());
int i = 0;
// Get the central value for each shock
for (DoubleArray> shock : _config.getAggregateExogenousStates())
{
shocks[i++] = shock.numberOfElements() / 2;
}
return shocks;
}
public int[] initialShocks(DiscretisedDistribution state_)
{
return initialShocks();
}
/**
* The default fixed point value delegate does nothing - i.e. it assumes
* that no fixed point needs to be found
*/
@Override
public FixedPointValueDelegate>> getFixedPointDelegate()
{
return new FixedPointValueDelegate>>()
{
@Override
public void setInputs(double[] inputs_)
{
}
@Override
public double[] getOutputs(AggregateFixedPointState> state_)
{
return new double[0];
}
@Override
public double[] getInitialInputs()
{
return new double[0];
}
};
}
/**
* Calculates the sums of the values of the provides function over the provided distribution, first interpolating
* to get the overflow function values if necessary
*
* @param valOnGrid_ The values of the function defined on the grid underlying the distribution
* @param gridXValues_ The dimension 0 values of the coordinates on the grid
* @param distribution_ The distribution across which to calculate it
*
* @return The calculated sum
*/
public DoubleArray> sumAcrossDistribution(
DoubleArray> valOnGrid_,
DoubleArray> gridXValues_,
DiscretisedDistribution distribution_)
{
// First, interpolate the values on the grid to the overflow averages
final DoubleArray> overflowVals = overflowValues(valOnGrid_, gridXValues_, distribution_);
return sumAcrossDistributionOF(valOnGrid_, overflowVals, distribution_);
}
/**
* Calculates the sums of the values of the provides function over the provided distribution
*
* @param valOnGrid_ The values of the function defined on the grid underlying the distribution
* @param overflowVals_ The values of the function at the overflow points
* @param distribution_ The distribution across which to calculate it
* @return The calculated sum
*/
public DoubleArray> sumAcrossDistributionOF(DoubleArray> valOnGrid_, DoubleArray> overflowVals_, DiscretisedDistribution distribution_)
{
// Then, multiply each grid value by the weight at that point and sum, along with the corresponding sum from
// the overflow
return valOnGrid_.across(0, 1).multiply(distribution_._density).across(0,1).sum().add(
overflowVals_.across(0, 1).multiply(distribution_._overflowProportions).across(0,1).sum());
}
/**
* Calculates the overflow values of a (possible multivalued) function defined on the grid
*
* @param valOnGrid_ The values defined on the grid
* @param gridXValues_ The dimension 0 values of the coordinates on the grid
* @param distribution_ The distribution to use, which will specify the state values at the overflow points
* @return The function values at the overflow points of the distribution
*/
protected DoubleArray> overflowValues(
DoubleArray> valOnGrid_,
DoubleArray> gridXValues_,
DiscretisedDistribution distribution_)
{
// If the function is one dimensional...
if (valOnGrid_.numberOfDimensions() == distribution_._density.numberOfDimensions())
{
// ...just interpolate
return interpolateFunction(gridXValues_, valOnGrid_, 0, distribution_._overflowAverages, new Params().constrained() );
} else
{
// Otherwise, iterate over the function dimensions and recursively call self for each
final int[] resultSize = valOnGrid_.size().clone();
resultSize[0] = 1;
final DoubleArray> results = createArrayOfSize(resultSize);
valOnGrid_.across(Utils.sequence(0, distribution_._density.numberOfDimensions())).reduce(
(IndexedReduction)(subSpaceIterator_ -> {
// Don't need to clone - returns a copy
final int[] fullIndex = subSpaceIterator_.getFullIndex();
fullIndex[0] = -1;
results.fillAt(overflowValues(valOnGrid_.at(fullIndex), gridXValues_, distribution_),
fullIndex);
// The result is not meaningful
return Double.NaN;
}));
return results;
}
}
/**
* Calculates the expected aggregates from the aggregate transition on the provided state class, this
* should be used whenever the aggregate transition rules have been set
*
* @param state_ The current state of the calculation
*/
@Override
public void adjustExpectedAggregates(S state_)
{
DoubleArray> oldExpStates = state_.getExpectedAggregateStates();
DoubleArray> expectedStates = createAggregateExpectationGrid();
expectedStates.fillDimensions(
state_.getAggregateTransition().at(_aggVarAtDimensions).
copy().arrangeDimensions(_transitionArrangeDimensions),
_expectationFillDimensions);
state_.setExpectedAggregateStates(expectedStates);
notifyAggregateExpectationListeners(oldExpStates, expectedStates, state_);
}
/**
* Notifies all listeners of the updated expected aggregate states
*
* @param oldExpStates_ The expected states before this update
* @param expectedStates_ The expected states after this update
* @param state_ The current calculation state
*/
protected void notifyAggregateExpectationListeners(DoubleArray> oldExpStates_, DoubleArray> expectedStates_, S state_)
{
_aggExpNotifier.changed(oldExpStates_, expectedStates_, state_);
}
/**
* Adds the provided listener to the list of those notified when the aggregate expectations array is changed
*
* @param listener_ The listener to add
*/
public void addAggregateExpectationListener(ArrayObserver listener_)
{
_aggExpNotifier.registerListener(listener_);
}
/**
* Given an on-grid individual or aggregate variable, interpolates it to the
* expected future values conditional current aggregates (controls only where specified) and
* on the realisation of future aggregate
* shocks
*
* @param currentVar_ The variable to interpolate, which should be on-grid
* @param state_ The current processing state
*/
@Override
public DoubleArray> conditionalExpectation(DoubleArray> currentVar_, final S state_)
{
return conditionalExpectation(currentVar_, state_, _config.isConstrained());
}
final public DoubleArray> conditionalExpectation(DoubleArray> currentVar_, S state_, final boolean constrained_)
{
// Create a new array with the appropriate dimensions to hold the result
DoubleArray> result;
boolean indVar = false;
if( currentVar_.numberOfDimensions() >= _individualVarDimensions.length )
{
indVar = true;
result = createIndividualExpectationGrid(currentVar_.size()[currentVar_.numberOfDimensions()-1]);
}
else
{
result = createAggregateExpectationGrid(currentVar_.size()[currentVar_.numberOfDimensions()-1]);
}
final boolean isIndividual = indVar;
final int nAggShocks = _config.getAggregateExogenousStateCount();
final int nAggFutureShocks = _config.getAggregateNormalisingStateCount();
final int nAggStates = _config.getAggregateEndogenousStateCount();
final int nAggControls = _config.getAggregateControlCount();
DoubleArray> expectedFutureAggregateStates = state_.getExpectedAggregateStates();
final List> aggregateVars = new ArrayList>();
aggregateVars.addAll(_config.getAggregateEndogenousStates());
aggregateVars.addAll(_config.getAggregateControls());
// Where to start interpolating depends on the type of variable -
// individual or aggregate
// Either way start at the first aggregate state dimension
final int firstInterpDimension = isIndividual ? getAggDetStateStart() : 0;
if(nAggStates > 0) {
// Iterate across aggregate state transitions; ignore the highest
// dimension, which is across different variables
DoubleSubspaceSplitIterator futStateIter = expectedFutureAggregateStates.iteratorAcross(Utils.sequence(0,
expectedFutureAggregateStates.numberOfDimensions() - 1));
DoubleSubspaceSplitIterator futControlIter = null;
// ditto for controls, if present
if (state_ instanceof StateWithControls && nAggControls > 0)
{
final DoubleArray> expectedControls = ((StateWithControls>) state_).getExpectedAggregateControls();
futControlIter = expectedControls.iteratorAcross(
Utils.sequence(0, expectedControls.numberOfDimensions() - 1));
}
List callables = new ArrayList();
while (futStateIter.hasNext())
{
futStateIter.nextDouble();
if (nAggControls > 0)
{
futControlIter.nextDouble();
}
final DoubleSubspaceSplitIterator stateDimIter = futStateIter.getOrthogonalIterator();
final DoubleSubspaceSplitIterator controlDimIter = futControlIter == null ? null : futControlIter.getOrthogonalIterator();
callables.add(()->{
Specification[] dimSpecsPerThread = new Specification[nAggStates + nAggControls];
int i = 0;
while (stateDimIter.hasNext())
{
// Get the value of the future state variable given the expectations
double futureStateValue = stateDimIter.nextDouble();
// Set it as the target along the appropriate
// interpolation dimension
dimSpecsPerThread[i] = spec(firstInterpDimension + i,
aggregateVars.get(i), futureStateValue);
i++;
}
if (controlDimIter != null)
{
while (controlDimIter.hasNext())
{
// Get the value of the future control variable given expectations
double futureControlValue = controlDimIter.nextDouble();
// Set it as the target along the appropriate
// interpolation dimension
dimSpecsPerThread[i] = spec(firstInterpDimension + i,
aggregateVars.get(i), futureControlValue);
i++;
}
}
int[] index = stateDimIter.getOtherIndex();
int[] subArrayIndex = Utils.repeatArray(-1, currentVar_.numberOfDimensions());
System.arraycopy(index, nAggShocks, subArrayIndex, firstInterpDimension + nAggControls + nAggStates, nAggShocks
+ (isIndividual ? nAggFutureShocks : 0));
// Interpolate along the non-stochastic aggregate state
// dimensions
DoubleArray> intermediate = interp(currentVar_.at(subArrayIndex), dimSpecsPerThread);
// Fill into the results array
result.fillAt(intermediate, index);
});
}
getNumerics().getExecutor().executeAndWait(callables);
}
else
{
int[] subArrayIndex = Utils.repeatArray(-1, currentVar_.numberOfDimensions());
/* Create an iterator over future exogenous states
*/
List dimList = new ArrayList();
Utils.addLengthsToList(dimList, _config.getAggregateExogenousStates());
Utils.addLengthsToList(dimList, _config.getAggregateNormalisingExogenousStates());
Index futureExoStatesIndex = new Index(ArrayUtils.toPrimitive(dimList.toArray(new Integer[dimList.size()])));
IndexIterator fesi = futureExoStatesIndex.iterator();
while(fesi.hasNext())
{
fesi.nextInt();
int[] index = fesi.getCurrentIndex();
System.arraycopy(index, 0, subArrayIndex, firstInterpDimension, nAggShocks
+ nAggFutureShocks);
// No interpretation in this case!
DoubleArray> intermediate = currentVar_.at(subArrayIndex);
// Prepare to fill at the correct index
int[] fillIndex = Utils.repeatArray(-1, result.numberOfDimensions());
// Copy the current agg stochastic state indices
// System.arraycopy(index, 0, fillIndex, 0, nAggShocks);
// Copy the future agg stochastic state indices
System.arraycopy(index, 0, fillIndex, nAggShocks + firstInterpDimension, nAggShocks + nAggFutureShocks);
// Record this for later use
result.at(fillIndex).fillDimensions(intermediate, Utils.sequence(1,firstInterpDimension+1));
}
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy