Ejemplo n.º 1
0
 def generate_spec(self):
     assert self.fspec.targetlang == "python", "Wrong target language for this" " call"
     assert self.fspec.varspecs != {}, "varspecs attribute must be defined"
     specnames_unsorted = list(self.fspec.varspecs.keys())
     _vbfs_inv = invertMap(self.fspec._varsbyforspec)
     # Process state variable specifications
     if len(_vbfs_inv) > 0:
         specname_vars = []
         specname_auxvars = []
         for varname in self.fspec.vars:
             # check if varname belongs to a for macro grouping in
             # self.fspec.varspecs
             if varname not in specname_vars:
                 specname_vars.append(varname)
         for varname in self.fspec.auxvars:
             # check if varname belongs to a for macro grouping in
             # self.fspec.varspecs
             if varname not in specname_auxvars:
                 specname_auxvars.append(varname)
     else:
         specname_vars = intersect(self.fspec.vars, specnames_unsorted)
         specname_auxvars = intersect(self.fspec.auxvars, specnames_unsorted)
     specname_vars.sort()
     for vn, vs in list(self.fspec.varspecs.items()):
         if any([pt in vs for pt in ("^", "**")]):
             self.fspec.varspecs[vn] = convertPowers(vs, "pow")
     self.fspec.vars.sort()
     reusestr, specupdated = self._processReusedPy(specname_vars, self.fspec.varspecs)
     self.fspec.varspecs.update(specupdated)
     temp = self._specStrParse(specname_vars, self.fspec.varspecs, "xnew")
     specstr_py = self._generate_fun("_specfn", reusestr + temp, "xnew", specname_vars, docodeinserts=True)
     # Process auxiliary variable specifications
     specname_auxvars.sort()
     assert self.fspec.auxvars == specname_auxvars, (
         "Mismatch between declared auxiliary" " variable names and varspecs keys"
     )
     reusestraux, specupdated = self._processReusedPy(specname_auxvars, self.fspec.varspecs)
     self.fspec.varspecs.update(specupdated)
     tempaux = self._specStrParse(specname_auxvars, self.fspec.varspecs, "auxvals")
     auxspecstr_py = self._generate_fun(
         "_auxspecfn", reusestraux + tempaux, "auxvals", specname_auxvars, docodeinserts=True
     )
     try:
         spec_info = makeUniqueFn(specstr_py)
     except SyntaxError:
         print("Syntax error in specification:\n" + specstr_py)
         raise
     try:
         auxspec_info = makeUniqueFn(auxspecstr_py)
     except SyntaxError:
         print("Syntax error in auxiliary spec:\n" + auxspecstr_py)
         raise
     self.fspec.spec = spec_info
     self.fspec.auxspec = auxspec_info
Ejemplo n.º 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
Ejemplo n.º 3
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
Ejemplo n.º 4
0
 def generate_spec(self):
     assert self.fspec.targetlang == 'python', (
         'Wrong target language for this'
         ' call')
     assert self.fspec.varspecs != {}, 'varspecs attribute must be defined'
     specnames_unsorted = list(self.fspec.varspecs.keys())
     _vbfs_inv = invertMap(self.fspec._varsbyforspec)
     # Process state variable specifications
     if len(_vbfs_inv) > 0:
         specname_vars = []
         specname_auxvars = []
         for varname in self.fspec.vars:
             # check if varname belongs to a for macro grouping in
             # self.fspec.varspecs
             if varname not in specname_vars:
                 specname_vars.append(varname)
         for varname in self.fspec.auxvars:
             # check if varname belongs to a for macro grouping in
             # self.fspec.varspecs
             if varname not in specname_auxvars:
                 specname_auxvars.append(varname)
     else:
         specname_vars = intersect(self.fspec.vars, specnames_unsorted)
         specname_auxvars = intersect(self.fspec.auxvars,
                                      specnames_unsorted)
     specname_vars.sort()
     for vn, vs in list(self.fspec.varspecs.items()):
         if any([pt in vs for pt in ('^', '**')]):
             self.fspec.varspecs[vn] = convertPowers(vs, 'pow')
     self.fspec.vars.sort()
     reusestr, specupdated = self._processReusedPy(specname_vars,
                                                   self.fspec.varspecs)
     self.fspec.varspecs.update(specupdated)
     temp = self._specStrParse(specname_vars, self.fspec.varspecs, 'xnew')
     specstr_py = self._generate_fun('_specfn',
                                     reusestr + temp,
                                     'xnew',
                                     specname_vars,
                                     docodeinserts=True)
     # Process auxiliary variable specifications
     specname_auxvars.sort()
     assert self.fspec.auxvars == specname_auxvars, \
         ('Mismatch between declared auxiliary'
          ' variable names and varspecs keys')
     reusestraux, specupdated = self._processReusedPy(
         specname_auxvars, self.fspec.varspecs)
     self.fspec.varspecs.update(specupdated)
     tempaux = self._specStrParse(specname_auxvars, self.fspec.varspecs,
                                  'auxvals')
     auxspecstr_py = self._generate_fun('_auxspecfn',
                                        reusestraux + tempaux,
                                        'auxvals',
                                        specname_auxvars,
                                        docodeinserts=True)
     try:
         spec_info = makeUniqueFn(specstr_py)
     except SyntaxError:
         print("Syntax error in specification:\n" + specstr_py)
         raise
     try:
         auxspec_info = makeUniqueFn(auxspecstr_py)
     except SyntaxError:
         print("Syntax error in auxiliary spec:\n" + auxspecstr_py)
         raise
     self.fspec.spec = spec_info
     self.fspec.auxspec = auxspec_info
Ejemplo n.º 5
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
Ejemplo n.º 6
0
 def generate_spec(self):
     assert self.fspec.targetlang == "c", "Wrong target language for this" " call"
     assert self.fspec.varspecs != {}, "varspecs attribute must be defined"
     specnames_unsorted = list(self.fspec.varspecs.keys())
     _vbfs_inv = invertMap(self.fspec._varsbyforspec)
     # Process state variable specifications
     if len(_vbfs_inv) > 0:
         specname_vars = []
         specname_auxvars = []
         for varname in self.fspec.vars:
             # check if varname belongs to a for macro grouping in
             # self.fspec.varspecs
             if varname not in specname_vars:
                 specname_vars.append(varname)
         for varname in self.fspec.auxvars:
             # check if varname belongs to a for macro grouping in
             # self.fspec.varspecs
             if varname not in specname_auxvars:
                 specname_auxvars.append(varname)
     else:
         specname_vars = intersect(self.fspec.vars, specnames_unsorted)
         specname_auxvars = intersect(self.fspec.auxvars, specnames_unsorted)
     specname_vars.sort()
     # sorted version of var and par names
     pnames = self.fspec.pars
     inames = self.fspec.inputs
     pnames.sort()
     inames.sort()
     pardefines = ""
     vardefines = ""
     inpdefines = ""
     parundefines = ""
     varundefines = ""
     inpundefines = ""
     # produce vector field specification
     assert self.fspec.vars == specname_vars, (
         "Mismatch between declared " " variable names and varspecs keys"
     )
     valid_depTargNames = self.fspec.inputs + self.fspec.vars + self.fspec.auxvars
     for specname, specstr in self.fspec.varspecs.items():
         assert type(specstr) == str, (
             "Specification for %s was not a string" % specname
         )
         if any([pt in specstr for pt in ("^", "**")]):
             self.fspec.varspecs[specname] = convertPowers(specstr, "pow")
     # pre-process reused sub-expression dictionary to adapt for
     # known calling sequence in C
     reusestr, specupdated = self._processReusedC(specname_vars, self.fspec.varspecs)
     self.fspec.varspecs.update(specupdated)
     specstr_C = self._generate_fun(
         "vfieldfunc",
         reusestr,
         specname_vars,
         pardefines,
         vardefines,
         inpdefines,
         parundefines,
         varundefines,
         inpundefines,
         True,
     )
     self.fspec.spec = specstr_C
     # produce auxiliary variables specification
     specname_auxvars.sort()
     assert self.fspec.auxvars == specname_auxvars, (
         "Mismatch between declared auxiliary" " variable names and varspecs keys"
     )
     if self.fspec.auxvars != []:
         reusestraux, specupdated = self._processReusedC(
             specname_auxvars, self.fspec.varspecs
         )
         self.fspec.varspecs.update(specupdated)
     if self.fspec.auxvars == []:
         auxspecstr_C = self._generate_fun(
             "auxvars", "", specname_auxvars, "", "", "", "", "", "", False
         )
     else:
         auxspecstr_C = self._generate_fun(
             "auxvars",
             reusestraux,
             specname_auxvars,
             pardefines,
             vardefines,
             inpdefines,
             parundefines,
             varundefines,
             inpundefines,
             False,
         )
     self.fspec.auxspec = auxspecstr_C
Ejemplo n.º 7
0
def test_convertPowers(target, expected):
    s = 'pow(x,3)'
    assert expected == convertPowers(s, target=target)
Ejemplo n.º 8
0
 def _normalize_spec(self, spec):
     if any([pt in spec for pt in ('pow', '**', '^')]):
         spec = convertPowers(spec, self.opts['power_sign'])
     spec = self._process_builtins(spec)
     return spec
Ejemplo n.º 9
0
 def generate_spec(self):
     assert self.fspec.targetlang == 'c', ('Wrong target language for this'
                                      ' call')
     assert self.fspec.varspecs != {}, 'varspecs attribute must be defined'
     specnames_unsorted = list(self.fspec.varspecs.keys())
     _vbfs_inv = invertMap(self.fspec._varsbyforspec)
     # Process state variable specifications
     if len(_vbfs_inv) > 0:
         specname_vars = []
         specname_auxvars = []
         for varname in self.fspec.vars:
             # check if varname belongs to a for macro grouping in
             # self.fspec.varspecs
             if varname not in specname_vars:
                 specname_vars.append(varname)
         for varname in self.fspec.auxvars:
             # check if varname belongs to a for macro grouping in
             # self.fspec.varspecs
             if varname not in specname_auxvars:
                 specname_auxvars.append(varname)
     else:
         specname_vars = intersect(self.fspec.vars, specnames_unsorted)
         specname_auxvars = intersect(self.fspec.auxvars, specnames_unsorted)
     specname_vars.sort()
     # sorted version of var and par names
     pnames = self.fspec.pars
     inames = self.fspec.inputs
     pnames.sort()
     inames.sort()
     pardefines = ""
     vardefines = ""
     inpdefines = ""
     parundefines = ""
     varundefines = ""
     inpundefines = ""
     # produce vector field specification
     assert self.fspec.vars == specname_vars, ('Mismatch between declared '
                                          ' variable names and varspecs keys')
     valid_depTargNames = self.fspec.inputs + self.fspec.vars + self.fspec.auxvars
     for specname, specstr in self.fspec.varspecs.items():
         assert type(
             specstr) == str, "Specification for %s was not a string" % specname
         if any([pt in specstr for pt in ('^', '**')]):
             self.fspec.varspecs[specname] = convertPowers(specstr, 'pow')
     # pre-process reused sub-expression dictionary to adapt for
     # known calling sequence in C
     reusestr, specupdated = self._processReusedC(specname_vars,
                                                  self.fspec.varspecs)
     self.fspec.varspecs.update(specupdated)
     specstr_C = self._generate_fun(
         'vfieldfunc', reusestr, specname_vars,
         pardefines, vardefines, inpdefines,
         parundefines, varundefines, inpundefines,
         True)
     self.fspec.spec = specstr_C
     # produce auxiliary variables specification
     specname_auxvars.sort()
     assert self.fspec.auxvars == specname_auxvars, \
         ('Mismatch between declared auxiliary'
          ' variable names and varspecs keys')
     if self.fspec.auxvars != []:
         reusestraux, specupdated = self._processReusedC(
             specname_auxvars,
             self.fspec.varspecs)
         self.fspec.varspecs.update(specupdated)
     if self.fspec.auxvars == []:
         auxspecstr_C = self._generate_fun('auxvars', '',
                                           specname_auxvars,
                                           '', '', '',
                                           '', '', '', False)
     else:
         auxspecstr_C = self._generate_fun('auxvars', reusestraux,
                                           specname_auxvars, pardefines,
                                           vardefines, inpdefines, parundefines,
                                           varundefines, inpundefines,
                                           False)
     self.fspec.auxspec = auxspecstr_C
Ejemplo n.º 10
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
Ejemplo n.º 11
0
 def _normalize_spec(self, spec):
     if any([pt in spec for pt in ('pow', '**', '^')]):
         spec = convertPowers(spec, self.opts['power_sign'])
     spec = self._process_builtins(spec)
     return spec
Ejemplo n.º 12
0
def test_convertPowers(target, expected):
    s = 'pow(x,3)'
    assert expected == convertPowers(s, target=target)
Ejemplo n.º 13
0
 def _normalize_spec(self, spec):
     if any([pt in spec for pt in ("pow", "**", "^")]):
         spec = convertPowers(spec, self.opts["power_sign"])
     spec = self._process_builtins(spec)
     return spec