Generative Functions
Overview
A function that has been made executable by the Generative Engineering Platform is referred to as a Generative Function.
For example, a function that analyses a cantilever beam might take height, length, width, material, and applied load as inputs and return its maximum deflection, an estimated cost, and a visual representation.
Turning this into a Generative Function allows design space exploration and optimisation to be performed in the app: minimising the cantilever mass for a given load case, finding tradeoffs between cost and stiffness, or other explorations over these parameters.
All inputs and outputs from Generative Functions run in the app are stored securely in the cloud.
This section explains how to create a Generative Function from a simple Python function.
Creating a Generative Function using the decorator
To create a Generative Function in Python,
apply the @generative_function
decorator from generative.core
to a standard Python function.
Here’s a simple example using a classical cantilever deflection calculation:
where is load, is load distance from origin, is length, is youngs modulus and is second moment of area.
This example will be built on through-out this guide:
If you don’t have generative.core
available to import from, see how to initialise a code repository.
The only thing which makes this different from a standard Python function is the @generative_function
decorator.
If you don’t know what a Python decorator is, then don’t worry, you don’t need to understand it in detail. All you need to know is that adding this lets the function be exposed to the Platform when you command it to be.
If you want to learn more about Python decorators, there are lots of good resources online, for example Real Python’s guide.
This is all you need to create a basic Generative Function.
You can now connect this function to the app
using the generative.server
package and start exploring!
When you get to the app, you’ll see that each of the functions input arguments and its output are automatically created as Parameters for use in Experiments.
Typing
Standard Python type hints,
like width_m: float
and -> float
in the function signature of the above example are required.
They represent what type of data the inputs and outputs are,
and are used by the app to know what kind of data to provide for each input and what to expect to receive as output.
Parameter naming
Use clear, descriptive names for parameters, as they will be visible in the app. These names can also be updated later!
Versioning and caching
By default, the Generative app remembers (or caches) results for each Generative Function version and set of inputs. If you run the same function version with the same inputs again, the cached result is used instead of redoing the calculation. This saves time and compute costs.
Function versions are automatically generated from the Python code. Any changes to the Python code defining the Generative Functions will mean a new function version.
Caching works best when the function is pure — meaning it always produces the same output for the same inputs. If your function does use things like random numbers or an external resource (like data from a file or a web service), you might not want these results reused. In that case, you can switch off caching so that the function always recalculates:
Running in parallel
The Platform supports customisable parallel execution of Generative Functions, allowing multiple evaluations to run simultaneously with different inputs. This is configurable in the Experiments setup section of the app.
When designing Generative Functions, make sure you account for this parallelism. For instance, if the Generative Function wraps an external tool or API, structure it to avoid conflicts, for example ensuring that each evaluation doesn’t modify the same resource simultaneously.