### Copyright 2023 IBM Corp. All Rights Reserved.## SPDX-License-Identifier: Apache-2.0### flake8: noqa: E501importcopyimportitertoolsfromtypingimportSet,Union,Tuplefrom.formulaimportFormulafrom.unary_operatorimportNotfrom.connective_neuronimport_ConnectiveNeuronfrom...import_utilsfrom...constantsimportDirection,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]classAnd(_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]classOr(_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]classXOr(_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)forfinitertools.combinations(formula,2)]self.negations=[Not(f)forfinself.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]defupward(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)fornodeinself.conjunctions][node.upward(**kwds)fornodeinself.negations]self.disjunction.upward(**kwds)returnsuper().upward(**kwds)
[docs]defdownward(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)fornodeinself.negations][node.downward(**kwds)fornodeinself.conjunctions]self.disjunction.downward(**kwds)returnresult