예제 #1
0
    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)
예제 #2
0
    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
예제 #3
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)
예제 #4
0
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))
예제 #5
0
 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)
예제 #6
0
    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)
예제 #7
0
 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))
예제 #8
0
    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)
예제 #9
0
 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
예제 #10
0
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)
예제 #11
0
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)
예제 #12
0
 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)
예제 #13
0
    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()
예제 #14
0
    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))