Make a function node, a representation of a mathematical relationship. This factory function creates a function node, one of the core nodes in any program. The resulting object is able to be called with NumPy vectorized arguments and return a resulting vector based on a mathematical
(function, name, arity, wrap=True)
| 50 | |
| 51 | |
| 52 | def make_function(function, name, arity, wrap=True): |
| 53 | """Make a function node, a representation of a mathematical relationship. |
| 54 | |
| 55 | This factory function creates a function node, one of the core nodes in any |
| 56 | program. The resulting object is able to be called with NumPy vectorized |
| 57 | arguments and return a resulting vector based on a mathematical |
| 58 | relationship. |
| 59 | |
| 60 | Parameters |
| 61 | ---------- |
| 62 | function : callable |
| 63 | A function with signature `function(x1, *args)` that returns a Numpy |
| 64 | array of the same shape as its arguments. |
| 65 | |
| 66 | name : str |
| 67 | The name for the function as it should be represented in the program |
| 68 | and its visualizations. |
| 69 | |
| 70 | arity : int |
| 71 | The number of arguments that the `function` takes. |
| 72 | |
| 73 | wrap : bool, optional (default=True) |
| 74 | When running in parallel, pickling of custom functions is not supported |
| 75 | by Python's default pickler. This option will wrap the function using |
| 76 | cloudpickle allowing you to pickle your solution, but the evolution may |
| 77 | run slightly more slowly. If you are running single-threaded in an |
| 78 | interactive Python session or have no need to save the model, set to |
| 79 | `False` for faster runs. |
| 80 | |
| 81 | """ |
| 82 | if not isinstance(arity, int): |
| 83 | raise ValueError('arity must be an int, got %s' % type(arity)) |
| 84 | if not isinstance(function, np.ufunc): |
| 85 | if function.__code__.co_argcount != arity: |
| 86 | raise ValueError('arity %d does not match required number of ' |
| 87 | 'function arguments of %d.' |
| 88 | % (arity, function.__code__.co_argcount)) |
| 89 | if not isinstance(name, str): |
| 90 | raise ValueError('name must be a string, got %s' % type(name)) |
| 91 | if not isinstance(wrap, bool): |
| 92 | raise ValueError('wrap must be an bool, got %s' % type(wrap)) |
| 93 | |
| 94 | # Check output shape |
| 95 | args = [np.ones(10) for _ in range(arity)] |
| 96 | try: |
| 97 | function(*args) |
| 98 | except ValueError: |
| 99 | raise ValueError('supplied function %s does not support arity of %d.' |
| 100 | % (name, arity)) |
| 101 | if not hasattr(function(*args), 'shape'): |
| 102 | raise ValueError('supplied function %s does not return a numpy array.' |
| 103 | % name) |
| 104 | if function(*args).shape != (10,): |
| 105 | raise ValueError('supplied function %s does not return same shape as ' |
| 106 | 'input vectors.' % name) |
| 107 | |
| 108 | # Check closure for zero & negative input arguments |
| 109 | args = [np.zeros(10) for _ in range(arity)] |