Source code for lnn.symbolic.logic.leaf_formula

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

# flake8: noqa: E501

from typing import Union

from .formula import Formula
from .node_activation import _NodeActivation
from .variable import Variable
from ... import _utils, utils
from ...constants import Fact

_utils.logger_setup()


class _LeafFormula(Formula):
    r"""Specifies activation functionality as nodes instead of neurons.

    Assumes that all leaf formulae are propositions or predicates, therefore
        uses the _NodeActivation accordingly

    """

    def __init__(self, *args, **kwds):
        super().__init__(*args, **kwds)
        kwds.setdefault("propositional", self.propositional)
        self.neuron = _NodeActivation()(**kwds.get("activation", {}), **kwds)


[docs]class Predicate(_LeafFormula): r"""Creates a container for a predicate Stores a table of truths, with columns specified by the arity and rows indexed by the grounding Parameters ---------- name : str name of the predicate arity : int, optional If unspecified, assumes a unary predicate Examples -------- ```python P1 = Predicate('P1') P2 = Predicate('P2', arity=2) ``` """ def __init__(self, name: str, arity: int = 1, **kwds): if arity is None: raise Exception(f"arity expected as int > 0, received {arity}") super().__init__(name=name, arity=arity, propositional=False, **kwds) self._update_variables(tuple(Variable(f"?{i}") for i in range(self.arity)))
[docs] def add_data(self, facts: Union[dict, set]): r"""Populate predicate with facts Facts required in dict or set - dict for grounding-based facts - set for broadcasting facts across all groundings requires a set of 1 item dict keys for groundings and values as facts tuple facts required in bounds form `(Lower, Upper)` """ super().add_data(facts)
def __call__(self, *args, **kwds): r"""A called first-order logic predicate This correctly instantiates a predicate with variables - which is required when using the predicate in a compound formula. Calling the predicate allows the LNN to construct the inheritance tree from subformulae. Examples -------- ```python P, Q = Predicates('P', 'Q') x, y = Variables('x', 'y') And(P(x), Q(y)) # calling both predicates ``` Here the conjunction inherits its variables from all subformulae, treating it as an ordered unique collection (list). """ return super().__call__(*args, **kwds)
[docs]def Predicates(*predicates: str, **kwds): r"""Instantiates multiple predicates. Examples -------- ```python P1, P2 = Predicates("P1", "P2", arity=2) ``` """ return utils.return1([Predicate(p, **kwds) for p in predicates])
[docs]class Proposition(_LeafFormula): r"""Creates propositional containers Stores and retrieves single truth bounds instead of tables as in FOL case Parameters ---------- name : str name of the proposition Examples -------- ```python P = Proposition('Person') ``` """ def __init__(self, name: str, **kwds): super().__init__(name=name, arity=1, propositional=True, **kwds)
[docs] def add_data(self, fact: Union[Fact, bool]): """Populate proposition with facts Facts required in bool, tuple or None None fact assumes `Unknown` tuple fact required in bounds form `(Lower, Upper)` """ super().add_data(fact)
[docs]def Propositions(*propositions: str, **kwds): r"""Instantiates multiple propositions. Examples -------- ```python P1, P2 = Propositions("P1", "P2") ``` """ return utils.return1([Proposition(p, **kwds) for p in propositions])