Changeset 956
- Timestamp:
- 06/25/20 03:03:28 (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
framspy/FramsticksCLI.py
r953 r956 2 2 from enum import Enum 3 3 from typing import List 4 from itertools import count # for tracking multiple instances 4 5 import json 5 6 import sys, os … … 11 12 """Runs Framsticks CLI (command-line) executable and communicates with it using standard input and output. 12 13 You can perform basic operations like mutation, crossover, and evaluation of genotypes. 13 This way you can perform evolution controlled by python ,access and manipulate genotypes.14 This way you can perform evolution controlled by python as well as access and manipulate genotypes. 14 15 You can even design and use in evolution your own genetic representation implemented entirely in python. 15 16 … … 30 31 SETEXPEDEF_CMD = "expdef standard-eval" + "\n" 31 32 GETSIMPLEST_CMD = "getsimplest" 32 GETSIMPLEST_FILE = FILE_PREFIX +"simplest.gen"33 EVALUATE_CMD = "evaluate eval-allcriteria.sim 33 GETSIMPLEST_FILE = "simplest.gen" 34 EVALUATE_CMD = "evaluate eval-allcriteria.sim" 34 35 EVALUATE_FILE = "genos_eval.json" 35 36 CROSSOVER_CMD = "crossover" 36 CROSSOVER_FILE = FILE_PREFIX +"child.gen"37 CROSSOVER_FILE = "child.gen" 37 38 DISSIMIL_CMD = "dissimil" 38 DISSIMIL_FILE = FILE_PREFIX +"dissimilarity_matrix.gen"39 DISSIMIL_FILE = "dissimilarity_matrix.gen" 39 40 ISVALID_CMD = "isvalid" 40 ISVALID_FILE = FILE_PREFIX +"validity.gen"41 ISVALID_FILE = "validity.gen" 41 42 MUTATE_CMD = "mutate" 42 MUTATE_FILE = FILE_PREFIX + "mutant.gen" 43 44 CLI_INPUT_FILE = FILE_PREFIX + "genotypes.gen" 43 MUTATE_FILE = "mutant.gen" 44 45 CLI_INPUT_FILE = "genotypes.gen" 46 47 _last_instance_id = count(0) # "static" counter incremented when a new instance is created. Used for unique filenames 45 48 46 49 47 50 def __init__(self, framspath, framsexe): 51 self.id = next(FramsticksCLI._last_instance_id) 48 52 self.frams_path = framspath 49 53 self.frams_exe = framsexe if framsexe is not None else 'frams.exe' if os.name == "nt" else 'frams.linux' … … 89 93 print('OK.') 90 94 print('Performing a basic test 2/3... ', end='') 91 assert self.isValid("X[0:0]") ==True95 assert self.isValid("X[0:0]") is True 92 96 print('OK.') 93 97 print('Performing a basic test 3/3... ', end='') 94 assert self.isValid("X[0:0],") ==False98 assert self.isValid("X[0:0],") is False 95 99 print('OK.') 96 100 if not self.DETERMINISTIC: … … 105 109 106 110 107 def __saveGenotypeToFile(self, genotype, name, mode): 108 outpath = os.path.join(self.writing_path, name) 109 outfile = open(outpath, mode) 110 outfile.write("org:\n") 111 outfile.write("genotype:~\n") 112 outfile.write(genotype + "~\n\n") # TODO proper quoting of special characters in genotype... 113 outfile.close() 114 return name 115 116 117 def __saveToFile(self, genotype, name, mode): 118 outpath = os.path.join(self.writing_path, name) 119 outfile = open(outpath, mode) 120 outfile.write(genotype) 121 outfile.close() 122 return name 123 124 125 def __removeFile(self, path): 126 filepath = os.path.join(self.writing_path, path) 127 if os.path.exists(filepath): 128 os.remove(filepath) 111 def __getPrefixedFilename(self, filename: str) -> str: 112 # Returns filename with unique instance id appended so there is no clash when many instances of this class use the same Framsticks CLI executable 113 return FramsticksCLI.FILE_PREFIX + str(chr(ord('A') + self.id)) + '_' + filename 114 115 116 def __saveGenotypeToFile(self, genotype, name, mode, saveformat): 117 relname = self.__getPrefixedFilename(name) 118 absname = os.path.join(self.writing_path, relname) 119 if mode == 'd': # special mode, 'delete' 120 if os.path.exists(absname): 121 os.remove(absname) 122 else: 123 outfile = open(absname, mode) 124 if saveformat == self.GENO_SAVE_FILE_FORMAT["RAWGENO"]: 125 outfile.write(genotype) 126 else: 127 outfile.write("org:\n") 128 outfile.write("genotype:~\n") 129 outfile.write(genotype + "~\n\n") # TODO proper quoting of special characters in genotype... 130 outfile.close() 131 return relname, absname 129 132 130 133 … … 140 143 141 144 def __runCommand(self, command, genotypes, result_file_name, saveformat) -> List[str]: 142 filenames = [] # list of file names with input data for the command 145 filenames_rel = [] # list of file names with input data for the command 146 filenames_abs = [] # same list but absolute paths actually used 143 147 if saveformat == self.GENO_SAVE_FILE_FORMAT["RAWGENO"]: 144 148 for i in range(len(genotypes)): 145 filenames.append(self.__saveToFile(genotypes[i], "genotype" + str(i) + ".gen", "w")) # plain text format = must have a separate file for each genotype 149 # plain text format = must have a separate file for each genotype 150 rel, abs = self.__saveGenotypeToFile(genotypes[i], "genotype" + str(i) + ".gen", "w", self.GENO_SAVE_FILE_FORMAT["RAWGENO"]) 151 filenames_rel.append(rel) 152 filenames_abs.append(abs) 146 153 elif saveformat == self.GENO_SAVE_FILE_FORMAT["NATIVEFRAMS"]: 147 self.__ removeFile(self.CLI_INPUT_FILE) #ensure there is nothing left from the last run of the program because we "a"ppend to file in the loop below154 self.__saveGenotypeToFile(None, self.CLI_INPUT_FILE, 'd', None) # 'd'elete: ensure there is nothing left from the last run of the program because we "a"ppend to file in the loop below 148 155 for i in range(len(genotypes)): 149 outfilename = self.__saveGenotypeToFile(genotypes[i], self.CLI_INPUT_FILE, "a") 150 filenames.append(outfilename) # since we use the same file in the loop above, add this file only once (i.e., outside of the loop) 151 152 if result_file_name != self.EVALUATE_FILE: # all functions except for evaluate provide frams with the file name to write to 153 self.child.sendline(command + " " + " ".join(filenames) + " " + result_file_name + "\n") 154 else: 155 self.child.sendline(command + " " + " ".join(filenames) + "\n") 156 rel, abs = self.__saveGenotypeToFile(genotypes[i], self.CLI_INPUT_FILE, "a", self.GENO_SAVE_FILE_FORMAT["NATIVEFRAMS"]) 157 # since we use the same file in the loop above, add this file only once (i.e., outside of the loop) 158 filenames_rel.append(rel) 159 filenames_abs.append(abs) 160 161 result_file_name = self.__getPrefixedFilename(result_file_name) 162 cmd = command + " " + " ".join(filenames_rel) + " " + result_file_name 163 self.child.sendline(cmd + '\n') 156 164 self.__readFromFramsCLIUntil(self.STDOUT_ENDOPER_MARKER) 157 filenames.append(os.path.join(self.writing_path, self.OUTPUT_DIR, result_file_name)) 158 return filenames # last element is a path to the file containing results 159 160 161 def __cleanUpCommandResults(self, filepaths): 162 """Deletes files with results created by the command.""" 163 for i in filepaths: 164 if i == filepaths[-1]: 165 os.remove(i) # the result is written with its full path and we have used it before so the file surely exists 166 else: 167 self.__removeFile(i) 165 filenames_abs.append(os.path.join(self.writing_path, self.OUTPUT_DIR, result_file_name)) 166 return filenames_abs # last element is a path to the file containing results 167 168 169 def __cleanUpCommandResults(self, filenames): 170 """Deletes files with results just created by the command.""" 171 for name in filenames: 172 os.remove(name) 168 173 169 174 … … 237 242 parser.add_argument('-path', type=ensureDir, required=True, help='Path to Framsticks CLI without trailing slash.') 238 243 parser.add_argument('-exe', required=False, help='Executable name. If not given, "frams.exe" or "frams.linux" is assumed.') 239 parser.add_argument('-genformat', required=False, help='Genetic format for the demo run, for example 4, 9, or B. If not given, f1 is assumed.')244 parser.add_argument('-genformat', required=False, help='Genetic format for the demo run, for example 4, 9, or S. If not given, f1 is assumed.') 240 245 return parser.parse_args() 241 246
Note: See TracChangeset
for help on using the changeset viewer.