Changeset 2e49f9e in sasmodels for sasmodels/generate.py


Ignore:
Timestamp:
Sep 12, 2016 1:41:55 AM (8 years ago)
Author:
Paul Kienzle <pkienzle@…>
Branches:
master, core_shell_microgels, costrafo411, magnetic_model, release_v0.94, release_v0.95, ticket-1257-vesicle-product, ticket_1156, ticket_1265_superball, ticket_822_more_unit_tests
Children:
80013a6
Parents:
b217c71
Message:

improve plugin portability: OSX wants 1e8⇒1e8f and acos(0)⇒ acos(0.f)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/generate.py

    r6592f56 r2e49f9e  
    362362    for long double precision. 
    363363    """ 
     364    source = _fix_tgmath_int(source) 
    364365    if dtype == F16: 
    365366        fbytes = 2 
     
    391392    source = re.sub(r'(^|[^a-zA-Z0-9_]c?)double(([248]|16)?($|[^a-zA-Z0-9_]))', 
    392393                    r'\1%s\2'%type_name, source) 
     394    source = _tag_float(source, constant_flag) 
     395    return source 
     396 
     397TGMATH_INT_RE = re.compile(r""" 
     398(?: # Non-capturing match; not lookbehind since pattern length is variable 
     399  \b              # word boundary 
     400   # various math functions 
     401  (a?(sin|cos|tan)h? | atan2 
     402   | erfc? | tgamma 
     403   | exp(2|10|m1)? | log(2|10|1p)? | pow[nr]? | sqrt | rsqrt | rootn 
     404   | fabs | fmax | fmin 
     405   ) 
     406  \s*[(]\s*       # open parenthesis 
     407) 
     408[+-]?(0|[1-9]\d*) # integer 
     409(?=               # lookahead match: don't want to move from end of int 
     410  \s*[,)]         # comma or close parenthesis for end of argument 
     411)                 # end lookahead 
     412""", re.VERBOSE) 
     413def _fix_tgmath_int(source): 
     414    # type: (str) -> str 
     415    """ 
     416    Replace f(integer) with f(integer.) for sin, cos, pow, etc. 
     417 
     418    OS X OpenCL complains that it can't resolve the type generic calls to 
     419    the standard math functions when they are called with integer constants, 
     420    but this does not happen with the Windows Intel driver for example. 
     421    To avoid confusion on the matrix marketplace, automatically promote 
     422    integers to floats if we recognize them in the source. 
     423 
     424    The specific functions we look for are: 
     425 
     426        trigonometric: sin, asin, sinh, asinh, etc., and atan2 
     427        exponential:   exp, exp2, exp10, expm1, log, log2, log10, logp1 
     428        power:         pow, pown, powr, sqrt, rsqrt, rootn 
     429        special:       erf, erfc, tgamma 
     430        float:         fabs, fmin, fmax 
     431 
     432    Note that we don't convert the second argument of dual argument 
     433    functions: atan2, fmax, fmin, pow, powr.  This could potentially 
     434    be a problem for pow(x, 2), but that case seems to work without change. 
     435    """ 
     436    out = TGMATH_INT_RE.sub(r'\g<0>.', source) 
     437    return out 
     438 
     439 
     440# Floating point regular expression 
     441# 
     442# Define parts: 
     443# 
     444#    E = [eE][+-]?\d+    : Exponent 
     445#    P = [.]             : Decimal separator 
     446#    N = [1-9]\d*        : Natural number, no leading zeros 
     447#    Z = 0               : Zero 
     448#    F = \d+             : Fractional number, maybe leading zeros 
     449#    F? = \d*            : Optional fractional number 
     450# 
     451# We want to reject bare natural numbers and bare decimal points, so we 
     452# need to tediously outline the cases where we have either a fraction or 
     453# an exponent: 
     454# 
     455#   ( ZP | ZPF | ZE | ZPE | ZPFE | NP | NPF | NE | NPE | NPFE | PF | PFE ) 
     456# 
     457# 
     458# We can then join cases by making parts optional.  The following are 
     459# some ways to do this: 
     460# 
     461#   ( (Z|N)(P|PF|E|PE|PFE) | PFE? )                   # Split on lead 
     462#     => ( (Z|N)(PF?|(PF?)?E) | PFE? ) 
     463#   ( ((Z|N)PF?|PF)E? | (Z|N)E)                       # Split on point 
     464#   ( (ZP|ZPF|NP|NPF|PF) | (Z|ZP|ZPF|N|NP|NPF|PF)E )  # Split on E 
     465#     => ( ((Z|N)PF?|PF) | ((Z|N)(PF?)? | PF) E ) 
     466FLOAT_RE = re.compile(r""" 
     467    (?<!\w)  # use negative lookbehind since '.' confuses \b test 
     468    # use split on lead to match float ( (Z|N)(PF?|(PF?)?E) | PFE? ) 
     469    ( ( 0 | [1-9]\d* )                     # ( ( Z | N ) 
     470      ([.]\d* | ([.]\d*)? [eE][+-]?\d+ )   #   (PF? | (PF?)? E ) 
     471    | [.]\d+ ([eE][+-]?\d+)?               # | PF (E)? 
     472    )                                      # ) 
     473    (?!\w)  # use negative lookahead since '.' confuses \b test 
     474    """, re.VERBOSE) 
     475def _tag_float(source, constant_flag): 
    393476    # Convert floating point constants to single by adding 'f' to the end, 
    394477    # or long double with an 'L' suffix.  OS/X complains if you don't do this. 
    395     source = re.sub(r'[^a-zA-Z_](\d*[.]\d+|\d+[.]\d*)([eE][+-]?\d+)?', 
    396                     r'\g<0>%s'%constant_flag, source) 
    397     return source 
     478    out = FLOAT_RE.sub(r'\g<0>%s'%constant_flag, source) 
     479    #print("in",repr(source),"out",repr(out), constant_flag) 
     480    return out 
     481 
     482def test_tag_float(): 
     483 
     484    cases=""" 
     485ZP  : 0. 
     486ZPF : 0.0,0.01,0.1 
     487Z  E: 0e+001 
     488ZP E: 0.E0 
     489ZPFE: 0.13e-031 
     490NP  : 1., 12. 
     491NPF : 1.0001, 1.1, 1.0 
     492N  E: 1e0, 37E-080 
     493NP E: 1.e0, 37.E-080 
     494NPFE: 845.017e+22 
     495 PF : .1, .0, .0100 
     496 PFE: .6e+9, .82E-004 
     497# isolated cases 
     4980. 
     4991e0 
     5000.13e-013 
     501# untouched 
     502struct3.e3, 03.05.67, 37 
     503# expressions 
     5043.75+-1.6e-7-27+13.2 
     505a3.e2 - 0. 
     5064*atan(1) 
     5074.*atan(1.) 
     508""" 
     509 
     510    output=""" 
     511ZP  : 0.f 
     512ZPF : 0.0f,0.01f,0.1f 
     513Z  E: 0e+001f 
     514ZP E: 0.E0f 
     515ZPFE: 0.13e-031f 
     516NP  : 1.f, 12.f 
     517NPF : 1.0001f, 1.1f, 1.0f 
     518N  E: 1e0f, 37E-080f 
     519NP E: 1.e0f, 37.E-080f 
     520NPFE: 845.017e+22f 
     521 PF : .1f, .0f, .0100f 
     522 PFE: .6e+9f, .82E-004f 
     523# isolated cases 
     5240.f 
     5251e0f 
     5260.13e-013f 
     527# untouched 
     528struct3.e3, 03.05.67, 37 
     529# expressions 
     5303.75f+-1.6e-7f-27+13.2f 
     531a3.e2 - 0.f 
     5324*atan(1) 
     5334.f*atan(1.f) 
     534""" 
     535 
     536    for case_in, case_out in zip(cases.split('\n'), output.split('\n')): 
     537        out = _tag_float(case_in, 'f') 
     538        assert case_out == out, "%r => %r"%(case_in, out) 
    398539 
    399540 
Note: See TracChangeset for help on using the changeset viewer.