Source code for lnn.symbolic.logic.n_ary_neuron

##
# Copyright 2023 IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
##

# flake8: noqa: E501

import copy
import itertools
from typing import Set, Union, Tuple

from .formula import Formula
from .unary_operator import Not
from .connective_neuron import _ConnectiveNeuron
from ... import _utils
from ...constants import Direction, NeuralActivation

_utils.logger_setup()


class _NAryNeuron(_ConnectiveNeuron):
    r"""N-ary connective neuron."""

    def __init__(self, *formula, **kwds):
        super().__init__(*formula, arity=len(formula), **kwds)


[docs]class And(_NAryNeuron): r"""Symbolic n-ary [conjunction](https://en.wikipedia.org/wiki/Logical_conjunction). Returns a logical conjunction where inputs can be [propositions](LNN.html#lnn.Proposition), `called` first-order logic [predicates](LNN.html#lnn.Predicate) or any other [connective formulae](LNN.html#symbolic-structure). Propositional inputs yield a propositional node, whereas if any input is a predicate it will cause the connective to increase its dimension to also be a FOL node (i.e. stores a table of facts). Parameters ---------- ``*formula`` : Formula A variable length argument list that accepts any number of input formulae objects as arguments. name : str, optional A custom name for the node to be used for identification and custom printing. If unspecified, defaults the structure of the node. activation : dict, optional Parameters given as a dictionary of configuration options, see the [neural configuration](../usage.html#neural-configuration) for more details Examples -------- ```python # Propositional A, B, C = Propositions('A', 'B', 'C') And(A, B, C) ``` ```python # First-order logic x, y = Variables('x', 'y') A, C = Predicates('A', 'C') B = Predicate('B', arity=2) And(A(x), B(x, y), C(y))) ``` """ def __init__(self, *formula: Formula, **kwds): kwds.setdefault("activation", {}) self.connective_str = "∧" super().__init__(*formula, **kwds)
[docs]class Or(_NAryNeuron): r"""Symbolic n-ary [disjunction](https://en.wikipedia.org/wiki/Logical_disjunction). Returns a logical disjunction where inputs can be [propositions](LNN.html#lnn.Proposition), `called` first-order logic [predicates](LNN.html#lnn.Predicate) or any other [connective formulae](LNN.html#symbolic-structure). Propositional inputs yield a propositional node, whereas if any input is a predicate it will cause the connective to increase its dimension to also be a FOL node (i.e. stores a table of facts). Parameters ---------- ``*formula`` : Formula A variable length argument list that accepts any number of input formulae objects as arguments. name : str, optional A custom name for the node to be used for identification and custom printing. If unspecified, defaults the structure of the node. activation : dict, optional Parameters given as a dictionary of configuration options, see the [neural configuration](../usage.html#neural-configuration) for more details Examples -------- ```python # Propositional A, B, C = Propositions('A', 'B', 'C') Or(A, B, C) ``` ```python # First-order logic x, y = Variables('x', 'y') A, C = Predicates('A', 'C') B = Predicate('B', arity=2) Or(A(x), B(x, y), C(y))) ``` """ def __init__(self, *formula, **kwds): kwds.setdefault("activation", {}) self.connective_str = "∨" super().__init__(*formula, **kwds)
[docs]class XOr(_NAryNeuron): r""" Symbolic nAry [Exclusive or](https://en.wikipedia.org/wiki/Exclusive_or). Returns a logical exclusive disjunction node where inputs can be [propositions]( LNN.html#lnn.Proposition), `called` first-order logic [predicates]( LNN.html#lnn.Predicate) or any other [connective formulae]( LNN.html#symbolic-structure). Propositional inputs yield a propositional node, whereas if any input is a predicate it will cause the connective to increase its dimension to also be a FOL node (i.e. stores a table of facts). Parameters ---------- ``*formula`` : Formula A variable length argument list that accepts any number of input formulae objects as arguments. name : str, optional A custom name for the node to be used for identification and custom printing. If unspecified, defaults the structure of the node. activation : dict, optional Parameters given as a dictionary of configuration options, see the [neural configuration](../usage.html#neural-configuration) for more details Examples -------- ```python # Propositional A, B, C = Propositions('A', 'B', 'C') XOr(A, B, C) ``` ```python # First-order logic x, y = Variables('x', 'y') A, C = Predicates('A', 'C') B = Predicate('B', arity=2) XOr(A(x), B(x, y), C(y))) ``` """ def __init__(self, *formula, **kwds): self.connective_str = "∧" kwds.setdefault("activation", {}) conjunction_activation = copy.copy(kwds["activation"]) conjunction_activation.setdefault("bias_learning", False) conjunction_activation.setdefault("weights_learning", False) self.conjunctions = [ And(*f, activation=conjunction_activation) for f in itertools.combinations(formula, 2) ] self.negations = [Not(f) for f in self.conjunctions] self.disjunction = Or(*formula, **kwds) super().__init__(*self.negations, self.disjunction, **kwds) self.func = self.neuron.activation("And", direction=Direction.UPWARD) self.func_inv = self.neuron.activation("And", direction=Direction.DOWNWARD)
[docs] def upward( self, groundings: Set[Union[str, Tuple[str, ...]]] = None, **kwds ) -> float: r"""Upward inference from the operands to the operator. Parameters ---------- groundings : str or tuple of str restrict upward inference to a specific grounding or row in the truth table Returns ------- tightened_bounds : float The amount of bounds tightening or new information that is leaned by the inference step. """ [node.upward(**kwds) for node in self.conjunctions] [node.upward(**kwds) for node in self.negations] self.disjunction.upward(**kwds) return super().upward(**kwds)
[docs] def downward( self, index: int = None, groundings: Set[Union[str, Tuple[str, ...]]] = None, **kwds, ) -> float: r"""Downward inference from the operator to the operands. Parameters ---------- index : int, optional restricts downward inference to an operand at the specified index. If unspecified, all operands are updated. groundings : str or tuple of str, optional restrict upward inference to a specific grounding or row in the truth table Returns ------- tightened_bounds : float The amount of bounds tightening or new information that is leaned by the inference step. """ result = super().downward(index, groundings, **kwds) [node.downward(**kwds) for node in self.negations] [node.downward(**kwds) for node in self.conjunctions] self.disjunction.downward(**kwds) return result