T-Norms
pysignet.tnorms.RProductTNorm
Bases: SProductTNorm
R-Product t-norm (R-logics: axiomatic residuum-based implication).
- AND: prod(values) along dim=0 (inherited from S-Product)
- OR: 1 - prod(1 - values) along dim=0 (inherited from S-Product)
- IMPLIES: 1 if a <= b else b/a (residuum, overrides S-Product)
R-Product defines implication axiomatically using residua rather than treating it as disjunction. According to "Evaluating Relaxations of Logic for Neural Networks" (2107.13646v1.pdf): - R-Product empirically outperforms all other t-norms (Tables 3-9) - R-Product is self-consistent for all formulas (Proposition 1) - R-Product is the recommended default t-norm for neural networks
This is the default t-norm used by LogicCompiler.
recommended_postprocessing
property
R-Product recommends logarithmic post-processing.
implication(a, b)
Relaxed IMPLIES using R-Product residuum.
R-Product implication: 1 if a <= b else b/a
This axiomatic definition makes R-Product self-consistent and more suitable for neural network training than S-Product.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
Tensor
|
Antecedent tensor (values in [0, 1]) |
required |
b
|
Tensor
|
Consequent tensor (values in [0, 1]) |
required |
Returns:
| Type | Description |
|---|---|
Tensor
|
Implication result: 1 where a <= b, else b/a |
pysignet.tnorms.SProductTNorm
Bases: TNorm
S-Product t-norm (S-logics: implication as disjunction).
- AND: prod(values) along dim=0
- OR: 1 - prod(1 - values) along dim=0
- IMPLIES: 1 - a + a * b (treats implication as NOT(a) OR b)
S-Product uses the standard implication-as-disjunction approach. According to "Evaluating Relaxations of Logic for Neural Networks", S-Product is less consistent than R-Product and performs worse empirically, but is equivalent to cross-entropy for labeled data.
recommended_postprocessing
property
S-Product recommends logarithmic post-processing.
conjunction(values)
Product conjunction: prod(values) along dim=0.
disjunction(values)
Product disjunction: 1 - prod(1 - values) along dim=0.
pysignet.tnorms.LukasiewiczTNorm
Bases: TNorm
Lukasiewicz t-norm (bounded difference).
- AND: max(0, sum(values) - (n - 1))
- OR: min(1, sum(values))
Good for enforcing stricter logical constraints.
recommended_postprocessing
property
Lukasiewicz recommends linear post-processing.
conjunction(values)
Lukasiewicz conjunction: max(0, sum - (n-1)).
disjunction(values)
Lukasiewicz disjunction: min(1, sum).
pysignet.tnorms.GodelTNorm
Bases: TNorm
Godel t-norm (minimum/maximum).
- AND: min(values) along dim=0
- OR: max(values) along dim=0
Most conservative option, but can have gradient issues.
Uses torch.amin/amax rather than values.min(dim=0).values / values.max(dim=0).values: the latter also compute and discard an unused argmin/argmax index, which is far more expensive for no benefit (~60x slower, measured on small batches) and, for tied values, gives the entire gradient to a single arbitrary (first-occurring) index rather than splitting it fairly across every tied element.
recommended_postprocessing
property
Godel recommends linear post-processing.
conjunction(values)
Godel conjunction: min along dim=0.
disjunction(values)
Godel disjunction: max along dim=0.
pysignet.tnorms.MixedTNorm
Bases: TNorm
Mixed t-norm: Godel for large arities, RProduct for small arities.
This t-norm switches behavior based on the number of arguments: - For arities <= threshold: uses RProduct (product/probabilistic sum) - For arities > threshold: uses Godel (min/max)
This addresses numerical stability issues with product t-norms when combining many values. For example, 0.9^20 = 0.12, which can cause gradient vanishing during training. Godel (min/max) is stable for large arities.
Binary operations (implication, equivalence) always use RProduct since they only involve 2 operands.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
threshold
|
int
|
Maximum arity for RProduct. Arities > threshold use Godel. Default is 4. |
4
|
Example
tnorm = MixedTNorm(threshold=4)
# Small conjunction (3 args) -> RProduct
values = torch.tensor([[0.8], [0.7], [0.6]])
tnorm.conjunction(values) # 0.8 * 0.7 * 0.6 = 0.336
# Large conjunction (6 args) -> Godel
values = torch.tensor([[0.9], [0.8], [0.7], [0.6], [0.5], [0.4]])
tnorm.conjunction(values) # min = 0.4
recommended_postprocessing
property
Return recommended loss post-processing mode.
Returns 'log' since RProduct is used for small arities and binary operations (implication, equivalence).
__init__(threshold=4)
Initialize MixedTNorm.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
threshold
|
int
|
Maximum arity for RProduct. Arities > threshold use Godel. Default is 4. |
4
|
conjunction(values)
Relaxed AND operation, reducing along dim=0.
Uses RProduct (product) for small arities (<=threshold), Godel (min) for large arities (>threshold).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
Tensor
|
Tensor of shape (n, ...) with values in [0, 1]. |
required |
Returns:
| Type | Description |
|---|---|
Tensor
|
Tensor of shape (...) with conjunction applied. |
disjunction(values)
Relaxed OR operation, reducing along dim=0.
Uses RProduct (probabilistic sum) for small arities (<=threshold), Godel (max) for large arities (>threshold).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
Tensor
|
Tensor of shape (n, ...) with values in [0, 1]. |
required |
Returns:
| Type | Description |
|---|---|
Tensor
|
Tensor of shape (...) with disjunction applied. |
equivalence(a, b)
Relaxed EQUIVALENCE using RProduct.
Equivalence is conjunction of two implications (binary), so RProduct is used for better gradient properties.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
Tensor
|
First operand tensor (values in [0, 1]) |
required |
b
|
Tensor
|
Second operand tensor (values in [0, 1]) |
required |
Returns:
| Type | Description |
|---|---|
Tensor
|
Equivalence result using RProduct. |
implication(a, b)
Relaxed IMPLIES using RProduct residuum.
Implication is always binary, so RProduct is used for better gradient properties.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
Tensor
|
Antecedent tensor (values in [0, 1]) |
required |
b
|
Tensor
|
Consequent tensor (values in [0, 1]) |
required |
Returns:
| Type | Description |
|---|---|
Tensor
|
Implication result using RProduct. |