### Copyright 2023 IBM Corp. All Rights Reserved.## SPDX-License-Identifier: Apache-2.0### flake8: noqa: E501fromtypingimportUnion,Tuple,Setfrom.connective_neuronimport_ConnectiveNeuronfrom.formulaimportFormulafrom...import_utilsfrom...constantsimportDirection,NeuralActivation_utils.logger_setup()class_BinaryNeuron(_ConnectiveNeuron):r"""Restrict neurons to 2 inputs."""def__init__(self,*formula,**kwds):iflen(formula)!=2:raiseException("Binary neurons expect 2 formulae as inputs, received "f"{len(formula)}")super().__init__(*formula,arity=2,**kwds)
[docs]classImplies(_BinaryNeuron):r""" Symbolic binary [implication](https://en.wikipedia.org/wiki/Logical_implication). Returns a logical implication 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 ---------- lhs : Formula The left-hand side formula of the binary inputs to the connective. rhs : Formula The right-hand side formula of the binary inputs to the connective. 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 = Propositions('A', 'B') Implies(A, B) ``` ```python # First-order logic x, y = Variables('x', 'y') A = Predicate('A') B = Predicate('B', arity=2) Implies(A(x), B(x, y))) ``` """def__init__(self,lhs:Formula,rhs:Formula,**kwds):self.connective_str="→"kwds.setdefault("activation",{})kwds["activation"].setdefault("bias_learning",True)super().__init__(lhs,rhs,**kwds)
[docs]classIff(_BinaryNeuron):r"""Symbolic Equivalence - a bidirectional binary implication or IFF (if and only if) node. Returns a logical bidirectional equivalence 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 ---------- lhs : Formula The left-hand side formula of the binary inputs to the connective. rhs : Formula The right-hand side formula of the binary inputs to the connective. 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 = Propositions('A', 'B') Iff(A, B) ``` ```python # First-order logic x, y = Variables('x', 'y') A = Predicate('A') B = Predicate('B', arity=2) Iff(A(x), B(x, y))) ``` """def__init__(self,lhs:Formula,rhs:Formula,**kwds):self.connective_str="∧"self.Imp1,self.Imp2=Implies(lhs,rhs,**kwds),Implies(rhs,lhs,**kwds)super().__init__(self.Imp1,self.Imp2,**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. """self.Imp1.upward(groundings,**kwds)self.Imp2.upward(groundings,**kwds)returnsuper().upward(groundings,**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)self.Imp1.downward(index,groundings,**kwds)self.Imp2.downward(index,groundings,**kwds)returnresult