Changeset ef6a512 in sasmodels


Ignore:
Timestamp:
Dec 1, 2017 4:21:44 PM (6 years ago)
Author:
Paul Kienzle <pkienzle@…>
Children:
0a9fcab
Parents:
13cf47a
Message:

order the code so dependent functions come after their dependencies

Location:
sasmodels
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/autoc.py

    rdb03406 ref6a512  
    66import ast 
    77import inspect 
     8from functools import reduce 
    89 
    910import numpy as np 
     
    3738} 
    3839 
     40DEFINES = frozenset("M_PI M_PI_2 M_PI_4 M_SQRT1_2 M_E NAN INFINITY M_PI_180 M_4PI_3".split()) 
     41 
    3942def convert(info, module): 
    4043    # type: ("ModelInfo", ModuleType) -> bool 
     
    4447    # Check if there is already C code 
    4548    if info.source or info.c_code is not None: 
    46         print("a", info.source, info.c_code) 
    4749        return 
    4850 
    4951    public_methods = "Iq", "Iqxy", "form_volume" 
    5052 
    51     tagged = [] 
    52     translate = [] 
     53    tagged = [] # type: List[str] 
     54    translate = [] # type: List[Callable] 
    5355    for function_name in public_methods: 
    5456        function = getattr(info, function_name) 
    5557        if callable(function): 
    56             translate.append(function) 
    5758            tagged.append(function_name) 
     59            translate.append((function_name, function)) 
    5860    if not translate: 
    59         print("b") 
    60         return  # nothing to translate---maybe Iq, etc. are already C snippets? 
     61        # nothing to translate---maybe Iq, etc. are already C snippets? 
     62        return 
    6163 
    62     deps = [] 
    63     code = [] 
     64    libs = []  # type: List[str] 
     65    code = {}  # type: Dict[str, str] 
     66    depends = {}  # type: Dict[str, List[str]] 
    6467    while translate: 
    65         function = translate.pop(0) 
     68        function_name, function = translate.pop(0) 
    6669        source = inspect.getsource(function) 
    6770        tree = ast.parse(source) 
     
    7073        refs = function.__code__.co_names 
    7174        snippet = codegen.to_source(tree) #, filename, offset) 
    72         code.insert(0, snippet) 
     75        code[function_name] = snippet 
     76        depends[function_name] = set(refs) 
    7377        for name in refs: 
     78            if name in tagged or name in DEFINES: 
     79                continue 
     80            tagged.append(name) 
    7481            obj = getattr(module, name, None) 
    7582            if obj is None: 
    7683                pass # ignore unbound variables for now 
    7784                #raise ValueError("global %s is not defined" % name) 
    78             elif getattr(special, name, None): 
    79                 # special symbol: look up depenencies 
    80                 deps.extend(DEPENDENCY.get(name, [])) 
    8185            elif callable(obj): 
    82                 if name not in tagged: 
    83                     translate.append(obj) 
    84                     tagged.append(name) 
     86                if getattr(special, name, None): 
     87                    # special symbol: look up depenencies 
     88                    libs.extend(DEPENDENCY.get(name, [])) 
     89                else: 
     90                    # not special: add function to translate stack 
     91                    translate.append((name, obj)) 
    8592            elif isinstance(obj, float): 
    86                 code.insert(0, "const double %s = %.15g\n"%(name, obj)) 
     93                code[name] = "const double %s = %.15g\n"%(name, obj) 
    8794            elif isinstance(obj, int): 
    88                 code.insert(0, "const int %s = %d\n"%(name, obj)) 
     95                code[name] = "const int %s = %d\n"%(name, obj) 
    8996            elif isinstance(obj, (list, tuple, np.ndarray)): 
    9097                vals = ", ".join("%.15g"%v for v in obj) 
    91                 code.insert(0, "const double %s[] = {%s};\n" %(name, vals)) 
     98                code[name] = "const double %s[] = {%s};\n" %(name, vals) 
    9299            elif isinstance(obj, special.Gauss): 
    93                 deps.append('lib/gauss%d.c'%obj.n) 
     100                libs.append('lib/gauss%d.c'%obj.n) 
    94101            else: 
    95102                raise TypeError("Could not convert global %s of type %s" 
     
    97104 
    98105    # remove duplicates from the dependecy list 
    99     unique_deps = [] 
    100     for dep in deps: 
    101         if dep not in unique_deps: 
    102             unique_deps.append(dep) 
     106    unique_libs= [] 
     107    for filename in libs: 
     108        if filename not in unique_libs: 
     109            unique_libs.append(filename) 
    103110 
    104     info.source = unique_deps 
    105     info.c_code = "\n".join(code) 
     111    info.source = unique_libs 
     112    info.c_code = "\n".join(code[k] for k in ordered_dag(depends) if k in code) 
    106113 
    107114    info.Iq = info.Iqxy = info.form_volume = None 
     
    111118 
    112119    raise RuntimeError("not yet converted...") 
     120 
     121 
     122# Modified from the following: 
     123# 
     124#    http://code.activestate.com/recipes/578272-topological-sort/ 
     125#    Copyright (C) 2012 Sam Denton 
     126#    License: MIT 
     127def ordered_dag(dag): 
     128    # type: (Dict[T, Set[T]]) -> Iterator[T] 
     129    dag = dag.copy() 
     130 
     131    # make leaves depend on the empty set 
     132    leaves = reduce(set.union, dag.values()) - set(dag.keys()) 
     133    dag.update({node: set() for node in leaves}) 
     134    while True: 
     135        leaves = set(node for node, links in dag.items() if not links) 
     136        if not leaves: 
     137            break 
     138        for node in leaves: 
     139            yield node 
     140        dag = {node: (links-leaves) 
     141               for node, links in dag.items() if node not in leaves} 
     142    if dag: 
     143        raise ValueError("Cyclic dependes exists amongst these items:\n%s" 
     144                            % ", ".join(str(node) for node in dag.keys())) 
  • sasmodels/special.py

    rdb03406 ref6a512  
    206206from numpy import fmin, fmax, trunc, rint 
    207207from numpy import pi, nan, inf 
    208 NAN = nan 
    209 INFINITY = inf 
    210  
    211208from scipy.special import gamma as sas_gamma 
    212209from scipy.special import erf as sas_erf 
     
    220217# C99 standard math constants 
    221218M_PI, M_PI_2, M_PI_4, M_SQRT1_2, M_E = np.pi, np.pi/2, np.pi/4, np.sqrt(0.5), np.e 
     219NAN = nan 
     220INFINITY = inf 
    222221 
    223222# non-standard constants 
Note: See TracChangeset for help on using the changeset viewer.