src/de/pik/lagom/generic/Household.java

00001 
00002 // Copyright 2010 by Carlo Jaeger, Antoine Mandel, Steffen Fuerst and European Climate Forum
00003 // Licensed under the Open Software License version 3.0
00004 // See the file "License-OSL-3.0.txt" in the distribution for more information
00005 // The License text can be also found under http://www.opensource.org/licenses/osl-3.0.php
00007 
00008 package de.pik.lagom.generic;
00009 
00010 import java.util.Collections;
00011 import java.util.Comparator;
00012 import java.util.Iterator;
00013 import java.util.LinkedHashMap;
00014 import java.util.LinkedList;
00015 import java.util.List;
00016 
00017 import net.sf.oval.constraint.GreaterOrApproxZero;
00018 import net.sf.oval.constraint.NotNegative;
00019 import net.sf.oval.constraint.NotNull;
00020 import net.sf.oval.constraint.ValidateWithMethod;
00021 import net.sf.oval.guard.Guarded;
00022 import net.sf.oval.guard.Post;
00023 import net.sf.oval.guard.PostValidateThis;
00024 import net.sf.oval.guard.Pre;
00025 import net.sf.oval.guard.PreValidateThis;
00026 import de.pik.lagom.annotations.Comment;
00027 import de.pik.lagom.annotations.Description;
00028 import de.pik.lagom.annotations.Initialization;
00029 import de.pik.lagom.annotations.NameInUI;
00030 import de.pik.lagom.annotations.Variability;
00031 import de.pik.lagom.annotations.WriteToFile;
00032 import de.pik.lagom.exceptions.ParameterParserException;
00033 import de.pik.lagom.generic.consumptiontechnology.ConsumptionTechnology;
00034 import de.pik.lagom.generic.consumptiontechnology.ConsumptionTechnologyFactory;
00035 import de.pik.lagom.generic.initvalues.HouseholdInitValues;
00036 import de.pik.lagom.toolbox.ArrayTools;
00037 import de.pik.lagom.toolbox.IIdentifiable;
00038 import de.pik.lagom.toolbox.ProbeBase;
00039 import de.pik.lagom.toolbox.StepManager;
00040 import de.pik.lagom.toolbox.StepManager.Callback;
00041 import de.pik.lagom.toolbox.math.DoubleInterval;
00042 import de.pik.lagom.toolbox.math.FloatMath;
00043 import de.pik.lagom.toolbox.math.RandomGenerator;
00044 import de.pik.lagom.toolbox.math.ValueMemory;
00045 
00046 
00047 import static de.pik.lagom.annotations.Initialization.*;
00048 import static de.pik.lagom.annotations.Variability.*;
00049 
00055 @Guarded
00056 public class Household implements IBuyer  {
00058   static private final double BELIEF_CHANGE_RATE = 0.1d;
00059   
00061   public class Probe extends ProbeBase implements IIdentifiable {
00063     @Description("The id of the household")
00064     @Variability(SIMULATION)
00065     @Initialization(INDIVIDUAL)
00066     private int id;
00067 
00068     public void init() {
00069       id = nextId++;
00070     }
00071 
00072     // needed for the IIdentifiable interface, that allows to sort the probes in the UI
00073     public int getId() {
00074       return id;
00075     }
00076 
00077     @Override
00078     public String toString() {
00079       return "Household with Id " + id;
00080     }
00081 
00082     @WriteToFile
00083     @NameInUI("Wealth")
00084     public double getWealth() {
00085       return getMoney();
00086     }
00087 
00088     @WriteToFile
00089     @NameInUI("Savings")
00090     public double getSavings() {
00091       return savings;
00092     }
00093 
00094     @WriteToFile
00095     @NameInUI("Fallback")
00096     public double getFallback() {
00097       return fallback;
00098     }
00099 
00100     @WriteToFile
00101     @NameInUI("Number of Owned Firms")
00102     public int getNumOwnedFirms() {
00103       return ownedFirms.size();
00104     }
00105 
00106     @WriteToFile
00107     @NameInUI("Work Amount")
00108     @Description("Total work amount of all work contracts")
00109     public double getWorkAmount() {
00110       return calcWorkAmount();
00111     }
00112 
00113     @WriteToFile
00114     @NameInUI("Number of Work Contracts")
00115     public int getNumWorkContracts() {
00116       return employers.size();
00117     }
00118 
00119     @WriteToFile
00120     @NameInUI("Stock")
00121     public double[] getStock() {
00122       return stock;
00123     }
00124 
00125     @WriteToFile
00126     @NameInUI("Consumption Coefficients")
00127     public double[] getConsumptionTechnologyCoefficients() {
00128       return consumptionTechnologyCoefficients;
00129     }
00130   } // end of class Probe
00131 
00132   class Stats {
00133     private ValueMemory incomeMemory;
00134     private ValueMemory moneyMemory;
00135  
00136     void init(StepManager pStepManager) {
00137       incomeMemory = new ValueMemory(Foundation.getInitValues().
00138                                      getGeneticEvolutionPricesInterval());
00139       moneyMemory = new ValueMemory(Foundation.getInitValues().
00140                                     getGeneticEvolutionPricesInterval());
00141 
00142       pStepManager.registerEndOfPeriodCallback(1, new Callback(){
00143         @Override
00144         public void endOfPeriod() {
00145           incomeMemory.add(netIncome);
00146           moneyMemory.add(money);
00147         }
00148 
00149         @Override
00150         public Object getOwner() {
00151           return Household.Stats.this;
00152         }}
00153       ); // end of registerEndOfPeriodCallback
00154     }
00155 
00156     public double getLastPeriodIncome() {
00157       return incomeMemory.last();
00158     }
00159 
00160     public double getLastPeriodMoney() {
00161       return moneyMemory.last();
00162     } 
00163   } // end of class Stats
00164     
00170   static public class WorkAmountComparator implements Comparator<Household> {
00171     public int compare(Household pHousehold0, Household pHousehold1) {
00172       // first determine the work amount of both households ...
00173       final double lWorkAmount0 = pHousehold0.calcWorkAmount();
00174       final double lWorkAmount1 = pHousehold1.calcWorkAmount();
00175 
00176       // ... then compare it
00177       if (lWorkAmount0 <= lWorkAmount1) {
00178         return -1;
00179       } else {
00180         return 1;
00181       }
00182     }
00183   }
00184 
00188   static public class FallbackComparator implements Comparator<Household> {
00189     public int compare(Household pHousehold0, Household pHousehold1) {
00190       // first determine the fallback of both households ...
00191       final double lFallback0 = pHousehold0.getFallback();
00192       final double lFallback1 = pHousehold1.getFallback();
00193 
00194       // ... then compare it
00195       if (lFallback0 < lFallback1) {
00196         return -1;
00197       } else if (lFallback0 > lFallback1) {
00198         return 1;
00199       } else { // they are equal, so we return a random isLower or isHigher to get
00200                // a shuffled order for households with the same fallback
00201         return (random.nextDouble() > 0.5d) ? 1 : -1;
00202       }
00203     }
00204   }
00205 
00209   static public class InverseFallbackComparator implements Comparator<Household> {
00210     public int compare(Household pHousehold0, Household pHousehold1) {
00211       // first determine the fallback of both households ...
00212       final double lFallback0 = pHousehold0.getFallback();
00213       final double lFallback1 = pHousehold1.getFallback();
00214 
00215       // ... then compare it
00216       if (lFallback0 > lFallback1) {
00217         return -1;
00218       } else if (lFallback0 < lFallback1) {
00219         return 1;
00220       } else { // they are equal, so we return a random isLower or isHigher to get
00221                // a shuffled order for households with the same fallback
00222         return (random.nextDouble() > 0.5d) ? 1 : -1;
00223       }
00224     }
00225   }
00226 
00230   static public class SavingsComparator implements Comparator<Household> {
00231     public int compare(Household pHousehold0, Household pHousehold1) {
00232       // first determine the savings of both households ...
00233       final double lSavings0 = pHousehold0.getSavings();
00234       final double lSavings1 = pHousehold1.getSavings();
00235 
00236       // ... then compare it
00237       if (lSavings0 < lSavings1) {
00238         return -1;
00239       } else if (lSavings0 > lSavings1) {
00240         return 1;
00241       } else { // they are equal, so i return a random isLower or isHigher to get
00242                // a shuffled order for households with the same savings
00243         return (random.nextDouble() > 0.5d) ? 1 : -1;
00244       }
00245     }
00246   }
00247   
00252   public class UtilityComparator implements Comparator<Household> {
00253     public int compare(Household pHousehold0, Household pHousehold1) {
00254       // determine the utility of both households ...
00255       final double[] lCoeffs0 = pHousehold0.getConsumptionTechnologyCoefficients();
00256       final double[] lCoeffs1 = pHousehold1.getConsumptionTechnologyCoefficients();
00257       final int numSectors = foundation.getNumSectors();
00258       final double lMoney0 = pHousehold0.getMoney();
00259       final double lMoney1 = pHousehold0.getMoney();
00260 
00261       final double lUtility0 = consumptionTechnology.calcUtility(lCoeffs0, numSectors,lMoney0);
00262       final double lUtility1 = consumptionTechnology.calcUtility(lCoeffs1, numSectors,lMoney1);
00263       // determine the utility per monetary unit
00264       final double lNormalizedUtility0 = lUtility0 /
00265                                           ArrayTools.scalarArrays(priceVector, lCoeffs0);
00266       final double lNormalizedUtility1 = lUtility1 /
00267                                           ArrayTools.scalarArrays(priceVector, lCoeffs1);
00268       
00269       // ... then compare
00270       if (lNormalizedUtility0 < lNormalizedUtility1) {
00271         return -1;
00272       } else  {
00273         return 1;
00274       } 
00275     }
00276   }
00277 
00284   @Guarded
00285   private class Employers implements Iterable<WorkContract> {
00286     @ValidateWithMethod(methodName = "isValidEmployerList",
00287                         parameterType = LinkedHashMap.class)
00289     @Description("The firms employing the household with the respective WorkContracts")
00290     @Variability(N_PERIODS)
00291     @Initialization(INDIVIDUAL)                    
00292     private final LinkedHashMap<Firm, WorkContract> firmWorkContractMap =
00293                                                       new LinkedHashMap<Firm, WorkContract>();
00294     // The OVal framework validates the firmWorkContractMap using this method
00295     @SuppressWarnings("unused")
00296     private boolean isValidEmployerList(LinkedHashMap<Household, WorkContract> pListToTest) {
00297       // a household cannot be employed by more firms than there currently exist 
00298       if (pListToTest.size() > foundation.getNumFirms()) {
00299         return false;
00300       }
00301 
00302       double lSumAmount = 0.d;
00303       for (final Firm lFirm : firmWorkContractMap.keySet()) {
00304         // check that the firm and the household have the same WorkContract
00305         final WorkContract lWorkContract = employers.get(lFirm);
00306         if (!lWorkContract.equals(lFirm.getWorkContractForWorker(Household.this))) {
00307           return false;
00308         }
00309         // and check the status of the work contract
00310         if (lWorkContract.getStatus() != WorkContract.Status.ACCEPTED) {
00311           return false;
00312         }
00313 
00314         lSumAmount += lWorkContract.getAmount();
00315       }
00316       // the total amount of work should not be higher than 1, representing full employment
00317       return FloatMath.lowerOrApproxEqual(lSumAmount, 1.d);
00318     }
00319 
00321     // @Steffen: TODO, maybe it would be a good idea to remove this field and replace it with
00322     // firmWorkContractMap.values() and create a list in the iterator, sort it, and
00323     // return it iterator there. But check the performance before.
00324     @Description("The list of work contracts of the household")
00325     @Variability(N_PERIODS)
00326     @Initialization(INDIVIDUAL)     
00327     private final List<WorkContract> workContractSorted = new LinkedList<WorkContract>();
00328 
00332     @Description("The sum of the work amount in all of the household's WorkContracts")
00333     @Variability(N_PERIODS)
00334     @Initialization(INDIVIDUAL)                    
00335     private double totalWorkAmount = 0.d;
00336 
00337     @Description("A marker to check whether work contracts of the household have changed")
00338     @Variability(N_PERIODS)
00339     @Initialization(INDIVIDUAL)                    
00340     private boolean workContractsChanged = true;
00341 
00342     private int size() {
00343       return firmWorkContractMap.size();
00344     }
00345 
00346     public boolean containsKey(Firm pEmployer) {
00347       return firmWorkContractMap.containsKey(pEmployer);
00348     }
00349 
00350     public WorkContract get(Firm pEmployer) {
00351       return firmWorkContractMap.get(pEmployer);
00352     }
00353 
00357     public void addContract(Firm pEmployer, WorkContract pWorkContract) {
00358       if (containsKey(pEmployer)) {
00359         workContractSorted.remove(firmWorkContractMap.get(pEmployer));
00360       }
00361       firmWorkContractMap.put(pEmployer, pWorkContract);
00362       workContractSorted.add(pWorkContract);
00363       workContractsChanged();
00364     }
00365     
00368     public void removeContract(Firm pEmployer) {
00369       workContractSorted.remove(firmWorkContractMap.get(pEmployer));
00370       firmWorkContractMap.remove(pEmployer);
00371       workContractsChanged();
00372     }
00373 
00374     public double getWorkAmount() {
00375       return totalWorkAmount;
00376     }
00377 
00381     private void workContractsChanged(){
00382       workContractsChanged = true;
00383       foundation.getHouseholds().workContractsChanged(Household.this);
00384       totalWorkAmount = calcWorkAmount();
00385     }
00386 
00394     @NotNegative
00395     @Post(expr = "de.pik.lagom.toolbox.math.FloatMath.lowerOrApproxEqual(_returns, 1)",
00396           lang = "groovy")
00397     private double calcWorkAmount() {
00398       double lSumAmount = 0.d;
00399 
00400       for (final WorkContract lWorkContract : workContractSorted) {
00401         lSumAmount += lWorkContract.getAmount();
00402       }
00403 
00404       return lSumAmount;
00405     }
00406 
00413     @PreValidateThis
00414     @NotNegative
00415     double calcCurrentWage() {
00416       double lSumWage = 0.d;
00417 
00418       for (final WorkContract lWorkContract : workContractSorted) {
00419         lSumWage += lWorkContract.getWageCurrentWorkAmount();
00420       }
00421 
00422       return lSumWage;
00423     }
00424 
00427     public Iterator<WorkContract> iterator() {
00428       if (workContractsChanged) {
00429         Collections.sort(workContractSorted, new WorkContract.WageComparator());
00430         workContractsChanged = false;
00431       }
00432       return workContractSorted.iterator();
00433     }
00434   }//end of class Employers
00435 
00436   //variables etc.
00437   @NotNull
00438   private static Foundation foundation;
00439 
00440   @Description("Statistics of the household, collected in each period")
00441   @Variability(PERIOD)
00442   @Initialization(INDIVIDUAL)
00443   private final Stats stats = new Stats();
00444 
00446   @NotNull
00447   @Description("The initialization Values of the Households")
00448   @Variability(SIMULATION)
00449   @Initialization(EQUAL)
00450   private final HouseholdInitValues initValues;
00451 
00453   @Description("The list of Firms that are employing the Household, wrapped in a helper class")
00454   @Variability(N_PERIODS)
00455   @Initialization(INDIVIDUAL)
00456   private final Employers employers;
00457 
00461   @Description("The fallback position of the Household. This number, adjusted by the " +
00462       "unemployment rate, is compared to the firm's wage reference in order to decide whether" +
00463       " to accept a work contract offer")
00464   @Variability(SIMULATION) 
00465   @Initialization(INDIVIDUAL)
00466   private double fallback;
00467 
00469   @Description("The net income of the Household, including wage, dividends and interest on " +
00470       "savings")
00471   @Variability(PERIOD) 
00472   @Initialization(INDIVIDUAL)
00473   private double netIncome;
00474 
00476   @Description("The expected income of the Household")
00477   @Variability(PERIOD)
00478   @Initialization(EQUAL)
00479   private double expectedIncome;
00480 
00482   @Description("The growth rate of the expected income of the Household")
00483   @Variability(PERIOD)
00484   @Initialization(INDIVIDUAL)
00485   private double expectedIncomeGrowthRate = 0.01d;
00486   
00487 
00489   private double expectedIncomeTrend = 0.01d;
00490 
00492   @GreaterOrApproxZero
00493   @Description("The savings (as of last period) of the Household")
00494   @Variability(PERIOD) 
00495   @Initialization(EQUAL)
00496   private double savings = 0.d;
00497 
00499   @GreaterOrApproxZero
00500   @Description("The share of unexpected income the household saves")
00501   @Variability(SIMULATION) 
00502   @Initialization(EQUAL)
00503   private double savingsRate;
00504 
00506   @Description("The Household's money holdings (excluding savings, i.e. money is cash)")
00507   @Variability(VOLATILE) 
00508   @Initialization(EQUAL)
00509   @GreaterOrApproxZero
00510   private double money;
00511   
00513   @GreaterOrApproxZero
00514   @Description("The variation of the Household's money holdings from one accounting step " +
00515       "to the next")
00516   @Variability(PERIOD) 
00517   @Initialization(INDIVIDUAL)
00518   private double moneyVariation = 0;
00519   
00521   @GreaterOrApproxZero
00522   @Description("The value of consumption, expressed in money")
00523   @Variability(PERIOD) 
00524   @Initialization(INDIVIDUAL)
00525   private double consumptionValue = 0;
00526 
00528   @GreaterOrApproxZero
00529   @Description("The taxes paid by the household in the current period")
00530   @Variability(PERIOD) 
00531   @Initialization(INDIVIDUAL)
00532   private double taxesPaid = 0;
00533 
00535   @GreaterOrApproxZero
00536   @Description("The income from unemployment assurance, paid by the government for the " +
00537       "amount of working time for which the household is not employed.")
00538   @Variability(PERIOD) 
00539   @Initialization(INDIVIDUAL)
00540   private double unemploymentIncome = 0;
00541   
00543   @GreaterOrApproxZero
00544   @Description("The income from the household's work contracts.")
00545   @Variability(PERIOD) 
00546   @Initialization(INDIVIDUAL)
00547   private double employmentIncome = 0;
00548   
00550   @GreaterOrApproxZero
00551   @Description("The interest received on savings.")
00552   @Variability(PERIOD) 
00553   @Initialization(INDIVIDUAL)
00554   private double interestOnSavings = 0;
00555   
00557   @Description("The dividends received from the firms the household owns.")
00558   @Variability(PERIOD) 
00559   @Initialization(INDIVIDUAL)
00560   @GreaterOrApproxZero
00561   private double dividends = 0;
00562 
00564   @GreaterOrApproxZero
00565   @Description("Array of goods the Household owns.")
00566   @Variability(VOLATILE) 
00567   @Initialization(INDIVIDUAL)
00568   private double stock[];
00569 
00571   static private int nextId = 0;
00572 
00573   @Description("Probe of the household, outputs information to the UI")
00574   @Variability(VOLATILE) 
00575   @Initialization(INDIVIDUAL)
00576   private final Household.Probe probe = new Household.Probe();
00577 
00579   @Description("The list of firms the household owns")
00580   @Variability(VOLATILE) 
00581   @Initialization(INDIVIDUAL)
00582   private final LinkedList<Firm> ownedFirms = new LinkedList<Firm>();
00583 
00584   @Description("An array of Supplier Objects, one for each Sector")
00585   @Variability(SIMULATION)
00586   @Initialization(EQUAL)
00587   private final Suppliers[] suppliers;
00588 
00589   @Description("An array of prices, one for each Sector, containing the average price" +
00590       " observed among suppliers of that sector")
00591   @Variability(PERIOD)
00592   @Initialization(INDIVIDUAL)
00593   private final double[] priceVector;
00594 
00595   @Description("An array of coefficients which determine the fraction of money allocated " +
00596       "to each Sector in consumption.")
00597   @Variability(N_PERIODS)
00598   @Initialization(EQUAL)
00599   private double[] consumptionTechnologyCoefficients;
00600 
00601   @Description("The initial array of coefficients which determine the fraction of money" +
00602       " allocated to each Sector in consumption.")
00603   @Variability(SIMULATION)
00604   @Initialization(EQUAL)
00605   private double[] initialConsumptionTechnologyCoefficients;
00606 
00607   @Description("A helper class that determines the utility function of the household.")
00608   @Variability(SIMULATION)
00609   @Initialization(EQUAL)
00610   @Comment("I vote for renaming this thing to UtilityMechanism or similar, it does not " +
00611       "influence what the household consumes, which makes this name confusing. Grüße, Sarah")
00612   private final ConsumptionTechnology consumptionTechnology;
00613 
00614   @Description("An interval giving the range of mutation of the consumption technology " +
00615       "coefficients")
00616   @Variability(SIMULATION)
00617   @Initialization(EQUAL)
00618   private DoubleInterval[] consumptionTechnologyMutation;
00619 
00620   static private RandomGenerator random;
00621   
00622   private double[] rationing;
00623 
00624 
00625   //construct and then initialize
00627   Household (Foundation pFoundation, HouseholdInitValues pInitValues) throws 
00628               ParameterParserException {
00629     foundation = pFoundation;
00630     initValues = pInitValues;
00631     random = Foundation.getRandomGenerator();
00632     employers = new Employers();
00633     suppliers = new Suppliers[foundation.getNumSectors()];
00634     priceVector = new double[foundation.getNumSectors()];
00635     consumptionTechnology = ConsumptionTechnologyFactory.getConsumptionTechnologyWithName(
00636                                                initValues.getConsumptionTechnologyName(),
00637                                                this, foundation.getNumSectors());
00638     consumptionTechnologyCoefficients = new double[foundation.getNumSectors()];
00639   }
00640 
00642   @PostValidateThis
00643   void init() {
00644     final int lNumSectors = foundation.getNumSectors();
00645     final double lUnemploymentRate = Foundation.getInitValues().governmentInitValues().getInitUnemploymentRate();
00646     final double lMaxNumberSuppliersRatio=0.5;
00647     
00648     for (final Sector lSector : foundation.getSectorList()) {
00649       suppliers[lSector.getArrayIndex()] = new Suppliers();
00650       suppliers[lSector.getArrayIndex()].init( foundation,this, lSector,
00651                                                lMaxNumberSuppliersRatio);
00652       consumptionTechnologyCoefficients[lSector.getArrayIndex()] =
00653           lSector.getInitConsumption() / foundation.getInitOverallConsumption();
00654     }
00655     initialConsumptionTechnologyCoefficients = ArrayTools.deepCopy(
00656                                                             consumptionTechnologyCoefficients);
00657     stock = new double[foundation.getNumSectors()];
00658     rationing =new double[foundation.getNumSectors()];
00659     
00660     // fallback is initialized uniformly  and in such a way that the share of agents with fallback above one
00661     //equals the unemployment rate.
00662     fallback=(1+lUnemploymentRate/(1-lUnemploymentRate))*random.nextDouble();
00663     //fallback=0;
00664     savings =initValues.getSavings() / foundation.getNumHouseholdsTotal();
00665     expectedIncome = Foundation.getInitValues().overallConsumption() / foundation.getNumHouseholdsTotal();
00666     setMoney(expectedIncome);
00667     // TODO v2:  this formulation would be more convenient (stf)
00668     // money = savings;
00669     // expectedIncome = savings;
00670     savingsRate = initValues.getSavingRate();
00671     // construct the MutationIntervals
00672     consumptionTechnologyMutation = new DoubleInterval[lNumSectors];
00673     for (int iSector = 0; iSector < lNumSectors; iSector++) {
00674       consumptionTechnologyMutation[iSector] = new DoubleInterval(
00675           initValues.getConsumptionTechnologyMutationMin()[iSector],
00676           initValues.getConsumptionTechnologyMutationMax()[iSector]);
00677     }
00678 
00679     probe.init();
00680     foundation.getProbeManager().addProbe(probe);
00681     stats.init(foundation.getStepManager());
00682   }
00683 
00689   @PostValidateThis
00690   public void trade() {
00691     final double lMoneyBeforeTrade = getMoney();
00692     consumptionValue=0;
00693     assert (FloatMath.lowerOrApproxEqual(0, getMoney()));
00694 
00695     for (int iSector = 0; iSector < foundation.getNumSectors(); iSector++) {
00696       suppliers[iSector].updateSuppliers(Suppliers.SellerSet.INCLUDE_IMPORT);
00697       priceVector[iSector] = suppliers[iSector].averagePrice();
00698     }
00699 
00700     // the initial demand.
00701     double[] lDemand = calcDemand(lMoneyBeforeTrade, priceVector);
00702     //assert (FloatMath.lowerOrApproxEqual(ArrayTools.scalarArrays(lDemand,priceVector),lMoneyBeforeTrade));
00703     
00704     // In case of rationning, add suppliers 
00705     for (int iSector = 0; iSector < foundation.getNumSectors(); iSector++) {
00706       suppliers[iSector].addSuppliers(lDemand[iSector],Suppliers.SellerSet.INCLUDE_IMPORT);     
00707       priceVector[iSector] = suppliers[iSector].averagePrice();
00708       rationing[iSector]=Math.max(0,lDemand[iSector]-suppliers[iSector].maxSupply());
00709     }
00710     // recompute the demand 
00711     lDemand = calcDemand(lMoneyBeforeTrade, priceVector);
00712     
00713     // compute the total value of demand
00714     double lTotalDemandValue = ArrayTools.scalarArrays(lDemand,priceVector);
00715     if (lTotalDemandValue>0){
00716       // compute the value demanded for each good
00717       assert (FloatMath.lowerOrApproxEqual(lTotalDemandValue,lMoneyBeforeTrade));
00718       double[] lDemandValue = new double[foundation.getNumSectors()];
00719       for (int iSector = 0; iSector < foundation.getNumSectors(); iSector++) {
00720         lDemandValue[iSector]= (lDemand[iSector]*priceVector[iSector]/lTotalDemandValue)*lMoneyBeforeTrade;       
00721       // purchase the goods.
00722         final double lTradeValue = Math.min(lDemandValue[iSector], suppliers[iSector].costOfTotalStock());
00723         final double lAmount = suppliers[iSector].buyValue(lTradeValue);
00724         consumptionValue +=lTradeValue;
00725         stock[iSector] += lAmount;
00726         setMoney(getMoney() - lTradeValue);
00727       }
00728     }
00729 
00730     assert(FloatMath.greaterOrApproxZero(money));
00731   }
00732   
00733 
00743   private double[] calcDemand(double m, double[] price) {
00744     return calcDemand(m, price, consumptionTechnologyCoefficients);
00745   }
00746 
00747   //adjust employemnt step
00751   @PostValidateThis
00752   void adjustEmploymentStatus() {   
00753     //  first check the existing work contracts, find those jobs that are paid too little...
00754     final LinkedList<WorkContract> lListOfJobsToQuit = new LinkedList<WorkContract>();
00755     for (final WorkContract lExistingContract : employers)
00756     {
00757       if (!FloatMath.greaterOrApproxEqual(getEmployersWageReference(lExistingContract),
00758                                           getUnemploymentAdjustedFallback())) {
00759         lListOfJobsToQuit.add(lExistingContract);
00760       }
00761     }
00762     // ... and quit them
00763     for  (final WorkContract lJobToQuit : lListOfJobsToQuit) {
00764       quitJob(lJobToQuit);
00765     }
00766 
00767     //Then try to find new jobs
00768     final long lNumRemainingFirmsToObserve =
00769       Math.round(Math.max(1.d, initValues.getObservedEmployersQuotient() * 
00770                                                                foundation.getNumFirms()));        
00771     final LinkedList<Firm> lAllFirms = foundation.generateFirmList();
00772     for (int i = 0; i < lNumRemainingFirmsToObserve; i++) {
00773       // draw a random firm
00774       final Firm lFirm = lAllFirms.get(random.nextInt(lAllFirms.size()));
00775       // get a work contract ...
00776       final WorkContract lOffer = lFirm.constructActualWorkContract();
00777       // if the firm has a job to offer ...
00778       if (lOffer.getStatus() == WorkContract.Status.OFFERED) {
00779         // check whether it is acceptable ...
00780         final WorkContract lReply = checkWorkContractOffer(lOffer);
00781         // ... if so, accept
00782         if (lReply.getStatus() == WorkContract.Status.ACCEPTED) {
00783           lReply.getEmployer().householdAcceptWorkContract(this, lReply);
00784         }
00785       }
00786     }
00787   }
00788 
00797   @Pre(expr = "pOfferedContract.getStatus() == de.pik.lagom.generic.WorkContract.Status.OFFERED",
00798        lang = "groovy")
00799   @Post(expr = "de.pik.lagom.toolbox.math.FloatMath.lowerOrApproxEqual(" +
00800                "_returns.getAmount(), _old.getAmount()) &&" +
00801                "_returns.getWageFullEmployed() == _old.getWageFullEmployed() &&" +
00802                "_returns.getEffort() == _old.getEffort() &&" +
00803                "_returns.getEmployer() == _old.getEmployer() &&" +
00804                "_returns.getStatus() == de.pik.lagom.generic.WorkContract.Status.ACCEPTED ? " +
00805                  "de.pik.lagom.toolbox.math.FloatMath.approxEqual(_old.getAmount()," +
00806                     "_returns.getAmount() + pOfferedContract.getAmount()) : true &&" +
00807                "!(_returns.getStatus() == de.pik.lagom.generic.WorkContract.Status.OFFERED)",
00808         old =  "new de.pik.lagom.generic.WorkContract(pOfferedContract)", lang = "groovy")
00809   WorkContract checkWorkContractOffer(WorkContract pOfferedContract) {
00810     double lAcceptedAmount = 0.d;
00811     // check acceptability, i.e. whether the firm's wage reference is larger than 
00812     // the fallback adjusted by the current unemployment rate
00813     if (FloatMath.greaterOrApproxEqual(getEmployersWageReference(pOfferedContract),
00814                                           getUnemploymentAdjustedFallback())) {
00815       // if accepted, household offers up to its free time as work amount 
00816     lAcceptedAmount = Math.min(1.d - calcWorkAmount(), pOfferedContract.getAmount());
00817       pOfferedContract.reduceAmount(lAcceptedAmount);
00818     }
00819 
00820     // If there already exist a work contract with the firm that offers the new one,
00821     // add the current work amount to the accepted offer, else create a new contract.
00822     if (lAcceptedAmount > 0.d){
00823       final WorkContract lExisting = employers.get(pOfferedContract.getEmployer());
00824       if (lExisting != null) {
00825           lAcceptedAmount += lExisting.getAmount();
00826           removeEmployment(lExisting.getEmployer());
00827       }
00828       pOfferedContract.setAmount(lAcceptedAmount);
00829       pOfferedContract.setStatus(WorkContract.Status.ACCEPTED);
00830       addEmployment(pOfferedContract);
00831     }
00832     else {
00833       pOfferedContract.setStatus(WorkContract.Status.REJECTED);
00834     }
00835     //returns the actual contract with the work amount that firm and household agree on
00836     return pOfferedContract;
00837   }
00838 
00844   @Pre(expr = "_this.employers.containsValue(pWorkContract)", lang = "groovy")
00845   private void quitJob(WorkContract pWorkContract) {
00846     removeEmployment(pWorkContract.getEmployer());
00847     //cancel the worker form the employer's worker list
00848     pWorkContract.getEmployer().workerQuitJob(this);
00849   }
00850 
00854   @NotNegative
00855   private double getEmployersWageReference(WorkContract pWorkContract) {
00856     return pWorkContract.getEmployer().getWageReference();
00857   }
00858 
00865   @Pre(expr = "de.pik.lagom.toolbox.math.FloatMath.lowerOrApproxEqual(" +
00866       "pWorkContract.amount - (_this.employers.get(pWorkContract.employer)?.amount ?: 0)" +
00867       " + _this.calcWorkAmount(), 1)", lang = "groovy")
00868   void addEmployment(WorkContract pWorkContract) {
00869     employers.addContract(pWorkContract.getEmployer(), pWorkContract);
00870   }
00871 
00877   @Pre(expr = "_this.employers.get(pEmployer) != null", lang = "groovy")
00878   void removeEmployment(Firm pEmployer) {
00879     employers.removeContract(pEmployer);
00880   }
00881   
00882   //consumption step
00887   @PostValidateThis
00888   void consume() {
00889     final double lConsume[] = ArrayTools.multiplyArray(1, stock);
00890 
00891     // report consumption
00892     for (final Sector lSector : foundation.getSectorList()) {
00893       lSector.getProbe().reportConsumption(lConsume[lSector.getArrayIndex()]);
00894     }
00895 
00896     // remove consumption from stock
00897     stock = ArrayTools.subtractArrays(stock, lConsume);
00898   }
00899 
00900   //accounting step
00909   @PreValidateThis
00910   @PostValidateThis
00911   void account() {
00912     final double lTaxRate = foundation.getGovernment().getTaxRate();
00913     taxesPaid = lTaxRate * calcIncome();
00914     netIncome = calcIncome() - taxesPaid;
00915     assert (FloatMath.lowerOrApproxEqual(0, netIncome));
00916 
00917     //if the Household earned more than expected, it saves money
00918     if (netIncome > expectedIncome) {
00919       assert (FloatMath.lowerOrApproxEqual(0, netIncome));
00920       savings += savingsRate * (netIncome - expectedIncome);
00921       setMoney(getMoney() + (netIncome - savingsRate * (netIncome - expectedIncome)));
00922     } else {//otherwise it takes money out of the savings
00923       final double lWealth = getMoney() + netIncome + savings;
00924       setMoney(Math.min(expectedIncome, lWealth));
00925       savings = lWealth - getMoney();
00926     }
00927     assert (FloatMath.lowerOrApproxEqual(0, getMoney()));
00928     moneyVariation = money - stats.getLastPeriodMoney();
00929 
00930     double lOldBase= expectedIncome;
00931     double lOldTrend= expectedIncomeTrend;
00932     double lRate=initValues.getExpectedIncomeUpdateRate();
00933     expectedIncome=Math.max(0,(1-lRate)*(lOldBase+lOldTrend)+lRate*netIncome);
00934     expectedIncomeTrend=Math.max(0,(1-lRate)*lOldTrend+lRate*(expectedIncome-lOldBase));
00935 
00936   }
00937 
00941   @PreValidateThis
00942   @GreaterOrApproxZero
00943   double calcIncome() {
00944     final double r = foundation.getFinancial().getInterestRate();
00945     interestOnSavings = r * savings;
00946     // add wage and interest on savings
00947     double lIncome = calcCurrentWageInclUnemploymentAssurance() + interestOnSavings ;
00948     // add dividends from all firms owned
00949     dividends = 0;
00950     for (final Firm lOwnedFirm : ownedFirms) {
00951       dividends += lOwnedFirm.getDividend();
00952     }
00953     lIncome += dividends;
00954     return lIncome;
00955   }
00956   
00963   @PreValidateThis
00964   @NotNegative
00965   double calcCurrentWage() {
00966     return employers.calcCurrentWage();
00967   }
00968 
00976   @Post(expr = "_returns >= _this.environment.getGovernment().getUnemploymentWage()",
00977         lang = "groovy")
00978   double calcCurrentWageInclUnemploymentAssurance() {
00979     employmentIncome = calcCurrentWage();
00980     
00981     final double lUnemploymentWage = foundation.getGovernment().getUnemploymentWage();
00982     final double lWorkAmount = calcWorkAmount();
00983     //the government pays unemployment income for the amount of time that the household is not
00984     // working
00985     unemploymentIncome= (1 - lWorkAmount) * lUnemploymentWage;
00986     if (lWorkAmount > 0){
00987       assert (employmentIncome > 0);
00988     }
00989     assert ((employmentIncome + unemploymentIncome) > 0);
00990     return (employmentIncome + unemploymentIncome);
00991   }
00992 
00993   //genetic evolution of technologies step, imitation and mutation
00994 /*  *//*
01000   public void copyTechnologyFrom() {
01001     // We can only copy technologies when we have more than one household
01002     if (foundation.getHouseholds().size() == 1) {
01003       return;
01004     }
01005 
01006     // observe the consumption technology of another household
01007     // if the randomly drawn household is the household itself, redraw
01008     Household lObservedHousehold;
01009     do {
01010       lObservedHousehold = foundation.getHouseholds().getRandomHousehold();
01011     } while (lObservedHousehold.equals(this));
01012 
01013     // compare the consumption technology coefficients for the utility per money spent, given
01014     // the prices observed by the household
01015     final double[] lObservedTechnologyCoef =
01016                                       lObservedHousehold.getConsumptionTechnologyCoefficients();
01017 
01018     final double lUtilityWithObservedCoef =
01019         consumptionTechnology.calcUtility(lObservedTechnologyCoef, foundation.getNumSectors(),
01020                                          money);
01021 
01022     final double lUtilityWithOwnCoef =
01023         consumptionTechnology.calcUtility(consumptionTechnologyCoefficients,
01024                                           foundation.getNumSectors(),money);
01025     
01026     //if the observed coefficients yield a higher utility, imitate 
01027     if (lUtilityWithObservedCoef / ArrayTools.scalarArrays(priceVector,
01028                                                            lObservedTechnologyCoef) >
01029         lUtilityWithOwnCoef / ArrayTools.scalarArrays(priceVector,
01030                                                       consumptionTechnologyCoefficients))
01031     {
01032       imitate(lObservedTechnologyCoef);
01033     }
01034   }*/
01035   
01043   void imitate(double[] observedTechnologyCoefficients) {
01044     consumptionTechnologyCoefficients = ArrayTools.addArrays(
01045                 ArrayTools.multiplyArray(initValues.getImitationFactor(),
01046                                          observedTechnologyCoefficients),
01047                 ArrayTools.multiplyArray(1.d - initValues.getImitationFactor(),
01048                                          consumptionTechnologyCoefficients));
01049   }
01050 
01054   public void mutateTechnologies() {
01055     consumptionTechnologyCoefficients = consumptionTechnology.mutateCoefficients(
01056                                     consumptionTechnologyMutation, foundation.getNumSectors());
01057   }
01058 
01067   @GreaterOrApproxZero
01068   public double[] calcDemand(double m, double[] price, 
01069                              double[] pConsumptionTechnologyCoefficients) {
01070     final int lNumSectors = foundation.getNumSectors();
01071     final double[] lDemand = new double[lNumSectors];
01072 
01073     //The household allocates the fraction of money given by the coefficient of a sector to 
01074     //that sector. Demand for that sector is then the amount that can be bought with that 
01075     //fraction of the money at the price of that sector (given by the price vector)   
01076     for (int iSector = 0; iSector < lNumSectors; iSector++) {
01077       lDemand[iSector] = m * pConsumptionTechnologyCoefficients[iSector] / price[iSector];
01078     }
01079 
01080     return lDemand;
01081   }
01082 
01083   //methods belonging to more than one step or to steps of other agents (like firms)
01089   @PostValidateThis
01090   void addFirmToProperty(Firm pFirm) {
01091     ownedFirms.add(pFirm);
01092     pFirm.setOwner(this);
01093   }
01094 
01100   @Pre(expr = "_this.ownedFirms.contains(pFirm)", lang = "groovy")
01101   void transferSavingsToFirmAndSetProduction(Firm pFirm) {
01102     final double lProduction = pFirm.getDesiredProduction();
01103     final double lSavings = savings;
01104     final double lTargetInvestment = pFirm.calcNeededMoneyForProduction(lProduction);
01105     final double lInvestment = Math.min(lTargetInvestment, lSavings);
01106     savings -= lInvestment;
01107     pFirm.setMoney(lInvestment);
01108     pFirm.setDesiredProduction((lInvestment/lTargetInvestment) * lProduction);
01109     foundation.getFinancial().setSavingsInvested(
01110                               foundation.getFinancial().getSavingsInvested() + lInvestment);
01111     //assert (foundation.getFinancial().getSavingsInvested() > 0);
01112   }
01113 
01119   @PostValidateThis
01120   void removeFirmFromProperty(Firm pFirm) {
01121     ownedFirms.remove(pFirm);
01122     pFirm.setOwner(null);
01123   }
01124 
01132   @NotNegative
01133   @Post(expr = "de.pik.lagom.toolbox.math.FloatMath.lowerOrApproxEqual(_returns, 1)",
01134         lang = "groovy")
01135   double calcWorkAmount() {
01136     return employers.getWorkAmount();
01137   }
01138 
01140   public boolean isEmployed() {
01141     return (calcWorkAmount() > 0.d);
01142   }
01143   
01145   public static void resetId() {
01146     nextId = 0;
01147   }
01148 
01149   // getter/setter methods
01150   public Household.Probe getProbe() {
01151     return probe;
01152   }
01153 
01154   public WorkContract getWorkContractForFirm(Firm pFirm) {
01155     return employers.get(pFirm);
01156   }
01157 
01158   public double getSavings() {
01159     return savings;
01160   }
01161 
01162   public double getMoney() {
01163     return money;
01164   }
01165 
01166   public double getConsumptionValue() {
01167     return consumptionValue;
01168   }
01169 
01170 
01171   public double getEmploymentIncome() {
01172     return employmentIncome;
01173   }
01174   
01175   public double getTaxesPaid() {
01176     return taxesPaid;
01177   }
01178 
01179   public double getInterestsOnSavings() {
01180     return interestOnSavings;
01181   }
01182 
01183   public double getUnemploymentIncome() {
01184     return unemploymentIncome;
01185   }
01186   
01187 
01188   public double getDividends() {
01189     return dividends;
01190   }
01191 
01192   public double getMoneyVariation() {
01193     return moneyVariation;
01194   }
01195 
01196   public double getFallback() {
01197     return fallback;
01198   }
01199   
01200   public double getUnemploymentAdjustedFallback() {
01201     return (1 - foundation.getGovernment().getUnemploymentRate()) * fallback;
01202   }
01203 
01204   public double[] getConsumptionTechnologyCoefficients() {
01205     return consumptionTechnologyCoefficients;
01206   }
01207 
01208   public ConsumptionTechnology getConsumptionTechnology() {
01209     return consumptionTechnology;
01210   }
01211 
01212   public void setConsumptionTechnologyCoefficients(double[] pCTC) {
01213     consumptionTechnologyCoefficients = pCTC;
01214   }
01215 
01216   public void setMoney(double pMoney) {
01217    money = pMoney;
01218   }
01219 
01220   public void setEmploymentIncome(double pEmploymentIncome) {
01221     employmentIncome = pEmploymentIncome;
01222   }
01223 
01224   public double[] getInitialConsumptionTechnologyCoefficients() {
01225     return initialConsumptionTechnologyCoefficients;
01226   }
01227 
01228   public double getInitConsumptionElasticity() {
01229     return initValues.getConsumptionElasticity();
01230   }
01231   
01232   public Suppliers getSuppliers(Sector lSector) {
01233     return suppliers[lSector.getArrayIndex()];
01234   }
01235   
01236   public Suppliers[] getSuppliers() {
01237     return suppliers;
01238   }
01239 
01240   public double[] getRationing() {
01241     return rationing;
01242   }
01243   
01244   public double getBenchmarkDemand(Sector lSector){
01245     return calcDemand(money,foundation.generatePriceVector())[lSector.getArrayIndex()];
01246   }
01247   
01248   public double getObservedSuppliersQuotient(){
01249     return initValues.getObservedSuppliersQuotient();
01250   }
01251 }
01252 
01254 // EOF

Generated on Tue Sep 14 11:11:48 2010 for lagom_generiC by  doxygen 1.5.4