unit ConsumerUn;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

const numconsumers = 50;
      numgoods     = 20;
      numutilities = 5;


type consumertype =
  record

    // SCALAR VARIABLES

    CWage,            //  Dollars per hour worked by the consumer

    CHours,           // 1.0 = full-time

    CIncome,          // Money per hour earned = cwage * chours

    CSavingsRef,       // Reference amount of money in savings

    CSavings,          // Perceived & actual money in savings

    CSavingsError,     // Savings error

    CSavingsGain,      // Gain for lowering/raising expenditures

    CSavingsOutput:    // output of savings control level

             single;

    // Goods, ARRAY VARIABLES

    CBuyGoodRate, // number of purchases of the i-th good per hour

    CUseRate,     // consumer's rate of use of Good[i], number per hour

    CDeprecRate,  // consumer's rate of depreciation of goods on hand, fraction/hour

    CGoodRef,     // consumer's reference number of number of good[i] on hand

    CGood,        // number of consumer good on hand
                  // ( = consumer's perception of goods on hand)

    CGoodError,   // Error signal for goods

    CGoodGain:    // consumer's output gain for controlling good[i]

                array[0..numgoods - 1] of single;

  // UTILITIES, ARRAY VARIABLES

    CUtility,       // consumer's perceived utility for good[i]

    CUtilityRef,    // consumer's desired utility for good[i]

    CUtilityError,  // consumer's utility error for good[i]

    CUtilityGain,   // importance of each utility

    CUtilityOutput: //  output from each utility controller

           array[0..NumUtilities] of single;

    CUtilityInputWeight,    // contribution of goods to each utility

    CUtilityOutputWeight:   // contribution of each utility error to goods ref

          array[0..numUtilities - 1,0..Numgoods - 1] of single;


  end; { of consumertype}

var
  ConsumerFm: TConsumerFm;
  ConsumerList: array[0.. numconsumers - 1] of consumertype;
  dt: single;   // duration of one iteration, hours
  Price: array[0..numgoods - 1] of single;   //price of the i-th good

procedure ControlSavings;
procedure ControlUtility;
procedure ControlGoods;

implementation

{$R *.dfm}

// CONTROL OF CONSUMER GOODS ON HAND (lowest level)

procedure ControlGoods;
var consumer, good: integer;
begin
 for consumer := 0 to numconsumers - 1 do
 with consumerlist[consumer] do
 begin
  for good := 0 to numgoods - 1 do
  begin
   // compute income for this iteration
   CIncome := CWage*CHours*dt;
   // Add income to savings
   CSavings := CSavings + CIncome;
   // depreciate goods on hand
   CGood[good] := (1 - CDeprecRate[good]) * CGood[good] * dt;
   // use up goods
   CGood[good] := CGood[good] - CUseRate[good]*dt;
   // error in goods possessed
   CGoodError[good] := CGoodRef[good] - CGood[good];
   // quantity to buy, this iteration
   CBuyGoodRate[good] := CGoodGain[good] * CGoodError[good];
   // if enough money, buy the good, increase goods on hand, reduce savings
   if CBuyGoodRate[good]*Price[good] <= CSavings then
   begin
    CGood[good] := CGood[good] + CBuygoodRate[good]*dt;
    CSavings := CSavings - CBuyGoodRate[good] * Price[good]*dt;
   end;
  end; { of per-good controls}
 end;
end;

   // CONTROL OF CONSUMER SAVINGS
   // Reduces purchase reference levels if savings less than desired

procedure ControlSavings;
var consumer: integer;
begin
 for consumer := 0 to numconsumers - 1 do
 with consumerlist[consumer] do
 begin
  CSavingsError := CSavingsRef - CSavings;            // Error in savings
  // if reference less than savings, generate output for goods purchase refs
  if CSavingsError <= 0 then
   CSavingsOutput := CSavingsGain*CSavingsError;
 end;
end;

// CONTROL OF UTILITIES OF GOODS
// Increases purchase reference levels if utility less than desired.

procedure ControlUtility;
var consumer, good, util: integer;
begin
 for consumer := 0 to numconsumers - 1 do
 with ConsumerList[consumer] do
  for util := 0 to numutilities do
  begin
   // compute each utility as weighted sum of goods
   CUtility[util] := 0.0;
   for good := 0 to numgoods - 1 do
    CUtility[util] := CUtility[util] +
                      CUtilityInputWeight[util,good]* CGood[good];
   // compute error and output for each utility
   CUtilityError[util] := CUtilityRef[util] - CUtility[util];
   CUtilityOutput[util] := CUtilityGain[util]*CutilityError[util];
  end;
end;

procedure SetRefGoods
var consumer, good, util: integer;
begin
 for consumer := 0 to numconsumers - 1 do
 with ConsumerList[consumer] do
  for good := 0 to numgoods - 1 do
  begin
   CGoodRef[good] := 0.0;
   for util := 0 to numutilities do
    CGoodRef[good] := CGoodRef[good] +
           CUtilityOutput[util]*CUtilityOutputWeight[util, good];
   CGoodRef[good] := CGoodRef[good] - CSavingsOutput*CSavingsGain;
  end;
end.
