Skip to content

Quickstart¤

This notebook walks you through a complete f3dasm workflow: defining a parameter space, sampling experiments, evaluating them with an objective function, running an optimization loop, and inspecting the results.

By the end, you'll understand the core building blocks and how they fit together.

1. Define a parameter space¤

Every experiment starts with a Domain — the parameter space that defines what inputs your experiment can have.

from f3dasm.design import Domain

domain = Domain()
domain.add_float(name="x0", low=-5.0, high=5.0)
domain.add_float(name="x1", low=-5.0, high=5.0)
domain.add_output("y")

domain

2. Create an ExperimentData object¤

ExperimentData is the central data container that holds all your experiments (inputs and outputs).

from f3dasm import ExperimentData

data = ExperimentData(domain=domain)
data

3. Sample initial experiments¤

Use a sampler to generate initial experiments. Here we use Latin Hypercube sampling to create 10 samples.

from f3dasm import create_sampler

sampler = create_sampler("latin", seed=42)
data = sampler.call(data, n_samples=10)

data

4. Evaluate experiments¤

Use a data generator to evaluate each sample. Here we define our own objective with the @datagenerator decorator: a simple paraboloid with its minimum at (1.5, -2.0).

from f3dasm import datagenerator


@datagenerator(output_names="y")
def f(x0: float, x1: float) -> float:
    return (x0 - 1.5) ** 2 + (x1 + 2.0) ** 2


f.arm(data)
data = f.call(data)

data

5. Optimize¤

Optimization in f3dasm is expressed by composing blocks. We use the built-in TPE update-step block, chain it with our data generator, and wrap the pair in a LoopBlock to run 30 iterations:

(update_step >> data_generator).loop(n_iterations)

See the Optimization Loops tutorial for a deeper explanation of this pattern.

from f3dasm import create_optimizer

update_step = create_optimizer("tpesampler", output_name="y")
loop = (update_step >> f).loop(30)
loop.arm(data)
data = loop.call(data)

print(
    f"Total rows after optimization: {len(data)}"
)  # 10 initial + 30 iterations

6. Inspect the results¤

You can convert the data to a pandas DataFrame for inspection.

df_input, df_output = data.to_pandas()

print("Best result:")
best_idx = df_output["y"].idxmin()
print(f"  x0 = {df_input.loc[best_idx, 'x0']:.4f}")
print(f"  x1 = {df_input.loc[best_idx, 'x1']:.4f}")
print(f"  y  = {df_output.loc[best_idx, 'y']:.4f}")

Next steps¤

Now that you've seen the basics, explore the tutorials in more depth: