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:

deflection=Pa2(3La)/(6EIxx)deflection = P * a^2 * (3 * L - a) / (6 * E * Ixx)

where PP is load, aa is load distance from origin, LL is length, EE is youngs modulus and IxxIxx is second moment of area.

This example will be built on through-out this guide:

from generative.core import generative_function

@generative_function
def cantilever_point_load_analysis(
    width_m: float,
    depth_m: float,
    length_m: float,
    force_newtons: float,
    force_location_proportion: float,
    modulus_pascals: float
) -> float:
    load_location = force_location_proportion * length_m
    second_mom_area_m4 = (width_m * depth_m**3) / 12
    numerator = force_newtons * load_location**2 * (3 * length_m - load_location)
    deflection = numerator / (6 * modulus_pascals * second_mom_area_m4)
    return deflection

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:

from generative.core import generative_function

@generative_function(cacheable=False)
def my_function(value: int) -> int:
    ...

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.