saturday work session

mostly focused on data formatting and some data viz. minor refactors on some of the social systems logic in preparation for this weeks workshop
This commit is contained in:
Michael Zargham 2020-08-01 19:18:50 -07:00
parent 484db212f5
commit 51955e4246
17 changed files with 456 additions and 613 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 142 KiB

View File

@ -13,7 +13,7 @@ from .partial_state_update_block import partial_state_update_blocks
sim_config = config_sim({ sim_config = config_sim({
'N': 1, 'N': 1,
'T': range(100), #day 'T': range(183), #day
}) })
seeds = { seeds = {

View File

@ -95,7 +95,7 @@ def gen_new_participant(network, new_participant_holdings):
def gen_new_proposal(network, funds, supply, scale_factor = 1.0/100): def gen_new_proposal(network, funds, supply, scale_factor = 1.0/1000):
''' '''
Definition: Definition:
Driving processes for the arrival of proposals. Driving processes for the arrival of proposals.
@ -163,14 +163,16 @@ def get_nodes_by_type(g, node_type_selection):
''' '''
return [node for node in g.nodes if g.nodes[node]['type']== node_type_selection ] return [node for node in g.nodes if g.nodes[node]['type']== node_type_selection ]
def get_sentimental(sentiment, force, decay=0): def get_sentimental(sentiment, force, decay=.1):
''' '''
''' '''
mu = decay mu = decay
sentiment = sentiment*(1-mu) + force sentiment = sentiment*(1-mu) + force*mu
if sentiment > 1: if sentiment > 1:
sentiment = 1 sentiment = 1
elif sentiment < 0:
sentiment = 0
return sentiment return sentiment
@ -424,7 +426,7 @@ def quantile_plot(xkey, ykey, dataframe, dq=.1, logy=False, return_df = False):
if return_df: if return_df:
return data return data
def affinities_plot(df): def affinities_plot(df, dims = (8.5, 11) ):
''' '''
''' '''
last_net= df.network.values[-1] last_net= df.network.values[-1]
@ -440,7 +442,6 @@ def affinities_plot(df):
j = last_props[j_ind] j = last_props[j_ind]
affinities[i_ind][j_ind] = last_net.edges[(i,j)]['affinity'] affinities[i_ind][j_ind] = last_net.edges[(i,j)]['affinity']
dims = (20, 5)
fig, ax = plt.subplots(figsize=dims) fig, ax = plt.subplots(figsize=dims)
sns.heatmap(affinities.T, sns.heatmap(affinities.T,
@ -448,6 +449,7 @@ def affinities_plot(df):
yticklabels=last_props, yticklabels=last_props,
square=True, square=True,
cbar=True, cbar=True,
cmap = plt.cm.RdYlGn,
ax=ax) ax=ax)
plt.title('affinities between participants and proposals') plt.title('affinities between participants and proposals')
@ -457,12 +459,14 @@ def affinities_plot(df):
def trigger_sweep(field, trigger_func,beta,rho,alpha,xmax=.2): def trigger_sweep(field, trigger_func,beta,rho,alpha,supply=10**9):
''' '''
''' '''
xmax= beta
if field == 'effective_supply': if field == 'effective_supply':
share_of_funds = np.arange(.001,xmax,.001) share_of_funds = np.arange(.001,xmax,.001)
total_supply = np.arange(0,10**9, 10**6) total_supply = np.arange(0,supply*10, supply/100)
demo_data_XY = np.outer(share_of_funds,total_supply) demo_data_XY = np.outer(share_of_funds,total_supply)
demo_data_Z0=np.empty(demo_data_XY.shape) demo_data_Z0=np.empty(demo_data_XY.shape)
@ -484,11 +488,12 @@ def trigger_sweep(field, trigger_func,beta,rho,alpha,xmax=.2):
'share_of_max_conv': demo_data_Z2, 'share_of_max_conv': demo_data_Z2,
'log10_share_of_max_conv':demo_data_Z3, 'log10_share_of_max_conv':demo_data_Z3,
'total_supply':total_supply, 'total_supply':total_supply,
'share_of_funds':share_of_funds} 'share_of_funds':share_of_funds,
'alpha':alpha}
elif field == 'alpha': elif field == 'alpha':
alpha = np.arange(0,1,.001) #note if alpha >.01 then this will give weird results max alpha will be >1
alpha = np.arange(0,.5,.001)
share_of_funds = np.arange(.001,xmax,.001) share_of_funds = np.arange(.001,xmax,.001)
total_supply = 10**9
demo_data_XY = np.outer(share_of_funds,alpha) demo_data_XY = np.outer(share_of_funds,alpha)
demo_data_Z4=np.empty(demo_data_XY.shape) demo_data_Z4=np.empty(demo_data_XY.shape)
@ -498,7 +503,7 @@ def trigger_sweep(field, trigger_func,beta,rho,alpha,xmax=.2):
for sof_ind in range(len(share_of_funds)): for sof_ind in range(len(share_of_funds)):
sof = share_of_funds[sof_ind] sof = share_of_funds[sof_ind]
for a_ind in range(len(alpha)): for a_ind in range(len(alpha)):
ts = total_supply ts = supply
a = alpha[a_ind] a = alpha[a_ind]
tc = ts /(1-a) tc = ts /(1-a)
trigger = trigger_func(sof, 1, ts, beta, rho, a) trigger = trigger_func(sof, 1, ts, beta, rho, a)
@ -512,7 +517,8 @@ def trigger_sweep(field, trigger_func,beta,rho,alpha,xmax=.2):
'share_of_max_conv': demo_data_Z6, 'share_of_max_conv': demo_data_Z6,
'log10_share_of_max_conv':demo_data_Z7, 'log10_share_of_max_conv':demo_data_Z7,
'alpha':alpha, 'alpha':alpha,
'share_of_funds':share_of_funds} 'share_of_funds':share_of_funds,
'supply':supply}
else: else:
return "invalid field" return "invalid field"
@ -535,53 +541,125 @@ def trigger_plotter(share_of_funds,Z, color_label,y, ylabel,cmap='jet'):
def trigger_grid(supply_sweep, alpha_sweep): def trigger_grid(supply_sweep, alpha_sweep):
fig, axs = plt.subplots(nrows=2, ncols=2,figsize=(20,20)) fig, axs = plt.subplots(nrows=2, ncols=1,figsize=(20,20))
axs = axs.flatten() axs = axs.flatten()
share_of_funds = alpha_sweep['share_of_funds'] # cut out the plots that didn't require the heatmap
Z = alpha_sweep['log10_share_of_max_conv'] # and switch to (2,1) subplots
y = alpha_sweep['alpha']
ylabel = 'alpha'
axs[0].contourf(share_of_funds, y, Z.T,100, cmap='jet', ) # share_of_funds = alpha_sweep['share_of_funds']
#axs[0].colorbar(cf) # Z = alpha_sweep['log10_share_of_max_conv']
axs[0].axis([share_of_funds[0], share_of_funds[-1], y[0], y[-1]]) # y = alpha_sweep['alpha']
axs[0].set_ylabel(ylabel) # ylabel = 'alpha'
axs[0].set_xlabel('Share of Funds Requested')
axs[0].set_title('Trigger Function Map - Alpha sweep')
# axs[0].contourf(share_of_funds, y, Z.T,100, cmap='jet', )
# #axs[0].colorbar(cf)
# axs[0].axis([share_of_funds[0], share_of_funds[-1], y[0], y[-1]])
# axs[0].set_ylabel(ylabel)
# axs[0].set_xlabel('Share of Funds Requested')
# axs[0].set_title('Trigger Function Map - Alpha sweep')
share_of_funds = alpha_sweep['share_of_funds'] share_of_funds = alpha_sweep['share_of_funds']
Z = alpha_sweep['log10_trigger'] Z = alpha_sweep['log10_trigger']
y = alpha_sweep['alpha'] y = alpha_sweep['alpha']
ylabel = 'alpha' ylabel = 'alpha'
supply = alpha_sweep['supply']
axs[1].contourf(share_of_funds, y, Z.T,100, cmap='jet', ) cp0=axs[0].contourf(share_of_funds, y, Z.T,100, cmap='jet', )
axs[1].axis([share_of_funds[0], share_of_funds[-1], y[0], y[-1]]) axs[0].axis([share_of_funds[0], share_of_funds[-1], y[0], y[-1]])
axs[1].set_ylabel(ylabel) axs[0].set_ylabel(ylabel)
axs[1].set_xlabel('Share of Funds Requested') axs[0].set_xlabel('Share of Funds Requested')
axs[1].set_title('Trigger Function Map - Alpha sweep - Z: log10_trigger') axs[0].set_title('Trigger Function Map - Alpha sweep; Supply ='+str(supply))
cb0=plt.colorbar(cp0, ax=axs[0])
cb0.set_label('log10 of conviction to trigger')
share_of_funds = supply_sweep['share_of_funds'] # share_of_funds = supply_sweep['share_of_funds']
Z = supply_sweep['log10_share_of_max_conv'] # Z = supply_sweep['log10_share_of_max_conv']
y = supply_sweep['total_supply'] # y = supply_sweep['total_supply']
ylabel = 'Effective Supply' # ylabel = 'Effective Supply'
axs[2].contourf(share_of_funds, y, Z.T,100, cmap='jet', ) # axs[2].contourf(share_of_funds, y, Z.T,100, cmap='jet', )
axs[2].axis([share_of_funds[0], share_of_funds[-1], y[0], y[-1]]) # axs[2].axis([share_of_funds[0], share_of_funds[-1], y[0], y[-1]])
axs[2].set_ylabel(ylabel) # axs[2].set_ylabel(ylabel)
axs[2].set_xlabel('Share of Funds Requested') # axs[2].set_xlabel('Share of Funds Requested')
axs[2].set_title('Trigger Function Map - Supply sweep - Z: share_of_max_conv') # axs[2].set_title('Trigger Function Map - Supply sweep - Z: share_of_max_conv')
share_of_funds = supply_sweep['share_of_funds'] share_of_funds = supply_sweep['share_of_funds']
Z = supply_sweep['log10_trigger'] Z = supply_sweep['log10_trigger']
y = supply_sweep['total_supply'] y = supply_sweep['total_supply']
ylabel = 'Effective Supply' ylabel = 'Effective Supply'
alpha = supply_sweep['alpha']
axs[3].contourf(share_of_funds, y, Z.T,100, cmap='jet', ) max_conv = y/(1-alpha)
axs[3].axis([share_of_funds[0], share_of_funds[-1], y[0], y[-1]])
axs[3].set_ylabel(ylabel) cp1=axs[1].contourf(share_of_funds, y, Z.T,100, cmap='jet', )
axs[3].set_xlabel('Share of Funds Requested') axs[1].axis([share_of_funds[0], share_of_funds[-1], y[0], y[-1]])
axs[3].set_title('Trigger Function Map - Supply sweep') axs[1].set_ylabel(ylabel)
axs[1].set_xlabel('Share of Funds Requested')
axs[1].set_title('Trigger Function Map - Supply sweep; alpha='+str(alpha))
axs[1].set_label('log10 of conviction to trigger')
cb1=plt.colorbar(cp1, ax=axs[1])
cb1.set_label('log10 of conviction to trigger')
def initialize_network(n,m, initial_funds, supply):
'''
Definition:
Function to initialize network x object
Parameters:
Assumptions:
Returns:
Example:
'''
# initilize network x graph
network = nx.DiGraph()
# create participant nodes with type and token holding
for i in range(n):
network.add_node(i)
network.nodes[i]['type']= "participant"
h_rv = expon.rvs(loc=0.0, scale= supply/n)
network.nodes[i]['holdings'] = h_rv # SOL check
s_rv = np.random.rand()
network.nodes[i]['sentiment'] = s_rv
participants = get_nodes_by_type(network, 'participant')
initial_supply = np.sum([ network.nodes[i]['holdings'] for i in participants])
# Generate initial proposals
for ind in range(m):
j = n+ind
network.add_node(j)
network.nodes[j]['type']="proposal"
network.nodes[j]['conviction'] = 0
network.nodes[j]['status'] = 'candidate'
network.nodes[j]['age'] = 0
r_rv = gamma.rvs(3,loc=0.001, scale=100)
network.nodes[j]['funds_requested'] = r_rv
network.nodes[j]['trigger']= trigger_threshold(r_rv, initial_funds, initial_supply,beta,rho,alpha)
for i in range(n):
network.add_edge(i, j)
rv = np.random.rand()
a_rv = np.random.uniform(-1,1,1)[0]
network.edges[(i, j)]['affinity'] = a_rv
network.edges[(i, j)]['tokens'] = 0
network.edges[(i, j)]['conviction'] = 0
network.edges[(i, j)]['type'] = 'support'
proposals = get_nodes_by_type(network, 'proposal')
total_requested = np.sum([ network.nodes[i]['funds_requested'] for i in proposals])
network = initial_conflict_network(network, rate = .25)
network = initial_social_network(network, scale = 1)
return network

View File

@ -10,7 +10,8 @@ from .conviction_helper_functions import *
beta = .2 #later we should set this to be param so we can sweep it beta = .2 #later we should set this to be param so we can sweep it
# tuning param for the trigger function # tuning param for the trigger function
rho = .001 rho = .001
alpha = 1 - 0.9999599 #alpha = 1 - 0.9999599 #native timescale for app as in contract code
alpha = .5**3 #timescale set in days with 3 day halflife (from comments in contract comments)
supply = 21706 # Honey supply balance as of 7-17-2020 supply = 21706 # Honey supply balance as of 7-17-2020
initial_sentiment = .6 initial_sentiment = .6
@ -28,65 +29,4 @@ base_failure_rate = 200
initial_funds = 48000 # in xDai initial_funds = 48000 # in xDai
def initialize_network(n,m, inital_funds, supply): network = initialize_network(n,m,initial_funds,supply)
'''
Definition:
Function to initialize network x object
Parameters:
Assumptions:
Returns:
Example:
'''
# initilize network x graph
network = nx.DiGraph()
# create participant nodes with type and token holding
for i in range(n):
network.add_node(i)
network.nodes[i]['type']= "participant"
h_rv = expon.rvs(loc=0.0, scale= supply/n)
network.nodes[i]['holdings'] = h_rv # SOL check
s_rv = np.random.rand()
network.nodes[i]['sentiment'] = s_rv
participants = get_nodes_by_type(network, 'participant')
initial_supply = np.sum([ network.nodes[i]['holdings'] for i in participants])
# Generate initial proposals
for ind in range(m):
j = n+ind
network.add_node(j)
network.nodes[j]['type']="proposal"
network.nodes[j]['conviction'] = 0
network.nodes[j]['status'] = 'candidate'
network.nodes[j]['age'] = 0
r_rv = gamma.rvs(3,loc=0.001, scale=100)
network.nodes[j]['funds_requested'] = r_rv
network.nodes[j]['trigger']= trigger_threshold(r_rv, initial_funds, initial_supply,beta,rho,alpha)
for i in range(n):
network.add_edge(i, j)
a_rv = np.random.uniform(-1,1,1)[0]
network.edges[(i, j)]['affinity'] = a_rv
network.edges[(i, j)]['tokens'] = 0
network.edges[(i, j)]['conviction'] = 0
network.edges[(i, j)]['type'] = 'support'
proposals = get_nodes_by_type(network, 'proposal')
total_requested = np.sum([ network.nodes[i]['funds_requested'] for i in proposals])
network = initial_conflict_network(network, rate = .25)
network = initial_social_network(network, scale = 1)
return network, initial_funds
#initializers
network, initial_funds = initialize_network(n,m,initial_funds,supply)

View File

@ -76,27 +76,19 @@ def complete_proposal(params, step, sL, s, _input):
return (key, value) return (key, value)
def update_sentiment_on_completion(params, step, sL, s, _input): def update_sentiment_on_completion(params, step, sL, s, _input):
network = s['network'] network = s['network']
proposals = get_nodes_by_type(network, 'proposal')
completed = _input['completed'] completed = _input['completed']
failed = _input['failed'] failed = _input['failed']
grants_outstanding = np.sum([network.nodes[j]['funds_requested'] for j in proposals if network.nodes[j]['status']=='active'])
grants_completed = np.sum([network.nodes[j]['funds_requested'] for j in completed])
grants_failed = np.sum([network.nodes[j]['funds_requested'] for j in failed])
sentiment = s['sentiment'] sentiment = s['sentiment']
if grants_outstanding>0: completed_count = len(completed)
force = (grants_completed-grants_failed)/grants_outstanding failed_count = len(failed)
else:
force=1
if (force >=0) and (force <=1):
sentiment = get_sentimental(sentiment, force, mu)
else:
sentiment = get_sentimental(sentiment, 0, mu)
if completed_count+failed_count>0:
sentiment = get_sentimental(sentiment,completed_count-failed_count, .25)
else:
sentiment = get_sentimental(sentiment, 0, 0)
key = 'sentiment' key = 'sentiment'
value = sentiment value = sentiment
@ -134,8 +126,10 @@ def participants_decisions(params, step, sL, s):
booster = social_affinity_booster(network, j, i) booster = social_affinity_booster(network, j, i)
affinity = network.edges[(i, j)]['affinity']+booster affinity = network.edges[(i, j)]['affinity']+booster
cutoff = sensitivity*np.max([network.edges[(i,p)]['affinity'] for p in candidates]) cutoff = sensitivity*np.max([network.edges[(i,p)]['affinity'] for p in candidates])
if cutoff <.5: # range is [-1,1], where 0 is indifference, this determines min affinity supported
cutoff = .5 # if no proposal meets this threshold participants may support a null proposal
if cutoff <.3:
cutoff = .3
if affinity > cutoff: if affinity > cutoff:
support.append(j) support.append(j)

View File

@ -76,11 +76,11 @@ def update_sentiment_on_release(params, step, sL, s, _input):
proposals_accepted = np.sum([network.nodes[j]['funds_requested'] for j in accepted]) proposals_accepted = np.sum([network.nodes[j]['funds_requested'] for j in accepted])
sentiment = s['sentiment'] sentiment = s['sentiment']
force = proposals_accepted/proposals_outstanding force = len(accepted)
if (force >=0) and (force <=1): if force>0:
sentiment = get_sentimental(sentiment, force, False) sentiment = get_sentimental(sentiment, force, .25)
else: else:
sentiment = get_sentimental(sentiment, 0, False) sentiment = get_sentimental(sentiment, 0, 0)
key = 'sentiment' key = 'sentiment'
value = sentiment value = sentiment

View File

@ -16,11 +16,21 @@ def driving_process(params, step, sL, s):
arrival_rate = 10/(1+s['sentiment']) arrival_rate = 10/(1+s['sentiment'])
rv1 = np.random.rand() rv1 = np.random.rand()
new_participant = bool(rv1<1/arrival_rate) new_participant = bool(rv1<1/arrival_rate)
supporters = get_edges_by_type(s['network'], 'support')
network = s['network']
len_parts = len(get_nodes_by_type(s['network'], 'participant')) proposals = get_nodes_by_type(network, 'proposal')
participants = get_nodes_by_type(network, 'participant')
cadidate_proposals = [j for j in proposals if network.nodes[j]['status']=='candidate']
subgraph_nodes = cadidate_proposals+participants
candidate_subgraph = s['network'].subgraph(subgraph_nodes)
supporters = get_edges_by_type(candidate_subgraph, 'support')
len_parts = len(participants)
#supply = s['supply'] #supply = s['supply']
expected_holdings = .1*supply/len_parts expected_holdings = .01*supply/len_parts
if new_participant: if new_participant:
h_rv = expon.rvs(loc=0.0, scale=expected_holdings) h_rv = expon.rvs(loc=0.0, scale=expected_holdings)
new_participant_holdings = h_rv new_participant_holdings = h_rv
@ -28,16 +38,15 @@ def driving_process(params, step, sL, s):
new_participant_holdings = 0 new_participant_holdings = 0
network = s['network'] network = s['network']
affinities = [network.edges[e]['affinity'] for e in supporters ] affinities = [network.edges[e]['affinity'] for e in supporters]
median_affinity = np.median(affinities) median_affinity = np.median(affinities)
proposals = get_nodes_by_type(network, 'proposal') fund_requests = [network.nodes[j]['funds_requested'] for j in cadidate_proposals]
fund_requests = [network.nodes[j]['funds_requested'] for j in proposals if network.nodes[j]['status']=='candidate']
funds = s['funds'] funds = s['funds']
total_funds_requested = np.sum(fund_requests) total_funds_requested = np.sum(fund_requests)
proposal_rate = 1/median_affinity * (1+total_funds_requested/funds) proposal_rate = 1/(1+median_affinity) * (1+total_funds_requested/funds)
rv2 = np.random.rand() rv2 = np.random.rand()
new_proposal = bool(rv2<1/proposal_rate) new_proposal = bool(rv2<1/proposal_rate)