`ExpressionMath` (Python)
=========================

.. module:: ExpressionMath

ExpressionMath is a C++/Python Library that provides access to commonly used 
graphics functions. 

All functions listed below are pre-imported in the context of parameter 
expressions, so you can use them directly, for example: ``lerp(0.5, 1, 12)``

In a Python tab or shelf script, the functions are available from the 
ExpressionMath module, for example: ``ExpressionMath.lerp(0.5, 1, 12)``

Utilities
---------

.. function:: ifelse(expression, a, b)

   If *expression* evaluates to True, return object *a*. Otherwise, return 
   object *b*. 
   
   .. warning:: BOTH inputs (*a* and *b*) are evaluated, no matter what the 
      expression evaluates to. Unfortunately. this is inherent to Python 
      argument handling and is not fixable.

.. function:: clamp(value, a, b)

   Return value, clamped between the extremes *a* and *b*. It is not necessary 
   for ``b > a``. Mixed scalar / vector inputs are supported for all arguments.
   
      >>> clamp(-0.5, 0.1, 0.9)
      0.1
      >>> clamp(-0.5, 0.9, 0.1)
      0.1
      >>> clamp((-0.5,0.0,0.5,1.0), 0.1, 0.9)
      (0.1, 0.1, 0.5, 0.9) 

.. function:: lerp(mix, a, b)

   Return a linear interpolation between *a* and *b*, combined using the 
   fraction *mix*. *mix* is not clamped between [0,1]. A *mix* value of 0.0 
   returns *a*. Mixed scalar / vector inputs are supported for all arguments.
   
      >>> lerp(0.0, 10, 20)
      10.0
      >>> lerp(0.5, 10, 20)
      15.0
      >>> lerp(1.5, 10, 20)
      25.0
      >>> lerp((0.0,0.5,1.5), 10, 20)
      (10.0, 15.0, 25.0)
      >>> lerp(0.5, 10, (20,30,40))
      (15.0, 20.0, 25.0)

.. function:: smoothstep(t)

   Compute a smoothstep (ease in, ease out) version of *t*: [0,1]. This will 
   clamp the output to [0,1].
   
   Both scalar and vector input is supported.
   
   .. note:: This is the 'classic' smoothstep: ``3t**2 - 2t**3``, rather Perlin
      [02] modified smoothstep: ``6t**5 - 15t**4 + 10t**3``. The two are quite 
      similar, the differences being that Perlin's smoothstep has zero 1st and 
      2nd derivatives at ``t=0`` and ``t=1``, and is thus generally preferred 
      for general use.  
    
   ::
   
      >>> smoothstep(0.2)
      0.05792
      >>> smoothstep((-0.5, 0.0, 0.25, 0.5, 0.75, 1.0, 1.5))
      (0.0, 0.0, 0.103515625, 0.5, 0.896484375, 1.0, 1.0) 

.. function:: fit(value, oldmin, oldmax, newmin, newmax)

   Returns a number between *newmin* and *newmax*, which is relative to *value*
   in the range between *oldmin* and *oldmax*.
   
   Mixed scalar / vector inputs are supported for all arguments. 
   
      >>> fit(0, -1, 1, 10, 20)
      15.0
      >>> fit(2, -1, 1, 10, 20)
      25.0
      >>> fit((-1,0.5,0.5,1), -1, 1, 10, 20)
      (10.0, 17.5, 17.5, 20.0) 

.. function:: cfit(value, oldmin, oldmax, newmin, newmax) 

   Same as fit, but the result is clamped to [*newmin*, *newmax*].
   
   Mixed scalar / vector inputs are supported for all arguments. 
   
      >>> cfit(0, -1, 1, 10, 20)
      15.0
      >>> cfit(2, -1, 1, 10, 20)
      20.0
      >>> cfit((-1,0.5,0.5,1), -1, 1, 10, 20)
      (10.0, 17.5, 17.5, 20.0)

.. function:: softcfit(value, oldmin, oldmax, newmin, newmax)

   Same as cfit, but value is interpolates between *oldmin* and *oldmax* using 
   :func:`smoothstep`. 
   
   Mixed scalar / vector inputs are supported for all arguments. 
   
      >>> softcfit(0, -1, 1, 10, 20)
      15.0
      >>> softcfit(2, -1, 1, 10, 20)
      20.0
      >>> softcfit((-1,0.5,0.5,1), -1, 1, 10, 20)
      (10.0, 18.96484375, 18.96484375, 20.0) 

.. function:: retime(frame, start, end, inMode, outMode)

   Performs frame interpolation using specified hold mode: 'freeze', 'repeat',
   or 'mirror'. 
   
   freeze
      Hold the first/last frame of the sequence: ``1111 1234 4444``
   repeat
      Repeat the sequence: ``1234 1234 1234``
   mirror
      Mirror the sequence, end points are only used once: ``3432 1234 3212``
   
   .. note:: Repeat mode may generate values outside of [*start*, *end*] at 
      non-integer time samples (due to extrapolation). 
   
   Supports float input for {*frame*, *start*, *end*}. It is not necessary for 
   ``start < end`` (though ``start != end``). 
   
      >>> retime(110, 101, 110, 'repeat', 'repeat')
      110.0
      >>> retime(111, 101, 110, 'repeat', 'repeat')
      101.0
      >>> retime(112, 101, 110, 'repeat', 'repeat')
      102.0
      >>> retime(111, 101, 110, 'repeat', 'freeze')
      110.0
      >>> retime(112, 101, 110, 'repeat', 'freeze')
      110.0
      >>> retime(111, 101, 110, 'repeat', 'mirror')
      109.0
      >>> retime(112, 101, 110, 'repeat', 'mirror')
      108.0

Noise
-----

.. function:: noise(x [,y [,z [,w]]]]) 

   Improved Perlin noise [02], contained within the range [0,1]. The noise is 
   generated by smoothing interpolating a set a pseudo-random gradients at 
   regularly spaced points in space (integer lattice locations). The 
   statistical characteristics of this call closely approximates that of 
   PRman's noise operator. One, two, three, and four-dimensional interpolants 
   are provided. 
   
      >>> noise(0.0)
      0.5
      >>> noise(0.5)
      0.40600001811981201
      >>> noise(1.0)
      0.5
      >>> noise(0.5,0.5)
      0.6901249885559082
      >>> noise(0.5)
      0.6901249885559082 

.. function:: snoise(x [,y [,z [,w]]]])

   Signed equivalent of :func:`noise`.
   
      >>> snoise(0.0)
      0.0
      >>> snoise(0.5)
      -0.18799999356269836
      >>> snoise(1.0)
      0.0
      >>> snoise(0.5,0.5)
      0.38025002181529999 

.. function:: randval(min, max, seedInt)

   Return a random value between [*min*, *max*] using the specified seed 
   integer. The distribution is identical to Splat's randVal3 function. 
   
      >>> randval(0,1,0)
      0.22541344799693055
      >>> randval(0,1,1)
      0.16124458358652066
      >>> randval(0,2,1)
      0.32248916717304132
      >>> [randval(0,1,frame) for frame in xrange(101,103)]
      [0.77299156360630683, 0.83146012384245638, 0.099642227194188679] 

Hashing
-------

.. function:: stablehash(string)

   Return a 32-bit signed integer hash of the specified string. This result is 
   stable across architectures (i.e., you get the same answer on both 32- and 
   64-bit platforms.) This result is often useful for turning strings (such as 
   scenegraph locations) into seedIntegers for use in randval (see above). 

      >>> stablehash('')
      2118318316
      >>> stablehash('/root/world/lights/rig/key1')
      -847711557
      >>> stablehash('/root/world/lights/rig/key2')
      652177629 

Floating Point
--------------

.. function:: isinf(number)

   Return whether the argument value is an infinity (positive or negative). 
   
      >>> isinf(1.0)
      False
      >>> isinf(float('inf'))
      True 

.. function:: isnan(number) 

   Return whether the argument value is a NaN. 
   
      >>> isnan(1.0)
      False
      >>> isinf(float('nan'))
      True 

.. function:: isfinite(number)

   Return whether the argument value is a finite value (zero, subnormal, or 
   normal, and not infinite or NaN).
   
      >>> isfinite(1.0)
      True
      >>> isfinite(float('nan'))
      False
      >>> isfinite(float('inf'))
      False
      >>> isfinite(float('-inf'))
      False