model.scenario.OneLinkSupplyChainResult.java Source code

Java tutorial

Introduction

Here is the source code for model.scenario.OneLinkSupplyChainResult.java

Source

/*
 * Copyright (c) 2014 by Ernesto Carrella
 * Licensed under MIT license. Basically do what you want with it but cite me and don't sue me. Which is just politeness, really.
 * See the file "LICENSE" for more information
 */

package model.scenario;

import agents.EconomicAgent;
import agents.firm.Firm;
import agents.firm.personell.HumanResources;
import agents.firm.production.Blueprint;
import agents.firm.production.control.maximizer.algorithms.marginalMaximizers.MarginalMaximizer;
import agents.firm.purchases.PurchasesDepartment;
import agents.firm.purchases.prediction.ErrorCorrectingPurchasePredictor;
import agents.firm.purchases.prediction.FixedIncreasePurchasesPredictor;
import agents.firm.sales.SalesDepartment;
import agents.firm.sales.SalesDepartmentOneAtATime;
import agents.firm.sales.prediction.ErrorCorrectingSalesPredictor;
import agents.firm.sales.prediction.FixedDecreaseSalesPredictor;
import agents.firm.sales.prediction.SalesPredictor;
import agents.firm.sales.pricing.AskPricingStrategy;
import com.google.common.base.Preconditions;
import financial.market.Market;
import javafx.collections.ObservableSet;
import model.MacroII;
import model.utilities.logs.LogLevel;
import model.utilities.logs.LogToFile;
import model.utilities.stats.collectors.DailyStatCollector;
import model.utilities.stats.collectors.enums.MarketDataType;
import model.utilities.stats.collectors.enums.PurchasesDataType;
import model.utilities.stats.collectors.enums.SalesDataType;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.function.Function;

import static model.experiments.tuningRuns.MarginalMaximizerPIDTuning.printProgressBar;

/**
 * <h4>Description</h4>
 * <p/> A simple struct to return when a test is done in multithreading!
 * <p/>
 * <p/>
 * <h4>Notes</h4>
 * Created with IntelliJ
 * <p/>
 * <p/>
 * <h4>References</h4>
 *
 * @author carrknight
 * @version 2013-08-05
 * @see
 */
public class OneLinkSupplyChainResult {

    final private double beefPrice;

    final private double foodPrice;

    final private double quantity;

    final private MacroII macroII;

    public OneLinkSupplyChainResult(double beefPrice, double foodPrice, double quantity, MacroII macroII) {
        this.beefPrice = beefPrice;
        this.foodPrice = foodPrice;
        this.quantity = quantity;
        this.macroII = macroII;
    }

    public static OneLinkSupplyChainResult beefMonopolistOneRun(long random, float divideMonopolistGainsByThis,
            int monopolistSpeed, final boolean beefLearned, final boolean foodLearned) {
        return beefMonopolistOneRun(random, divideMonopolistGainsByThis, monopolistSpeed, beefLearned, foodLearned,
                null, null, null);
    }

    public static OneLinkSupplyChainResult beefMonopolistOneRun(long random, float divideMonopolistGainsByThis,
            int monopolistSpeed, final boolean beefLearned, final boolean foodLearned,
            Function<SalesDepartment, AskPricingStrategy> woodPricingFactory,
            Function<SalesDepartment, AskPricingStrategy> furniturePricingFactory, File csvFileToWrite,
            File logFileToWrite, Path regressionLogToWrite) {
        final MacroII macroII = new MacroII(random);
        final OneLinkSupplyChainScenarioWithCheatingBuyingPrice scenario1 = new OneLinkSupplyChainScenarioWithCheatingBuyingPrice(
                macroII) {

            @Override
            protected void buildBeefSalesPredictor(SalesDepartment dept) {
                if (beefLearned) {
                    FixedDecreaseSalesPredictor predictor = SalesPredictor.Factory
                            .newSalesPredictor(FixedDecreaseSalesPredictor.class, dept);
                    predictor.setDecrementDelta(2);
                    dept.setPredictorStrategy(predictor);
                } else {
                    assert dept.getPredictorStrategy() instanceof ErrorCorrectingSalesPredictor; //assuming here nothing has been changed and we are still dealing with recursive sale predictors
                    try {
                        if (regressionLogToWrite != null)
                            ((ErrorCorrectingSalesPredictor) dept.getPredictorStrategy())
                                    .setDebugWriter(regressionLogToWrite);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            @Override
            public void buildFoodPurchasesPredictor(PurchasesDepartment department) {
                if (foodLearned)
                    department.setPredictor(new FixedIncreasePurchasesPredictor(0));

            }

            @Override
            protected SalesDepartment createSalesDepartment(Firm firm, Market goodmarket) {
                SalesDepartment department = super.createSalesDepartment(firm, goodmarket);
                if (goodmarket.getGoodType().equals(OneLinkSupplyChainScenario.OUTPUT_GOOD)) {
                    if (foodLearned)
                        department.setPredictorStrategy(new FixedDecreaseSalesPredictor(0));
                }
                return department;
            }

            @Override
            protected HumanResources createPlant(Blueprint blueprint, Firm firm, Market laborMarket) {
                HumanResources hr = super.createPlant(blueprint, firm, laborMarket);
                if (blueprint.getOutputs().containsKey(OneLinkSupplyChainScenario.INPUT_GOOD)) {
                    if (beefLearned) {
                        hr.setPredictor(new FixedIncreasePurchasesPredictor(1));
                    }
                }
                if (blueprint.getOutputs().containsKey(OneLinkSupplyChainScenario.OUTPUT_GOOD)) {
                    if (foodLearned)
                        hr.setPredictor(new FixedIncreasePurchasesPredictor(0));
                }
                return hr;
            }
        };
        scenario1.setControlType(MarginalMaximizer.class);
        scenario1.setSalesDepartmentType(SalesDepartmentOneAtATime.class);
        scenario1.setBeefPriceFilterer(null);

        if (woodPricingFactory != null)
            scenario1.setBeefPricingFactory(woodPricingFactory);
        if (furniturePricingFactory != null)
            scenario1.setFoodPricingFactory(furniturePricingFactory);

        //competition!
        scenario1.setNumberOfBeefProducers(1);
        scenario1.setBeefTargetInventory(100);
        scenario1.setFoodTargetInventory(100);
        scenario1.setNumberOfFoodProducers(5);

        scenario1.setDivideProportionalGainByThis(divideMonopolistGainsByThis);
        scenario1.setDivideIntegrativeGainByThis(divideMonopolistGainsByThis);
        //no delay
        scenario1.setBeefPricingSpeed(monopolistSpeed);

        //add csv writer if needed
        if (csvFileToWrite != null)
            DailyStatCollector.addDailyStatCollectorToModel(csvFileToWrite, macroII);

        macroII.setScenario(scenario1);
        macroII.start();
        macroII.schedule.step(macroII);

        if (logFileToWrite != null)
            scenario1.getMarkets().get(OneLinkSupplyChainScenario.INPUT_GOOD).getSellers().iterator().next()
                    .addLogEventListener(new LogToFile(logFileToWrite, LogLevel.DEBUG, macroII));

        while (macroII.schedule.getTime() < 14000) {
            macroII.schedule.step(macroII);

        }

        SummaryStatistics averageFoodPrice = new SummaryStatistics();
        SummaryStatistics averageBeefProduced = new SummaryStatistics();
        SummaryStatistics averageBeefPrice = new SummaryStatistics();
        SummaryStatistics averageSalesSlope = new SummaryStatistics();
        SummaryStatistics averageHrSlope = new SummaryStatistics();
        final Firm monopolist = (Firm) scenario1.getMarkets().get(OneLinkSupplyChainScenario.INPUT_GOOD)
                .getSellers().iterator().next();
        for (int j = 0; j < 1000; j++) {
            //make the model run one more day:
            macroII.schedule.step(macroII);

            averageFoodPrice.addValue(macroII.getMarket(OneLinkSupplyChainScenario.OUTPUT_GOOD)
                    .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE));
            averageBeefProduced
                    .addValue(macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD).getYesterdayVolume());
            averageBeefPrice.addValue(macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE));
            averageSalesSlope.addValue(monopolist.getSalesDepartment(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .getLatestObservation(SalesDataType.PREDICTED_DEMAND_SLOPE));
            averageHrSlope.addValue(monopolist.getHRs().iterator().next()
                    .getLatestObservation(PurchasesDataType.PREDICTED_SUPPLY_SLOPE));
        }

        System.out.println("seed: " + random);
        System.out.println("beef price: " + averageBeefPrice.getMean());
        System.out.println("food price: " + averageFoodPrice.getMean());
        System.out.println("produced: " + averageBeefProduced.getMean());
        extractAndPrintSlopesOfBeefSellers(macroII);
        System.out.println();

        macroII.finish();

        return new OneLinkSupplyChainResult(averageBeefPrice.getMean(), averageFoodPrice.getMean(),
                averageBeefProduced.getMean(), macroII);

    }

    public static OneLinkSupplyChainResult beefMonopolistOneRun(long random, float divideMonopolistGainsByThis,
            int monopolistSpeed, final boolean beefLearned, final boolean foodLearned, File csvFileToWrite,
            File logFileToWrite, Path regressionLogToWrite) {

        return beefMonopolistOneRun(random, divideMonopolistGainsByThis, monopolistSpeed, beefLearned, foodLearned,
                null, null, csvFileToWrite, logFileToWrite, regressionLogToWrite);
    }

    public static OneLinkSupplyChainResult beefMonopolistFixedProductionsOneRun(long seed,
            float divideMonopolistGainsByThis, int monopolistSpeed, final boolean foodLearned,
            File csvFileToWrite) {
        final MacroII macroII = new MacroII(seed);
        final OneLinkSupplyChainScenarioCheatingBuyPriceAndForcedMonopolist scenario1 = new OneLinkSupplyChainScenarioCheatingBuyPriceAndForcedMonopolist(
                macroII, OneLinkSupplyChainScenario.INPUT_GOOD) {
            @Override
            public void buildFoodPurchasesPredictor(PurchasesDepartment department) {
                if (foodLearned)
                    department.setPredictor(new FixedIncreasePurchasesPredictor(0));

            }

            @Override
            protected SalesDepartment createSalesDepartment(Firm firm, Market goodmarket) {
                SalesDepartment department = super.createSalesDepartment(firm, goodmarket); //To change body of overridden methods use File | Settings | File Templates.
                if (foodLearned && goodmarket.getGoodType().equals(OneLinkSupplyChainScenario.OUTPUT_GOOD))
                    department.setPredictorStrategy(new FixedDecreaseSalesPredictor(0));
                return department;
            }

            @Override
            protected HumanResources createPlant(Blueprint blueprint, Firm firm, Market laborMarket) {
                HumanResources hr = super.createPlant(blueprint, firm, laborMarket); //To change body of overridden methods use File | Settings | File Templates.
                if (foodLearned && !blueprint.getOutputs().containsKey(OneLinkSupplyChainScenario.INPUT_GOOD))
                    hr.setPredictor(new FixedIncreasePurchasesPredictor(0));
                return hr;
            }

        };
        scenario1.setControlType(MarginalMaximizer.class);
        scenario1.setSalesDepartmentType(SalesDepartmentOneAtATime.class);
        //use standard PID parameters
        scenario1.setDivideProportionalGainByThis(divideMonopolistGainsByThis);
        scenario1.setDivideIntegrativeGainByThis(divideMonopolistGainsByThis);
        //100 days delay
        scenario1.setBeefPricingSpeed(monopolistSpeed);
        //no need for filter with the cheating price
        scenario1.setBeefPriceFilterer(null);
        scenario1.setBeefTargetInventory(100);
        scenario1.setFoodTargetInventory(100);
        //add csv writer if needed
        if (csvFileToWrite != null)
            DailyStatCollector.addDailyStatCollectorToModel(csvFileToWrite, macroII);

        macroII.setScenario(scenario1);
        macroII.start();

        SummaryStatistics averageFoodPrice = new SummaryStatistics();
        SummaryStatistics averageBeefPrice = new SummaryStatistics();
        SummaryStatistics averageBeefTraded = new SummaryStatistics();
        while (macroII.schedule.getTime() < 15000) {
            macroII.schedule.step(macroII);

            if (macroII.schedule.getTime() >= 14500) {
                averageFoodPrice.addValue(macroII.getMarket(OneLinkSupplyChainScenario.OUTPUT_GOOD)
                        .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE));
                averageBeefPrice.addValue(macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                        .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE));
                averageBeefTraded
                        .addValue(macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD).getYesterdayVolume());

            }
        }

        macroII.finish();

        System.out.println("done with price: " + averageBeefPrice.getMean() + ", and standard deviation : "
                + averageBeefPrice.getStandardDeviation());
        System.out.println("seed: " + macroII.seed());
        System.out.println();
        //the beef price is in the ballpark

        return new OneLinkSupplyChainResult(averageBeefPrice.getMean(), averageFoodPrice.getMean(),
                averageBeefTraded.getMean(), macroII);
    }

    public static OneLinkSupplyChainResult everybodyLearnedCompetitivePIDRun(long random,
            final float dividePIByThis, final int beefPricingSpeed, File csvFileToWrite) {
        final MacroII macroII = new MacroII(random);
        final OneLinkSupplyChainScenarioWithCheatingBuyingPrice scenario1 = new OneLinkSupplyChainScenarioWithCheatingBuyingPrice(
                macroII) {

            @Override
            protected void buildBeefSalesPredictor(SalesDepartment dept) {
                FixedDecreaseSalesPredictor predictor = SalesPredictor.Factory
                        .newSalesPredictor(FixedDecreaseSalesPredictor.class, dept);
                predictor.setDecrementDelta(0);
                dept.setPredictorStrategy(predictor);
            }

            @Override
            public void buildFoodPurchasesPredictor(PurchasesDepartment department) {
                department.setPredictor(new FixedIncreasePurchasesPredictor(0));

            }

            @Override
            protected SalesDepartment createSalesDepartment(Firm firm, Market goodmarket) {
                SalesDepartment department = super.createSalesDepartment(firm, goodmarket);
                if (goodmarket.getGoodType().equals(OneLinkSupplyChainScenario.OUTPUT_GOOD))
                    department.setPredictorStrategy(new FixedDecreaseSalesPredictor(0));
                return department;
            }

            @Override
            protected HumanResources createPlant(Blueprint blueprint, Firm firm, Market laborMarket) {
                HumanResources hr = super.createPlant(blueprint, firm, laborMarket);
                hr.setPredictor(new FixedIncreasePurchasesPredictor(0));
                return hr;
            }
        };

        scenario1.setControlType(MarginalMaximizer.class);
        scenario1.setSalesDepartmentType(SalesDepartmentOneAtATime.class);
        scenario1.setBeefPriceFilterer(null);

        //competition!
        scenario1.setNumberOfBeefProducers(5);
        scenario1.setNumberOfFoodProducers(5);

        scenario1.setDivideProportionalGainByThis(dividePIByThis);
        scenario1.setDivideIntegrativeGainByThis(dividePIByThis);
        //no delay
        scenario1.setBeefPricingSpeed(beefPricingSpeed);

        //add csv writer if needed
        if (csvFileToWrite != null)
            DailyStatCollector.addDailyStatCollectorToModel(csvFileToWrite, macroII);

        macroII.setScenario(scenario1);
        macroII.start();

        while (macroII.schedule.getTime() < 14000) {
            macroII.schedule.step(macroII);

        }

        //I used to assert this:
        //Assert.assertEquals(macroII.getMarket(OneLinkSupplyChainScenario.OUTPUT_GOOD).getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE),85l,6l );
        //but that's too hard because while on average the price hovers there, competition is noisy. Sometimes a lot.
        //so what I did was to attach a daily stat collector and then check the average of the last 10 prices
        SummaryStatistics averageFoodPrice = new SummaryStatistics();
        SummaryStatistics averageBeefProduced = new SummaryStatistics();
        SummaryStatistics averageBeefPrice = new SummaryStatistics();
        for (int j = 0; j < 1000; j++) {
            //make the model run one more day:
            macroII.schedule.step(macroII);
            averageFoodPrice.addValue(macroII.getMarket(OneLinkSupplyChainScenario.OUTPUT_GOOD)
                    .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE));
            averageBeefProduced.addValue(macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .countTodayProductionByRegisteredSellers());
            averageBeefPrice.addValue(macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE));
        }

        System.out.println("beef price: " + averageBeefPrice.getMean());
        System.out.println("food price: " + averageFoodPrice.getMean());
        System.out.println("produced: " + averageBeefProduced.getMean());
        extractAndPrintSlopesOfBeefSellers(macroII);
        System.out.println();
        macroII.finish();

        return new OneLinkSupplyChainResult(averageBeefPrice.getMean(), averageFoodPrice.getMean(),
                averageBeefProduced.getMean(), macroII);

    }

    public static OneLinkSupplyChainResult everybodyLearningCompetitiveSlowPIDRun(long random) {
        final MacroII macroII = new MacroII(random);
        final OneLinkSupplyChainScenarioWithCheatingBuyingPrice scenario1 = new OneLinkSupplyChainScenarioWithCheatingBuyingPrice(
                macroII);

        scenario1.setControlType(MarginalMaximizer.class);
        scenario1.setSalesDepartmentType(SalesDepartmentOneAtATime.class);
        scenario1.setBeefPriceFilterer(null);

        //competition!
        scenario1.setNumberOfBeefProducers(5);
        scenario1.setNumberOfFoodProducers(5);

        scenario1.setDivideProportionalGainByThis(100f);
        scenario1.setDivideIntegrativeGainByThis(100f);
        //no delay
        scenario1.setBeefPricingSpeed(0);

        macroII.setScenario(scenario1);
        macroII.start();

        while (macroII.schedule.getTime() < 14000) {
            macroII.schedule.step(macroII);

        }

        //I used to assert this:
        //Assert.assertEquals(macroII.getMarket(OneLinkSupplyChainScenario.OUTPUT_GOOD).getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE),85l,6l );
        //but that's too hard because while on average the price hovers there, competition is noisy. Sometimes a lot.
        //so what I did was to attach a daily stat collector and then check the average of the last 10 prices
        float averageFoodPrice = 0;
        float averageBeefProduced = 0;
        float averageBeefPrice = 0;

        for (int j = 0; j < 1000; j++) {
            //make the model run one more day:
            macroII.schedule.step(macroII);
            averageFoodPrice += macroII.getMarket(OneLinkSupplyChainScenario.OUTPUT_GOOD)
                    .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE);
            averageBeefProduced += macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .countTodayProductionByRegisteredSellers();
            averageBeefPrice += macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE);

        }

        System.out.println("beef price: " + averageBeefPrice / 1000f);
        System.out.println("food price: " + averageFoodPrice / 1000f);
        System.out.println("produced: " + averageBeefProduced / 1000f);
        extractAndPrintSlopesOfBeefSellers(macroII);

        System.out.println();
        macroII.finish();

        return new OneLinkSupplyChainResult(averageBeefPrice / 1000f, averageFoodPrice / 1000f,
                averageBeefProduced / 1000f, macroII);

    }

    public static OneLinkSupplyChainResult foodMonopolistOneRun(long random, float divideMonopolistGainsByThis,
            int beefSpeed, final boolean beefLearned, final boolean foodLearned, File csvFileToWrite,
            Path regressionCSV) {
        final MacroII macroII = new MacroII(random);
        final OneLinkSupplyChainScenarioWithCheatingBuyingPrice scenario1 = new OneLinkSupplyChainScenarioWithCheatingBuyingPrice(
                macroII) {

            @Override
            protected void buildBeefSalesPredictor(SalesDepartment dept) {
                if (beefLearned) {
                    FixedDecreaseSalesPredictor predictor = SalesPredictor.Factory
                            .newSalesPredictor(FixedDecreaseSalesPredictor.class, dept);
                    predictor.setDecrementDelta(0);
                    dept.setPredictorStrategy(predictor);
                } else {

                }
            }

            @Override
            public void buildFoodPurchasesPredictor(PurchasesDepartment department) {
                if (foodLearned)
                    department.setPredictor(new FixedIncreasePurchasesPredictor(1));
                else {
                    final ErrorCorrectingPurchasePredictor predictor = new ErrorCorrectingPurchasePredictor(macroII,
                            department);
                    try {
                        if (regressionCSV != null)
                            predictor.setDebugWriter(regressionCSV);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    department.setPredictor(predictor);

                }

            }

            @Override
            protected SalesDepartment createSalesDepartment(Firm firm, Market goodmarket) {
                SalesDepartment department = super.createSalesDepartment(firm, goodmarket);
                if (goodmarket.getGoodType().equals(OneLinkSupplyChainScenario.OUTPUT_GOOD)) {
                    if (foodLearned)
                        department.setPredictorStrategy(new FixedDecreaseSalesPredictor(1));
                }
                return department;
            }

            @Override
            protected HumanResources createPlant(Blueprint blueprint, Firm firm, Market laborMarket) {
                HumanResources hr = super.createPlant(blueprint, firm, laborMarket);
                if (blueprint.getOutputs().containsKey(OneLinkSupplyChainScenario.INPUT_GOOD)) {
                    if (beefLearned) {
                        hr.setPredictor(new FixedIncreasePurchasesPredictor(0));
                    }
                }
                if (blueprint.getOutputs().containsKey(OneLinkSupplyChainScenario.OUTPUT_GOOD)) {
                    if (foodLearned)
                        hr.setPredictor(new FixedIncreasePurchasesPredictor(1));

                }
                return hr;
            }
        };
        scenario1.setControlType(MarginalMaximizer.class);
        scenario1.setSalesDepartmentType(SalesDepartmentOneAtATime.class);
        scenario1.setBeefPriceFilterer(null);

        //competition!
        scenario1.setNumberOfBeefProducers(5);
        scenario1.setBeefTargetInventory(100);
        scenario1.setNumberOfFoodProducers(1);
        scenario1.setFoodTargetInventory(100);

        scenario1.setDivideProportionalGainByThis(divideMonopolistGainsByThis);
        scenario1.setDivideIntegrativeGainByThis(divideMonopolistGainsByThis);
        //no delay
        scenario1.setBeefPricingSpeed(beefSpeed);

        //add csv writer if needed
        if (csvFileToWrite != null)
            DailyStatCollector.addDailyStatCollectorToModel(csvFileToWrite, macroII);

        macroII.setScenario(scenario1);
        macroII.start();

        while (macroII.schedule.getTime() < 14000) {
            macroII.schedule.step(macroII);

        }

        SummaryStatistics averageFoodPrice = new SummaryStatistics();
        SummaryStatistics averageBeefProduced = new SummaryStatistics();
        SummaryStatistics averageBeefPrice = new SummaryStatistics();
        for (int j = 0; j < 1000; j++) {
            //make the model run one more day:
            macroII.schedule.step(macroII);

            averageFoodPrice.addValue(macroII.getMarket(OneLinkSupplyChainScenario.OUTPUT_GOOD)
                    .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE));
            averageBeefProduced
                    .addValue(macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD).getYesterdayVolume());
            averageBeefPrice.addValue(macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE));
        }

        System.out.println("seed: " + random);
        System.out.println("beef price: " + averageBeefPrice.getMean());
        System.out.println("food price: " + averageFoodPrice.getMean());
        System.out.println("produced: " + averageBeefProduced.getMean());
        extractAndPrintSlopesOfBeefSellers(macroII);

        System.out.println();

        ((Firm) (macroII.getMarket(OneLinkSupplyChainScenario.OUTPUT_GOOD).getSellers().iterator().next()))
                .getPurchaseDepartment(OneLinkSupplyChainScenario.INPUT_GOOD).getData()
                .writeToCSVFile(Paths.get("runs", "purchases.csv").toFile());
        macroII.finish();

        return new OneLinkSupplyChainResult(averageBeefPrice.getMean(), averageFoodPrice.getMean(),
                averageBeefProduced.getMean(), macroII);

    }

    public static OneLinkSupplyChainResult everybodyLearningCompetitiveStickyPIDRun(long random, float timidity,
            int stickiness) {
        final MacroII macroII = new MacroII(random);
        final OneLinkSupplyChainScenarioWithCheatingBuyingPrice scenario1 = new OneLinkSupplyChainScenarioWithCheatingBuyingPrice(
                macroII);

        scenario1.setControlType(MarginalMaximizer.class);
        scenario1.setSalesDepartmentType(SalesDepartmentOneAtATime.class);
        scenario1.setBeefPriceFilterer(null);

        //competition!
        scenario1.setNumberOfBeefProducers(5);
        scenario1.setNumberOfFoodProducers(5);

        scenario1.setDivideProportionalGainByThis(timidity);
        scenario1.setDivideIntegrativeGainByThis(timidity);
        //no delay
        scenario1.setBeefPricingSpeed(stickiness);

        macroII.setScenario(scenario1);
        macroII.start();

        while (macroII.schedule.getTime() < 9000) {
            macroII.schedule.step(macroII);
            printProgressBar(9001, (int) macroII.schedule.getSteps(), 100);
        }

        //I used to assert this:
        //Assert.assertEquals(macroII.getMarket(OneLinkSupplyChainScenario.OUTPUT_GOOD).getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE),85l,6l );
        //but that's too hard because while on average the price hovers there, competition is noisy. Sometimes a lot.
        //so what I did was to attach a daily stat collector and then check the average of the last 10 prices
        float averageFoodPrice = 0;
        float averageBeefProduced = 0;
        float averageBeefPrice = 0;
        for (int j = 0; j < 1000; j++) {
            //make the model run one more day:
            macroII.schedule.step(macroII);
            averageFoodPrice += macroII.getMarket(OneLinkSupplyChainScenario.OUTPUT_GOOD)
                    .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE);
            averageBeefProduced += macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .countTodayProductionByRegisteredSellers();
            averageBeefPrice += macroII.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .getLatestObservation(MarketDataType.AVERAGE_CLOSING_PRICE);
        }

        System.out.println("beef price: " + averageBeefPrice / 1000f);
        System.out.println("food price: " + averageFoodPrice / 1000f);
        System.out.println("produced: " + averageBeefProduced / 1000f);
        extractAndPrintSlopesOfBeefSellers(macroII);

        System.out.println();
        macroII.finish();

        return new OneLinkSupplyChainResult(averageBeefPrice / 1000f, averageFoodPrice / 1000f,
                averageBeefProduced / 1000f, macroII);

    }

    public static void extractAndPrintSlopesOfBeefSellers(MacroII model) {
        Preconditions.checkState(OneLinkSupplyChainScenario.class.isAssignableFrom(model.getScenario().getClass()));
        //wood
        final ObservableSet<EconomicAgent> lumberMills = model.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                .getSellers();
        double salesSlopes[] = new double[lumberMills.size()];
        double hrSlopes[] = new double[lumberMills.size()];
        int i = 0;
        for (EconomicAgent e : lumberMills) {
            Firm f = (Firm) e;
            final double hrSlope = f.getHRs().iterator().next()
                    .getLatestObservation(PurchasesDataType.PREDICTED_SUPPLY_SLOPE);
            hrSlopes[i] = hrSlope;
            final double saleSlope = f.getSalesDepartment(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .getLatestObservation(SalesDataType.PREDICTED_DEMAND_SLOPE);
            salesSlopes[i] = saleSlope;
            i++;
        }
        System.out.println("wood slopes");
        System.out.println("sales: " + Arrays.toString(salesSlopes));
        System.out.println("hr: " + Arrays.toString(hrSlopes));

        //furniture
        final ObservableSet<EconomicAgent> furniturePlants = model.getMarket(OneLinkSupplyChainScenario.INPUT_GOOD)
                .getBuyers();
        salesSlopes = new double[furniturePlants.size()];
        hrSlopes = new double[furniturePlants.size()];
        double pdSlopes[] = new double[furniturePlants.size()];

        i = 0;
        for (EconomicAgent e : furniturePlants) {
            Firm f = (Firm) e;
            final double hrSlope = f.getHRs().iterator().next()
                    .getLatestObservation(PurchasesDataType.PREDICTED_SUPPLY_SLOPE);
            hrSlopes[i] = hrSlope;
            final double saleSlope = f.getSalesDepartment(OneLinkSupplyChainScenario.OUTPUT_GOOD)
                    .getLatestObservation(SalesDataType.PREDICTED_DEMAND_SLOPE);
            salesSlopes[i] = saleSlope;
            final double pdSlope = f.getPurchaseDepartment(OneLinkSupplyChainScenario.INPUT_GOOD)
                    .getLatestObservation(PurchasesDataType.PREDICTED_SUPPLY_SLOPE);
            pdSlopes[i] = pdSlope;
            i++;
        }
        System.out.println("furniture slopes");
        System.out.println("sales: " + Arrays.toString(salesSlopes));
        System.out.println("hr: " + Arrays.toString(hrSlopes));
        System.out.println("pd: " + Arrays.toString(pdSlopes));
    }

    public double getBeefPrice() {
        return beefPrice;
    }

    public double getFoodPrice() {
        return foodPrice;
    }

    public double getQuantity() {
        return quantity;
    }

    public MacroII getMacroII() {
        return macroII;
    }
}