Пример #1
0
    def __init__(self, unique_id, model, liquid_assets, market_share):
        super().__init__(unique_id, model)

        self.group = None

        self.liquid_assets = d(liquid_assets)
        self.market_share = d(market_share)
Пример #2
0
class Firm(Agent):

    log = logging.getLogger(__name__)

    debt_stock = d(0)
    unit_production_cost = d(0)
    competitiveness = d(100)
    capital_employed = d(0)
    debt_employed = d(0)
    residual_assets = None
    available_debt = None

    bankrupt = False

    def __init__(self, unique_id, model, liquid_assets, market_share):
        super().__init__(unique_id, model)

        self.group = None

        self.liquid_assets = d(liquid_assets)
        self.market_share = d(market_share)

    def fix_price(self):
        return (1 + self.model.mark_up) * self.unit_production_cost

    def finance_operations(self, quantity, unit_cost):
        cost = unit_cost * quantity
        capital_employed = min(cost, self.residual_assets)
        debt_employed = min(cost - capital_employed, self.available_debt)
        return capital_employed, debt_employed
Пример #3
0
    def __init__(self, unique_id, model, liquid_assets, market_share, **kwargs):
        super().__init__(unique_id, model, liquid_assets, market_share)

        self.group = 'capital_firm'

        self.machine = Machine(
            producer=unique_id,
            generation=1,
            lpc=d(100),
            price=d(1)
        )
Пример #4
0
 def forecast_expansion_investment(self):
     trigger_level = d(int(self.capital_stock * (1 + self.model.trigger_rule)))
     planned_ei = 0
     if self.desired_capital_stock >= trigger_level:
         # NOTE: in paper this is trigger_level
         planned_ei = trigger_level - self.capital_stock
     return planned_ei
Пример #5
0
 def replace_and_add_machines(self):  # TODO: add logging
     supplier = self.model.schedule.get_agent(self.supplier)
     if supplier.output < supplier.demand:
         # TODO: assign residual orders to firms
         received_orders = (
             int(d(self.investment / supplier.orders) * supplier.output)
         )
         self.reimburse_investment(received_orders)
     new_machines = self.expansion_investment
     for machine_type in self.want_to_scrap:
         stock = self.machines[machine_type]['stock']
         if stock <= self.replacement_investment:
             self.machines.pop(machine_type)
             new_machines += stock
         else:
             self.machines[machine_type]['stock'] -= self.replacement_investment
             new_machines += self.replacement_investment
             break
     new_type = (supplier.unique_id, supplier.machine.generation)
     if new_type in self.machines:
         self.machines[new_type]['stock'] += new_machines
         return None
     self.machines[new_type] = {
         'machine': deepcopy(supplier.machine),
         'stock': new_machines
     }
Пример #6
0
 def update_employment(self):
     self.employment = min(self.labour_demand, self.labour_supply)
     self.unemployment = max(0, self.labour_supply - self.employment)
     unemployment_rate = d(self.unemployment / self.labour_supply)
     delta_unemployment = unemployment_rate - self.unemployment_rate
     self.unemployment_rate = unemployment_rate
     self.delta_unemployment = delta_unemployment
Пример #7
0
 def compute_average_productivity(self):
     productivities = []
     machine_set = list(self.machines.keys())
     for machine_type in machine_set:
         machine = self.machines[machine_type]['machine']
         stock = self.machines[machine_type]['stock']
         productivity = (
             machine.labour_productivity_coefficient * stock
         )
         productivities.append(productivity)
     avgp = sum(productivities) / self.capital_stock
     return d(float(avgp))
Пример #8
0
 def compute_market_share(self):
     sector_avg_comp = self.model.avg_comp_competitiveness
     if self.unique_id == 50:
         self.log.info('computing market share')
         self.log.info(f'own competitiveness: {self.competitiveness}')
         self.log.info(f'sector average competitiveness: {sector_avg_comp}')
     ms = (
         self.market_share
         * (1 + self.model.replicator_dynamics_coeff[0]
            * (self.competitiveness - sector_avg_comp)
            / sector_avg_comp)
     )
     return d(max(0, ms))
Пример #9
0
 def forecast_demand(self, myopic=True):
     if myopic:
         return self.demand
     firm_data = self.model.datacollector.get_table_dataframe(
         'consumption_firm'
     )
     # model_data = self.model.datacollector.get_model_vars_dataframe()
     past_demand = firm_data.loc[
         firm_data.agent_id == self.unique_id, 'demand'
     ].tolist()[-4:]
     return sum([
         b * d(t) for b, t in zip(self.model.betas, past_demand)
     ])
Пример #10
0
 def innovate(self):
     if not self.model.innovation:
         return None
     epsilon = d(self.random.uniform(*self.model.distribution_bounds))
     new_lpc = (
         self.machine.labour_productivity_coefficient
         * (1 + epsilon)
     )
     if new_lpc > self.machine.labour_productivity_coefficient:
         self.machine = Machine(
             producer=self.unique_id,
             generation=self.machine.generation + 1,
             lpc=new_lpc,
             price=self.machine.price
         )
Пример #11
0
def gov_base_consumption(model):
    government_consumption = (
        d(model.wage_share) * model.market_wage * model.labour_supply
    )
    return government_consumption
Пример #12
0
class ConsumptionGoodFirm(Firm):

    inventory = d(0)
    unfilled_demand_rate = d(0)
    average_productivity = d(0)
    price = d(0)
    expected_demand = d(0)
    desired_production = d(0)
    desired_capital_stock = d(0)
    production_rationed = False
    planned_production = d(0)
    want_to_scrap = []
    desired_ei = d(0)
    desired_ri = d(0)
    expansion_investment = d(0)
    replacement_investment = d(0)
    labour_demand = d(0)
    profit = d(0)

    def __init__(self, unique_id, model, liquid_assets, capital_stock,
                 market_share, supplier=None):
        super().__init__(unique_id, model, liquid_assets, market_share)

        self.group = 'consumption_firm'
        self.supplier = supplier

        # initial values
        self.capital_stock = capital_stock

        # calculated
        capital_firms = self.model.get_group('capital_firm')
        self.machines = {
            (supplier.unique_id, supplier.machine.generation): {
                'machine': supplier.machine,
                'stock': 40
            } for supplier in capital_firms
        }
        self.demand = self.market_share * self.model.consumption  # / self.model.cpi
        self.production = self.demand
        self.output = self.production
        self.sales = self.output

        row = {
            'step': -1,
            'agent_id': self.unique_id,
            'market_share': self.market_share,
            'demand': self.demand,
            'production': self.production,
            'output': self.output,
            'inventory': self.inventory,
            'sales': self.sales,
            'liquid_assets': self.liquid_assets,
            'capital_stock': self.capital_stock,
            'debt_stock': self.debt_stock,
            'supplier': self.supplier
        }
        self.model.datacollector.add_table_row(
            'consumption_firm', row, ignore_missing=True
        )

    @property
    def investment(self):
        return self.expansion_investment + self.replacement_investment

    @property
    def available_financing(self):
        return self.residual_assets + self.available_debt

    def compute_max_quantity(self, unit_cost):
        return d(int(self.available_financing / unit_cost))

    def compute_unfilled_demand(self):
        if self.demand == 0:
            return 0
        return 1 - self.sales / self.demand

    def compute_average_productivity(self):
        productivities = []
        machine_set = list(self.machines.keys())
        for machine_type in machine_set:
            machine = self.machines[machine_type]['machine']
            stock = self.machines[machine_type]['stock']
            productivity = (
                machine.labour_productivity_coefficient * stock
            )
            productivities.append(productivity)
        avgp = sum(productivities) / self.capital_stock
        return d(float(avgp))

    def compute_unit_production_cost(self):
        return (
            self.model.market_wage / self.average_productivity
        )

    def adjust_competitiveness(self):
        w1, w2 = self.model.competitiveness_weights[0]
        adj = round(-w1 * self.price - w2 * self.unfilled_demand_rate, 2)
        self.competitiveness = max(0, self.competitiveness - adj)

    def compute_debt_availability(self):
        max_debt = self.model.max_debt_sales_ratio * self.sales
        return max(0, max_debt - self.debt_stock)

    def forecast_demand(self, myopic=True):
        if myopic:
            return self.demand
        firm_data = self.model.datacollector.get_table_dataframe(
            'consumption_firm'
        )
        # model_data = self.model.datacollector.get_model_vars_dataframe()
        past_demand = firm_data.loc[
            firm_data.agent_id == self.unique_id, 'demand'
        ].tolist()[-4:]
        return sum([
            b * d(t) for b, t in zip(self.model.betas, past_demand)
        ])

    def forecast_production(self):
        demand_net = self.expected_demand - self.inventory
        return max(0, demand_net)

    def forecast_capital_stock(self):
        return d(int(
            self.desired_production / self.model.desired_capital_utilization
        ))

    def plan_production(self):
        production_max = self.compute_max_quantity(
            self.unit_production_cost
        )
        production = min(self.desired_production, production_max)
        # check if production has to be rationed
        if production < self.desired_production:
            self.production_rationed = True
        else:
            self.production_rationed = False
        return production

    def plan_production_financing(self):
        return self.finance_operations(
            self.planned_production, self.unit_production_cost
        )

    def compute_labour_demand(self):
        return self.planned_production / self.average_productivity

    def forecast_expansion_investment(self):
        trigger_level = d(int(self.capital_stock * (1 + self.model.trigger_rule)))
        planned_ei = 0
        if self.desired_capital_stock >= trigger_level:
            # NOTE: in paper this is trigger_level
            planned_ei = trigger_level - self.capital_stock
        return planned_ei

    def choose_supplier(self, subset=10):
        # NOTE: in the paper, supplier is chosen based on market share
        current_supplier = self.model.schedule.get_agent(self.supplier, _raise=False)
        capital_firms = self.model.get_group('capital_firm')
        sample = self.random.sample(capital_firms, subset)
        ratios = [s.machine.lpc_price_ratio for s in sample]
        new_supplier_id = sample[ratios.index(max(ratios))].unique_id
        if not current_supplier or current_supplier.bankrupt:
            return new_supplier_id
        return (
            new_supplier_id
            if max(ratios) > current_supplier.machine.lpc_price_ratio
            else self.supplier  # NOTE: causes consolidation in cap market?
        )

    def plan_replacement(self):
        supplier = self.model.schedule.get_agent(self.supplier)
        machine_set = [k for k, v in self.machines.items() if v['stock'] > 0]
        want_to_scrap = []
        for machine_type in machine_set:
            machine = self.machines[machine_type]['machine']
            unit_labour_cost = machine.compute_unit_labour_cost(self.model)
            if unit_labour_cost == supplier.unit_production_cost:
                continue
            x = (
                supplier.price
                / (unit_labour_cost - supplier.unit_production_cost)
            )
            if x <= self.model.payback_period_parameter:
                want_to_scrap.append(machine_type)
        return want_to_scrap

    def forecast_replacement_investment(self):
        return sum([self.machines[m]['stock'] for m in self.want_to_scrap])

    def fix_investment(self):
        """Allocate between expanding capital stock and replacement
        """
        if self.production_rationed:
            return 0, 0
        machine_cost = self.model.schedule.get_agent(self.supplier).machine.price
        ce_q, de_q = self.plan_production_financing()
        self.residual_assets -= ce_q
        self.available_debt -= de_q
        investment_max = self.compute_max_quantity(machine_cost)

        expansion_i = min(self.desired_ei, investment_max)
        ce_ei, de_ei = self.finance_operations(expansion_i, machine_cost)
        self.residual_assets -= ce_ei
        self.available_debt -= de_ei

        replacement_i = min(self.desired_ri, investment_max - expansion_i)
        ce_ri, de_ri = self.finance_operations(replacement_i, machine_cost)
        self.residual_assets = self.residual_assets - ce_ri + ce_q
        self.available_debt = self.available_debt - de_ri + de_q

        self.capital_employed = ce_ei + ce_ri
        self.debt_employed = de_ei + de_ri

        return expansion_i, replacement_i

    def compute_market_share(self):
        sector_avg_comp = self.model.avg_comp_competitiveness
        if self.unique_id == 50:
            self.log.info('computing market share')
            self.log.info(f'own competitiveness: {self.competitiveness}')
            self.log.info(f'sector average competitiveness: {sector_avg_comp}')
        ms = (
            self.market_share
            * (1 + self.model.replicator_dynamics_coeff[0]
               * (self.competitiveness - sector_avg_comp)
               / sector_avg_comp)
        )
        return d(max(0, ms))

    def compute_demand(self):  # TODO: should be dependant on price?
        return self.model.consumption * self.market_share  # / self.price

    def compute_labour_availability(self):
        return self.market_share * (
            self.model.labour_supply - self.model.capital_labour_demand
        )

    def fix_production(self):
        labour_res = self.compute_labour_availability()
        max_q = labour_res * self.average_productivity
        production = min(max_q, self.planned_production)
        ce_q, de_q = self.finance_operations(production, self.unit_production_cost)
        self.residual_assets -= ce_q
        self.available_debt -= de_q
        self.debt_stock += self.debt_employed + de_q
        return production

    def compute_sales(self):
        return min(self.demand, self.output)

    def compute_inventory(self):
        inventory = self.output - self.sales
        # deprecate inventory
        if inventory > 0:
            inventory = (
                int(inventory * (1 - self.model.inventory_deprecation))
            )
        return inventory

    def compute_profit(self):
        revenue = self.price * self.sales
        production_cost = self.unit_production_cost * self.production
        debt_payments = self.model.interest_rate * self.debt_stock
        return revenue - production_cost - debt_payments

    def compute_liquid_assets(self):
        return self.liquid_assets + self.profit - self.capital_employed

    def reimburse_investment(self, received_orders):
        self.liquid_assets += (
            received_orders * self.model.schedule.get_agent(self.supplier).price
        )
        if received_orders < self.expansion_investment:
            self.expansion_investment = received_orders
            self.replacement_investment = 0
        else:
            self.replacement_investment = received_orders - self.expansion_investment

    def replace_and_add_machines(self):  # TODO: add logging
        supplier = self.model.schedule.get_agent(self.supplier)
        if supplier.output < supplier.demand:
            # TODO: assign residual orders to firms
            received_orders = (
                int(d(self.investment / supplier.orders) * supplier.output)
            )
            self.reimburse_investment(received_orders)
        new_machines = self.expansion_investment
        for machine_type in self.want_to_scrap:
            stock = self.machines[machine_type]['stock']
            if stock <= self.replacement_investment:
                self.machines.pop(machine_type)
                new_machines += stock
            else:
                self.machines[machine_type]['stock'] -= self.replacement_investment
                new_machines += self.replacement_investment
                break
        new_type = (supplier.unique_id, supplier.machine.generation)
        if new_type in self.machines:
            self.machines[new_type]['stock'] += new_machines
            return None
        self.machines[new_type] = {
            'machine': deepcopy(supplier.machine),
            'stock': new_machines
        }

    def compute_capital_stock(self):
        return sum([mtype['stock'] for mtype in self.machines.values()])

    # stage methods
    def stage_one(self):
        if self.bankrupt:
            return None

        self.residual_assets = self.liquid_assets
        self.available_debt = self.compute_debt_availability()

        self.unfilled_demand_rate = self.compute_unfilled_demand()
        self.average_productivity = self.compute_average_productivity()
        self.unit_production_cost = self.compute_unit_production_cost()
        self.price = self.fix_price()
        # if demand was underestimated, competitiveness decreases
        if self.output < self.demand:
            self.adjust_competitiveness()
        # self.debt_availability = self.compute_debt_availability()

        if self.unique_id == 50:
            self.log.info(messages.comp_stage_one.format(
                step=self.model.schedule.steps,
                stage=self.model.schedule.stage,
                group=self.group,
                agent_id=self.unique_id,
                res_assets=self.residual_assets,
                res_debt=self.available_debt,
                unfilled_demand=self.unfilled_demand_rate,
                avg_prod=self.average_productivity,
                upc=self.unit_production_cost,
                price=self.price,
                compet=self.competitiveness
            ))

    def stage_two(self):
        if self.bankrupt:
            return None

        self.expected_demand = self.forecast_demand()
        self.desired_production = self.forecast_production()
        self.desired_capital_stock = self.forecast_capital_stock()
        self.planned_production = self.plan_production()
        self.labour_demand = self.compute_labour_demand()
        self.supplier = self.choose_supplier()
        self.want_to_scrap = self.plan_replacement()
        self.desired_ei = self.forecast_expansion_investment()
        self.desired_ri = self.forecast_replacement_investment()
        self.expansion_investment, self.replacement_investment = self.fix_investment()
        # register order with supplier
        self.model.schedule.get_agent(self.supplier).orders += self.investment

        if self.unique_id == 50:
            self.log.info(messages.comp_stage_two.format(
                step=self.model.schedule.steps,
                stage=self.model.schedule.stage,
                group=self.group,
                agent_id=self.unique_id,
                demand_e=self.expected_demand,
                production_d=self.desired_production,
                cap_stock_d=self.desired_capital_stock,
                production_p=self.planned_production,
                labour_demand=self.labour_demand,
                supplier=self.supplier,
                scrap=pformat(self.want_to_scrap),
                expansion_i=self.expansion_investment,
                replacement_i=self.replacement_investment
            ))

    def stage_three(self):
        if self.bankrupt:
            return None

        pass

    def stage_four(self):
        if self.bankrupt:
            return None

        self.market_share = self.compute_market_share()
        self.demand = self.compute_demand()
        self.production = self.fix_production()  # need to adjust labour demand here
        self.output = self.production + self.inventory
        self.sales = self.compute_sales()
        self.inventory = self.compute_inventory()
        self.profit = self.compute_profit()
        self.liquid_assets = self.compute_liquid_assets()

        if self.unique_id == 50:
            self.log.info(messages.comp_stage_four.format(
                step=self.model.schedule.steps,
                stage=self.model.schedule.stage,
                group=self.group,
                agent_id=self.unique_id,
                market_share=self.market_share,
                demand=self.demand,
                production=self.production,
                output=self.output,
                sales=self.sales,
                inventory=self.inventory,
                profit=self.profit,
                assets=self.liquid_assets
            ))

    def stage_five(self):

        row = {
            'step': self.model.schedule.steps,
            'agent_id': self.unique_id,
            'competitiveness': self.competitiveness,
            'expected_demand': self.expected_demand,
            'market_share': self.market_share,
            'demand': self.demand,
            'desired_production': self.desired_production,
            'desired_capital_stock': self.desired_capital_stock,
            'labour_demand': self.labour_demand,
            'desired_ei': self.desired_ei,
            'desired_ri': self.desired_ri,
            'supplier': self.supplier,
            'expansion_investment': self.expansion_investment,
            'replacement_investment': self.replacement_investment,
            'production': self.production,
            'output': self.output,
            'inventory': self.inventory,
            'sales': self.sales,
            'profit': self.profit,
            'liquid_assets': self.liquid_assets,
            'capital_stock': self.capital_stock,
            'debt_stock': self.debt_stock,
            'price': self.price,
            'upc': self.unit_production_cost,
            'average_productivity': self.average_productivity,
            'available_debt': self.available_debt,
            'bankrupt': self.bankrupt
        }
        self.model.datacollector.add_table_row('consumption_firm', row)

        if self.bankrupt:
            return None

        self.replace_and_add_machines()
        self.capital_stock = self.compute_capital_stock()
Пример #13
0
 def compute_market_share(self):
     investment = self.model.investment
     market_share = (
         d(self.demand / investment) if investment > 0 else self.market_share
     )
     return market_share
Пример #14
0
class ComplexEconomy(Model):

    log = logging.getLogger(__name__)
    groups = ['consumption_firm', 'capital_firm']
    stages = ['stage_one', 'stage_two', 'stage_three', 'stage_four', 'stage_five']
    stage_functions = {
        'stage_one': [
            'update_average_prices',
            'update_avg_ulc',
            'update_average_labour_productivity',
            'update_sector_competitiveness'
        ],
        'stage_two': [
            'aggregate_investment'
        ],
        'stage_three': [
            'update_labour_supply',
            'aggregate_labour_demand',
            'update_employment',
            'update_market_wage',
            'update_consumption'
        ],
        'stage_four': [
            'aggregate_production',
            'aggregate_inventories'
        ],
        'stage_five': [
            'exit_and_entry'
        ]
    }

    avg_cap_price = d(0)
    avg_comp_competitiveness = d(0)
    avg_cap_competitiveness = d(0)
    average_unit_labour_cost = d(0)
    consumption_labour_demand = d(0)
    unemployment = d(0)
    delta_cpi = d(0)
    delta_productivity = d(0)
    delta_unemployment = d(0)
    expansion_investment = d(0)
    replacement_investment = d(0)
    agg_inventories = d(0)
    agg_production = d(0)

    def __init__(self, parameters, market_wage, cpi, avg_labour_productivity,
                 liquid_assets, capital_stock, labour_supply, innovation,
                 seed=None):
        self.schedule = GroupedActivation(
            self, self.groups, self.stages,
            interim_functions=self.stage_functions
        )
        self.datacollector = DataCollector(
            model_reporters={
                'market_wage': 'market_wage',
                'consumption': 'consumption',
                'expansion_investment': 'expansion_investment',
                'replacement_investment': 'replacement_investment',
                'investment': 'investment',
                'inventories': 'agg_inventories',
                'production': 'agg_production',
                'cpi': 'cpi',
                'avg_cap_price': 'avg_cap_price',
                'avg_labour_prod': 'avg_labour_prod',
                'labour_supply': 'labour_supply',
                'labour_demand': 'labour_demand',
                'employment': 'employment',
                'unemployment': 'unemployment',
                'avg_comp_competitiveness': 'avg_comp_competitiveness',
                'avg_cap_competitiveness': 'avg_cap_competitiveness',
                'gdp': compute_gdp
            },
            tables={
                'consumption_firm': {
                    'step': [],
                    'agent_id': [],
                    'competitiveness': [],
                    'expected_demand': [],
                    'market_share': [],
                    'demand': [],
                    'desired_production': [],
                    'desired_capital_stock': [],
                    'labour_demand': [],
                    'desired_ei': [],
                    'desired_ri': [],
                    'supplier': [],
                    'expansion_investment': [],
                    'replacement_investment': [],
                    'production': [],
                    'output': [],
                    'inventory': [],
                    'sales': [],
                    'profit': [],
                    'liquid_assets': [],
                    'capital_stock': [],
                    'debt_stock': [],
                    'price': [],
                    'upc': [],
                    'average_productivity': [],
                    'available_debt': [],
                    'bankrupt': []
                },
                'capital_firm': {
                    'step': [],
                    'agent_id': [],
                    'competitiveness': [],
                    'demand': [],
                    'production': [],
                    'labour_demand': [],
                    'output': [],
                    'sales': [],
                    'profit': [],
                    'liquid_assets': [],
                    'debt_stock': [],
                    'market_share': [],
                    'machine_generation': [],
                    'price': [],
                    'upc': [],
                    'labour_productivity': [],
                    'available_debt': [],
                    'bankrupt': []
                }
            }
        )
        self.innovation = innovation
        self.social_policy = parameters['social_policy']
        self.inventory_deprecation = parameters['inventory_deprecation']

        # parameters  # TODO: convert parameters to decimal
        n_consumption_firms = parameters['n_consumption_firms']
        n_capital_firms = parameters['n_capital_firms']
        replicators = parameters['replicator_dynamics_coeff']
        self.replicator_dynamics_coeff = (d(replicators[0]), d(replicators[1]))
        comp_weights = parameters['competitiveness_weights']
        self.competitiveness_weights = (
            (d(comp_weights[0][0]), d(comp_weights[0][1])),
            (d(comp_weights[1][0]), d(comp_weights[1][1]))
        )
        self.distribution_bounds = parameters['distribution_bounds']
        self.labour_supply_growth = d(parameters['labour_supply_growth'])
        self.wage_setting = {
            k: d(v) for k, v in
            parameters['wage_setting'].items()
        }
        self.desired_capital_utilization = d(parameters['desired_capital_utilization'])
        self.trigger_rule = d(parameters['trigger_rule'])
        self.payback_period_parameter = d(parameters['payback_period_parameter'])
        self.mark_up = d(parameters['mark_up'])
        self.interest_rate = d(parameters['interest_rate'])
        self.wage_share = d(parameters['wage_share'])
        self.betas = [d(b) for b in parameters['betas']]
        # NOTE: max_debt_sales_ratio is not specified in the paper
        self.max_debt_sales_ratio = d(parameters['max_debt_sales_ratio'])

        # initial conditions
        self.market_wage = d(market_wage)
        self.cpi = d(cpi)
        self.avg_labour_prod = d(avg_labour_productivity)
        self.labour_supply = labour_supply

        # computed and derived
        self.max_capital_labour_share = d(
            n_capital_firms / (n_consumption_firms + n_capital_firms)
        )
        init_market_share = (d(1 / n_consumption_firms), d(1 / n_capital_firms))
        self.employment = labour_supply
        self.consumption = self.compute_consumption()
        self.unemployment_rate = d(self.unemployment / self.employment)

        # create capital good firms
        for i in range(n_capital_firms):
            f = CapitalGoodFirm(i, self, liquid_assets, init_market_share[1])
            self.schedule.add(f)
        # create consumption good firms
        supplier = 0
        for i in range(n_consumption_firms):
            if parameters['fix_supplier']:
                if i % 4 == 0 and i != 0:
                    supplier += 1
            else:
                supplier = None
            f = ConsumptionGoodFirm(
                i + n_capital_firms, self, liquid_assets, capital_stock,
                init_market_share[0], supplier=supplier
            )
            self.schedule.add(f)

        self.running = True
        self.datacollector.collect(self)

        self.log.info(messages.model_init_message.format(
            wage=self.market_wage,
            cpi=self.cpi,
            avg_labour_prod=self.avg_labour_prod,
            labour_supply=self.labour_supply,
            comp_market_share=init_market_share[0],
            cap_market_share=init_market_share[1],
            employment=self.employment,
            consumption=self.consumption,
            unemployment_rate=self.unemployment_rate,
            parameters=pformat(parameters)
        ))

    @property
    def investment(self):
        return self.expansion_investment + self.replacement_investment

    @property
    def max_capital_labour(self):
        return self.max_capital_labour_share * self.labour_supply

    @property
    def capital_labour_demand(self):
        capital_firms = self.get_group('capital_firm')
        return sum([a.labour_demand for a in capital_firms])
    
    @property
    def labour_demand(self):
        return self.capital_labour_demand + self.consumption_labour_demand

    def get_group(self, group, include_bankrupt=False, bankrupt_only=False):
        if include_bankrupt and bankrupt_only:
            raise ValueError('include_bankrupt and bankrupt_only are mutually exclusive')
        firms = [
            a for a in self.schedule.agents if a.group == group
        ]
        if include_bankrupt:
            return firms
        elif bankrupt_only:
            return [f for f in firms if f.bankrupt]
        return [f for f in firms if not f.bankrupt]

    def compute_average_price(self, group, weighted=False):
        firms = self.get_group(group)
        if not weighted:
            prices = [firm.price for firm in firms]
            return sum(prices) / len(prices)
        return sum([firm.market_share * firm.price for firm in firms])

    def update_average_prices(self):
        cpi = self.compute_average_price('consumption_firm')
        self.delta_cpi = (cpi - self.cpi) / self.cpi
        self.cpi = cpi
        self.avg_cap_price = self.compute_average_price('capital_firm')

    def update_avg_ulc(self):  # currently not used
        capital_firms = self.get_group('capital_firm')
        lpcs = [a.machine.compute_unit_labour_cost(self) for a in capital_firms]
        self.average_unit_labour_cost = sum(lpcs) / len(lpcs)

    def update_average_labour_productivity(self, weighted=True):
        firms = self.get_group('capital_firm')
        if weighted:
            avg_labour_prod = sum([
                firm.market_share * firm.machine.labour_productivity_coefficient
                for firm in firms
            ])
        else:
            avg_labour_prod = (
                sum([f.machine.labour_productivity_coefficient for f in firms])
                / len(firms)
            )
        self.delta_productivity = (
            (avg_labour_prod - self.avg_labour_prod) / self.avg_labour_prod
        )
        self.avg_labour_prod = avg_labour_prod

    def compute_sector_competitiveness(self, group):
        firms = self.get_group(group)
        comp = sum([
            f.competitiveness * f.market_share for f in firms
        ])
        return round(comp, 2)

    def update_sector_competitiveness(self):
        self.avg_comp_competitiveness = self.compute_sector_competitiveness('consumption_firm')
        self.avg_cap_competitiveness = self.compute_sector_competitiveness('capital_firm')

    def aggregate_investment(self):
        firms = self.get_group('consumption_firm')
        self.expansion_investment = sum([
            f.expansion_investment for f in firms
        ])
        self.replacement_investment = sum([
            f.replacement_investment for f in firms
        ])

    def update_labour_supply(self):
        self.labour_supply = (
            self.labour_supply * (1 + self.labour_supply_growth)
        )

    def aggregate_labour_demand(self):
        self.consumption_labour_demand = sum([
            a.labour_demand for a in self.get_group('consumption_firm')
        ])

    def update_employment(self):
        self.employment = min(self.labour_demand, self.labour_supply)
        self.unemployment = max(0, self.labour_supply - self.employment)
        unemployment_rate = d(self.unemployment / self.labour_supply)
        delta_unemployment = unemployment_rate - self.unemployment_rate
        self.unemployment_rate = unemployment_rate
        self.delta_unemployment = delta_unemployment

    def update_market_wage(self):
        psi1 = self.wage_setting['cpi_weight']
        psi2 = self.wage_setting['avg_lp_weight']
        psi3 = self.wage_setting['unemployment_weight']
        self.market_wage = (
            self.market_wage + (  # NOTE: in the paper, this is +
                1 + psi1 * self.delta_cpi
                + psi2 * self.delta_productivity
                + psi3 * self.delta_unemployment
            )
        )

    def compute_consumption(self):
        household_consumption = self.market_wage * self.employment
        policy_func = social_policy.get(self.social_policy)
        gov_consumption = policy_func(self)
        return household_consumption + gov_consumption

    def update_consumption(self):
        self.consumption = self.compute_consumption()

    def aggregate_production(self):
        firms = self.get_group('consumption_firm')
        self.agg_production = sum([
            f.production for f in firms
        ])

    def aggregate_inventories(self):
        firms = self.get_group('consumption_firm')
        self.agg_inventories = sum([
            f.inventory for f in firms
        ])

    def exit_and_entry(self):
        for group in self.groups:  # TODO: move setting bankrupt to firms
            self.log.info(f'entry and exit for group {group}')
            firms = self.get_group(group)
            dead_firms = [
                f for f in firms
                if f.market_share <= 0 or f.liquid_assets < 0
            ]
            self.log.info(f'Bankrupt firms: {len(dead_firms)}')
            alive_firms = [
                f for f in firms if f not in dead_firms
            ]
            for firm in dead_firms:
                firm.bankrupt = True
                copy_firm = self.random.choice(alive_firms)
                next_id = max([a.unique_id for a in self.schedule.agents]) + 1
                assets = copy_firm.liquid_assets
                market_share = copy_firm.market_share
                capital_stock = (
                    copy_firm.capital_stock if group == 'consumption_firm'
                    else None
                )
                constructor = {
                    'consumption_firm': ConsumptionGoodFirm,
                    'capital_firm': CapitalGoodFirm
                }.get(group)
                new_firm = constructor(
                    int(next_id), self, assets,
                    market_share=market_share, capital_stock=capital_stock
                )
                if group == 'capital_firm':
                    new_firm.machine.labour_productivity_coefficient = (
                        copy_firm.machine.labour_productivity_coefficient
                    )
                    new_firm.machine.price = copy_firm.machine.price
                self.schedule.add(new_firm)
            self._calibrate_market_share(group)

    def _calibrate_market_share(self, group):
        # TODO: adjust market share after re-entry
        firms = self.get_group(group)
        market_shares_sum = [f.market_share for f in firms]
        if market_shares_sum != 1:
            for firm in firms:
                firm.market_share = firm.market_share / sum(market_shares_sum)

    def _distribute_leftover_machines(self):
        pass

    def step(self):
        # run all stages of a step
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)
Пример #15
0
class CapitalGoodFirm(Firm):

    # debt_stock = 0
    # unit_production_cost = 1
    demand = d(0)
    output = d(0)
    sales = d(0)
    labour_demand = d(0)
    profit = d(0)
    orders = d(0)

    def __init__(self, unique_id, model, liquid_assets, market_share, **kwargs):
        super().__init__(unique_id, model, liquid_assets, market_share)

        self.group = 'capital_firm'

        self.machine = Machine(
            producer=unique_id,
            generation=1,
            lpc=d(100),
            price=d(1)
        )

    @property
    def price(self):
        return self.machine.price

    @property
    def available_financing(self):
        return self.residual_assets + self.available_debt

    def compute_max_quantity(self, unit_cost):
        return self.available_financing // unit_cost

    @property
    def max_production(self):
        max_labour = self.market_share * self.model.max_capital_labour
        max_quantity = self.compute_max_quantity(self.unit_production_cost)
        return min(
            max_quantity,
            max_labour * self.machine.labour_productivity_coefficient
        )

    def compute_unit_production_cost(self):
        return (
            self.model.market_wage
            / self.machine.labour_productivity_coefficient
        )

    def compute_competitiveness(self):
        w3, w4 = self.model.competitiveness_weights[1]
        return (
            -w3 * self.machine.price + w4 * self.machine.labour_productivity_coefficient
        )

    def compute_debt_availability(self):
        max_debt = self.model.max_debt_sales_ratio * self.sales
        return max(0, max_debt - self.debt_stock)

    def compute_demand(self):
        # consumption_firms = self.model.get_group('consumption_firm')
        # return sum([
        #     a.investment for a in consumption_firms
        #     if a.supplier == self.unique_id
        # ])
        return self.orders

    def fix_production(self):
        production = min(self.demand, self.max_production)
        ce, de = self.finance_operations(production, self.unit_production_cost)
        self.debt_stock += de
        return production

    def compute_labour_demand(self):
        return (
            self.output / self.machine.labour_productivity_coefficient
        )

    def compute_profit(self):
        return (
            (self.price - self.unit_production_cost) * self.sales
            - self.model.interest_rate * self.debt_stock
        )

    def compute_liquid_assets(self):
        return self.liquid_assets + self.profit

    def compute_market_share(self):
        investment = self.model.investment
        market_share = (
            d(self.demand / investment) if investment > 0 else self.market_share
        )
        return market_share

    def innovate(self):
        if not self.model.innovation:
            return None
        epsilon = d(self.random.uniform(*self.model.distribution_bounds))
        new_lpc = (
            self.machine.labour_productivity_coefficient
            * (1 + epsilon)
        )
        if new_lpc > self.machine.labour_productivity_coefficient:
            self.machine = Machine(
                producer=self.unique_id,
                generation=self.machine.generation + 1,
                lpc=new_lpc,
                price=self.machine.price
            )

    # stage methods
    def stage_one(self):
        if self.bankrupt:
            return None

        self.residual_assets = self.liquid_assets
        self.available_debt = self.compute_debt_availability()

        self.unit_production_cost = self.compute_unit_production_cost()
        self.machine.price = self.fix_price()
        self.competitiveness = self.compute_competitiveness()

    def stage_two(self):
        if self.bankrupt:
            return None

    def stage_three(self):
        if self.bankrupt:
            return None

        self.demand = self.compute_demand()
        self.output = self.sales = self.fix_production()
        self.labour_demand = self.compute_labour_demand()
        self.profit = self.compute_profit()
        self.liquid_assets = self.compute_liquid_assets()
        self.market_share = self.compute_market_share()

    def stage_four(self):
        if self.bankrupt:
            return None

    def stage_five(self):

        row = {
            'step': self.model.schedule.steps,
            'agent_id': self.unique_id,
            'competitiveness': self.competitiveness,
            'demand': self.demand,
            'production': self.output,
            'labour_demand': self.labour_demand,
            'output': self.output,
            'sales': self.sales,
            'profit': self.profit,
            'liquid_assets': self.liquid_assets,
            'debt_stock': self.debt_stock,
            'market_share': self.market_share,
            'machine_generation': self.machine.generation,
            'price': self.price,
            'upc': self.unit_production_cost,
            'labour_productivity': self.machine.labour_productivity_coefficient,
            'available_debt': self.available_debt,
            'bankrupt': self.bankrupt
        }

        self.model.datacollector.add_table_row('capital_firm', row)

        if self.bankrupt:
            return None

        self.innovate()
        self.orders = 0
Пример #16
0
    def __init__(self, parameters, market_wage, cpi, avg_labour_productivity,
                 liquid_assets, capital_stock, labour_supply, innovation,
                 seed=None):
        self.schedule = GroupedActivation(
            self, self.groups, self.stages,
            interim_functions=self.stage_functions
        )
        self.datacollector = DataCollector(
            model_reporters={
                'market_wage': 'market_wage',
                'consumption': 'consumption',
                'expansion_investment': 'expansion_investment',
                'replacement_investment': 'replacement_investment',
                'investment': 'investment',
                'inventories': 'agg_inventories',
                'production': 'agg_production',
                'cpi': 'cpi',
                'avg_cap_price': 'avg_cap_price',
                'avg_labour_prod': 'avg_labour_prod',
                'labour_supply': 'labour_supply',
                'labour_demand': 'labour_demand',
                'employment': 'employment',
                'unemployment': 'unemployment',
                'avg_comp_competitiveness': 'avg_comp_competitiveness',
                'avg_cap_competitiveness': 'avg_cap_competitiveness',
                'gdp': compute_gdp
            },
            tables={
                'consumption_firm': {
                    'step': [],
                    'agent_id': [],
                    'competitiveness': [],
                    'expected_demand': [],
                    'market_share': [],
                    'demand': [],
                    'desired_production': [],
                    'desired_capital_stock': [],
                    'labour_demand': [],
                    'desired_ei': [],
                    'desired_ri': [],
                    'supplier': [],
                    'expansion_investment': [],
                    'replacement_investment': [],
                    'production': [],
                    'output': [],
                    'inventory': [],
                    'sales': [],
                    'profit': [],
                    'liquid_assets': [],
                    'capital_stock': [],
                    'debt_stock': [],
                    'price': [],
                    'upc': [],
                    'average_productivity': [],
                    'available_debt': [],
                    'bankrupt': []
                },
                'capital_firm': {
                    'step': [],
                    'agent_id': [],
                    'competitiveness': [],
                    'demand': [],
                    'production': [],
                    'labour_demand': [],
                    'output': [],
                    'sales': [],
                    'profit': [],
                    'liquid_assets': [],
                    'debt_stock': [],
                    'market_share': [],
                    'machine_generation': [],
                    'price': [],
                    'upc': [],
                    'labour_productivity': [],
                    'available_debt': [],
                    'bankrupt': []
                }
            }
        )
        self.innovation = innovation
        self.social_policy = parameters['social_policy']
        self.inventory_deprecation = parameters['inventory_deprecation']

        # parameters  # TODO: convert parameters to decimal
        n_consumption_firms = parameters['n_consumption_firms']
        n_capital_firms = parameters['n_capital_firms']
        replicators = parameters['replicator_dynamics_coeff']
        self.replicator_dynamics_coeff = (d(replicators[0]), d(replicators[1]))
        comp_weights = parameters['competitiveness_weights']
        self.competitiveness_weights = (
            (d(comp_weights[0][0]), d(comp_weights[0][1])),
            (d(comp_weights[1][0]), d(comp_weights[1][1]))
        )
        self.distribution_bounds = parameters['distribution_bounds']
        self.labour_supply_growth = d(parameters['labour_supply_growth'])
        self.wage_setting = {
            k: d(v) for k, v in
            parameters['wage_setting'].items()
        }
        self.desired_capital_utilization = d(parameters['desired_capital_utilization'])
        self.trigger_rule = d(parameters['trigger_rule'])
        self.payback_period_parameter = d(parameters['payback_period_parameter'])
        self.mark_up = d(parameters['mark_up'])
        self.interest_rate = d(parameters['interest_rate'])
        self.wage_share = d(parameters['wage_share'])
        self.betas = [d(b) for b in parameters['betas']]
        # NOTE: max_debt_sales_ratio is not specified in the paper
        self.max_debt_sales_ratio = d(parameters['max_debt_sales_ratio'])

        # initial conditions
        self.market_wage = d(market_wage)
        self.cpi = d(cpi)
        self.avg_labour_prod = d(avg_labour_productivity)
        self.labour_supply = labour_supply

        # computed and derived
        self.max_capital_labour_share = d(
            n_capital_firms / (n_consumption_firms + n_capital_firms)
        )
        init_market_share = (d(1 / n_consumption_firms), d(1 / n_capital_firms))
        self.employment = labour_supply
        self.consumption = self.compute_consumption()
        self.unemployment_rate = d(self.unemployment / self.employment)

        # create capital good firms
        for i in range(n_capital_firms):
            f = CapitalGoodFirm(i, self, liquid_assets, init_market_share[1])
            self.schedule.add(f)
        # create consumption good firms
        supplier = 0
        for i in range(n_consumption_firms):
            if parameters['fix_supplier']:
                if i % 4 == 0 and i != 0:
                    supplier += 1
            else:
                supplier = None
            f = ConsumptionGoodFirm(
                i + n_capital_firms, self, liquid_assets, capital_stock,
                init_market_share[0], supplier=supplier
            )
            self.schedule.add(f)

        self.running = True
        self.datacollector.collect(self)

        self.log.info(messages.model_init_message.format(
            wage=self.market_wage,
            cpi=self.cpi,
            avg_labour_prod=self.avg_labour_prod,
            labour_supply=self.labour_supply,
            comp_market_share=init_market_share[0],
            cap_market_share=init_market_share[1],
            employment=self.employment,
            consumption=self.consumption,
            unemployment_rate=self.unemployment_rate,
            parameters=pformat(parameters)
        ))
Пример #17
0
 def compute_max_quantity(self, unit_cost):
     return d(int(self.available_financing / unit_cost))
Пример #18
0
 def forecast_capital_stock(self):
     return d(int(
         self.desired_production / self.model.desired_capital_utilization
     ))