def _create(self, rows): phase_lines_afterlabel = list() # First iteration through lines: Create list of lines (and labels) for row in rows: label, afterlabel = LsUtil.split1_strip(row) if afterlabel is None: raise Exception('Error on line\n"{}"'.format(row)) coincide_err = "The phase line label '{0}' coincides with the name of a " if label in self.stimulus_elements: raise LsParseException((coincide_err + "stimulus element.").format(label)) if label in self.behaviors: raise LsParseException((coincide_err + "behavior.").format(label)) self.linelabels.append(label) phase_lines_afterlabel.append(afterlabel) if self.first_label is None: self.first_label = label # Second iteration: Create PhaseLine objects for all lines and put in the dict # self.phase_lines for i in range(len(self.linelabels)): label = self.linelabels[i] after_label = phase_lines_afterlabel[i] self.phase_lines[label] = PhaseLine(label, after_label, self.linelabels, self.stimulus_elements, self.behaviors)
def __init__(self, endcond_str, valid_items): item, number_str = LsUtil.parse_equals(endcond_str) if item not in valid_items: raise LsParseException("Error on condition {0}. Invalid item {1}.".format(endcond_str, item)) self.item = item isnumber, number = LsUtil.is_posint(number_str) if not isnumber: raise LsParseException("Error on condition {0}. {1} is not an integer.".format(endcond_str, number)) self.limit = number self.itemfreq = 0
def parse_block(block): first_row, content = LsUtil.split1_strip(block, '\n') keyword, pvstr = LsUtil.split1_strip(first_row) pvdict = dict() if pvstr is not None: try: pvdict = ast.literal_eval(pvstr) if type(pvdict) is not dict: raise LsParseException("Expected a dictionary. Got\n'" + pvstr + "'.") except Exception: raise LsParseException("Expected a dictionary. Got\n'" + pvstr + "'.") return ScriptBlock(keyword, pvdict, content)
def parse_eval_prop(cmd, expr, eval_prop, valid_prop): # if type(expr) is not str: # raise LsParseException("First input to {} must be a string, got {}".format(cmd, expr)) for p in eval_prop: if p not in valid_prop: raise LsParseException("Invalid property '{}' to {}".format( p, cmd))
def add(self, newblock): try: newdict = ast.literal_eval(newblock.content) except Exception: raise LsParseException(PARAMETERS + " must be a valid Python dictionary.") self.parameters.update(newdict)
def __init__(self, label, after_label, all_linelabels, stimulus_elements, behaviors): self.label = label self.consec_linecnt = 1 self.consec_respcnt = 1 self.prev_response = None stimulus, conditions_str = LsUtil.split1_strip(after_label, PHASEDIV) if conditions_str is None: raise LsParseException("Line with label {} has no conditions.".format(label)) stimulus_is_tuple, stimulus_tuple = LsUtil.is_tuple(stimulus) if not stimulus_is_tuple: stimulus = LsUtil.strip_quotes(stimulus) # Accept stimulus with or without quotes stimulus_tuple = (stimulus,) for element in stimulus_tuple: if element not in stimulus_elements: raise LsParseException("Unknown stimulus element '{}'.".format(element)) self.stimulus = stimulus_tuple self.conditions = PhaseLineConditions(conditions_str, stimulus_elements, behaviors, all_linelabels)
def _parse(self): blocks = LsUtil.strsplit(self.script, KWP) # ALL_KEYWORDS for block in blocks: first_row, _ = LsUtil.split1_strip(block, '\n') kw, _ = LsUtil.split1_strip(first_row) if kw not in ALL_KEYWORDS: raise LsParseException("Unknown keyword '{}'".format(kw)) if kw in ALL_POSTCMDS: postcmd, cmdarg = LsUtil.split1_strip(first_row) postcmd_obj = parse_postcmd(postcmd, cmdarg, self.parameters) self.postcmds.add(postcmd_obj) else: scriptblock = parse_block(block) if kw == COMMENT: self.comment.add(scriptblock) elif kw == PARAMETERS: self.parameters.add(scriptblock) elif kw == PHASE: if LABEL not in scriptblock.pvdict: scriptblock.pvdict[LABEL] = self._next_unnamed_phase() if END not in scriptblock.pvdict: raise LsParseException( "The property 'end' is required in {}.".format( PHASE)) self.phases.add(scriptblock, self.parameters) # .clone() elif kw == RUN: # If 'phases' not specified, use empty tuple (which means all phases) phases_to_use = scriptblock.pvdict.get(PHASES, tuple()) if type(phases_to_use ) != tuple: # Allow string for single phase phases_to_use = (phases_to_use, ) world = self.phases.make_world(phases_to_use) mechanism_obj = self.parameters.make_mechanism_obj() run_label = scriptblock.pvdict.get( LABEL, self._next_unnamed_run()) n_subjects = self.parameters.parameters.get(SUBJECTS, 1) self.runs.add(run_label, world, mechanism_obj, n_subjects) else: raise LsParseException("Unknown keyword '{}'".format(kw))
def run(self, simulation_data): if EVAL_FILENAME not in self.eval_prop: raise LsParseException("Property {0} to {1} is mandatory.".format( EVAL_FILENAME, self.cmd)) filename = self.eval_prop[EVAL_FILENAME] if not filename.endswith(".csv"): filename = filename + ".csv" file = open(filename, 'w', newline='') if self.cmd == HEXPORT: self._h_export(file, simulation_data) else: self._vwpn_export(file, simulation_data)
def make_mechanism_obj(self): if MECHANISM not in self.parameters: raise LsParseException( "The parameter {0} is required.".format(MECHANISM)) mechanism_name = self.parameters[MECHANISM].lower() if mechanism_name == RESCORLA_WAGNER or mechanism_name == "sr": # XXX sr is alias mechanism_obj = LsMechanism.RescorlaWagner(**self.parameters) elif mechanism_name == Q_LEARNING: mechanism_obj = LsMechanism.Qlearning(**self.parameters) # elif mechanism_name == SARSA: # mechanism_obj = LsMechanism.SARSA(**self.parameters) elif mechanism_name == EXP_SARSA: mechanism_obj = LsMechanism.EXP_SARSA(**self.parameters) elif mechanism_name == ACTOR_CRITIC: mechanism_obj = LsMechanism.ActorCritic(**self.parameters) elif mechanism_name == ENQUIST: mechanism_obj = LsMechanism.Enquist(**self.parameters) else: raise Exception('Unknown mechanism "' + mechanism_name + '".') return mechanism_obj
def parse_subplotspec(spec, errmsg): if type(spec) is tuple: if len(spec) != 3: raise LsParseException(errmsg) for i in spec: if type(spec[i]) != int: raise LsParseException(errmsg) if spec[i] <= 0: raise LsParseException(errmsg) elif type(spec) is int: if spec <= 0: raise LsParseException(errmsg) strspec = str(spec) if len(strspec) != 3: raise LsParseException(errmsg) if '0' in strspec: raise LsParseException(errmsg) else: raise LsParseException(errmsg)
def parse_postcmd(cmd, cmdarg, simulation_parameters): if cmdarg is not None: args = LsUtil.parse_sso(cmdarg) if args is None: # Parse failed raise LsParseException("Invalid argument list to {}".format(cmd)) nargs = len(args) else: args = list() # Empty list nargs = 0 if cmd == FIGURE: if nargs > 2: raise LsParseException( "The number of arguments to {} must be <= 2.".format(cmd)) title = None mpl_prop = dict() if nargs == 2: title = args[0] mpl_prop = args[1] elif nargs == 1: either = args[0] if type(either) is str: title = either elif type(either) is dict: mpl_prop = either else: raise LsParseException( "Arguments to {} must be string and/or dict.".format(cmd)) if title is not None: if type(title) != str: raise LsParseException( "Title argument to {} must be a string.".format(cmd)) if type(mpl_prop) != dict: raise LsParseException( "Figure properties argument to {} must be a dict.".format(cmd)) return FigureCmd(title, mpl_prop) elif cmd == SUBPLOT: if nargs > 2 or nargs == 0: raise LsParseException( "The number of arguments to {} must be 1 or 2.".format(cmd)) spec = args[0] errmsg = "First argument (subplot specification) to {} must be a tuple or three-positive-digits integer.".format( cmd) parse_subplotspec(spec, errmsg) mpl_prop = dict() if nargs == 2: mpl_prop = args[1] if type(mpl_prop) is not dict: raise LsParseException( "Second argument to {} must be a dictionary.".format(cmd)) return SubplotCmd(spec, mpl_prop) elif cmd == LEGEND: if nargs > 2: raise LsParseException( "The number of arguments to {} must be <=2.".format(cmd)) labels = None mpl_prop = dict() if nargs == 2: labels = args[0] mpl_prop = args[1] elif nargs == 1: either = args[0] if (type(either) is tuple) or (type(either) is str): labels = either elif type(either) is dict: mpl_prop = either else: raise LsParseException( "Arguments to {} must be tuple, string or dict.".format( cmd)) if labels is not None: if type(labels) is str: labels = (labels, ) if type(labels) is not tuple: raise LsParseException( "Legend labels must be a tuple ('label1','label2',...) or a string." .format(cmd)) if type(mpl_prop) is not dict: raise LsParseException( "Second argument to {} must be a dictionary.".format(cmd)) return LegendCmd(labels, mpl_prop) elif cmd == PPLOT or cmd == PEXPORT: if nargs == 0: raise LsParseException("No arguments given to {}".format(cmd)) expr = args[0] if type(expr) is not tuple: raise LsParseException( "First argument to {} must be a tuple.".format(cmd)) if type(expr[0]) is not tuple: listexpr = list(expr) listexpr[0] = (listexpr[0], ) expr = tuple(listexpr) beta = simulation_parameters.get(BETA) eval_prop = {BETA: beta} if nargs >= 2: eval_prop.update(args[1]) if cmd == PPLOT: plot_prop = dict() if nargs >= 3: plot_prop = args[2] return PlotCmd(cmd, expr, eval_prop, plot_prop) else: if nargs >= 3: raise LsParseException( "The number of arguments to {} must be 1 or 2.".format( cmd)) return ExportCmd(cmd, expr, eval_prop) elif cmd == NPLOT or cmd == NEXPORT: if cmd == NPLOT: if (nargs == 0) or (nargs > 4): raise LsParseException( "The number of arguments to {} must be 1, 2, 3 or 4.". format(cmd)) elif cmd == NEXPORT: if (nargs == 0) or (nargs > 3): raise LsParseException( "The number of arguments to {} must be 1, 2 or 3.".format( cmd)) seq = args[0] seqref = None eval_prop = dict() if nargs >= 2: if (type(args[1]) is str) or (type(args[1]) is tuple) or (type( args[1]) is list): seqref = args[1] elif type(args[1]) is dict: eval_prop = args[1] else: raise LsParseException( "Invalid second argument to {}.".format(cmd)) if cmd == NPLOT: plot_prop = dict() if nargs >= 3: if seqref is None: plot_prop = args[2] else: eval_prop = args[2] if nargs == 4: plot_prop = args[3] return PlotCmd(cmd, (seq, seqref), eval_prop, plot_prop) else: if nargs >= 3: if seqref is None: raise LsParseException( "Invalid arguments to {}.".format(cmd)) else: eval_prop = args[2] return ExportCmd(cmd, (seq, seqref), eval_prop) elif cmd == VPLOT or cmd == WPLOT: if nargs == 0: raise LsParseException("No arguments given to {}".format(cmd)) expr = args[0] if cmd == VPLOT: if type(expr) is not tuple: raise LsParseException( "First argument to {} must be a tuple.".format(cmd)) for e in expr: if type(e) is not str: raise LsParseException( "First argument to {} must be a tuple of strings.". format(cmd)) else: # WPLOT if type(expr) is not str: raise LsParseException( "First argument to {} must be a string.".format(cmd)) eval_prop = dict() if nargs >= 2: eval_prop = args[1] if type(eval_prop) is not dict: raise LsParseException( "Properties to {} must be a dict.".format(cmd)) plot_prop = dict() if nargs >= 3: plot_prop = args[2] if type(plot_prop) is not dict: raise LsParseException( "Plot properties to {} must be a dict.".format(cmd)) return PlotCmd(cmd, expr, eval_prop, plot_prop) elif cmd == VEXPORT or cmd == WEXPORT: if nargs == 0: raise LsParseException("No arguments given to {}".format(cmd)) expr = args[0] if cmd == VEXPORT: if type(expr) is not tuple: raise LsParseException( "First argument to {} must be a tuple.".format(cmd)) for e in expr: if type(e) is not str: raise LsParseException( "First argument to {} must be a tuple of strings.". format(cmd)) else: # WEXPORT if type(expr) is not str: raise LsParseException( "First argument to {} must be a string.".format(cmd)) eval_prop = dict() if nargs >= 2: eval_prop = args[1] if nargs >= 3: raise LsParseException( "The number of arguments to {} must be 1 or 2.".format(cmd)) return ExportCmd(cmd, expr, eval_prop) else: # cmd == HEXPORT if nargs == 0: raise LsParseException("No arguments given to {}".format(cmd)) if nargs > 1: raise LsParseException( "The number of arguments to {} must be 1.".format(cmd)) eval_prop = args[0] if type(eval_prop) is not dict: raise LsParseException( "Export properties to {} must be a dict.".format(cmd)) return ExportCmd(cmd, expr=None, eval_prop=eval_prop)
def add(self, label, world, mechanism_obj, n_subjects): if label in self.runs: raise LsParseException("Run label " + label + " is duplicated.") self.runs[label] = ScriptRun(label, world, mechanism_obj, n_subjects)
def __init__(self, **kwargs): for p in kwargs: if p not in ALL_PARAMETER_NAMES: raise LsParseException("Unknown parameter '{}'".format(p)) # Required for required in [BEHAVIORS, STIMULUS_ELEMENTS]: if required not in kwargs: raise LsParseException("The parameter '" + required + "' is required.") self.behaviors = kwargs[BEHAVIORS] self.stimulus_elements = kwargs[STIMULUS_ELEMENTS] # Optional self.start_v = kwargs.get(START_V, get_default(START_V)) self.alpha_v = kwargs.get(ALPHA_V, get_default(ALPHA_V)) self.alpha_w = kwargs.get(ALPHA_W, get_default(ALPHA_W)) self.beta = kwargs.get(BETA, get_default(BETA)) self.omit_learning = kwargs.get(OMIT_LEARNING, get_default(OMIT_LEARNING)) self.set_omit_learning = set(self.omit_learning) self.response_req = kwargs.get(RR, get_default(RR)) # Needs to be copies since they are input and they are altered (in initialize_uc) self.u = dict(kwargs.get(U, get_default(U))) self.c = dict(kwargs.get(C, get_default(C))) # Be nice - if DEFAULT not given, assume it is DEFAULT_{UC}_VALUE if DEFAULT not in self.u: self.u[DEFAULT] = DEFAULT_U_VALUE if DEFAULT not in self.c: self.c[DEFAULT] = DEFAULT_C_VALUE for key in self.start_v: if (key != DEFAULT): if type(key) is not tuple: raise LsParseException( "Keys in {0} must be tuples or '{1}'.".format( START_V, DEFAULT)) if len(key) != 2: raise LsParseException( "Keys in {0} must be tuples of length two or {1}.". format(START_V, DEFAULT)) if (key[0] not in self.stimulus_elements): raise LsParseException( "Unknown stimulus element '{0}' in '{1}'".format( key[0], START_V)) if (key[1] not in self.behaviors): raise LsParseException( "Unknown behavior '{0}' in '{1}'".format( key[1], START_V)) self.alpha_v_all = dict() alpha_v_type = type(self.alpha_v) if alpha_v_type is dict: for key in self.alpha_v: if (key != DEFAULT): if type(key) is not tuple: raise LsParseException( "Keys in {0} must be tuples or '{1}'.".format( ALPHA_V, DEFAULT)) if len(key) != 2: raise LsParseException( "Keys in {0} must be tuples of length two or {1}.". format(ALPHA_V, DEFAULT)) if (key[0] not in self.stimulus_elements): raise LsParseException( "Unknown stimulus element '{0}' in '{1}'".format( key[0], ALPHA_V)) if (key[1] not in self.behaviors): raise LsParseException( "Unknown behavior '{0}' in '{1}'".format( key[1], ALPHA_V)) if DEFAULT not in self.alpha_v: raise LsParseException( "The parameter {0} must have the key '{1}'.".format( ALPHA_V, DEFAULT)) elif (alpha_v_type is not int and alpha_v_type is not float) or alpha_v_type is bool: # ? raise LsParseException("Invalid value {0} for '{1}'".format( self.alpha_v, ALPHA_V)) self._initialize_alpha_v_all() self.alpha_w_all = dict() alpha_w_type = type(self.alpha_w) if alpha_w_type is dict: for key in self.alpha_w: if (key != DEFAULT): if type(key) is not str: raise LsParseException( "Keys in {0} must be stimulus elements or '{1}'.". format(ALPHA_W, DEFAULT)) if key not in self.stimulus_elements: raise LsParseException( "Keys in {0} must be stimulus elements or '{1}'.". format(ALPHA_W, DEFAULT)) if DEFAULT not in self.alpha_w: raise LsParseException( "The parameter {0} must have the key '{1}'.".format( ALPHA_W, DEFAULT)) elif (alpha_w_type is not int and alpha_w_type is not float) or alpha_w_type is bool: # ? raise LsParseException("Invalid value {0} for '{1}'".format( self.alpha_w, ALPHA_W)) self._initialize_alpha_w_all() if DEFAULT not in self.start_v: raise LsParseException( "The parameter {0} must have the key '{1}'.".format( START_V, DEFAULT)) for key in self.u: if (key != DEFAULT) and (key not in self.stimulus_elements): raise LsParseException( "Unknown stimulus element '{0}' in '{1}'".format(key, U)) if (DEFAULT not in self.u) and (set(self.stimulus_elements) != set( self.u.keys())): raise LsParseException( "The parameter {0} must have the key '{1}' or be exhaustive.". format(U, DEFAULT)) for key in self.c: if (key != DEFAULT) and (key not in self.behaviors): raise LsParseException( "Unknown behavior '{0}' in '{1}'".format(key, C)) if (DEFAULT not in self.c) and (set(self.behaviors) != set(self.c.keys())): raise LsParseException( "The parameter {0} must have the key '{1}' or be exhaustive.". format(C, DEFAULT)) if type(self.response_req) is not dict: raise LsParseException("{0} must be a dict.".format(RR)) for key, val in self.response_req.items(): if key not in self.behaviors: raise LsParseException("Unknown behavior '{0}' in {1}.".format( key, RR)) if type(val) is str: if val not in self.stimulus_elements: raise LsParseException( "Unknown stimulus element {0} in {1}.".format(val, RR)) elif type(val) is list: for e in val: if e not in self.stimulus_elements: raise LsParseException( "Unknown stimulus element {0} in {1}.".format( val, RR)) else: raise LsParseException( "Value for {0} in {1} must be a string or a list of strings." .format(key, RR)) # Make self.stimulus_req self.response_req = dict( self.response_req) # Copy since input and will be altered for response in self.behaviors: if response not in self.response_req: self.response_req[response] = list(self.stimulus_elements) self.stimulus_req = LsUtil.dict_inv(self.response_req) # Check that all stimulus elements has at least one feasible response if set(self.stimulus_req) != set(self.stimulus_elements): elements_without_response = set(self.stimulus_elements) - set( self.stimulus_req) raise LsParseException( "Invalid response_requirements: Stimulus elements {} has no possible responses." .format(elements_without_response)) self._initialize_uc() self.subject_reset()
def _parse(self, condition_str, stimulus_elements, behaviors, all_linelabels): if condition_str.count(':') > 1: raise LsParseException("Condition '{}' has more than one colon.".format(condition_str)) lcolon, rcolon = LsUtil.split1_strip(condition_str, ':') if rcolon is None: rcolon = lcolon lcolon = None # ---------- First parse lcolon ---------- if lcolon is not None: if '=' in lcolon: response, count_str = LsUtil.split1_strip(lcolon, '=') is_pos_int, intval = LsUtil.is_posint(count_str) if not is_pos_int: raise LsParseException("Expected an integer, got '{}'.".format(count_str)) self.count = intval else: isposint, intval = LsUtil.is_posint(lcolon) if isposint: response = None self.count = intval else: response = lcolon # Allow response with or without quotes if response is not None: response = LsUtil.strip_quotes(response) # Check that response is valid if response is not None: if response not in behaviors: raise LsParseException("Unknown response '{}'.".format(response)) else: self.response = response # ---------- Then parse rcolon ---------- lbls_and_probs = rcolon.split(',') for lbl_and_prob in lbls_and_probs: if lbl_and_prob in all_linelabels: if len(lbls_and_probs) > 1: raise LsParseException("Invalid condition '{}'.".format(lbls_and_probs)) self.goto.append((1, lbl_and_prob)) else: if '(' and ')' in lbl_and_prob: if lbl_and_prob.count('(') > 1 or lbl_and_prob.count(')') > 1: raise LsParseException("Invalid condition '{}'. Too many parentheses".format(lbl_and_prob)) if lbl_and_prob.find('(') > lbl_and_prob.find('('): raise LsParseException("Invalid condition '{}'.".format(lbl_and_prob)) lindex = lbl_and_prob.find('(') rindex = lbl_and_prob.find(')') lbl = lbl_and_prob[0:lindex] if lbl not in all_linelabels: raise LsParseException("Invalid line label '{}'.".format(lbl)) prob_str = lbl_and_prob[(lindex + 1): rindex] isprob, prob = LsUtil.is_prob(prob_str) if not isprob: raise LsParseException("Expected a probability, got {}.".format(prob_str)) for prob_lbl in self.goto: if prob_lbl[1] == lbl: raise LsParseException("Label {0} duplicated in {1}.".format(lbl, rcolon)) self.goto.append((prob, lbl)) else: raise LsParseException("Malformed condition '{}'.".format(condition_str)) self.goto_prob_cumsum = list() cumsum = 0 for prob_lbl in self.goto: cumsum += prob_lbl[0] self.goto_prob_cumsum.append(cumsum) if cumsum > 1: raise LsParseException("Sum of probabilities in '{0}'' is {1}>1.".format(rcolon, cumsum))