from __future__ import print_function
import numpy as np
import sys
import os
import random
from random import seed
from random import random
from random import gauss
import datetime
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
from matplotlib.ticker import MultipleLocator
from matplotlib.ticker import ScalarFormatter
from matplotlib.ticker import NullFormatter
import matplotlib.image as image
import matplotlib.patches as patches
import matplotlib.lines as lines
import matplotlib.ticker as ticker
from scipy.optimize import curve_fit

from matplotlib.patches import Circle, Ellipse, Wedge, Polygon
from matplotlib.collections import PatchCollection


class Generation(object):
	Generation_id = None
	Individuals = None
	def __init__(self,Generation_id=None, Individuals=None):
		self.generation_id = Generation_id
		self.individuals = Individuals
	def get_individuals(self):
		return self.individuals
	def get_individual(self,i):
		return self.individuals[i]
		
class Individual(object):
	Individual_id = None
	Fitness = None
	Action0 = None
	Action1 = None
	Nodes = None
	Connections = None
	def __init__(self,Individual_id = None, Fitness=None, Action0=None, Action1=None, Nodes=None, Connections=None):
		self.individual_id = Individual_id
		self.fitness = Fitness
		self.action0 = Action0
		self.action1 = Action1
		self.nodes = Nodes
		self.connections = Connections
	def get_id(self):
		return self.individual_id
	def get_fitness(self):
		return self.fitness
	def get_action0(self):
		return self.action0
	def get_action1(self):
		return self.action1
	def get_nodes(self):
		return self.nodes
	def get_connections(self):
		return self.connections
	def get_node_number(self):
		return len(self.nodes)
		
class Node(object):
	Node_id = None
	Node_bias=None
	Node_response=None
	Node_activation=None
	Node_aggregation=None
	def __init__(self, Node_id = None, Node_bias=None, Node_response=None, Node_activation=None, Node_aggregation=None):
		self.node_id = Node_id
		self.node_bias = Node_bias
		self.node_response = Node_response
		self.node_activation = Node_activation
		self.node_aggregation = Node_aggregation
	def get_id(self):
		return self.node_id
	def get_bias(self):
		return self.node_bias
	def get_response(self):
		return self.node_response
	def get_activation(self):
		return self.node_activation
	def get_aggregation(self):
		return self.node_aggregation
		
class Connection(object):
	Connection_node1 = None
	Connection_node2=None
	Connection_weight=None
	Connection_enabled=None
	def __init__(self, Connection_node1 = None, Connection_node2=None, Connection_weight=None, Connection_enabled=None):
		self.connection_node1 = Connection_node1
		self.connection_node2 = Connection_node2
		self.connection_weight = Connection_weight
		self.connection_enabled = Connection_enabled
	def get_node1(self):
		return self.connection_node1
	def get_node2(self):
		return self.connection_node2
	def get_weight(self):
		return self.connection_weight
	def get_enabled(self):
		return self.connection_enabled

def read_output (filename):
	f=open(filename,'r')
	lines=f.readlines()
	f.close()
	
	p = lines[1].split()
	generation_id = int(p[3])
	generations=[]
	individuals=[]
	l_nodes=0
	l_connections=0
	nodes=[]
	connections=[]
	
	for line in lines[2:]:
		string = line.replace(':',' :')
		string2 = string.replace('key=(','key=( ')
		string3 = string2.replace('key=','key= ')
		string4 = string3.replace(',',' ,')
		string5 = string4.replace('bias=','bias= ')
		string6 = string5.replace('response=','response= ')
		string7 = string6.replace('activation=','activation= ')
		string8 = string7.replace('aggregation=','aggregation= ')
		string9 = string8.replace(')',' )')
		string10 = string9.replace('weight=','weight= ')
		string11 = string10.replace('enabled=','enabled= ')
#0 DefaultNodeGene(key= 0 , bias= -1.81278556018 , response= 1.0 , activation= clamped , aggregation= sum )
#DefaultConnectionGene(key= ( -2 , 0 ) , weight= -1.60598535251 , enabled= True )
		
		p = string11.split()
		if (len(p)>1):
			if (p[1]=='Running' and p[2]=='generation'):
				generation_id = int(p[3])-1
				if (generation_id>=0):
					generation = Generation(Generation_id=generation_id,Individuals=individuals)
					generations.append(generation)
					individuals=[]
			
			if (p[0]=='Key'):
				individual_id = int(p[2])
			if (p[0]=='Nodes'):
				l_nodes=1
			if (p[0]=='Connections'):
				l_nodes=0
				l_connections=1
			if (p[0]=='Ntargets'):
				l_connections=0
				fitness = float(p[2])
				a0 = int(p[5])
				a1 = int(p[6])
				individual = Individual(Individual_id = individual_id, Fitness=fitness, Action0=a0, Action1=a1, Nodes=nodes, Connections=connections)
				individuals.append(individual)
				nodes=[]
				connections=[]
			
			if (l_nodes==1 and p[0]!='Nodes'): # read nodes
				node_id = int(p[2])
				node_bias = float(p[5])
				node_response = float(p[8])
				node_activation = p[11]
				node_aggregation = p[14]
				node = Node(Node_id=node_id, Node_bias=node_bias, Node_response=node_response, Node_activation=node_activation, Node_aggregation=node_aggregation)
				nodes.append(node)
				
			if (l_connections==1 and p[0]!='Connections'): # read connections
				connection_node1 = int(p[2])
				connection_node2 = int(p[4])
				connection_weight = float(p[8])
				connection_enabled = p[11]
				connection = Connection(Connection_node1 = connection_node1, Connection_node2=connection_node2, Connection_weight=connection_weight, Connection_enabled=connection_enabled)
				connections.append(connection)

	generation = Generation(Generation_id=generation_id+1,Individuals=individuals)
	generations.append(generation)

	return generations

def make_analysis_subspecies(generations,n_generations,a0,a1,generations2):
	xdata = np.zeros((n_generations))
	n_individuals_gen = np.zeros((n_generations))
	
	f_individuals_gen_0hidden = np.zeros((n_generations))
	f_individuals_gen_1hidden = np.zeros((n_generations))
	f_individuals_gen_2hidden = np.zeros((n_generations))
	f_individuals_gen_3hidden = np.zeros((n_generations))
	
	for index in range(n_generations):
		individuals = generations[index].get_individuals()
		for individual in individuals:
			if (individual.get_action0()==a0 and individual.get_action1()==a1):
				n_individuals_gen[index]+=1.0
				n_hidden = individual.get_node_number()-4
				if (n_hidden==0): 
					f_individuals_gen_0hidden[index]+=1.0
				if (n_hidden==1): 
					f_individuals_gen_1hidden[index]+=1.0
				if (n_hidden==2): 
					f_individuals_gen_2hidden[index]+=1.0
				if (n_hidden>=3): f_individuals_gen_3hidden[index]+=1.0
				
	
	for index in range(n_generations):
		xdata[index] = index
		f_individuals_gen_0hidden[index] /= n_individuals_gen[index]
		f_individuals_gen_1hidden[index] /= n_individuals_gen[index]
		f_individuals_gen_2hidden[index] /= n_individuals_gen[index]
		f_individuals_gen_3hidden[index] /= n_individuals_gen[index]
		
	Results = [xdata,n_individuals_gen,f_individuals_gen_0hidden,f_individuals_gen_1hidden,f_individuals_gen_2hidden,f_individuals_gen_3hidden]
	
	
	selected_individuals_0nodes = []
	selected_individuals_1nodes = []
	selected_individuals_2nodes = []
	
	for index in range(10):
		individuals = generations2[index].get_individuals()
		for individual in individuals:
			if (individual.get_action0()==a0 and individual.get_action1()==a1):
				n_hidden = individual.get_node_number()-4
				if (n_hidden==0): 
					if (index==9): selected_individuals_0nodes.append(individual)
				if (n_hidden==1): 
					if (index==9): selected_individuals_1nodes.append(individual)
				if (n_hidden==2): 
					if (index==9): selected_individuals_2nodes.append(individual)
					
	selected_individuals = [selected_individuals_0nodes,selected_individuals_1nodes,selected_individuals_2nodes]
	
	return Results,selected_individuals

def makearrows(panel,individual,xc1,xc2,xc3,xc4,xc5,xc6,xc7,xc8,yc1,yc3,yc7):
	lw = 1.0
	n_hidden = individual.get_node_number()-4
	if (n_hidden == 1):
		nodes = individual.get_nodes()
		n1 = nodes[-1].get_id()
	if (n_hidden == 2):
		nodes = individual.get_nodes()
		n1 = nodes[-2].get_id()
		n2 = nodes[-1].get_id()
	
	connections = individual.get_connections()
	for connection in connections:
		node1 = connection.get_node1()
		node2 = connection.get_node2()
		weight = connection.get_weight()
		enab = connection.get_enabled()
		weight2 = abs(weight)
		print (node1, node2, weight, enab)
		if (enab == 'True'):
			if (node1 == -2 and node2 ==0):
				panel.arrow(xc1, yc1, xc3-xc1, yc3-yc1, shape='full', lw=lw*weight2, color = 'k')
			if (node1 == -2 and node2 ==1):
				panel.arrow(xc1, yc1, xc4-xc1, yc3-yc1, shape='full', lw=lw*weight2, color = 'k')
			if (node1 == -2 and node2 ==2):
				panel.arrow(xc1, yc1, xc5-xc1, yc3-yc1, shape='full', lw=lw*weight2, color = 'k')
			if (node1 == -2 and node2 ==3):
				panel.arrow(xc1, yc1, xc6-xc1, yc3-yc1, shape='full', lw=lw*weight2, color = 'k')
			if (node1 == -1 and node2 ==0):
				panel.arrow(xc2, yc1, xc3-xc2, yc3-yc1, shape='full', lw=lw*weight2, color = 'k')
			if (node1 == -1 and node2 ==1):
				panel.arrow(xc2, yc1, xc4-xc2, yc3-yc1, shape='full', lw=lw*weight2, color = 'k')
			if (node1 == -1 and node2 ==2):
				panel.arrow(xc2, yc1, xc5-xc2, yc3-yc1, shape='full', lw=lw*weight2, color = 'k')
			if (node1 == -1 and node2 ==3):
				panel.arrow(xc2, yc1, xc6-xc2, yc3-yc1, shape='full', lw=lw*weight2, color = 'k')
			if (n_hidden >= 1):
				if (node1 == -2 and node2 == n1):
					panel.arrow(xc1, yc1, xc7-xc1, yc7-yc1, shape='full', lw=lw*weight2, color = 'k')
				if (node1 == -1 and node2 == n1):
					panel.arrow(xc2, yc1, xc7-xc2, yc7-yc1, shape='full', lw=lw*weight2, color = 'k')
				if (node1 == n1 and node2 ==0):
					panel.arrow(xc7, yc7, xc3-xc7, yc3-yc7, shape='full', lw=lw*weight2, color = 'k')
				if (node1 == n1 and node2 ==1):
					panel.arrow(xc7, yc7, xc4-xc7, yc3-yc7, shape='full', lw=lw*weight2, color = 'k')
				if (node1 == n1 and node2 ==2):
					panel.arrow(xc7, yc7, xc5-xc7, yc3-yc7, shape='full', lw=lw*weight2, color = 'k')
				if (node1 == n1 and node2 ==3):
					panel.arrow(xc7, yc7, xc6-xc7, yc3-yc7, shape='full', lw=lw*weight2, color = 'k')
			if (n_hidden >= 2):
				if (node1 == -2 and node2 == n2):
					panel.arrow(xc1, yc1, xc8-xc1, yc7-yc1, shape='full', lw=lw*weight2, color = 'k')
				if (node1 == -1 and node2 == n2):
					panel.arrow(xc2, yc1, xc8-xc2, yc7-yc1, shape='full', lw=lw*weight2, color = 'k')
				if (node1 == n2 and node2 ==0):
					panel.arrow(xc8, yc7, xc3-xc8, yc3-yc7, shape='full', lw=lw*weight2, color = 'k')
				if (node1 == n2 and node2 ==1):
					panel.arrow(xc8, yc7, xc4-xc8, yc3-yc7, shape='full', lw=lw*weight2, color = 'k')
				if (node1 == n2 and node2 ==2):
					panel.arrow(xc8, yc7, xc5-xc8, yc3-yc7, shape='full', lw=lw*weight2, color = 'k')
				if (node1 == n2 and node2 ==3):
					panel.arrow(xc8, yc7, xc6-xc8, yc3-yc7, shape='full', lw=lw*weight2, color = 'k')
				
				
	print ('--------------------------------------')
	return

def make_figure (Results,selected_individuals,expected_fractions):
	# unpack the results
	xdata,n_individuals_gen,f_individuals_gen_0hidden,f_individuals_gen_1hidden,f_individuals_gen_2hidden,f_individuals_gen_3hidden = Results[0],Results[1],Results[2],Results[3],Results[4],Results[5]
	
	# xlimits
	factorx = 1.5 # =1 for 40 episodes
	xlima,xlimb=-1.8*factorx, 40*factorx-2*factorx
	xtic,xtic_minor = 4*factorx,2*factorx
	xwidth = 2.5*factorx
	
	# setto alcune variabili comuni
	axisticslabelfontsize=9
	axisticslabelfontsizeinset=7
	axislabelfontsize=11 
	axislabelfontsizeinset=9
	
	xfig,yfig=7.0,2.5
	factor = xfig/yfig
	
	with PdfPages('fig3.pdf') as pdf:
		fig = plt.figure(figsize=(xfig,yfig))
		plt.rc('text', usetex=True)
		plt.rc('text.latex', preamble = ','.join('''\usepackage{txfonts} \usepackage{lmodern}'''.split()))
		
		panel = fig.add_axes([0, 0, 1, 1])
		panel.spines['right'].set_visible(False)
		panel.spines['top'].set_visible(False)
		panel.spines['bottom'].set_visible(False)
		panel.spines['left'].set_visible(False)
		panel.axes.get_xaxis().set_ticks([])
		panel.axes.get_yaxis().set_ticks([])
		
		panel.text(0.01,0.93,r'(a)',fontsize=axislabelfontsize,transform=panel.transAxes)
		panel.text(0.42,0.93,r'(b)',fontsize=axislabelfontsize,transform=panel.transAxes)
		
		######################## panel A ########################################
		panel = fig.add_axes([0.08, 0.16, 0.31, 0.82])
		panel.tick_params(axis='both',which='both',direction='in',bottom=True,top=True,left=True,right=True)
		for tick in panel.xaxis.get_major_ticks(): tick.label.set_fontsize(axisticslabelfontsize)
		for tick in panel.yaxis.get_major_ticks(): tick.label.set_fontsize(axisticslabelfontsize)
		panel.set_xlabel(r'generation',fontsize=axislabelfontsize)
		panel.set_ylabel(r'$N_{\alpha_{5,5}^{(h)}} / N_{\alpha_{5,5}}$',fontsize=axislabelfontsize)
		panel.set_xlim(0,59)
		panel.set_ylim(-0.02, 1.02)
		panel.xaxis.set_major_locator(MultipleLocator(10))
		panel.xaxis.set_minor_locator(MultipleLocator(2))
		panel.yaxis.set_major_locator(MultipleLocator(0.2))
		panel.yaxis.set_minor_locator(MultipleLocator(0.1))
		
		panel.plot(xdata,f_individuals_gen_0hidden,'g-',markersize=2,linewidth=1.5,zorder=3,label=r'$h=0$')
		panel.plot(xdata,expected_fractions[0],'g--',linewidth=0.8,zorder=3)
		panel.plot(xdata,f_individuals_gen_1hidden,'r-',markersize=2,linewidth=1.5,zorder=3,label=r'$h=1$')
		panel.plot(xdata,expected_fractions[1],'r--',linewidth=0.8,zorder=3)
		panel.plot(xdata,f_individuals_gen_2hidden,'b-',markersize=2,linewidth=1.5,zorder=3,label=r'$h=2$')
		panel.plot(xdata,expected_fractions[2],'b--',linewidth=0.8,zorder=3)
		panel.plot(xdata,f_individuals_gen_3hidden,'-',color='gray',markersize=2,linewidth=1.0,zorder=3,label=r'$h>2$')
		panel.plot(xdata,expected_fractions[3],'--',color='gray',linewidth=0.8,zorder=3)
		
		panel.legend(loc='upper right', bbox_to_anchor=(0.99, 0.99),ncol=1,fontsize=8,handlelength=1.5,labelspacing=0.2)
		
		
		############# paramenters for network
		rc1 = 0.09
		deltay = 0.28
		yc1 = 0.81
		xc1,xc2 = 0.36, 0.64
		yc3 = yc1 - deltay
		xc7,xc8 = 0.85,0.15
		yc7 = yc1 - deltay/2
		xc3,xc4,xc5,xc6 = 0.2, 0.4, 0.6, 0.8
		yc1b = 0.37
		yc3b = yc1b - deltay
		yc7b = yc1b - deltay/2
		epsy = 0.01
		
		######################## panel B0 ############################ hidden = 0
		panel = fig.add_axes([0.45, 0.12, 0.18, 0.85])
		for axis in ['top', 'bottom', 'left', 'right']:
			panel.spines[axis].set_linewidth(0.8)  # change width
			panel.spines[axis].set_color('lightgray')   # change color
		panel.axes.get_xaxis().set_ticks([])
		panel.axes.get_yaxis().set_ticks([])
		panel.text(0.5,0.94,r'$h=0$',fontsize=10, horizontalalignment = 'center', transform=panel.transAxes)
		
		a0, b0 = panel.transAxes.transform((0, 0)) # lower left in pixels
		a1, b1 = panel.transAxes.transform((1, 1)) # upper right in pixes
		dxp = a1 - a0
		dyp = b1 - b0
		maxd = max(dxp,dyp)
		rc1x,rc1y = rc1*maxd/dxp,rc1*maxd/dyp
		# arrows
		makearrows(panel,selected_individuals[0][10],xc1,xc2,xc3,xc4,xc5,xc6,xc7,xc8,yc1,yc3,yc7)
		makearrows(panel,selected_individuals[0][1],xc1,xc2,xc3,xc4,xc5,xc6,xc7,xc8,yc1b,yc3b,yc7b)
		# circle s
		c1 = Ellipse((xc1,yc1),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c1)
		panel.text(xc1,yc1,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont BP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c2 = Ellipse((xc2,yc1),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c2)
		panel.text(xc2,yc1,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c1 = Ellipse((xc1,yc1b),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c1)
		panel.text(xc1,yc1b,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont BP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c2 = Ellipse((xc2,yc1b),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c2)
		panel.text(xc2,yc1b,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		# circle a
		c3 = Ellipse((xc3,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c3)
		panel.text(xc3,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c4 = Ellipse((xc4,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c4)
		panel.text(xc4,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c5 = Ellipse((xc5,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c5)
		panel.text(xc5,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c6 = Ellipse((xc6,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c6)
		panel.text(xc6,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c3 = Ellipse((xc3,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c3)
		panel.text(xc3,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c4 = Ellipse((xc4,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c4)
		panel.text(xc4,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c5 = Ellipse((xc5,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c5)
		panel.text(xc5,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c6 = Ellipse((xc6,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c6)
		panel.text(xc6,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		
		######################## panel B1 ############################ hidden = 1
		panel = fig.add_axes([0.63, 0.12, 0.18, 0.85])
		for axis in ['top', 'bottom', 'left', 'right']:
			panel.spines[axis].set_linewidth(0.8)  # change width
			panel.spines[axis].set_color('lightgray')   # change color
		panel.axes.get_xaxis().set_ticks([])
		panel.axes.get_yaxis().set_ticks([])
		panel.text(0.5,0.94,r'$h=1$',fontsize=10, horizontalalignment = 'center', transform=panel.transAxes)
		
		a0, b0 = panel.transAxes.transform((0, 0)) # lower left in pixels
		a1, b1 = panel.transAxes.transform((1, 1)) # upper right in pixes
		dxp = a1 - a0
		dyp = b1 - b0
		maxd = max(dxp,dyp)
		rc1x,rc1y = rc1*maxd/dxp,rc1*maxd/dyp
		# arrows
		makearrows(panel,selected_individuals[1][0],xc1,xc2,xc3,xc4,xc5,xc6,xc7,xc8,yc1,yc3,yc7)
		makearrows(panel,selected_individuals[1][3],xc1,xc2,xc3,xc4,xc5,xc6,xc7,xc8,yc1b,yc3b,yc7b)
		# circle s
		c1 = Ellipse((xc1,yc1),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c1)
		panel.text(xc1,yc1,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont BP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c2 = Ellipse((xc2,yc1),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c2)
		panel.text(xc2,yc1,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c1 = Ellipse((xc1,yc1b),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c1)
		panel.text(xc1,yc1b,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont BP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c2 = Ellipse((xc2,yc1b),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c2)
		panel.text(xc2,yc1b,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		# circle a
		c3 = Ellipse((xc3,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c3)
		panel.text(xc3,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c4 = Ellipse((xc4,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c4)
		panel.text(xc4,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c5 = Ellipse((xc5,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c5)
		panel.text(xc5,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c6 = Ellipse((xc6,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c6)
		panel.text(xc6,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c3 = Ellipse((xc3,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c3)
		panel.text(xc3,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c4 = Ellipse((xc4,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c4)
		panel.text(xc4,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c5 = Ellipse((xc5,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c5)
		panel.text(xc5,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c6 = Ellipse((xc6,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c6)
		panel.text(xc6,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		# circle h
		c7 = Ellipse((xc7,yc7),rc1x,rc1y,facecolor='lightgray',edgecolor='gray', lw=0.5, zorder=10)
		panel.add_patch(c7)
		c7 = Ellipse((xc7,yc7b),rc1x,rc1y,facecolor='lightgray',edgecolor='gray', lw=0.5, zorder=10)
		panel.add_patch(c7)
		
		
		######################## panel B2 ############################ hidden = 2
		panel = fig.add_axes([0.81, 0.12, 0.18, 0.85])
		for axis in ['top', 'bottom', 'left', 'right']:
			panel.spines[axis].set_linewidth(0.8)  # change width
			panel.spines[axis].set_color('lightgray')   # change color
		panel.axes.get_xaxis().set_ticks([])
		panel.axes.get_yaxis().set_ticks([])
		panel.text(0.5,0.94,r'$h=2$',fontsize=10, horizontalalignment = 'center', transform=panel.transAxes)
		
		a0, b0 = panel.transAxes.transform((0, 0)) # lower left in pixels
		a1, b1 = panel.transAxes.transform((1, 1)) # upper right in pixes
		dxp = a1 - a0
		dyp = b1 - b0
		maxd = max(dxp,dyp)
		rc1x,rc1y = rc1*maxd/dxp,rc1*maxd/dyp
		# arrows
		makearrows(panel,selected_individuals[2][2],xc1,xc2,xc3,xc4,xc5,xc6,xc7,xc8,yc1,yc3,yc7)
		makearrows(panel,selected_individuals[2][3],xc1,xc2,xc3,xc4,xc5,xc6,xc7,xc8,yc1b,yc3b,yc7b)
		# circle s
		c1 = Ellipse((xc1,yc1),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c1)
		panel.text(xc1,yc1,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont BP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c2 = Ellipse((xc2,yc1),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c2)
		panel.text(xc2,yc1,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c1 = Ellipse((xc1,yc1b),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c1)
		panel.text(xc1,yc1b,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont BP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c2 = Ellipse((xc2,yc1b),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c2)
		panel.text(xc2,yc1b,r'$\chi^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		# circle a
		c3 = Ellipse((xc3,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c3)
		panel.text(xc3,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c4 = Ellipse((xc4,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c4)
		panel.text(xc4,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c5 = Ellipse((xc5,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c5)
		panel.text(xc5,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c6 = Ellipse((xc6,yc3),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c6)
		panel.text(xc6,yc3-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c3 = Ellipse((xc3,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c3)
		panel.text(xc3,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c4 = Ellipse((xc4,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c4)
		panel.text(xc4,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont BP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c5 = Ellipse((xc5,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c5)
		panel.text(xc5,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_s$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		c6 = Ellipse((xc6,yc3b),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c6)
		panel.text(xc6,yc3b-epsy,r'$a^{\mbox{\fontsize{3.3}{4}\selectfont ABP}}_{\tau}$',fontsize=8, horizontalalignment = 'center', verticalalignment = 'center', transform=panel.transAxes, zorder=11)
		# circle h
		c7 = Ellipse((xc7,yc7),rc1x,rc1y,facecolor='lightgray',edgecolor='gray', lw=0.5, zorder=10)
		panel.add_patch(c7)
		c7 = Ellipse((xc7,yc7b),rc1x,rc1y,facecolor='lightgray',edgecolor='gray', lw=0.5, zorder=10)
		panel.add_patch(c7)
		c8 = Ellipse((xc8,yc7),rc1x,rc1y,facecolor='lightgray',edgecolor='gray', lw=0.5, zorder=10)
		panel.add_patch(c8)
		c8 = Ellipse((xc8,yc7b),rc1x,rc1y,facecolor='lightgray',edgecolor='gray', lw=0.5, zorder=10)
		panel.add_patch(c8)
		
		
		
		######################## panel BL ############################ legend
		panel = fig.add_axes([0.45, 0.02, 0.54, 0.1])
		panel.spines['right'].set_visible(False)
		panel.spines['top'].set_visible(False)
		panel.spines['bottom'].set_visible(False)
		panel.spines['left'].set_visible(False)
		panel.axes.get_xaxis().set_ticks([])
		panel.axes.get_yaxis().set_ticks([])
		
		a0, b0 = panel.transAxes.transform((0, 0)) # lower left in pixels
		a1, b1 = panel.transAxes.transform((1, 1)) # upper right in pixes
		dxp = a1 - a0
		dyp = b1 - b0
		maxd = max(dxp,dyp)
		yc = 0.4
		xc1,xc2,xc3=0.1, 0.42, 0.74
		rc1 = 0.04
		# circle s
		rc1x,rc1y = rc1*maxd/dxp,rc1*maxd/dyp
		c1 = Ellipse((xc1,yc),rc1x,rc1y,facecolor='forestgreen',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c1)
		panel.text(xc1+0.8*rc1x,0.2,r'input node',fontsize=9, transform=panel.transAxes)
		# circle a
		c2 = Ellipse((xc2,yc),rc1x,rc1y,facecolor='darkorange',edgecolor='k', lw=0.5, zorder=10)
		panel.add_patch(c2)
		panel.text(xc2+0.8*rc1x,0.2,r'output node',fontsize=9, transform=panel.transAxes)
		# circle h
		c3 = Ellipse((xc3,yc),rc1x,rc1y,facecolor='lightgray',edgecolor='gray', lw=0.5, zorder=10)
		panel.add_patch(c3)
		panel.text(xc3+0.8*rc1x,0.2,r'hidden node',fontsize=9, transform=panel.transAxes)
		

		pdf.savefig(fig)
	return

def solve_master_equation(n_generations,rate):
	sol = np.zeros((100,n_generations))
	sol2 = np.zeros((4,n_generations))
	sol[0][0] = 1.0
	
	for n in range(1,n_generations):
		sol[0][n] = sol[0][n-1]-sol[0][n-1]*rate + sol[1][n-1]*rate
		for j in range(1,99):
			sol[j][n] = sol[j][n-1]-sol[j][n-1]*rate*2 + sol[j+1][n-1]*rate + sol[j-1][n-1]*rate
	
	sol2[0]=sol[0]
	sol2[1]=sol[1]
	sol2[2]=sol[2]
	for j in range(3,99):
		sol2[3]+=sol[j]
	
	return sol2

def main():
	generations = read_output('out_Pe100.dat')
	n_generations=60
	
	generations2 = read_output('../FIG2/out_Pe100.dat')
	
	rate = 0.05
	expected_fractions = solve_master_equation(n_generations,rate)
	
	a0=10
	a1=10
	Results,selected_individuals = make_analysis_subspecies(generations,n_generations,a0,a1,generations2)
	make_figure (Results,selected_individuals,expected_fractions)

main()
