Skip to content

CombinedLoss

pysignet.combined_loss.CombinedLoss

Weight and sum the losses of several independent LogicLoss objects.

Parameters:

Name Type Description Default
losses dict[str, LogicLoss]

Dict mapping constraint name to LogicLoss.

required
weights dict[str, float | Parameter] | None

Dict mapping constraint name to a weight. Values may be a plain float (static) or an nn.Parameter (learnable, and picked up by trainable_parameters). If None, every constraint gets weight 1.0. Keys must exactly match losses.

None
normalize bool

If True, divide the weighted sum by the sum of weights, keeping the scale independent of constraint count and weight magnitude. Default False (raw weighted sum, matching manual loss_a.loss() + loss_b.loss() when weights are 1.0).

False

Raises:

Type Description
ValueError

If losses is empty, or weights keys do not exactly match losses keys.

Example
combined = CombinedLoss(
    {"symmetry": symmetry_loss, "addition": addition_loss},
    weights={"symmetry": 0.1, "addition": 1.0},
)
loss = combined.loss({
    "symmetry": {"X1": x1, "X2": x2},
    "addition": {"X": x, "Y": y},
})
optimizer = torch.optim.Adam(combined.trainable_parameters)

trainable_parameters property

All trainable parameters from sub-losses and learnable weights.

Parameters are deduplicated by identity, so a predicate or model shared across constraints is not double-counted (which would otherwise make an optimizer step it more than once per optimizer.step()).

Returns:

Type Description
list[Parameter]

List of torch.nn.Parameter objects.

Example
params = combined.trainable_parameters
optimizer = torch.optim.Adam(params, lr=0.001)

__init__(losses, weights=None, normalize=False)

Initialize CombinedLoss.

Parameters:

Name Type Description Default
losses dict[str, LogicLoss]

Dict mapping constraint name to LogicLoss.

required
weights dict[str, float | Parameter] | None

Dict mapping constraint name to a static float or learnable nn.Parameter. Defaults to 1.0 for every constraint.

None
normalize bool

If True, divide the weighted sum by the sum of weights.

False

__repr__()

Return string representation of CombinedLoss.

Returns:

Type Description
str

Multi-line string showing constraint names, weights, and

str

the normalize flag.

loss(bindings, quantify='forall', reduction='none', post_processing=None)

Compute the weighted sum of every constraint's loss.

Each constraint's loss is computed by calling its own LogicLoss.loss() with the given quantify/reduction (and, if provided, a per-constraint post_processing override), then multiplied by its weight and summed.

Parameters:

Name Type Description Default
bindings dict[str, dict[str, Tensor]]

Dict mapping constraint name to that constraint's variable bindings (e.g. {"a": {"X": x}}). Keys must exactly match the losses passed to __init__.

required
quantify Literal['forall', 'exists', 'none']

Batch quantification mode, forwarded to every sub-LogicLoss: 'forall', 'exists', or 'none'.

'forall'
reduction Literal['mean', 'sum', 'none']

Reduction mode, forwarded to every sub-LogicLoss: 'mean', 'sum', or 'none'. Only meaningful with quantify='none'.

'none'
post_processing dict[str, str | Callable[[Tensor], Tensor] | None] | None

Optional dict mapping constraint name to a post-processing override for that constraint's call. If a name is absent, that constraint uses its own default.

None

Returns:

Type Description
Tensor

Scalar tensor: the (optionally normalized) weighted sum of

Tensor

every constraint's loss.

Raises:

Type Description
ValueError

If bindings keys do not exactly match the constraint names, if quantify='none' and reduction='none' (each constraint's loss would not be a scalar), or if post_processing names an unknown constraint.

Example
loss = combined.loss({"a": {"X": x}, "b": {"Y": y}})