00001
00002
00003
00004
00005
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
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 }
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 );
00154 }
00155
00156 public double getLastPeriodIncome() {
00157 return incomeMemory.last();
00158 }
00159
00160 public double getLastPeriodMoney() {
00161 return moneyMemory.last();
00162 }
00163 }
00164
00170 static public class WorkAmountComparator implements Comparator<Household> {
00171 public int compare(Household pHousehold0, Household pHousehold1) {
00172
00173 final double lWorkAmount0 = pHousehold0.calcWorkAmount();
00174 final double lWorkAmount1 = pHousehold1.calcWorkAmount();
00175
00176
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
00191 final double lFallback0 = pHousehold0.getFallback();
00192 final double lFallback1 = pHousehold1.getFallback();
00193
00194
00195 if (lFallback0 < lFallback1) {
00196 return -1;
00197 } else if (lFallback0 > lFallback1) {
00198 return 1;
00199 } else {
00200
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
00212 final double lFallback0 = pHousehold0.getFallback();
00213 final double lFallback1 = pHousehold1.getFallback();
00214
00215
00216 if (lFallback0 > lFallback1) {
00217 return -1;
00218 } else if (lFallback0 < lFallback1) {
00219 return 1;
00220 } else {
00221
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
00233 final double lSavings0 = pHousehold0.getSavings();
00234 final double lSavings1 = pHousehold1.getSavings();
00235
00236
00237 if (lSavings0 < lSavings1) {
00238 return -1;
00239 } else if (lSavings0 > lSavings1) {
00240 return 1;
00241 } else {
00242
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
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
00264 final double lNormalizedUtility0 = lUtility0 /
00265 ArrayTools.scalarArrays(priceVector, lCoeffs0);
00266 final double lNormalizedUtility1 = lUtility1 /
00267 ArrayTools.scalarArrays(priceVector, lCoeffs1);
00268
00269
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
00295 @SuppressWarnings("unused")
00296 private boolean isValidEmployerList(LinkedHashMap<Household, WorkContract> pListToTest) {
00297
00298 if (pListToTest.size() > foundation.getNumFirms()) {
00299 return false;
00300 }
00301
00302 double lSumAmount = 0.d;
00303 for (final Firm lFirm : firmWorkContractMap.keySet()) {
00304
00305 final WorkContract lWorkContract = employers.get(lFirm);
00306 if (!lWorkContract.equals(lFirm.getWorkContractForWorker(Household.this))) {
00307 return false;
00308 }
00309
00310 if (lWorkContract.getStatus() != WorkContract.Status.ACCEPTED) {
00311 return false;
00312 }
00313
00314 lSumAmount += lWorkContract.getAmount();
00315 }
00316
00317 return FloatMath.lowerOrApproxEqual(lSumAmount, 1.d);
00318 }
00319
00321
00322
00323
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 }
00435
00436
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
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
00661
00662 fallback=(1+lUnemploymentRate/(1-lUnemploymentRate))*random.nextDouble();
00663
00664 savings =initValues.getSavings() / foundation.getNumHouseholdsTotal();
00665 expectedIncome = Foundation.getInitValues().overallConsumption() / foundation.getNumHouseholdsTotal();
00666 setMoney(expectedIncome);
00667
00668
00669
00670 savingsRate = initValues.getSavingRate();
00671
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
00701 double[] lDemand = calcDemand(lMoneyBeforeTrade, priceVector);
00702
00703
00704
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
00711 lDemand = calcDemand(lMoneyBeforeTrade, priceVector);
00712
00713
00714 double lTotalDemandValue = ArrayTools.scalarArrays(lDemand,priceVector);
00715 if (lTotalDemandValue>0){
00716
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
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
00751 @PostValidateThis
00752 void adjustEmploymentStatus() {
00753
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
00763 for (final WorkContract lJobToQuit : lListOfJobsToQuit) {
00764 quitJob(lJobToQuit);
00765 }
00766
00767
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
00774 final Firm lFirm = lAllFirms.get(random.nextInt(lAllFirms.size()));
00775
00776 final WorkContract lOffer = lFirm.constructActualWorkContract();
00777
00778 if (lOffer.getStatus() == WorkContract.Status.OFFERED) {
00779
00780 final WorkContract lReply = checkWorkContractOffer(lOffer);
00781
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
00812
00813 if (FloatMath.greaterOrApproxEqual(getEmployersWageReference(pOfferedContract),
00814 getUnemploymentAdjustedFallback())) {
00815
00816 lAcceptedAmount = Math.min(1.d - calcWorkAmount(), pOfferedContract.getAmount());
00817 pOfferedContract.reduceAmount(lAcceptedAmount);
00818 }
00819
00820
00821
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
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
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
00887 @PostValidateThis
00888 void consume() {
00889 final double lConsume[] = ArrayTools.multiplyArray(1, stock);
00890
00891
00892 for (final Sector lSector : foundation.getSectorList()) {
00893 lSector.getProbe().reportConsumption(lConsume[lSector.getArrayIndex()]);
00894 }
00895
00896
00897 stock = ArrayTools.subtractArrays(stock, lConsume);
00898 }
00899
00900
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
00918 if (netIncome > expectedIncome) {
00919 assert (FloatMath.lowerOrApproxEqual(0, netIncome));
00920 savings += savingsRate * (netIncome - expectedIncome);
00921 setMoney(getMoney() + (netIncome - savingsRate * (netIncome - expectedIncome)));
00922 } else {
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
00947 double lIncome = calcCurrentWageInclUnemploymentAssurance() + interestOnSavings ;
00948
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
00984
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
00994
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
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
01074
01075
01076 for (int iSector = 0; iSector < lNumSectors; iSector++) {
01077 lDemand[iSector] = m * pConsumptionTechnologyCoefficients[iSector] / price[iSector];
01078 }
01079
01080 return lDemand;
01081 }
01082
01083
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
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
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