Dependencies between objective functionsΒΆ

In multi-objective optimization, there are two main types of dependencies between objectives.

  • Shared decision variables β€” multiple objectives use common decision variables

  • Constraint-based dependencies β€” decision variables across objectives are linked by constraints

These can be handled individually or in combination.

Shared decision variablesΒΆ

This is the most basic case: multiple objectives share a variable β€” for example, g(x, y) and h(y, z) both use y.

from amplify_bbopt import blackbox, RealVariable

@blackbox
def bbfunc(
    x: float = RealVariable((0, 1)),
    y: float = RealVariable((0, 1)),
    z: float = RealVariable((0, 1)),
) -> list[float]:
    return [g(x, y), h(y, z)]

When the shared variable y changes, both objective values change. This dependency is fully expressed by the black-box function definition alone β€” no additional configuration is needed for MultiOptimizer.

from amplify_bbopt import KMTrainer, MultiOptimizer

optimizer = MultiOptimizer(
    blackbox=bbfunc,
    trainer=[KMTrainer(), KMTrainer()],
    client=my_client,
)
optimizer.add_random_training_data(num_data=10)
optimizer.optimize(10)
Using Optimizer instead
from amplify_bbopt import blackbox, KMTrainer, Optimizer, RealVariable

w_g = 10
w_h = 2

@blackbox
def bbfunc(
    x: float = RealVariable((0, 1)),
    y: float = RealVariable((0, 1)),
    z: float = RealVariable((0, 1)),
) -> float:
    return w_g * g(x, y) + w_h * h(y, z)

optimizer = Optimizer(
    blackbox=bbfunc,
    trainer=KMTrainer(),
    client=my_client,
)
optimizer.add_random_training_data(num_data=10)
optimizer.optimize(10)

Constraint-based dependenciesΒΆ

Even if objectives do not share decision variables β€” such as g(x, y) and h(z) β€” you can introduce an indirect dependency by imposing a constraint such as x + z ≀ 2.

from amplify_bbopt import blackbox, RealVariable
import amplify

@blackbox
def bbfunc(
    x: float = RealVariable((0, 2)),
    y: float = RealVariable((0, 1)),
    z: float = RealVariable((0, 2)),
) -> list[float]:
    return [g(x, y), h(z)]

# Extract decision variable objects and define the constraint
var = bbfunc.variables
constraint = amplify.less_equal(var.x + var.z, 2)

Pass the constraint when instantiating MultiOptimizer.

from amplify_bbopt import KMTrainer, MultiOptimizer

optimizer = MultiOptimizer(
    blackbox=bbfunc,
    trainer=[KMTrainer(), KMTrainer()],
    client=my_client,
    constraints=constraint,
)
optimizer.add_random_training_data(num_data=10)
optimizer.optimize(10)

Note

For details on constraint configuration (hard constraints, soft constraints), see Constraint Conditions.

Using Optimizer instead
from amplify_bbopt import blackbox, KMTrainer, Optimizer, RealVariable
import amplify

w_g = 10
w_h = 2

@blackbox
def bbfunc(
    x: float = RealVariable((0, 2)),
    y: float = RealVariable((0, 1)),
    z: float = RealVariable((0, 2)),
) -> float:
    return w_g * g(x, y) + w_h * h(z)

var = bbfunc.variables
constraint = amplify.less_equal(var.x + var.z, 2)

optimizer = Optimizer(
    blackbox=bbfunc,
    trainer=KMTrainer(),
    client=my_client,
    constraints=constraint,
)
optimizer.add_random_training_data(num_data=10)
optimizer.optimize(10)

Combining both typesΒΆ

You can also handle cases where both shared-variable and constraint-based dependencies exist simultaneously. For example, g(x, y) and h(y, z) share variable y while also being subject to the constraint x + z ≀ 2.

from amplify_bbopt import blackbox, RealVariable
import amplify

@blackbox
def bbfunc(
    x: float = RealVariable((0, 2)),
    y: float = RealVariable((0, 1)),
    z: float = RealVariable((0, 2)),
) -> list[float]:
    return [g(x, y), h(y, z)]  # y is shared

var = bbfunc.variables
constraint = amplify.less_equal(var.x + var.z, 2)  # plus a constraint

optimizer = MultiOptimizer(
    blackbox=bbfunc,
    trainer=[KMTrainer(), KMTrainer()],
    client=my_client,
    constraints=constraint,
)
optimizer.add_random_training_data(num_data=10)
optimizer.optimize(10)
Using Optimizer instead
from amplify_bbopt import blackbox, KMTrainer, Optimizer, RealVariable
import amplify

w_g = 10
w_h = 2

@blackbox
def bbfunc(
    x: float = RealVariable((0, 2)),
    y: float = RealVariable((0, 1)),
    z: float = RealVariable((0, 2)),
) -> float:
    return w_g * g(x, y) + w_h * h(y, z)  # y is shared

var = bbfunc.variables
constraint = amplify.less_equal(var.x + var.z, 2)  # plus a constraint

optimizer = Optimizer(
    blackbox=bbfunc,
    trainer=KMTrainer(),
    client=my_client,
    constraints=constraint,
)
optimizer.add_random_training_data(num_data=10)
optimizer.optimize(10)