Пример #1
0
 def generate_aux(self):
     auxnames = list(self.fspec._auxfnspecs.keys())
     # User aux fn interface
     uafi = {}
     # protectednames = auxnames + self.fspec._protected_mathnames + \
     #                  self.fspec._protected_randomnames + \
     #                  self.fspec._protected_scipynames + \
     #                  self.fspec._protected_specialfns + \
     #                  ['abs', 'and', 'or', 'not', 'True', 'False']
     auxfns = self.builtin_aux
     # the internal functions may be used by user-defined functions,
     # so need them to be accessible to processTokens when parsing
     self.fspec._pyauxfns = auxfns
     # add the user-defined function names for cross-referencing checks
     # (without their definitions)
     for auxname in auxnames:
         self.fspec._pyauxfns[auxname] = None
     # don't process the built-in functions -> unique fns because
     # they are global definitions existing throughout the
     # namespace
     self.fspec._protected_auxnames.extend(['Jacobian', 'Jacobian_pars'])
     # protected names are the names that must not be used for
     # user-specified auxiliary fn arguments
     protectednames = self.fspec.pars + self.fspec.inputs \
         + ['abs', 'pow', 'and', 'or', 'not', 'True', 'False'] \
         + self.fspec._protected_auxnames + auxnames \
         + self.fspec._protected_numpynames \
         + self.fspec._protected_scipynames \
         + self.fspec._protected_specialfns \
         + self.fspec._protected_macronames \
         + self.fspec._protected_mathnames \
         + self.fspec._protected_randomnames \
         + self.fspec._protected_reusenames
     # checks for user-defined auxiliary fns
     # name map for fixing inter-auxfn references
     auxfn_namemap = {}
     specials_base = self.fspec.pars + self.fspec._protected_auxnames \
         + ['abs', 'pow', 'and', 'or', 'not', 'True', 'False'] \
         + auxnames + self.fspec._protected_scipynames \
         + self.fspec._protected_numpynames + self.fspec._protected_specialfns \
         + self.fspec._protected_macronames + self.fspec._protected_mathnames \
         + self.fspec._protected_randomnames + self.fspec._protected_reusenames
     for auxname in auxnames:
         auxinfo = self.fspec._auxfnspecs[auxname]
         try:
             if len(auxinfo) != 2:
                 raise ValueError('auxinfo tuple must be of length 2')
         except TypeError:
             raise TypeError('fnspecs argument must contain pairs')
         # auxinfo[0] = tuple or list of parameter names
         # auxinfo[1] = string containing body of function definition
         assert isinstance(auxinfo[0], list), ('aux function arguments '
                                               'must be given as a list')
         assert isinstance(auxinfo[1], str), ('aux function specification '
                                              'must be a string '
                                              'of the function code')
         # Process Jacobian functions, etc., specially, if present
         if auxname == 'Jacobian':
             if not compareList(auxinfo[0], ['t'] + self.fspec.vars):
                 print(['t'] + self.fspec.vars)
                 print("Auxinfo =" + str(auxinfo[0]))
                 raise ValueError(
                     "Invalid argument list given in Jacobian.")
             auxparlist = ["t", "x", "parsinps"]
             # special symbols to allow in parsing function body
             specials = ["t", "x"]
             auxstr = auxinfo[1]
             if any([pt in auxstr for pt in ('^', '**')]):
                 auxstr = convertPowers(auxstr, 'pow')
             specvars = self.fspec.vars
             specvars.sort()
             specdict = {}.fromkeys(specvars)
             if len(specvars) == 1:
                 assert '[' not in auxstr, \
                        "'[' character invalid in Jacobian for 1D system"
                 assert ']' not in auxstr, \
                        "']' character invalid in Jacobian for 1D system"
                 specdict[specvars[0]] = auxstr
             else:
                 specdict = parseMatrixStrToDictStr(auxstr, specvars)
             reusestr, body_processed_dict = self._processReusedPy(
                 specvars, specdict, specials=specials + specials_base)
             body_processed = self._specStrParse(specvars,
                                                 body_processed_dict,
                                                 'xjac',
                                                 specials=specials +
                                                 specials_base)
             auxstr_py = self._generate_fun('_auxfn_Jac',
                                            reusestr + body_processed,
                                            'xjac', specvars)
             # check Jacobian
             m = n = len(specvars)
             specdict_check = {}.fromkeys(specvars)
             for specname in specvars:
                 temp = body_processed_dict[specname]
                 specdict_check[specname] = \
                     count_sep(temp.replace("[", "").replace("]", "")) + 1
             body_processed = ""
             for row in range(m):
                 if specdict_check[specvars[row]] != n:
                     print("Row %i: " % m + specdict[specvars[row]])
                     print("Found length %i" %
                           specdict_check[specvars[row]])
                     raise ValueError("Jacobian should be %sx%s" % (m, n))
         elif auxname == 'Jacobian_pars':
             if not compareList(auxinfo[0], ['t'] + self.fspec.pars):
                 print(['t'] + self.fspec.pars)
                 print("Auxinfo =" + str(auxinfo[0]))
                 raise ValueError(
                     "Invalid argument list given in Jacobian.")
             auxparlist = ["t", "x", "parsinps"]
             # special symbols to allow in parsing function body
             specials = ["t", "x"]
             auxstr = auxinfo[1]
             if any([pt in auxstr for pt in ('^', '**')]):
                 auxstr = convertPowers(auxstr, 'pow')
             specvars = self.fspec.pars
             specvars.sort()
             specdict = {}.fromkeys(self.fspec.vars)
             if len(specvars) == len(self.fspec.vars) == 1:
                 assert '[' not in auxstr, \
                        "'[' character invalid in Jacobian for 1D system"
                 assert ']' not in auxstr, \
                        "']' character invalid in Jacobian for 1D system"
                 specdict[specvars[0]] = auxstr
             else:
                 specdict = parseMatrixStrToDictStr(auxstr, self.fspec.vars)
             reusestr, body_processed_dict = self._processReusedPy(
                 self.fspec.vars,
                 specdict,
                 specials=specials + specials_base)
             body_processed = self._specStrParse(self.fspec.vars,
                                                 body_processed_dict,
                                                 'pjac',
                                                 specials=specials +
                                                 specials_base)
             auxstr_py = self._generate_fun('_auxfn_Jac_p',
                                            reusestr + body_processed,
                                            'pjac', self.fspec.vars)
             # check Jacobian
             n = len(specvars)
             m = len(self.fspec.vars)
             specdict_check = {}.fromkeys(self.fspec.vars)
             for specname in self.fspec.vars:
                 temp = body_processed_dict[specname]
                 specdict_check[specname] = \
                     count_sep(temp.replace("[", "").replace("]", "")) + 1
             body_processed = ""
             for row in range(m):
                 try:
                     if specdict_check[self.fspec.vars[row]] != n:
                         print("Row %i: " % m +
                               specdict[self.fspec.vars[row]])
                         print("Found length %i" %
                               specdict_check[self.fspec.vars[row]])
                         raise ValueError(
                             "Jacobian w.r.t. pars should be %sx%s" %
                             (m, n))
                 except IndexError:
                     print("\nFound:\n")
                     info(specdict)
                     raise ValueError(
                         "Jacobian w.r.t. pars should be %sx%s" % (m, n))
         elif auxname == 'massMatrix':
             if not compareList(auxinfo[0], ['t'] + self.fspec.vars):
                 print(['t'] + self.fspec.vars)
                 print("Auxinfo =" + str(auxinfo[0]))
                 raise ValueError(
                     "Invalid argument list given in Mass Matrix.")
             auxparlist = ["t", "x", "parsinps"]
             # special symbols to allow in parsing function body
             specials = ["t", "x"]
             auxstr = auxinfo[1]
             if any([pt in auxstr for pt in ('^', '**')]):
                 auxstr = convertPowers(auxstr, 'pow')
             specvars = self.fspec.vars
             specvars.sort()
             specdict = {}.fromkeys(specvars)
             if len(specvars) == 1:
                 assert '[' not in auxstr, \
                        "'[' character invalid in mass matrix for 1D system"
                 assert ']' not in auxstr, \
                        "']' character invalid in mass matrix for 1D system"
                 specdict[list(specvars.values())[0]] = auxstr
             else:
                 specdict = parseMatrixStrToDictStr(auxstr, specvars)
             reusestr, body_processed_dict = self._processReusedPy(
                 specvars, specdict, specials=specials + specials_base)
             body_processed = self._specStrParse(specvars,
                                                 body_processed_dict,
                                                 'xmat',
                                                 specials=specials +
                                                 specials_base)
             auxstr_py = self._generate_fun('_auxfn_massMatrix',
                                            reusestr + body_processed,
                                            'xmat', specvars)
             # check matrix
             m = n = len(specvars)
             specdict_check = {}.fromkeys(specvars)
             for specname in specvars:
                 specdict_check[specname] = 1 + \
                     count_sep(
                         body_processed_dict[specname].replace("[", "").replace("]", ""))
             body_processed = ""
             for row in range(m):
                 if specdict_check[specvars[row]] != n:
                     print("Row %i: " % m + specdict[specvars[row]])
                     print("Found length %i" %
                           specdict_check[specvars[row]])
                     raise ValueError("Mass matrix should be %sx%s" %
                                      (m, n))
         else:
             user_parstr = makeParList(auxinfo[0])
             # `parsinps` is always added to allow reference to own
             # parameters
             if user_parstr == '':
                 # no arguments, user calls as fn()
                 auxparstr = 'parsinps'
             else:
                 auxparstr = 'parsinps, ' + user_parstr
             auxstr_py = 'def _auxfn_' + auxname + '(ds, ' + auxparstr \
                         + '):\n'
             auxparlist = auxparstr.replace(" ", "").split(",")
             badparnames = intersect(auxparlist,
                                     remain(protectednames, auxnames))
             if badparnames != []:
                 print("Bad parameter names in auxiliary function %s: %r" %
                       (auxname, badparnames))
                 # print(str(auxinfo[0]))
                 # print(str(auxparlist))
                 raise ValueError(
                     "Cannot use protected names (including"
                     " globally visible system parameters for auxiliary "
                     "function arguments")
             # special symbols to allow in parsing function body
             specials = auxparlist
             specials.remove('parsinps')
             illegalterms = remain(self.fspec.vars + self.fspec.auxvars,
                                   specials)
             auxstr = auxinfo[1]
             if any([pt in auxstr for pt in ('^', '**')]):
                 auxstr = convertPowers(auxstr, 'pow')
             reusestr, body_processed_dict = self._processReusedPy(
                 [auxname], {auxname: auxstr},
                 specials=specials + specials_base,
                 dovars=False,
                 illegal=illegalterms)
             body_processed = self._specStrParse([auxname],
                                                 body_processed_dict,
                                                 specials=specials +
                                                 specials_base,
                                                 dovars=False,
                                                 noreturndefs=True,
                                                 illegal=illegalterms)
             auxstr_py += reusestr + _indentstr + 'return ' \
                 + body_processed
         # syntax validation done in makeUniqueFn
         try:
             auxfns[auxname] = makeUniqueFn(auxstr_py)
             # Note: this automatically updates self.fspec._pyauxfns too
         except Exception:
             print('Error in supplied auxiliary spec dictionary code')
             raise
         auxfn_namemap['ds.' + auxname] = 'ds.' + auxfns[auxname][1]
         # prepare user-interface wrapper function (not method)
         if specials == [''] or specials == []:
             fn_args = ''
         else:
             fn_args = ',' + ','.join(specials)
         fn_elts = [
             'def ', auxname, '(self', fn_args, ',__parsinps__=None):\n\t',
             'if __parsinps__ is None:\n\t\t',
             '__parsinps__=self.map_ixs(self.genref)\n\t',
             'return self.genref.', auxfns[auxname][1], '(__parsinps__',
             fn_args, ')\n'
         ]
         uafi[auxname] = ''.join(fn_elts)
     # resolve inter-auxiliary function references
     for auxname, auxspec in auxfns.items():
         dummyQ = QuantSpec('dummy',
                            auxspec[0],
                            preserveSpace=True,
                            treatMultiRefs=False)
         dummyQ.mapNames(auxfn_namemap)
         auxfns[auxname] = (dummyQ(), auxspec[1])
     self.fspec._user_auxfn_interface = uafi
     self.fspec._protected_auxnames.extend(auxnames)
     return auxfns
Пример #2
0
 def generate_aux(self):
     auxnames = list(self.fspec._auxfnspecs.keys())
     # User aux fn interface
     uafi = {}
     # protectednames = auxnames + self.fspec._protected_mathnames + \
     #                  self.fspec._protected_randomnames + \
     #                  self.fspec._protected_scipynames + \
     #                  self.fspec._protected_specialfns + \
     #                  ['abs', 'and', 'or', 'not', 'True', 'False']
     auxfns = self.builtin_aux
     # the internal functions may be used by user-defined functions,
     # so need them to be accessible to processTokens when parsing
     self.fspec._pyauxfns = auxfns
     # add the user-defined function names for cross-referencing checks
     # (without their definitions)
     for auxname in auxnames:
         self.fspec._pyauxfns[auxname] = None
     # don't process the built-in functions -> unique fns because
     # they are global definitions existing throughout the
     # namespace
     self.fspec._protected_auxnames.extend(["Jacobian", "Jacobian_pars"])
     # protected names are the names that must not be used for
     # user-specified auxiliary fn arguments
     protectednames = (
         self.fspec.pars
         + self.fspec.inputs
         + ["abs", "pow", "and", "or", "not", "True", "False"]
         + self.fspec._protected_auxnames
         + auxnames
         + self.fspec._protected_numpynames
         + self.fspec._protected_scipynames
         + self.fspec._protected_specialfns
         + self.fspec._protected_macronames
         + self.fspec._protected_mathnames
         + self.fspec._protected_randomnames
         + self.fspec._protected_reusenames
     )
     # checks for user-defined auxiliary fns
     # name map for fixing inter-auxfn references
     auxfn_namemap = {}
     specials_base = (
         self.fspec.pars
         + self.fspec._protected_auxnames
         + ["abs", "pow", "and", "or", "not", "True", "False"]
         + auxnames
         + self.fspec._protected_scipynames
         + self.fspec._protected_numpynames
         + self.fspec._protected_specialfns
         + self.fspec._protected_macronames
         + self.fspec._protected_mathnames
         + self.fspec._protected_randomnames
         + self.fspec._protected_reusenames
     )
     for auxname in auxnames:
         auxinfo = self.fspec._auxfnspecs[auxname]
         try:
             if len(auxinfo) != 2:
                 raise ValueError("auxinfo tuple must be of length 2")
         except TypeError:
             raise TypeError("fnspecs argument must contain pairs")
         # auxinfo[0] = tuple or list of parameter names
         # auxinfo[1] = string containing body of function definition
         assert isinstance(auxinfo[0], list), "aux function arguments " "must be given as a list"
         assert isinstance(auxinfo[1], six.string_types), (
             "aux function specification " "must be a string of the function code"
         )
         # Process Jacobian functions, etc., specially, if present
         if auxname == "Jacobian":
             if not compareList(auxinfo[0], ["t"] + self.fspec.vars):
                 print(["t"] + self.fspec.vars)
                 print("Auxinfo =" + str(auxinfo[0]))
                 raise ValueError("Invalid argument list given in Jacobian.")
             auxparlist = ["t", "x", "parsinps"]
             # special symbols to allow in parsing function body
             specials = ["t", "x"]
             auxstr = auxinfo[1]
             if any([pt in auxstr for pt in ("^", "**")]):
                 auxstr = convertPowers(auxstr, "pow")
             specvars = self.fspec.vars
             specvars.sort()
             specdict = {}.fromkeys(specvars)
             if len(specvars) == 1:
                 assert "[" not in auxstr, "'[' character invalid in Jacobian for 1D system"
                 assert "]" not in auxstr, "']' character invalid in Jacobian for 1D system"
                 specdict[specvars[0]] = auxstr
             else:
                 specdict = parseMatrixStrToDictStr(auxstr, specvars)
             reusestr, body_processed_dict = self._processReusedPy(
                 specvars, specdict, specials=specials + specials_base
             )
             body_processed = self._specStrParse(
                 specvars, body_processed_dict, "xjac", specials=specials + specials_base
             )
             auxstr_py = self._generate_fun("_auxfn_Jac", reusestr + body_processed, "xjac", specvars)
             # check Jacobian
             m = n = len(specvars)
             specdict_check = {}.fromkeys(specvars)
             for specname in specvars:
                 temp = body_processed_dict[specname]
                 specdict_check[specname] = count_sep(temp.replace("[", "").replace("]", "")) + 1
             body_processed = ""
             for row in range(m):
                 if specdict_check[specvars[row]] != n:
                     print("Row %i: " % m + specdict[specvars[row]])
                     print("Found length %i" % specdict_check[specvars[row]])
                     raise ValueError("Jacobian should be %sx%s" % (m, n))
         elif auxname == "Jacobian_pars":
             if not compareList(auxinfo[0], ["t"] + self.fspec.pars):
                 print(["t"] + self.fspec.pars)
                 print("Auxinfo =" + str(auxinfo[0]))
                 raise ValueError("Invalid argument list given in Jacobian.")
             auxparlist = ["t", "x", "parsinps"]
             # special symbols to allow in parsing function body
             specials = ["t", "x"]
             auxstr = auxinfo[1]
             if any([pt in auxstr for pt in ("^", "**")]):
                 auxstr = convertPowers(auxstr, "pow")
             specvars = self.fspec.pars
             specvars.sort()
             specdict = {}.fromkeys(self.fspec.vars)
             if len(specvars) == len(self.fspec.vars) == 1:
                 assert "[" not in auxstr, "'[' character invalid in Jacobian for 1D system"
                 assert "]" not in auxstr, "']' character invalid in Jacobian for 1D system"
                 specdict[specvars[0]] = auxstr
             else:
                 specdict = parseMatrixStrToDictStr(auxstr, self.fspec.vars)
             reusestr, body_processed_dict = self._processReusedPy(
                 self.fspec.vars, specdict, specials=specials + specials_base
             )
             body_processed = self._specStrParse(
                 self.fspec.vars, body_processed_dict, "pjac", specials=specials + specials_base
             )
             auxstr_py = self._generate_fun("_auxfn_Jac_p", reusestr + body_processed, "pjac", self.fspec.vars)
             # check Jacobian
             n = len(specvars)
             m = len(self.fspec.vars)
             specdict_check = {}.fromkeys(self.fspec.vars)
             for specname in self.fspec.vars:
                 temp = body_processed_dict[specname]
                 specdict_check[specname] = count_sep(temp.replace("[", "").replace("]", "")) + 1
             body_processed = ""
             for row in range(m):
                 try:
                     if specdict_check[self.fspec.vars[row]] != n:
                         print("Row %i: " % m + specdict[self.fspec.vars[row]])
                         print("Found length %i" % specdict_check[self.fspec.vars[row]])
                         raise ValueError("Jacobian w.r.t. pars should be %sx%s" % (m, n))
                 except IndexError:
                     print("\nFound:\n")
                     info(specdict)
                     raise ValueError("Jacobian w.r.t. pars should be %sx%s" % (m, n))
         elif auxname == "massMatrix":
             if not compareList(auxinfo[0], ["t"] + self.fspec.vars):
                 print(["t"] + self.fspec.vars)
                 print("Auxinfo =" + str(auxinfo[0]))
                 raise ValueError("Invalid argument list given in Mass Matrix.")
             auxparlist = ["t", "x", "parsinps"]
             # special symbols to allow in parsing function body
             specials = ["t", "x"]
             auxstr = auxinfo[1]
             if any([pt in auxstr for pt in ("^", "**")]):
                 auxstr = convertPowers(auxstr, "pow")
             specvars = self.fspec.vars
             specvars.sort()
             specdict = {}.fromkeys(specvars)
             if len(specvars) == 1:
                 assert "[" not in auxstr, "'[' character invalid in mass matrix for 1D system"
                 assert "]" not in auxstr, "']' character invalid in mass matrix for 1D system"
                 specdict[list(specvars.values())[0]] = auxstr
             else:
                 specdict = parseMatrixStrToDictStr(auxstr, specvars)
             reusestr, body_processed_dict = self._processReusedPy(
                 specvars, specdict, specials=specials + specials_base
             )
             body_processed = self._specStrParse(
                 specvars, body_processed_dict, "xmat", specials=specials + specials_base
             )
             auxstr_py = self._generate_fun("_auxfn_massMatrix", reusestr + body_processed, "xmat", specvars)
             # check matrix
             m = n = len(specvars)
             specdict_check = {}.fromkeys(specvars)
             for specname in specvars:
                 specdict_check[specname] = 1 + count_sep(
                     body_processed_dict[specname].replace("[", "").replace("]", "")
                 )
             body_processed = ""
             for row in range(m):
                 if specdict_check[specvars[row]] != n:
                     print("Row %i: " % m + specdict[specvars[row]])
                     print("Found length %i" % specdict_check[specvars[row]])
                     raise ValueError("Mass matrix should be %sx%s" % (m, n))
         else:
             user_parstr = makeParList(auxinfo[0])
             # `parsinps` is always added to allow reference to own
             # parameters
             if user_parstr == "":
                 # no arguments, user calls as fn()
                 auxparstr = "parsinps"
             else:
                 auxparstr = "parsinps, " + user_parstr
             auxstr_py = "def _auxfn_" + auxname + "(ds, " + auxparstr + "):\n"
             auxparlist = auxparstr.replace(" ", "").split(",")
             badparnames = intersect(auxparlist, remain(protectednames, auxnames))
             if badparnames != []:
                 print("Bad parameter names in auxiliary function %s: %r" % (auxname, badparnames))
                 # print(str(auxinfo[0]))
                 # print(str(auxparlist))
                 raise ValueError(
                     "Cannot use protected names (including"
                     " globally visible system parameters for auxiliary "
                     "function arguments"
                 )
             # special symbols to allow in parsing function body
             specials = auxparlist
             specials.remove("parsinps")
             illegalterms = remain(self.fspec.vars + self.fspec.auxvars, specials)
             auxstr = auxinfo[1]
             if any([pt in auxstr for pt in ("^", "**")]):
                 auxstr = convertPowers(auxstr, "pow")
             reusestr, body_processed_dict = self._processReusedPy(
                 [auxname], {auxname: auxstr}, specials=specials + specials_base, dovars=False, illegal=illegalterms
             )
             body_processed = self._specStrParse(
                 [auxname],
                 body_processed_dict,
                 specials=specials + specials_base,
                 dovars=False,
                 noreturndefs=True,
                 illegal=illegalterms,
             )
             auxstr_py += reusestr + _indentstr + "return " + body_processed
         # syntax validation done in makeUniqueFn
         try:
             auxfns[auxname] = makeUniqueFn(auxstr_py)
             # Note: this automatically updates self.fspec._pyauxfns too
         except Exception:
             print("Error in supplied auxiliary spec dictionary code")
             raise
         auxfn_namemap["ds." + auxname] = "ds." + auxfns[auxname][1]
         # prepare user-interface wrapper function (not method)
         if specials == [""] or specials == []:
             fn_args = ""
         else:
             fn_args = "," + ",".join(specials)
         fn_elts = [
             "def ",
             auxname,
             "(self",
             fn_args,
             ",__parsinps__=None):\n\t",
             "if __parsinps__ is None:\n\t\t",
             "__parsinps__=self.map_ixs(self.genref)\n\t",
             "return self.genref.",
             auxfns[auxname][1],
             "(__parsinps__",
             fn_args,
             ")\n",
         ]
         uafi[auxname] = "".join(fn_elts)
     # resolve inter-auxiliary function references
     for auxname, auxspec in auxfns.items():
         dummyQ = QuantSpec("dummy", auxspec[0], preserveSpace=True, treatMultiRefs=False)
         dummyQ.mapNames(auxfn_namemap)
         auxfns[auxname] = (dummyQ(), auxspec[1])
     self.fspec._user_auxfn_interface = uafi
     self.fspec._protected_auxnames.extend(auxnames)
     return auxfns
Пример #3
0
    def generate_aux(self):
        auxnames = list(self.fspec._auxfnspecs.keys())
        auxfns = {}
        # parameter and variable definitions
        # sorted version of var and par names sorted version of par
        # names (vars not #define'd in aux functions unless Jacobian)
        vnames = self.fspec.vars
        pnames = self.fspec.pars
        vnames.sort()
        pnames.sort()
        for auxname in auxnames:
            assert auxname not in ["auxvars", "vfieldfunc"], (
                "auxiliary function name '" + auxname + "' clashes with internal"
                " names"
            )
        # must add parameter argument so that we can name
        # parameters inside the functions! this would either
        # require all calls to include this argument (yuk!) or
        # else we add these extra parameters automatically to
        # every call found in the .c code (as is done currently.
        # this is still an untidy solution, but there you go...)
        for auxname in auxnames:
            auxspec = self.fspec._auxfnspecs[auxname]
            assert len(auxspec) == 2, "auxspec tuple must be of length 2"
            if not isinstance(auxspec[0], list):
                print("Found type " + type(auxspec[0]))
                print("Containing: " + auxspec[0])
                raise TypeError("aux function arguments " "must be given as a list")
            if not isinstance(auxspec[1], str):
                print("Found type " + type(auxspec[1]))
                print("Containing: " + auxspec[1])
                raise TypeError(
                    "aux function specification "
                    "must be a string of the function code"
                )
            # Process Jacobian functions specially, if present
            if auxname == "Jacobian":
                sig = "void jacobian("
                if not compareList(auxspec[0], ["t"] + self.fspec.vars):
                    print(["t"] + self.fspec.vars)
                    print("Auxspec =" + auxspec[0])
                    raise ValueError("Invalid argument list given in Jacobian.")
                if any([pt in auxspec[1] for pt in ("^", "**")]):
                    auxstr = convertPowers(auxspec[1], "pow")
                else:
                    auxstr = auxspec[1]
                parlist = "unsigned n_, unsigned np_, double t, double *Y_,"
                ismat = True
                sig += (
                    parlist
                    + " double *p_, double **f_, unsigned wkn_, double *wk_, unsigned xvn_, double *xv_)"
                )
                specvars = self.fspec.vars
                specvars.sort()
                n = len(specvars)
                m = n
                specdict_temp = {}.fromkeys(specvars)
                if m == 1:
                    assert (
                        "[" not in auxstr
                    ), "'[' character invalid in Jacobian for 1D system"
                    assert (
                        "]" not in auxstr
                    ), "']' character invalid in Jacobian for 1D system"
                    specdict_temp[specvars[0]] = auxstr
                else:
                    specdict_temp = parseMatrixStrToDictStr(auxstr, specvars)
                reusestr, body_processed_dict = self._processReusedC(
                    specvars, specdict_temp
                )
                specdict = {}.fromkeys(specvars)
                for specname in specvars:
                    temp = body_processed_dict[specname]
                    specdict[specname] = splitargs(
                        temp.replace("[", "").replace("]", "")
                    )
                body_processed = ""
                # C integrators expect column-major matrices
                for col in range(n):
                    for row in range(m):
                        try:
                            body_processed += (
                                "f_["
                                + str(col)
                                + "]["
                                + str(row)
                                + "] = "
                                + specdict[specvars[row]][col]
                                + ";\n"
                            )
                        except IndexError:
                            raise ValueError("Jacobian should be %sx%s" % (m, n))
                body_processed += "\n"
                auxspec_processedDict = {auxname: body_processed}
            elif auxname == "Jacobian_pars":
                sig = "void jacobianParam("
                if not compareList(auxspec[0], ["t"] + self.fspec.pars):
                    print(["t"] + self.fspec.pars)
                    print("Auxspec =" + auxspec[0])
                    raise ValueError("Invalid argument list given in Jacobian.")
                parlist = "unsigned n_, unsigned np_, double t, double *Y_,"
                if any([pt in auxspec[1] for pt in ("^", "**")]):
                    auxstr = convertPowers(auxspec[1], "pow")
                else:
                    auxstr = auxspec[1]
                ismat = True
                # specials = ["t","Y_","n_","np_","wkn_","wk_"]
                sig += (
                    parlist
                    + " double *p_, double **f_, unsigned wkn_, double *wk_, unsigned xvn_, double *xv_)"
                )
                specvars = self.fspec.pars
                specvars.sort()
                n = len(specvars)
                if n == 0:
                    raise ValueError(
                        "Cannot have a Jacobian w.r.t. pars"
                        " because no pars are defined"
                    )
                m = len(self.fspec.vars)
                specdict_temp = {}.fromkeys(self.fspec.vars)
                if m == n == 1:
                    assert (
                        "[" not in auxstr
                    ), "'[' character invalid in Jacobian for 1D system"
                    assert (
                        "]" not in auxstr
                    ), "']' character invalid in Jacobian for 1D system"
                    specdict_temp[list(self.fspec.vars.values())[0]] = auxstr
                else:
                    specdict_temp = parseMatrixStrToDictStr(auxstr, self.fspec.vars, m)
                reusestr, body_processed_dict = self._processReusedC(
                    self.fspec.vars, specdict_temp
                )
                specdict = {}.fromkeys(self.fspec.vars)
                for specname in self.fspec.vars:
                    temp = body_processed_dict[specname]
                    specdict[specname] = splitargs(
                        temp.replace("[", "").replace("]", "")
                    )
                body_processed = ""
                # C integrators expect column-major matrices
                for col in range(n):
                    for row in range(m):
                        try:
                            body_processed += (
                                "f_["
                                + str(col)
                                + "]["
                                + str(row)
                                + "] = "
                                + specdict[self.fspec.vars[row]][col]
                                + ";\n"
                            )
                        except (IndexError, KeyError):
                            print("%d %r" % (n, specvars))
                            print("\nFound matrix:\n")
                            info(specdict)
                            raise ValueError("Jacobian should be %sx%s" % (m, n))
                body_processed += "\n"
                auxspec_processedDict = {auxname: body_processed}
            elif auxname == "massMatrix":
                sig = "void massMatrix("
                if not compareList(auxspec[0], ["t"] + self.fspec.vars):
                    raise ValueError("Invalid argument list given in Mass Matrix.")
                if any([pt in auxspec[1] for pt in ("^", "**")]):
                    auxstr = convertPowers(auxspec[1], "pow")
                else:
                    auxstr = auxspec[1]
                parlist = "unsigned n_, unsigned np_,"
                ismat = True
                # specials = ["n_","np_","wkn_","wk_"]
                sig += (
                    parlist
                    + " double t, double *Y_, double *p_, double **f_, unsigned wkn_, double *wk_, unsigned xvn_, double *xv_)"
                )
                specvars = self.fspec.vars
                specvars.sort()
                n = len(specvars)
                m = n
                specdict_temp = {}.fromkeys(specvars)
                if m == 1:
                    assert (
                        "[" not in auxstr
                    ), "'[' character invalid in mass matrix for 1D system"
                    assert (
                        "]" not in auxstr
                    ), "']' character invalid in mass matrix for 1D system"
                    specdict_temp[list(specvars.values())[0]] = auxstr
                else:
                    specdict_temp = parseMatrixStrToDictStr(auxstr, specvars, m)
                reusestr, body_processed_dict = self._processReusedC(
                    specvars, specdict_temp
                )
                specdict = {}.fromkeys(specvars)
                for specname in specvars:
                    temp = (
                        body_processed_dict[specname].replace("[", "").replace("]", "")
                    )
                    specdict[specname] = splitargs(temp)
                body_processed = ""
                # C integrators expect column-major matrices
                for col in range(n):
                    for row in range(m):
                        try:
                            body_processed += (
                                "f_["
                                + str(col)
                                + "]["
                                + str(row)
                                + "] = "
                                + specdict[specvars[row]][col]
                                + ";\n"
                            )
                        except KeyError:
                            raise ValueError("Mass matrix should be %sx%s" % (m, n))
                body_processed += "\n"
                auxspec_processedDict = {auxname: body_processed}
            else:
                ismat = False
                sig = "double " + auxname + "("
                parlist = ""
                namemap = {}
                for parname in auxspec[0]:
                    if parname == "":
                        continue
                    parlist += "double " + "__" + parname + "__, "
                    namemap[parname] = "__" + parname + "__"
                sig += parlist + "double *p_, double *wk_, double *xv_)"
                auxstr = auxspec[1]
                if any([pt in auxspec[1] for pt in ("^", "**")]):
                    auxstr = convertPowers(auxstr, "pow")
                prep_auxstr = self._processSpecialC(auxstr)
                prep_auxstr_quant = QuantSpec(
                    "prep_q",
                    prep_auxstr.replace(" ", "").replace("\n", ""),
                    treatMultiRefs=False,
                    preserveSpace=True,
                )
                # have to do name map now in case function's formal arguments
                # coincide with state variable names, which may get tied up
                # in reused terms and not properly matched to the formal args.
                prep_auxstr_quant.mapNames(namemap)
                auxspec = (auxspec[0], prep_auxstr_quant())
                reusestr, auxspec_processedDict = self._processReusedC(
                    [auxname], {auxname: auxspec[1]}
                )
                # addition of parameter done in Generator code
                # dummyQ = QuantSpec('dummy', auxspec_processedDict[auxname])
                # auxspec_processed = ""
                # add pars argument to inter-aux fn call
                # auxfn_found = False   # then expect a left brace next
                # for tok in dummyQ:
                #     if auxfn_found:
                # expect left brace in this tok
                #         if tok == '(':
                #             auxspec_processed += tok + 'p_, '
                #             auxfn_found = False
                #         else:
                #             raise ValueError("Problem parsing inter-auxiliary"
                #                              " function call")
                #     elif tok in self.fspec.auxfns and tok not in \
                #             ['Jacobian', 'Jacobian_pars']:
                #         auxfn_found = True
                #         auxspec_processed += tok
                #     else:
                #         auxspec_processed += tok
                # body_processed = "return "+auxspec_processed + ";\n\n"
            # add underscore to local names, to avoid clash with global
            # '#define' names
            dummyQ = QuantSpec(
                "dummy",
                auxspec_processedDict[auxname],
                treatMultiRefs=False,
                preserveSpace=True,
            )
            body_processed = "return " * (not ismat) + dummyQ() + ";\n\n"
            # auxspecstr = sig + " {\n\n" + pardefines + vardefines*ismat \
            auxspecstr = (
                sig
                + " {\n\n"
                + "\n"
                + (len(reusestr) > 0) * "/* reused term definitions */\n"
                + reusestr
                + (len(reusestr) > 0) * "\n"
                + body_processed
                + "}"
            )
            # + parundefines + varundefines*ismat + "}"
            # sig as second entry, whereas Python-coded specifications
            # have the fn name there
            auxfns[auxname] = (auxspecstr, sig)
        # Don't apply #define's for built-in functions
        auxfns["heav"] = (
            "int heav(double x_, double *p_, double *wk_, double *xv_) {\n"
            + "  if (x_>0.0) {return 1;} else {return 0;}\n}",
            "int heav(double x_, double *p_, double *wk_, double *xv_)",
        )
        auxfns["__rhs_if"] = (
            "double __rhs_if(int cond_, double e1_, "
            + "double e2_, double *p_, double *wk_, double *xv_) {\n"
            + "  if (cond_) {return e1_;} else {return e2_;};\n}",
            "double __rhs_if(int cond_, double e1_, double e2_, double *p_, double *wk_, double *xv_)",
        )
        auxfns["__maxof2"] = (
            "double __maxof2(double e1_, double e2_, double *p_, double *wk_, double *xv_) {\n"
            + "if (e1_ > e2_) {return e1_;} else {return e2_;};\n}",
            "double __maxof2(double e1_, double e2_, double *p_, double *wk_, double *xv_)",
        )
        auxfns["__minof2"] = (
            "double __minof2(double e1_, double e2_, double *p_, double *wk_, double *xv_) {\n"
            + "if (e1_ < e2_) {return e1_;} else {return e2_;};\n}",
            "double __minof2(double e1_, double e2_, double *p_, double *wk_, double *xv_)",
        )
        auxfns["__maxof3"] = (
            "double __maxof3(double e1_, double e2_, double e3_, double *p_, double *wk_, double *xv_) {\n"
            + "double temp_;\nif (e1_ > e2_) {temp_ = e1_;} else {temp_ = e2_;};\n"
            + "if (e3_ > temp_) {return e3_;} else {return temp_;};\n}",
            "double __maxof3(double e1_, double e2_, double e3_, double *p_, double *wk_, double *xv_)",
        )
        auxfns["__minof3"] = (
            "double __minof3(double e1_, double e2_, double e3_, double *p_, double *wk_, double *xv_) {\n"
            + "double temp_;\nif (e1_ < e2_) {temp_ = e1_;} else {temp_ = e2_;};\n"
            + "if (e3_ < temp_) {return e3_;} else {return temp_;};\n}",
            "double __minof3(double e1_, double e2_, double e3_, double *p_, double *wk_, double *xv_)",
        )
        auxfns["__maxof4"] = (
            "double __maxof4(double e1_, double e2_, double e3_, double e4_, double *p_, double *wk_, double *xv_) {\n"
            + "double temp_;\nif (e1_ > e2_) {temp_ = e1_;} else {temp_ = e2_;};\n"
            + "if (e3_ > temp_) {temp_ = e3_;};\nif (e4_ > temp_) {return e4_;} else {return temp_;};\n}",
            "double __maxof4(double e1_, double e2_, double e3_, double e4_, double *p_, double *wk_, double *xv_)",
        )
        auxfns["__minof4"] = (
            "double __minof4(double e1_, double e2_, double e3_, double e4_, double *p_, double *wk_, double *xv_) {\n"
            + "double temp_;\nif (e1_ < e2_) {temp_ = e1_;} else {temp_ = e2_;};\n"
            + "if (e3_ < temp_) {temp_ = e3_;};\nif (e4_ < temp_) {return e4_;} else {return temp_;};\n}",
            "double __minof4(double e1_, double e2_, double e3_, double e4_, double *p_, double *wk_, double *xv_)",
        )
        # temporary placeholders for these built-ins...
        cases_ic = ""
        cases_index = ""
        for i in range(len(self.fspec.vars)):
            if i == 0:
                command = "if"
            else:
                command = "else if"
            vname = self.fspec.vars[i]
            cases_ic += (
                "  "
                + command
                + " (strcmp(varname, "
                + '"'
                + vname
                + '"'
                + ")==0)\n\treturn gICs["
                + str(i)
                + "];\n"
            )
            cases_index += (
                "  "
                + command
                + " (strcmp(name, "
                + '"'
                + vname
                + '"'
                + ")==0)\n\treturn "
                + str(i)
                + ";\n"
            )
        # add remaining par names for getindex
        for i in range(len(self.fspec.pars)):
            pname = self.fspec.pars[i]
            cases_index += (
                "  else if"
                + " (strcmp(name, "
                + '"'
                + pname
                + '"'
                + ")==0)\n\treturn "
                + str(i + len(self.fspec.vars))
                + ";\n"
            )
        cases_ic += (
            """  else {\n\tfprintf(stderr, "Invalid variable name %s for """
            + """initcond call\\n", varname);\n\treturn 0.0/0.0;\n\t}\n"""
        )
        cases_index += (
            """  else {\n\tfprintf(stderr, "Invalid name %s for """
            + """getindex call\\n", name);\n\treturn 0.0/0.0;\n\t}\n"""
        )
        auxfns["initcond"] = (
            "double initcond(char *varname, double *p_, double *wk_, double *xv_) {\n"
            + "\n"
            + cases_ic
            + "}",
            "double initcond(char *varname, double *p_, double *wk_, double *xv_)",
        )
        auxfns["getindex"] = (
            "int getindex(char *name, double *p_, double *wk_, double *xv_) {\n"
            + "\n"
            + cases_index
            + "}",
            "int getindex(char *name, double *p_, double *wk_, double *xv_)",
        )
        auxfns["globalindepvar"] = (
            "double globalindepvar(double t, double *p_, double *wk_, double *xv_)"
            + " {\n  return globalt0+t;\n}",
            "double globalindepvar(double t, double *p_, double *wk_, double *xv_)",
        )
        auxfns["getbound"] = (
            "double getbound(char *name, int which_bd, double *p_, double *wk_, double *xv_) {\n"
            + "  return gBds[which_bd][getindex(name)];\n}",
            "double getbound(char *name, int which_bd, double *p_, double *wk_, double *xv_)",
        )

        return auxfns
Пример #4
0
 def _processSpecialC(self, specStr):
     """Pre-process 'if' statements and names of 'abs' and 'sign' functions,
     as well as logical operators.
     """
     qspec = QuantSpec("spec", specStr, treatMultiRefs=False)
     qspec.mapNames(
         {
             "abs": "fabs",
             "sign": "signum",
             "mod": "fmod",
             "and": "&&",
             "or": "||",
             "not": "!",
             "True": 1,
             "False": 0,
             "max": "__maxof",
             "min": "__minof",
         }
     )
     qtoks = qspec.parser.tokenized
     # default value
     new_specStr = str(qspec)
     if "if" in qtoks:
         new_specStr = ""
         num_ifs = qtoks.count("if")
         if_ix = -1
         ix_continue = 0
         for _ in range(num_ifs):
             if_ix = qtoks[if_ix + 1 :].index("if") + if_ix + 1
             new_specStr += "".join(qtoks[ix_continue:if_ix]) + "__rhs_if("
             rbrace_ix = findEndBrace(qtoks[if_ix + 1 :]) + if_ix + 1
             ix_continue = rbrace_ix + 1
             new_specStr += "".join(qtoks[if_ix + 2 : ix_continue])
         new_specStr += "".join(qtoks[ix_continue:])
         qspec = QuantSpec("spec", new_specStr)
         qtoks = qspec.parser.tokenized
     if "__minof" in qtoks:
         new_specStr = ""
         num = qtoks.count("__minof")
         n_ix = -1
         ix_continue = 0
         for _ in range(num):
             n_ix = qtoks[n_ix + 1 :].index("__minof") + n_ix + 1
             new_specStr += "".join(qtoks[ix_continue:n_ix])
             rbrace_ix = findEndBrace(qtoks[n_ix + 1 :]) + n_ix + 1
             ix_continue = rbrace_ix + 1
             # assert qtoks[n_ix+2] == '[', "Error in min() syntax"
             # assert qtoks[rbrace_ix-1] == ']', "Error in min() syntax"
             # new_specStr += "".join(qtoks[n_ix+3:rbrace_ix-1]) + ")"
             num_args = qtoks[n_ix + 2 : ix_continue].count(",") + 1
             if num_args > 4:
                 raise NotImplementedError(
                     "Max of more than 4 arguments not currently supported in C"
                 )
             new_specStr += "__minof%s(" % str(num_args)
             new_specStr += "".join(
                 [q for q in qtoks[n_ix + 2 : ix_continue] if q not in ("[", "]")]
             )
         new_specStr += "".join(qtoks[ix_continue:])
         qspec = QuantSpec("spec", new_specStr)
         qtoks = qspec.parser.tokenized
     if "__maxof" in qtoks:
         new_specStr = ""
         num = qtoks.count("__maxof")
         n_ix = -1
         ix_continue = 0
         for _ in range(num):
             n_ix = qtoks[n_ix + 1 :].index("__maxof") + n_ix + 1
             new_specStr += "".join(qtoks[ix_continue:n_ix])
             rbrace_ix = findEndBrace(qtoks[n_ix + 1 :]) + n_ix + 1
             ix_continue = rbrace_ix + 1
             # assert qtoks[n_ix+2] == '[', "Error in max() syntax"
             # assert qtoks[rbrace_ix-1] == ']', "Error in max() syntax"
             # new_specStr += "".join(qtoks[n_ix+3:rbrace_ix-1]) + ")"
             num_args = qtoks[n_ix + 2 : ix_continue].count(",") + 1
             if num_args > 4:
                 raise NotImplementedError(
                     "Min of more than 4 arguments not currently supported in C"
                 )
             new_specStr += "__maxof%s(" % str(num_args)
             new_specStr += "".join(
                 [q for q in qtoks[n_ix + 2 : ix_continue] if q not in ("[", "]")]
             )
         new_specStr += "".join(qtoks[ix_continue:])
         qspec = QuantSpec("spec", new_specStr)
         qtoks = qspec.parser.tokenized
     return new_specStr
Пример #5
0
def _map_names(spec, namemap):
    if spec and namemap:
        q = QuantSpec('__temp__', spec, preserveSpace=True)
        q.mapNames(namemap)
        spec = q()
    return spec
Пример #6
0
def _map_names(spec, namemap):
    if spec and namemap:
        q = QuantSpec('__temp__', spec, preserveSpace=True)
        q.mapNames(namemap)
        spec = q()
    return spec
Пример #7
0
 def _processSpecialC(self, specStr):
     """Pre-process 'if' statements and names of 'abs' and 'sign' functions,
     as well as logical operators.
     """
     qspec = QuantSpec('spec', specStr, treatMultiRefs=False)
     qspec.mapNames({'abs': 'fabs', 'sign': 'signum', 'mod': 'fmod',
                     'and': '&&', 'or': '||', 'not': '!',
                     'True': 1, 'False': 0, 'if': '__rhs_if',
                     'max': '__maxof', 'min': '__minof'})
     qtoks = qspec.parser.tokenized
     # default value
     new_specStr = str(qspec)
     # NOTE: This simple iterative parsing of the arguments means that
     # user cannot nest calls to min() or max() with eachother
     if '__minof' in qtoks:
         new_specStr = ""
         num = qtoks.count('__minof')
         n_ix = -1
         ix_continue = 0
         for _ in range(num):
             n_ix = qtoks[n_ix + 1:].index('__minof') + n_ix + 1
             new_specStr += "".join(qtoks[ix_continue:n_ix])
             rbrace_ix = findEndBrace(qtoks[n_ix + 1:]) + n_ix + 1
             ix_continue = rbrace_ix + 1
             #assert qtoks[n_ix+2] == '[', "Error in min() syntax"
             #assert qtoks[rbrace_ix-1] == ']', "Error in min() syntax"
             #new_specStr += "".join(qtoks[n_ix+3:rbrace_ix-1]) + ")"
             num_args = qtoks[n_ix + 2:ix_continue].count(',') + 1
             if num_args > 4:
                 raise NotImplementedError(
                     "Max of more than 4 arguments not currently supported in C")
             new_specStr += '__minof%s(' % str(num_args)
             new_specStr += "".join(
                 [q for q in qtoks[n_ix + 2:ix_continue] if q not in ('[', ']')])
         new_specStr += "".join(qtoks[ix_continue:])
         qspec = QuantSpec('spec', new_specStr)
         qtoks = qspec.parser.tokenized
     if '__maxof' in qtoks:
         new_specStr = ""
         num = qtoks.count('__maxof')
         n_ix = -1
         ix_continue = 0
         for _ in range(num):
             n_ix = qtoks[n_ix + 1:].index('__maxof') + n_ix + 1
             new_specStr += "".join(qtoks[ix_continue:n_ix])
             rbrace_ix = findEndBrace(qtoks[n_ix + 1:]) + n_ix + 1
             ix_continue = rbrace_ix + 1
             #assert qtoks[n_ix+2] == '[', "Error in max() syntax"
             #assert qtoks[rbrace_ix-1] == ']', "Error in max() syntax"
             #new_specStr += "".join(qtoks[n_ix+3:rbrace_ix-1]) + ")"
             num_args = qtoks[n_ix + 2:ix_continue].count(',') + 1
             if num_args > 4:
                 raise NotImplementedError(
                     "Min of more than 4 arguments not currently supported in C")
             new_specStr += '__maxof%s(' % str(num_args)
             new_specStr += "".join(
                 [q for q in qtoks[n_ix + 2:ix_continue] if q not in ('[', ']')])
         new_specStr += "".join(qtoks[ix_continue:])
         qspec = QuantSpec('spec', new_specStr)
         qtoks = qspec.parser.tokenized
     return new_specStr
Пример #8
0
    def generate_aux(self):
        auxnames = list(self.fspec._auxfnspecs.keys())
        auxfns = {}
        # parameter and variable definitions
        # sorted version of var and par names sorted version of par
        # names (vars not #define'd in aux functions unless Jacobian)
        vnames = self.fspec.vars
        pnames = self.fspec.pars
        vnames.sort()
        pnames.sort()
        for auxname in auxnames:
            assert auxname not in ['auxvars', 'vfieldfunc'], \
                ("auxiliary function name '" + auxname + "' clashes with internal"
                 " names")
        # must add parameter argument so that we can name
        # parameters inside the functions! this would either
        # require all calls to include this argument (yuk!) or
        # else we add these extra parameters automatically to
        # every call found in the .c code (as is done currently.
        # this is still an untidy solution, but there you go...)
        for auxname in auxnames:
            auxspec = self.fspec._auxfnspecs[auxname]
            assert len(auxspec) == 2, 'auxspec tuple must be of length 2'
            if not isinstance(auxspec[0], list):
                print("Found type " + type(auxspec[0]))
                print("Containing: " + auxspec[0])
                raise TypeError('aux function arguments '
                                'must be given as a list')
            if not isinstance(auxspec[1], str):
                print("Found type " + type(auxspec[1]))
                print("Containing: " + auxspec[1])
                raise TypeError('aux function specification '
                                'must be a string of the function code')
            # Process Jacobian functions specially, if present
            if auxname == 'Jacobian':
                sig = "void jacobian("
                if not compareList(auxspec[0], ['t'] + self.fspec.vars):
                    print(['t'] + self.fspec.vars)
                    print("Auxspec =" + auxspec[0])
                    raise ValueError(
                        "Invalid argument list given in Jacobian.")
                if any([pt in auxspec[1] for pt in ('^', '**')]):
                    auxstr = convertPowers(auxspec[1], 'pow')
                else:
                    auxstr = auxspec[1]
                parlist = "unsigned n_, unsigned np_, double t, double *Y_,"
                ismat = True
                sig += parlist + \
                    " double *p_, double **f_, unsigned wkn_, double *wk_, unsigned xvn_, double *xv_)"
                specvars = self.fspec.vars
                specvars.sort()
                n = len(specvars)
                m = n
                specdict_temp = {}.fromkeys(specvars)
                if m == 1:
                    assert '[' not in auxstr, \
                           "'[' character invalid in Jacobian for 1D system"
                    assert ']' not in auxstr, \
                           "']' character invalid in Jacobian for 1D system"
                    specdict_temp[specvars[0]] = auxstr
                else:
                    specdict_temp = parseMatrixStrToDictStr(auxstr, specvars)
                reusestr, body_processed_dict = self._processReusedC(
                    specvars,
                    specdict_temp)
                specdict = {}.fromkeys(specvars)
                for specname in specvars:
                    temp = body_processed_dict[specname]
                    specdict[specname] = splitargs(
                        temp.replace("[", "").replace("]", ""))
                body_processed = ""
                # C integrators expect column-major matrices
                for col in range(n):
                    for row in range(m):
                        try:
                            body_processed += "f_[" + str(col) + "][" + str(row) \
                                + "] = " + specdict[specvars[row]][col] + ";\n"
                        except IndexError:
                            raise ValueError(
                                "Jacobian should be %sx%s" % (m, n))
                body_processed += "\n"
                auxspec_processedDict = {auxname: body_processed}
            elif auxname == 'Jacobian_pars':
                sig = "void jacobianParam("
                if not compareList(auxspec[0], ['t'] + self.fspec.pars):
                    print(['t'] + self.fspec.pars)
                    print("Auxspec =" + auxspec[0])
                    raise ValueError(
                        "Invalid argument list given in Jacobian.")
                parlist = "unsigned n_, unsigned np_, double t, double *Y_,"
                if any([pt in auxspec[1] for pt in ('^', '**')]):
                    auxstr = convertPowers(auxspec[1], 'pow')
                else:
                    auxstr = auxspec[1]
                ismat = True
                # specials = ["t","Y_","n_","np_","wkn_","wk_"]
                sig += parlist + \
                    " double *p_, double **f_, unsigned wkn_, double *wk_, unsigned xvn_, double *xv_)"
                specvars = self.fspec.pars
                specvars.sort()
                n = len(specvars)
                if n == 0:
                    raise ValueError("Cannot have a Jacobian w.r.t. pars"
                                     " because no pars are defined")
                m = len(self.fspec.vars)
                specdict_temp = {}.fromkeys(self.fspec.vars)
                if m == n == 1:
                    assert '[' not in auxstr, \
                           "'[' character invalid in Jacobian for 1D system"
                    assert ']' not in auxstr, \
                           "']' character invalid in Jacobian for 1D system"
                    specdict_temp[list(self.fspec.vars.values())[0]] = auxstr
                else:
                    specdict_temp = parseMatrixStrToDictStr(
                        auxstr, self.fspec.vars, m)
                reusestr, body_processed_dict = self._processReusedC(
                    self.fspec.vars,
                    specdict_temp)
                specdict = {}.fromkeys(self.fspec.vars)
                for specname in self.fspec.vars:
                    temp = body_processed_dict[specname]
                    specdict[specname] = splitargs(
                        temp.replace("[", "").replace("]", ""))
                body_processed = ""
                # C integrators expect column-major matrices
                for col in range(n):
                    for row in range(m):
                        try:
                            body_processed += "f_[" + str(col) + "][" + str(row) \
                                + "] = " + specdict[
                                    self.fspec.vars[row]][col] + ";\n"
                        except (IndexError, KeyError):
                            print("%d %r" % (n, specvars))
                            print("\nFound matrix:\n")
                            info(specdict)
                            raise ValueError(
                                "Jacobian should be %sx%s" % (m, n))
                body_processed += "\n"
                auxspec_processedDict = {auxname: body_processed}
            elif auxname == 'massMatrix':
                sig = "void massMatrix("
                if not compareList(auxspec[0], ['t'] + self.fspec.vars):
                    raise ValueError(
                        "Invalid argument list given in Mass Matrix.")
                if any([pt in auxspec[1] for pt in ('^', '**')]):
                    auxstr = convertPowers(auxspec[1], 'pow')
                else:
                    auxstr = auxspec[1]
                parlist = "unsigned n_, unsigned np_,"
                ismat = True
                # specials = ["n_","np_","wkn_","wk_"]
                sig += parlist + \
                    " double t, double *Y_, double *p_, double **f_, unsigned wkn_, double *wk_, unsigned xvn_, double *xv_)"
                specvars = self.fspec.vars
                specvars.sort()
                n = len(specvars)
                m = n
                specdict_temp = {}.fromkeys(specvars)
                if m == 1:
                    assert '[' not in auxstr, \
                           "'[' character invalid in mass matrix for 1D system"
                    assert ']' not in auxstr, \
                           "']' character invalid in mass matrix for 1D system"
                    specdict_temp[list(specvars.values())[0]] = auxstr
                else:
                    specdict_temp = parseMatrixStrToDictStr(
                        auxstr, specvars, m)
                reusestr, body_processed_dict = self._processReusedC(
                    specvars,
                    specdict_temp)
                specdict = {}.fromkeys(specvars)
                for specname in specvars:
                    temp = body_processed_dict[
                        specname].replace("[", "").replace("]", "")
                    specdict[specname] = splitargs(temp)
                body_processed = ""
                # C integrators expect column-major matrices
                for col in range(n):
                    for row in range(m):
                        try:
                            body_processed += "f_[" + str(col) + "][" + str(row) \
                                + "] = " + specdict[specvars[row]][col] + ";\n"
                        except KeyError:
                            raise ValueError(
                                "Mass matrix should be %sx%s" % (m, n))
                body_processed += "\n"
                auxspec_processedDict = {auxname: body_processed}
            else:
                ismat = False
                sig = "double " + auxname + "("
                parlist = ""
                namemap = {}
                for parname in auxspec[0]:
                    if parname == '':
                        continue
                    parlist += "double " + "__" + parname + "__, "
                    namemap[parname] = '__' + parname + '__'
                sig += parlist + "double *p_, double *wk_, double *xv_)"
                auxstr = auxspec[1]
                if any([pt in auxspec[1] for pt in ('^', '**')]):
                    auxstr = convertPowers(auxstr, 'pow')
                prep_auxstr = self._processSpecialC(auxstr)
                prep_auxstr_quant = QuantSpec('prep_q',
                                              prep_auxstr.replace(
                                                  ' ', '').replace('\n', ''),
                                              treatMultiRefs=False, preserveSpace=True)
                # have to do name map now in case function's formal arguments
                # coincide with state variable names, which may get tied up
                # in reused terms and not properly matched to the formal args.
                prep_auxstr_quant.mapNames(namemap)
                auxspec = (auxspec[0], prep_auxstr_quant())
                reusestr, auxspec_processedDict = self._processReusedC(
                    [auxname],
                    {auxname: auxspec[1]})
                # addition of parameter done in Generator code
                # dummyQ = QuantSpec('dummy', auxspec_processedDict[auxname])
                # auxspec_processed = ""
                # add pars argument to inter-aux fn call
                # auxfn_found = False   # then expect a left brace next
                # for tok in dummyQ:
                #     if auxfn_found:
                # expect left brace in this tok
                #         if tok == '(':
                #             auxspec_processed += tok + 'p_, '
                #             auxfn_found = False
                #         else:
                #             raise ValueError("Problem parsing inter-auxiliary"
                #                              " function call")
                #     elif tok in self.fspec.auxfns and tok not in \
                #             ['Jacobian', 'Jacobian_pars']:
                #         auxfn_found = True
                #         auxspec_processed += tok
                #     else:
                #         auxspec_processed += tok
                # body_processed = "return "+auxspec_processed + ";\n\n"
            # add underscore to local names, to avoid clash with global
            # '#define' names
            dummyQ = QuantSpec('dummy', auxspec_processedDict[auxname],
                               treatMultiRefs=False, preserveSpace=True)
            body_processed = "return " * (not ismat) + dummyQ() + ";\n\n"
            # auxspecstr = sig + " {\n\n" + pardefines + vardefines*ismat \
            auxspecstr = sig + " {\n\n" \
                + "\n" + (len(reusestr) > 0) * "/* reused term definitions */\n" \
                + reusestr + (len(reusestr) > 0) * "\n" + body_processed \
                + "}"
               # + parundefines + varundefines*ismat + "}"
            # sig as second entry, whereas Python-coded specifications
            # have the fn name there
            auxfns[auxname] = (auxspecstr, sig)
        # Don't apply #define's for built-in functions
        auxfns['heav'] = ("int heav(double x_, double *p_, double *wk_, double *xv_) {\n"
                                +
                                "  if (x_>0.0) {return 1;} else {return 0;}\n}",
                                "int heav(double x_, double *p_, double *wk_, double *xv_)")
        auxfns['__rhs_if'] = ("double __rhs_if(int cond_, double e1_, "
                                    +
                                    "double e2_, double *p_, double *wk_, double *xv_) {\n"
                                    +
                                    "  if (cond_) {return e1_;} else {return e2_;};\n}",
                                    "double __rhs_if(int cond_, double e1_, double e2_, double *p_, double *wk_, double *xv_)")
        auxfns['__maxof2'] = ("double __maxof2(double e1_, double e2_, double *p_, double *wk_, double *xv_) {\n"
                                    +
                                    "if (e1_ > e2_) {return e1_;} else {return e2_;};\n}",
                                    "double __maxof2(double e1_, double e2_, double *p_, double *wk_, double *xv_)")
        auxfns['__minof2'] = ("double __minof2(double e1_, double e2_, double *p_, double *wk_, double *xv_) {\n"
                                    +
                                    "if (e1_ < e2_) {return e1_;} else {return e2_;};\n}",
                                    "double __minof2(double e1_, double e2_, double *p_, double *wk_, double *xv_)")
        auxfns['__maxof3'] = ("double __maxof3(double e1_, double e2_, double e3_, double *p_, double *wk_, double *xv_) {\n"
                                    +
                                    "double temp_;\nif (e1_ > e2_) {temp_ = e1_;} else {temp_ = e2_;};\n"
                                    +
                                    "if (e3_ > temp_) {return e3_;} else {return temp_;};\n}",
                                    "double __maxof3(double e1_, double e2_, double e3_, double *p_, double *wk_, double *xv_)")
        auxfns['__minof3'] = ("double __minof3(double e1_, double e2_, double e3_, double *p_, double *wk_, double *xv_) {\n"
                                    +
                                    "double temp_;\nif (e1_ < e2_) {temp_ = e1_;} else {temp_ = e2_;};\n"
                                    +
                                    "if (e3_ < temp_) {return e3_;} else {return temp_;};\n}",
                                    "double __minof3(double e1_, double e2_, double e3_, double *p_, double *wk_, double *xv_)")
        auxfns['__maxof4'] = ("double __maxof4(double e1_, double e2_, double e3_, double e4_, double *p_, double *wk_, double *xv_) {\n"
                                    +
                                    "double temp_;\nif (e1_ > e2_) {temp_ = e1_;} else {temp_ = e2_;};\n"
                                    +
                                    "if (e3_ > temp_) {temp_ = e3_;};\nif (e4_ > temp_) {return e4_;} else {return temp_;};\n}",
                                    "double __maxof4(double e1_, double e2_, double e3_, double e4_, double *p_, double *wk_, double *xv_)")
        auxfns['__minof4'] = ("double __minof4(double e1_, double e2_, double e3_, double e4_, double *p_, double *wk_, double *xv_) {\n"
                                    +
                                    "double temp_;\nif (e1_ < e2_) {temp_ = e1_;} else {temp_ = e2_;};\n"
                                    +
                                    "if (e3_ < temp_) {temp_ = e3_;};\nif (e4_ < temp_) {return e4_;} else {return temp_;};\n}",
                                    "double __minof4(double e1_, double e2_, double e3_, double e4_, double *p_, double *wk_, double *xv_)")
        # temporary placeholders for these built-ins...
        cases_ic = ""
        cases_index = ""
        for i in range(len(self.fspec.vars)):
            if i == 0:
                command = 'if'
            else:
                command = 'else if'
            vname = self.fspec.vars[i]
            cases_ic += "  " + command + " (strcmp(varname, " + '"' + vname + '"'\
                + ")==0)\n\treturn gICs[" + str(i) + "];\n"
            cases_index += "  " + command + " (strcmp(name, " + '"' + vname + '"'\
                + ")==0)\n\treturn " + str(i) + ";\n"
        # add remaining par names for getindex
        for i in range(len(self.fspec.pars)):
            pname = self.fspec.pars[i]
            cases_index += "  else if" + " (strcmp(name, " + '"' + pname + '"'\
                           + ")==0)\n\treturn " + str(
                               i + len(self.fspec.vars)) + ";\n"
        cases_ic += """  else {\n\tfprintf(stderr, "Invalid variable name %s for """ \
            + """initcond call\\n", varname);\n\treturn 0.0/0.0;\n\t}\n"""
        cases_index += """  else {\n\tfprintf(stderr, "Invalid name %s for """ \
            + """getindex call\\n", name);\n\treturn 0.0/0.0;\n\t}\n"""
        auxfns['initcond'] = ("double initcond(char *varname, double *p_, double *wk_, double *xv_) {\n"
                                    + "\n" + cases_ic + "}",
                                    'double initcond(char *varname, double *p_, double *wk_, double *xv_)')
        auxfns['getindex'] = ("int getindex(char *name, double *p_, double *wk_, double *xv_) {\n"
                                    + "\n" + cases_index + "}",
                                    'int getindex(char *name, double *p_, double *wk_, double *xv_)')
        auxfns['globalindepvar'] = ("double globalindepvar(double t, double *p_, double *wk_, double *xv_)"
                                          + " {\n  return globalt0+t;\n}",
                                          'double globalindepvar(double t, double *p_, double *wk_, double *xv_)')
        auxfns['getbound'] = \
            ("double getbound(char *name, int which_bd, double *p_, double *wk_, double *xv_) {\n"
             + "  return gBds[which_bd][getindex(name)];\n}",
             'double getbound(char *name, int which_bd, double *p_, double *wk_, double *xv_)')

        return auxfns
Пример #9
0
 def _processSpecialC(self, specStr):
     """Pre-process 'if' statements and names of 'abs' and 'sign' functions,
     as well as logical operators.
     """
     qspec = QuantSpec('spec', specStr, treatMultiRefs=False)
     qspec.mapNames({'abs': 'fabs', 'sign': 'signum', 'mod': 'fmod',
                     'and': '&&', 'or': '||', 'not': '!',
                     'True': 1, 'False': 0,
                     'max': '__maxof', 'min': '__minof'})
     qtoks = qspec.parser.tokenized
     # default value
     new_specStr = str(qspec)
     if 'if' in qtoks:
         new_specStr = ""
         num_ifs = qtoks.count('if')
         if_ix = -1
         ix_continue = 0
         for _ in range(num_ifs):
             if_ix = qtoks[if_ix + 1:].index('if') + if_ix + 1
             new_specStr += "".join(qtoks[ix_continue:if_ix]) + "__rhs_if("
             rbrace_ix = findEndBrace(qtoks[if_ix + 1:]) + if_ix + 1
             ix_continue = rbrace_ix + 1
             new_specStr += "".join(qtoks[if_ix + 2:ix_continue])
         new_specStr += "".join(qtoks[ix_continue:])
         qspec = QuantSpec('spec', new_specStr)
         qtoks = qspec.parser.tokenized
     if '__minof' in qtoks:
         new_specStr = ""
         num = qtoks.count('__minof')
         n_ix = -1
         ix_continue = 0
         for _ in range(num):
             n_ix = qtoks[n_ix + 1:].index('__minof') + n_ix + 1
             new_specStr += "".join(qtoks[ix_continue:n_ix])
             rbrace_ix = findEndBrace(qtoks[n_ix + 1:]) + n_ix + 1
             ix_continue = rbrace_ix + 1
             #assert qtoks[n_ix+2] == '[', "Error in min() syntax"
             #assert qtoks[rbrace_ix-1] == ']', "Error in min() syntax"
             #new_specStr += "".join(qtoks[n_ix+3:rbrace_ix-1]) + ")"
             num_args = qtoks[n_ix + 2:ix_continue].count(',') + 1
             if num_args > 4:
                 raise NotImplementedError(
                     "Max of more than 4 arguments not currently supported in C")
             new_specStr += '__minof%s(' % str(num_args)
             new_specStr += "".join(
                 [q for q in qtoks[n_ix + 2:ix_continue] if q not in ('[', ']')])
         new_specStr += "".join(qtoks[ix_continue:])
         qspec = QuantSpec('spec', new_specStr)
         qtoks = qspec.parser.tokenized
     if '__maxof' in qtoks:
         new_specStr = ""
         num = qtoks.count('__maxof')
         n_ix = -1
         ix_continue = 0
         for _ in range(num):
             n_ix = qtoks[n_ix + 1:].index('__maxof') + n_ix + 1
             new_specStr += "".join(qtoks[ix_continue:n_ix])
             rbrace_ix = findEndBrace(qtoks[n_ix + 1:]) + n_ix + 1
             ix_continue = rbrace_ix + 1
             #assert qtoks[n_ix+2] == '[', "Error in max() syntax"
             #assert qtoks[rbrace_ix-1] == ']', "Error in max() syntax"
             #new_specStr += "".join(qtoks[n_ix+3:rbrace_ix-1]) + ")"
             num_args = qtoks[n_ix + 2:ix_continue].count(',') + 1
             if num_args > 4:
                 raise NotImplementedError(
                     "Min of more than 4 arguments not currently supported in C")
             new_specStr += '__maxof%s(' % str(num_args)
             new_specStr += "".join(
                 [q for q in qtoks[n_ix + 2:ix_continue] if q not in ('[', ']')])
         new_specStr += "".join(qtoks[ix_continue:])
         qspec = QuantSpec('spec', new_specStr)
         qtoks = qspec.parser.tokenized
     return new_specStr