text: 
  ####################
  # Import packages
  ####################
  import matplotlib
  import sys
  
  from deap import base, creator, tools, algorithms
  import pickle
  import time as timeski
  import os
  import numpy as np
  
  import matlab.engine 
  eng = matlab.engine.start_matlab() #start matlab engine
  
  
  ###################################################################
  #EA PARAMS
  ###################################################################
  
  number_of_runs = 1
  number_of_generations = 40
  number_of_individuals = 100
  mutation_rate = 0.1
  crossover_rate = 0.5
  number_of_params = 8
  filename = 'BT_1001.txt'
  
  
  
  
  ###################################################################
  # EA Functions
  ###################################################################
  
  
  def make_conversion_matrix(number_of_params):
      # want easily savable matrix to hold this info
      # interp boolean, interp range (min,max), power boolean, power number (y)
      arr_IandP = np.zeros((5,number_of_params))
      # Set all interp booleans to 1 - everything is going to be interpreted
      arr_IandP[0,:] = 1
      # Set all power booleans to 1 - everything is in the form of powers
      arr_IandP[3,:] = 1
      # Set all power numbers to 10 - everything has a base of 10
      arr_IandP[4,:] = 10
      # Set minimums and maximums for all parameters. Parameters are in the following order:
      # Da,Di,Dl, kcoff,Kcp,kcpmax,kcon, Kcf,kcfmax,kroff,kron,
      # Krp,krpmax,Krf,krfmax, kpc,kpr,kpf,delp, kac,kar,kaf,dela
  
      minimums = np.concatenate([np.ones(number_of_params)*-4.])
  
  
      maximums = np.concatenate([np.ones(number_of_params-1)*np.log(20)/np.log(10),np.array([np.log(0.76)/np.log(10)])])
  
      for i in range(len(minimums)):
          arr_IandP[1,i] = minimums[i] #interp_range_min
          arr_IandP[2,i] = maximums[i] #interp_range_max
  
      return arr_IandP
  
  #converts parameters from an EA individual using the conversion matrix
  def convert_individual(ea_individual, conversion_matrix, number_of_params):
      # copy and get len of individual
      arr_params_conv = np.zeros(number_of_params)#np.copy(arr_parameters)
      len_ind = len(ea_individual)
  
      # Interp:
      for idx in np.nonzero(conversion_matrix[0])[0]:
          ea_val = ea_individual[idx]
          r_min = conversion_matrix[1][idx]
          r_max = conversion_matrix[2][idx]
          arr_params_conv[idx] = np.interp(ea_val, (0,1), (r_min, r_max))
  
      # Exponentiate:
      for idx in np.nonzero(conversion_matrix[3])[0]:
          ea_val = arr_params_conv[idx]
          base_val = conversion_matrix[4][idx]
          arr_params_conv[idx] = np.power(base_val, ea_val)
  
      # arr_params_conv[-4:] = np.round(arr_params_conv[-4:],0)
  
      return arr_params_conv
  
  #Score function to score each parameter set
  def ScoreFxn(learned_params):
      arr_params = convert_individual(learned_params, arr_conversion_matrix, number_of_params)
      k1, k2, k3, k4, k6, k7, k8, f1 = [float(x) for x in arr_params]
      k5 = 0.0
      
      error = eng.markov_score_final(k1, k2, k3, k4, 0.0, k6, k7, k8, f1, 0.001)
      return error
  
  #helper 
  def scorefxn_helper(individual):
      return ScoreFxn(individual),
  
  
  ###################################################################
  #CHECK FOR / CREATE DIR FOR DATA
  ###################################################################
  def strip_filename(fn):
      #input = full path filename
      #output = filename only
      #EX input = '/home/iammoresentient/phd_lab/data/data_posnegfb_3cellsum.pickled'
      #EX output = 'data_posnegfb_3cellsum'
      if '/' in fn:
          fn = fn.split('/')[-1]
      fn = fn.split('.')[0]
      return fn
  
  
  def add_info(fn, gens, inds, mutationrate, crossoverrate):
      #input = filename only
      #output = date + filename + EA data
      # EX input = 'data_posnegfb_3cellsum'
      # EX output = '170327_data_posnegfb_3cellsum_#g#i#m#c'
  
      #get current date:
      cur_date = timeski.strftime('%y%m%d')
      # setup EA data:
      ea_data = str(gens) + 'g' + str(inds) + 'i' + str(int(mutationrate*100)) + 'm' + str(int(crossoverrate*100)) + 'c'
      #put it all together:
      #new_fn = cur_date + '_' + fn + '_' + ea_data
      new_fn = cur_date + '_' + os.path.basename(fn).split('.')[0].split('_')[-1] + '_' + ea_data
      return new_fn
  
  
  stripped_name = strip_filename(filename)
  informed_name = add_info(stripped_name, number_of_generations, number_of_individuals, mutation_rate, crossover_rate)
  fn_to_use = informed_name
  dir_to_use = os.getcwd() + '/' + stripped_name
  
  #check if dir exists and make
  if not os.path.isdir(dir_to_use):
      os.makedirs(dir_to_use)
      # print('Made: ' + dir_to_use)
      # and make README file:
      fn = dir_to_use + '/' + 'output.txt'
      file = open(fn, 'w')
  
      # write pertinent info at top
      file.write('OUTPUT\n\n')
      file.write('Filename: ' + stripped_name + '\n')
      file.write('Directory: ' + dir_to_use + '\n')
      file.write('Data file: ' + filename + '\n\n')
      file.write('Generations: ' + str(number_of_generations) + '\n')
      file.write('Individuals: ' + str(number_of_individuals) + '\n')
      file.write('Mutation rate: ' + str(mutation_rate) + '\n')
      file.write('Crossover rate: ' + str(crossover_rate) + '\n')
      file.write('\n\n\n\n')
  
      #write script to file
      #script_name = os.getcwd() + '/' + 'EA_1nf1pf.py'
      script_name = os.path.basename(__file__)#__file__)
      open_script = open(script_name, 'r')
      write_script = open_script.read()
      file.write(write_script)
      open_script.close()
  
      file.close()
  
  ###################################################################
  #LOOP: EVOLUTIONARY ALGORITHM + SAVE DATA
  ###################################################################
  
  arr_conversion_matrix = make_conversion_matrix(number_of_params)
  
  for i in range(number_of_runs):
      ###################################################################
      #EVOLUTIONARY ALGORITHM
      ###################################################################
      #TYPE
      #Create minimizing fitness class w/ single objective:
      creator.create('FitnessMin', base.Fitness, weights=(-1.0,))
      #Create individual class:
      creator.create('Individual', list, fitness=creator.FitnessMin)
  
      #TOOLBOX
      toolbox = base.Toolbox()
      #Register function to create a number in the interval [1-100?]:
      #toolbox.register('init_params', )
      #Register function to use initRepeat to fill individual w/ n calls to rand_num:
      toolbox.register('individual', tools.initRepeat, creator.Individual,
                       np.random.random, n=number_of_params)
      #Register function to use initRepeat to fill population with individuals:
      toolbox.register('population', tools.initRepeat, list, toolbox.individual)
  
      #GENETIC OPERATORS:
      # Register evaluate fxn = evaluation function, individual to evaluate given later
      toolbox.register('evaluate', scorefxn_helper)
      # Register mate fxn = two points crossover function
      toolbox.register('mate', tools.cxTwoPoint)
      # Register mutate by swapping two points of the individual:
      toolbox.register('mutate', tools.mutPolynomialBounded,
                       eta=0.1, low=0.0, up=1.0, indpb=0.2)
      # Register select = size of tournament set to 3
      toolbox.register('select', tools.selTournament, tournsize=3)
  
      #EVOLUTION!
      pop = toolbox.population(n=number_of_individuals)
      hof = tools.HallOfFame(1)
  
      stats = tools.Statistics(key = lambda ind: [ind.fitness.values, ind])
      stats.register('all', np.copy)
  
      # using built in eaSimple algo
      pop, logbook = algorithms.eaSimple(pop, toolbox, cxpb=crossover_rate,
                                         mutpb=mutation_rate,
                                         ngen=number_of_generations,
                                         stats=stats, halloffame=hof,
                                         verbose=False)
      # print(f'Run number completed: {i}')
  
      ###################################################################
      #MAKE LISTS
      ###################################################################
      # Find best scores and individuals in population
      arr_best_score = []
      arr_best_ind = []
      for a in range(len(logbook)):
          scores = []
          for b in range(len(logbook[a]['all'])):
              scores.append(logbook[a]['all'][b][0][0])
          #print(a, np.nanmin(scores), np.nanargmin(scores))
          arr_best_score.append(np.nanmin(scores))
          #logbook is of type 'deap.creator.Individual' and must be loaded later
          #don't want to have to load it to view data everytime, thus numpy
          ind_np = np.asarray(logbook[a]['all'][np.nanargmin(scores)][1])
          ind_np_conv = convert_individual(ind_np, arr_conversion_matrix, number_of_params)
          arr_best_ind.append(ind_np_conv)
          #arr_best_ind.append(np.asarray(logbook[a]['all'][np.nanargmin(scores)][1]))
  
  
      # print('Best individual is:\n %s\nwith fitness: %s' %(arr_best_ind[-1],arr_best_score[-1]))
  
      ###################################################################
      #PICKLE
      ###################################################################
      arr_to_pickle = [arr_best_score, arr_best_ind]
  
      def get_filename(val):
          filename_base = dir_to_use + '/' + stripped_name + '_'
          if val < 10:
              toret = '000' + str(val)
          elif 10 <= val < 100:
              toret = '00' + str(val)
          elif 100 <= val < 1000:
              toret = '0' + str(val)
          else:
              toret = str(val)
          return filename_base + toret + '.pickled'
  
      counter = 0
      filename = get_filename(counter)
      while os.path.isfile(filename) == True:
          counter += 1
          filename = get_filename(counter)
  
      pickle.dump(arr_to_pickle, open(filename,'wb'))
  #     print('Dumped data to file here: ', filename)
  
  eng.quit() #end matlab engine
  