Community_Inclusion_Currencies/Simulation_param/model/parts/system.py

280 lines
9.4 KiB
Python

import numpy as np
import pandas as pd
from cadCAD.configuration.utils import access_block
from .initialization import *
from .supportingFunctions import *
from collections import OrderedDict
# Parameters
agentsMinus = 2
# percentage of balance a user can redeem
redeemPercentage = 0.5
# Behaviors
def choose_agents(params, step, sL, s):
'''
Choose agents to interact during the given timestep and create their demand from a uniform distribution.
Based on probability, choose utility.
'''
outboundAgents = np.random.choice(mixingAgents,size=len(mixingAgents)-agentsMinus).tolist()
inboundAgents = np.random.choice(mixingAgents,size=len(mixingAgents)-agentsMinus).tolist()
stepDemands = np.random.uniform(low=1, high=500, size=len(mixingAgents)-agentsMinus).astype(int)
stepUtilities = np.random.choice(list(UtilityTypesOrdered.keys()),size=len(mixingAgents)-agentsMinus,p=list(utilityTypesProbability.values())).tolist()
return {'outboundAgents':outboundAgents,'inboundAgents':inboundAgents,'stepDemands':stepDemands,'stepUtilities':stepUtilities}
def spend_allocation(params, step, sL, s):
'''
Take mixing agents, demand, and utilities and allocate agent shillings and tokens based on utility and scarcity.
'''
# instantiate network state
network = s['network']
spendI = []
spendJ = []
spendAmount = []
# calculate max about of spend available to each agent
maxSpendShilling = {}
for i in mixingAgents:
maxSpendShilling[i] = network.nodes[i]['native_currency']
maxSpendCIC = {}
for i in mixingAgents:
maxSpendCIC[i] = network.nodes[i]['tokens']
for i in mixingAgents:
rankOrder = {}
rankOrderDemand = {}
for j in network.adj[i]:
try:
rankOrder[j] = UtilityTypesOrdered[network.adj[i][j]['utility']]
rankOrderDemand[j] = network.adj[i][j]['demand']
rankOrder = dict(OrderedDict(sorted(rankOrder.items(), key=lambda v: v, reverse=False)))
for k in rankOrder:
# if i or j is external, we transact 100% in shilling
if i == 'external':
amt = spendCalculationExternal(i,j,rankOrderDemand,maxSpendShilling)
spendI.append(i)
spendJ.append(j)
spendAmount.append(amt)
maxSpendShilling[i] = maxSpendShilling[i] - amt
elif j == 'external':
amt = spendCalculationExternal(i,j,rankOrderDemand,maxSpendShilling)
spendI.append(i)
spendJ.append(j)
spendAmount.append(amt)
maxSpendShilling[i] = maxSpendShilling[i] - amt
else:
amt = spendCalculation(i,j,rankOrderDemand,maxSpendShilling,maxSpendCIC,fractionOfDemandInCIC)
spendI.append(i)
spendJ.append(j)
spendAmount.append(amt)
maxSpendShilling[i] = maxSpendShilling[i] - amt * (1- fractionOfDemandInCIC)
maxSpendCIC[i] = maxSpendCIC[i] - (amt * fractionOfDemandInCIC)
except:
pass
return {'spendI':spendI,'spendJ':spendJ,'spendAmount':spendAmount}
def withdraw_calculation(params, step, sL, s):
''''''
# instantiate network state
network = s['network']
# Assumptions:
# * user is only able to withdraw up to 50% of balance, assuming they have spent 50% of balance
# * Agents will withdraw as much as they can.
withdraw = {}
fiftyThreshold = {}
startingBalance = s['startingBalance']
spend = s['30_day_spend']
timestep = s['timestep']
division = timestep % 30 == 0
if division == True:
for i,j in startingBalance.items():
fiftyThreshold[i] = j * 0.5
if s['timestep'] > 7:
for i,j in fiftyThreshold.items():
if spend[i] > 0 and fiftyThreshold[i] > 0:
if spend[i] * fractionOfActualSpendInCIC >= fiftyThreshold[i]:
spent = spend[i]
amount = spent * redeemPercentage
if network.nodes[i]['tokens'] > amount:
withdraw[i] = amount
elif network.nodes[i]['tokens'] < amount:
withdraw[i] = network.nodes[i]['tokens']
else:
pass
else:
pass
else:
pass
else:
pass
return {'withdraw':withdraw}
# Mechanisms
def update_agent_activity(params,step,sL,s,_input):
'''
Update the network for interacting agent, their demand, and utility.
'''
y = 'network'
network = s['network']
outboundAgents = _input['outboundAgents']
inboundAgents = _input['inboundAgents']
stepDemands = _input['stepDemands']
stepUtilities = _input['stepUtilities']
# create demand edge weights
try:
for i,j,l in zip(outboundAgents,inboundAgents,stepDemands):
network[i][j]['demand'] = l
except:
pass
# Create cic % edge weights
try:
for i,j in zip(outboundAgents,inboundAgents):
# if one of the agents is external, we will transact in 100% shilling
if i == 'external':
network[i][j]['fractionOfDemandInCIC'] = 1
elif j == 'external':
network[i][j]['fractionOfDemandInCIC'] = 1
else:
network[i][j]['fractionOfDemandInCIC'] = fractionOfDemandInCIC
except:
pass
# Create utility edge types
try:
for i,j,l in zip(outboundAgents,inboundAgents,stepUtilities):
network[i][j]['utility'] = l
except:
pass
x = network
return (y,x)
def update_outboundAgents(params,step,sL,s,_input):
'''
Update outBoundAgents state variable
'''
y = 'outboundAgents'
x = _input['outboundAgents']
return (y,x)
def update_inboundAgents(params,step,sL,s,_input):
'''
Update inBoundAgents state variable
'''
y = 'inboundAgents'
x = _input['inboundAgents']
return (y,x)
def update_node_spend(params, step, sL, s,_input):
'''
Update network with actual spend of agents.
'''
y = 'network'
network = s['network']
spendI = _input['spendI']
spendJ = _input['spendJ']
spendAmount = _input['spendAmount']
for i,j,l in zip(spendI,spendJ,spendAmount):
network[i][j]['spend'] = l
if i == 'external':
network[i][j]['fractionOfActualSpendInCIC'] = 1
elif j == 'external':
network[i][j]['fractionOfActualSpendInCIC'] = 1
else:
network[i][j]['fractionOfActualSpendInCIC'] = fractionOfActualSpendInCIC
outflowSpend, inflowSpend = iterateEdges(network,'spend')
for i, j in inflowSpend.items():
if i == 'external':
network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + inflowSpend[i]
elif j == 'external':
network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + inflowSpend[i]
else:
network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + inflowSpend[i] * (1- fractionOfDemandInCIC)
network.nodes[i]['tokens'] = network.nodes[i]['tokens'] + (inflowSpend[i] * fractionOfDemandInCIC)
for i, j in outflowSpend.items():
if i == 'external':
network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i]
elif j == 'external':
network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i]
else:
network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] - outflowSpend[i]* (1- fractionOfDemandInCIC)
network.nodes[i]['tokens'] = network.nodes[i]['tokens'] - (outflowSpend[i] * fractionOfDemandInCIC)
# Store the net of the inflow and outflow per step
network.nodes['external']['delta_native_currency'] = sum(inflowSpend.values()) - sum(outflowSpend.values())
x = network
return (y,x)
def update_withdraw(params, step, sL, s,_input):
'''
Update flow sstate variable with the aggregated amount of shillings withdrawn
'''
y = 'withdraw'
x = s['withdraw']
if _input['withdraw']:
x = _input['withdraw']
else:
x = 0
return (y,x)
def update_network_withraw(params, step, sL, s,_input):
'''
Update network for agents withdrawing
'''
y = 'network'
network = s['network']
withdraw = _input['withdraw']
if withdraw:
for i,j in withdraw.items():
# update agent nodes
network.nodes[i]['tokens'] = network.nodes[i]['tokens'] - j
network.nodes[i]['native_currency'] = network.nodes[i]['native_currency'] + (j * leverage)
withdrawnCICSum = []
for i,j in withdraw.items():
withdrawnCICSum.append(j)
# update cic node
network.nodes['cic']['native_currency'] = network.nodes[i]['native_currency'] - (sum(withdrawnCICSum) * leverage)
network.nodes['cic']['tokens'] = network.nodes[i]['tokens'] + (sum(withdrawnCICSum) * leverage)
else:
pass
x = network
return (y,x)