// Path: src/main/java/org/ojalgo/finance/portfolio/FinancePortfolio.java
// public interface Context {
// 
//     double calculatePortfolioReturn(final FinancePortfolio weightsPortfolio);
// 
//     double calculatePortfolioVariance(final FinancePortfolio weightsPortfolio);
// 
//     Primitive64Matrix getAssetReturns();
// 
//     Primitive64Matrix getAssetVolatilities();
// 
//     Primitive64Matrix getCorrelations();
// 
//     Primitive64Matrix getCovariances();
// 
//     int size();
// 
// }
// 
// Path: src/main/java/org/ojalgo/finance/portfolio/simulator/PortfolioSimulator.java
// public class PortfolioSimulator {
// 
//     private GeometricBrownian1D myProcess;
// 
//     public PortfolioSimulator(final Access2D<?> correlations, final List<GeometricBrownianMotion> assetProcesses) {
// 
//         super();
// 
//         if (assetProcesses == null || assetProcesses.size() < 1) {
//             throw new IllegalArgumentException();
//         }
// 
//         if (correlations != null) {
//             myProcess = new GeometricBrownian1D(correlations, assetProcesses);
//         } else {
//             myProcess = new GeometricBrownian1D(assetProcesses);
//         }
//     }
// 
//     @SuppressWarnings("unused")
//     private PortfolioSimulator() {
//         super();
//     }
// 
//     public RandomProcess.SimulationResults simulate(final int aNumberOfRealisations, final int aNumberOfSteps, final double aStepSize) {
//         return this.simulate(aNumberOfRealisations, aNumberOfSteps, aStepSize, null);
//     }
// 
//     public RandomProcess.SimulationResults simulate(final int aNumberOfRealisations, final int aNumberOfSteps, final double aStepSize,
//             final int rebalancingInterval) {
//         return this.simulate(aNumberOfRealisations, aNumberOfSteps, aStepSize, Integer.valueOf(rebalancingInterval));
//     }
// 
//     RandomProcess.SimulationResults simulate(final int aNumberOfRealisations, final int aNumberOfSteps, final double aStepSize,
//             final Integer rebalancingInterval) {
// 
//         final int tmpProcDim = myProcess.size();
// 
//         final Primitive64Array tmpInitialValues = myProcess.getValues();
//         final Comparable<?>[] tmpValues = new Comparable<?>[tmpProcDim];
//         for (int p = 0; p < tmpProcDim; p++) {
//             tmpValues[p] = tmpInitialValues.get(p);
//         }
//         final List<BigDecimal> tmpWeights = new SimplePortfolio(tmpValues).normalise().getWeights();
// 
//         final Array2D<Double> tmpRealisationValues = Array2D.PRIMITIVE64.make(aNumberOfRealisations, aNumberOfSteps);
// 
//         for (int r = 0; r < aNumberOfRealisations; r++) {
// 
//             for (int s = 0; s < aNumberOfSteps; s++) {
// 
//                 if (rebalancingInterval != null && s != 0 && s % rebalancingInterval == 0) {
// 
//                     final double tmpPortfolioValue = tmpRealisationValues.doubleValue(r, s - 1);
// 
//                     for (int p = 0; p < tmpProcDim; p++) {
//                         myProcess.setValue(p, tmpPortfolioValue * tmpWeights.get(p).doubleValue());
//                     }
//                 }
// 
//                 final Array1D<Double> tmpRealisation = myProcess.step(aStepSize);
// 
//                 final AggregatorFunction<Double> tmpAggregator = Aggregator.SUM.getFunction(PrimitiveAggregator.getSet());
//                 tmpRealisation.visitAll(tmpAggregator);
//                 tmpRealisationValues.set(r, s, tmpAggregator.doubleValue());
//             }
// 
//             myProcess.setValues(tmpInitialValues);
//         }
// 
//         final AggregatorFunction<Double> tmpAggregator = Aggregator.SUM.getFunction(PrimitiveAggregator.getSet());
//         for (int i = 0; i < tmpInitialValues.count(); i++) {
//             tmpAggregator.invoke(tmpInitialValues.doubleValue(i));
//         }
// 
//         return new RandomProcess.SimulationResults(tmpAggregator.doubleValue(), tmpRealisationValues);
//     }
// }


import org.ojalgo.scalar.Scalar;
import org.ojalgo.structure.Access2D;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.ojalgo.finance.portfolio.FinancePortfolio.Context;
import org.ojalgo.finance.portfolio.simulator.PortfolioSimulator;
import org.ojalgo.function.constant.PrimitiveMath;
import org.ojalgo.matrix.Primitive64Matrix;
import org.ojalgo.random.process.GeometricBrownianMotion;

        if (myMeanReturn == null) {
            final Primitive64Matrix tmpWeightsVector = this.getAssetWeights();
            final Primitive64Matrix tmpReturnsVector = this.getAssetReturns();
            myMeanReturn = MarketEquilibrium.calculatePortfolioReturn(tmpWeightsVector, tmpReturnsVector).get();
        }

        return Scalar.doubleValue(myMeanReturn);
    }

    public double getMeanReturn(final int index) {
        return myComponents.get(index).getMeanReturn();
    }

    @Override
    public double getReturnVariance() {

        if (myReturnVariance == null) {
            final MarketEquilibrium tmpMarketEquilibrium = new MarketEquilibrium(this.getCovariances());
            final Primitive64Matrix tmpWeightsVector = this.getAssetWeights();
            myReturnVariance = tmpMarketEquilibrium.calculatePortfolioVariance(tmpWeightsVector).get();
        }

        return Scalar.doubleValue(myReturnVariance);
    }

    public double getReturnVariance(final int index) {
        return myComponents.get(index).getReturnVariance();
    }

// Path: src/main/java/org/ojalgo/finance/portfolio/FinancePortfolio.java
// public interface Context {
// 
//     double calculatePortfolioReturn(final FinancePortfolio weightsPortfolio);
// 
//     double calculatePortfolioVariance(final FinancePortfolio weightsPortfolio);
// 
//     Primitive64Matrix getAssetReturns();
// 
//     Primitive64Matrix getAssetVolatilities();
// 
//     Primitive64Matrix getCorrelations();
// 
//     Primitive64Matrix getCovariances();
// 
//     int size();
// 
// }
// 
// Path: src/main/java/org/ojalgo/finance/portfolio/simulator/PortfolioSimulator.java
// public class PortfolioSimulator {
// 
//     private GeometricBrownian1D myProcess;
// 
//     public PortfolioSimulator(final Access2D<?> correlations, final List<GeometricBrownianMotion> assetProcesses) {
// 
//         super();
// 
//         if (assetProcesses == null || assetProcesses.size() < 1) {
//             throw new IllegalArgumentException();
//         }
// 
//         if (correlations != null) {
//             myProcess = new GeometricBrownian1D(correlations, assetProcesses);
//         } else {
//             myProcess = new GeometricBrownian1D(assetProcesses);
//         }
//     }
// 
//     @SuppressWarnings("unused")
//     private PortfolioSimulator() {
//         super();
//     }
// 
//     public RandomProcess.SimulationResults simulate(final int aNumberOfRealisations, final int aNumberOfSteps, final double aStepSize) {
//         return this.simulate(aNumberOfRealisations, aNumberOfSteps, aStepSize, null);
//     }
// 
//     public RandomProcess.SimulationResults simulate(final int aNumberOfRealisations, final int aNumberOfSteps, final double aStepSize,
//             final int rebalancingInterval) {
//         return this.simulate(aNumberOfRealisations, aNumberOfSteps, aStepSize, Integer.valueOf(rebalancingInterval));
//     }
// 
//     RandomProcess.SimulationResults simulate(final int aNumberOfRealisations, final int aNumberOfSteps, final double aStepSize,
//             final Integer rebalancingInterval) {
// 
//         final int tmpProcDim = myProcess.size();
// 
//         final Primitive64Array tmpInitialValues = myProcess.getValues();
//         final Comparable<?>[] tmpValues = new Comparable<?>[tmpProcDim];
//         for (int p = 0; p < tmpProcDim; p++) {
//             tmpValues[p] = tmpInitialValues.get(p);
//         }
//         final List<BigDecimal> tmpWeights = new SimplePortfolio(tmpValues).normalise().getWeights();
// 
//         final Array2D<Double> tmpRealisationValues = Array2D.PRIMITIVE64.make(aNumberOfRealisations, aNumberOfSteps);
// 
//         for (int r = 0; r < aNumberOfRealisations; r++) {
// 
//             for (int s = 0; s < aNumberOfSteps; s++) {
// 
//                 if (rebalancingInterval != null && s != 0 && s % rebalancingInterval == 0) {
// 
//                     final double tmpPortfolioValue = tmpRealisationValues.doubleValue(r, s - 1);
// 
//                     for (int p = 0; p < tmpProcDim; p++) {
//                         myProcess.setValue(p, tmpPortfolioValue * tmpWeights.get(p).doubleValue());
//                     }
//                 }
// 
//                 final Array1D<Double> tmpRealisation = myProcess.step(aStepSize);
// 
//                 final AggregatorFunction<Double> tmpAggregator = Aggregator.SUM.getFunction(PrimitiveAggregator.getSet());
//                 tmpRealisation.visitAll(tmpAggregator);
//                 tmpRealisationValues.set(r, s, tmpAggregator.doubleValue());
//             }
// 
//             myProcess.setValues(tmpInitialValues);
//         }
// 
//         final AggregatorFunction<Double> tmpAggregator = Aggregator.SUM.getFunction(PrimitiveAggregator.getSet());
//         for (int i = 0; i < tmpInitialValues.count(); i++) {
//             tmpAggregator.invoke(tmpInitialValues.doubleValue(i));
//         }
// 
//         return new RandomProcess.SimulationResults(tmpAggregator.doubleValue(), tmpRealisationValues);
//     }
// }


// Path: src/main/java/org/ojalgo/finance/portfolio/SimplePortfolio.java
import org.ojalgo.scalar.Scalar;
import org.ojalgo.structure.Access2D;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.ojalgo.finance.portfolio.FinancePortfolio.Context;
import org.ojalgo.finance.portfolio.simulator.PortfolioSimulator;
import org.ojalgo.function.constant.PrimitiveMath;
import org.ojalgo.matrix.Primitive64Matrix;
import org.ojalgo.random.process.GeometricBrownianMotion;


        if (myMeanReturn == null) {
            final Primitive64Matrix tmpWeightsVector = this.getAssetWeights();
            final Primitive64Matrix tmpReturnsVector = this.getAssetReturns();
            myMeanReturn = MarketEquilibrium.calculatePortfolioReturn(tmpWeightsVector, tmpReturnsVector).get();
        }

        return Scalar.doubleValue(myMeanReturn);
    }

    public double getMeanReturn(final int index) {
        return myComponents.get(index).getMeanReturn();
    }

    @Override
    public double getReturnVariance() {

        if (myReturnVariance == null) {
            final MarketEquilibrium tmpMarketEquilibrium = new MarketEquilibrium(this.getCovariances());
            final Primitive64Matrix tmpWeightsVector = this.getAssetWeights();
            myReturnVariance = tmpMarketEquilibrium.calculatePortfolioVariance(tmpWeightsVector).get();
        }

        return Scalar.doubleValue(myReturnVariance);
    }

    public double getReturnVariance(final int index) {
        return myComponents.get(index).getReturnVariance();
    }

    public PortfolioSimulator getSimulator() {