Skip to content

Commit

Permalink
Add Variable and Constant object to support typing
Browse files Browse the repository at this point in the history
  • Loading branch information
LukasZahradnik committed May 8, 2024
1 parent 788dd6e commit a102d47
Show file tree
Hide file tree
Showing 14 changed files with 144 additions and 54 deletions.
18 changes: 9 additions & 9 deletions examples/datasets/horses.py
@@ -1,4 +1,4 @@
from neuralogic.core import Relation, Template, Var, Constant
from neuralogic.core import Relation, Template, Var, Const
from neuralogic.dataset import Dataset


Expand All @@ -16,13 +16,13 @@
)

example = [
Relation.horse(Constant.aida)[1.0],
Relation.horse(Constant.cheyenne)[1.0],
Relation.horse(Constant.dakotta)[1.0],
Relation.parent(Constant.star, Constant.cheyenne)[1.0],
Relation.parent(Constant.star, Constant.aida)[1.0],
Relation.parent(Constant.star, Constant.dakotta)[1.0],
Relation.horse(Const.aida)[1.0],
Relation.horse(Const.cheyenne)[1.0],
Relation.horse(Const.dakotta)[1.0],
Relation.parent(Const.star, Const.cheyenne)[1.0],
Relation.parent(Const.star, Const.aida)[1.0],
Relation.parent(Const.star, Const.dakotta)[1.0],
]

dataset.add(Relation.foal(Constant.star)[1.0], example)
dataset.add(Relation.negFoal(Constant.star)[0.0], example)
dataset.add(Relation.foal(Const.star)[1.0], example)
dataset.add(Relation.negFoal(Const.star)[0.0], example)
12 changes: 6 additions & 6 deletions examples/datasets/multiple_examples_no_order_trains.py
@@ -1,7 +1,7 @@
from typing import List
from examples.datasets.data.train_example_data import train_example_data

from neuralogic.core import Relation, Template, Var, Constant
from neuralogic.core import Relation, Template, Var, Const
from neuralogic.dataset import Dataset


Expand All @@ -13,18 +13,18 @@

# fmt: off

shapes = [Constant.ellipse, Constant.rectangle, Constant.bucket, Constant.hexagon, Constant.u_shaped]
roofs = [Constant.jagged, Constant.arc, Constant.none, Constant.flat, Constant.peaked]
loadshapes = [Constant.hexagon, Constant.triangle, Constant.diamond, Constant.rectangle, Constant.circle]
shapes = [Const.ellipse, Const.rectangle, Const.bucket, Const.hexagon, Const.u_shaped]
roofs = [Const.jagged, Const.arc, Const.none, Const.flat, Const.peaked]
loadshapes = [Const.hexagon, Const.triangle, Const.diamond, Const.rectangle, Const.circle]
vagon_atoms = [Relation.shape, Relation.length, Relation.sides, Relation.wheels, Relation.loadnum, Relation.loadshape, Relation.roof]

Y = Var.Y # todo gusta: tohle je dobry trik, ten bych pouzival na vic mistech, a podobne pro Atom/Predicate factories udelat zkratky (treba P.)

template.add_rules(
[
*[Relation.shape(Y) <= Relation.shape(Y, s)[1, ] for s in shapes],
*[Relation.length(Y) <= Relation.length(Y, s)[1, ] for s in [Constant.short, Constant.long]],
*[Relation.sides(Y) <= Relation.sides(Y, s)[1, ] for s in [Constant.not_double, Constant.double]],
*[Relation.length(Y) <= Relation.length(Y, s)[1, ] for s in [Const.short, Const.long]],
*[Relation.sides(Y) <= Relation.sides(Y, s)[1, ] for s in [Const.not_double, Const.double]],
*[Relation.roof(Y) <= Relation.roof(Y, s)[1, ] for s in roofs],
*[Relation.wheels(Y) <= Relation.wheels(Y, s)[1, ] for s in [2, 3]],
*[Relation.loadnum(Y) <= Relation.loadnum(Y, s)[1, ] for s in [0, 1, 2, 3]],
Expand Down
12 changes: 6 additions & 6 deletions examples/datasets/multiple_examples_trains.py
@@ -1,7 +1,7 @@
from typing import List
from examples.datasets.data.train_example_data import train_example_data

from neuralogic.core import Relation, Template, Var, Constant
from neuralogic.core import Relation, Template, Var, Const
from neuralogic.dataset import Dataset


Expand All @@ -12,18 +12,18 @@

# fmt: off

shapes = [Constant.ellipse, Constant.rectangle, Constant.bucket, Constant.hexagon, Constant.u_shaped]
roofs = [Constant.jagged, Constant.arc, Constant.none, Constant.flat, Constant.peaked]
loadshapes = [Constant.hexagon, Constant.triangle, Constant.diamond, Constant.rectangle, Constant.circle]
shapes = [Const.ellipse, Const.rectangle, Const.bucket, Const.hexagon, Const.u_shaped]
roofs = [Const.jagged, Const.arc, Const.none, Const.flat, Const.peaked]
loadshapes = [Const.hexagon, Const.triangle, Const.diamond, Const.rectangle, Const.circle]
vagon_atoms = [Relation.shape, Relation.length, Relation.sides, Relation.wheels, Relation.loadnum, Relation.loadshape, Relation.roof]

Y = Var.Y

template.add_rules(
[
*[Relation.shape(Y) <= Relation.shape(Y, s)[1, ] for s in shapes],
*[Relation.length(Y) <= Relation.length(Y, s)[1, ] for s in [Constant.short, Constant.long]],
*[Relation.sides(Y) <= Relation.sides(Y, s)[1, ] for s in [Constant.not_double, Constant.double]],
*[Relation.length(Y) <= Relation.length(Y, s)[1, ] for s in [Const.short, Const.long]],
*[Relation.sides(Y) <= Relation.sides(Y, s)[1, ] for s in [Const.not_double, Const.double]],
*[Relation.roof(Y) <= Relation.roof(Y, s)[1, ] for s in roofs],
*[Relation.wheels(Y) <= Relation.wheels(Y, s)[1, ] for s in [2, 3]],
*[Relation.loadnum(Y) <= Relation.loadnum(Y, s)[1, ] for s in [0, 1, 2, 3]],
Expand Down
12 changes: 6 additions & 6 deletions examples/datasets/naive_trains.py
@@ -1,6 +1,6 @@
from examples.datasets.data.train_example_data import train_example_data

from neuralogic.core import Relation, Template, Var, Constant
from neuralogic.core import Relation, Template, Var, Const
from neuralogic.dataset import Dataset


Expand All @@ -11,9 +11,9 @@

# fmt: off

shapes = [Constant.ellipse, Constant.rectangle, Constant.bucket, Constant.hexagon, Constant.u_shaped]
roofs = [Constant.jagged, Constant.arc, Constant.none, Constant.flat, Constant.peaked]
loadshapes = [Constant.hexagon, Constant.triangle, Constant.diamond, Constant.rectangle, Constant.circle]
shapes = [Const.ellipse, Const.rectangle, Const.bucket, Const.hexagon, Const.u_shaped]
roofs = [Const.jagged, Const.arc, Const.none, Const.flat, Const.peaked]
loadshapes = [Const.hexagon, Const.triangle, Const.diamond, Const.rectangle, Const.circle]
vagon_atoms = [Relation.shape, Relation.length, Relation.sides, Relation.wheels, Relation.loadnum, Relation.loadshape, Relation.roof]

X = Var.X
Expand All @@ -22,8 +22,8 @@
template.add_rules(
[
*[Relation.shape(X, Y) <= Relation.shape(X, Y, s)[1, ] for s in shapes],
*[Relation.length(X, Y) <= Relation.length(X, Y, s)[1, ] for s in [Constant.short, Constant.long]],
*[Relation.sides(X, Y) <= Relation.sides(X, Y, s)[1, ] for s in [Constant.not_double, Constant.double]],
*[Relation.length(X, Y) <= Relation.length(X, Y, s)[1, ] for s in [Const.short, Const.long]],
*[Relation.sides(X, Y) <= Relation.sides(X, Y, s)[1, ] for s in [Const.not_double, Const.double]],
*[Relation.roof(X, Y) <= Relation.roof(X, Y, s)[1, ] for s in roofs],
*[Relation.wheels(X, Y) <= Relation.wheels(X, Y, s)[1, ] for s in [2, 3]],
*[Relation.loadnum(X, Y) <= Relation.loadnum(X, Y, s)[1, ] for s in [0, 1, 2, 3]],
Expand Down
4 changes: 2 additions & 2 deletions neuralogic/core/__init__.py
@@ -1,4 +1,4 @@
from neuralogic.core.constructs.factories import Var, Constant, Relation, V, C, R
from neuralogic.core.constructs.factories import Var, Const, Relation, V, C, R
from neuralogic.core.constructs.rule import Rule, RuleBody
from neuralogic.core.template import Template
from neuralogic.core.builder import BuiltDataset, GroundedDataset
Expand All @@ -11,7 +11,7 @@
__all__ = [
"Var",
"V",
"Constant",
"Const",
"C",
"Relation",
"R",
Expand Down
23 changes: 12 additions & 11 deletions neuralogic/core/constructs/factories.py
@@ -1,6 +1,7 @@
from typing import Dict
from typing import Dict, Optional
from neuralogic.core.constructs.predicate import Predicate
from neuralogic.core.constructs import relation
from neuralogic.core.constructs.term import Constant, Variable


class AtomFactory:
Expand Down Expand Up @@ -53,25 +54,25 @@ def __getattr__(self, item) -> relation.BaseRelation:


class VariableFactory:
def __getattr__(self, item: str) -> str:
return item.capitalize()
def __getattr__(self, item: str) -> Variable:
return self.get(item)

def get(self, item: str) -> str:
return item.capitalize()
def get(self, item: str, var_type: Optional[str] = None) -> Variable:
return Variable(item.capitalize(), var_type)


class ConstantFactory:
def __getattr__(self, item: str) -> str:
return item.lower()
def __getattr__(self, item: str) -> Constant:
return self.get(item)

def get(self, item: str) -> str:
return item.lower()
def get(self, item: str, const_type: Optional[str] = None) -> Constant:
return Constant(item.lower(), const_type)


Var = VariableFactory()
Relation = AtomFactory()
Constant = ConstantFactory()
Const = ConstantFactory()

V = Var
C = Constant
C = Const
R = Relation
10 changes: 10 additions & 0 deletions neuralogic/core/constructs/java_objects.py
Expand Up @@ -5,6 +5,7 @@
import jpype

from neuralogic import is_initialized, initialize
from neuralogic.core.constructs.term import Variable, Constant
from neuralogic.core.settings import SettingsProxy, Settings


Expand Down Expand Up @@ -128,6 +129,15 @@ def get_variable_factory(self):
return self.var_factory_class()

def get_term(self, term, variable_factory):
if isinstance(term, Variable):
if term.type is None:
return variable_factory.construct(term.name)
return variable_factory.construct(term.name, term.type)
if isinstance(term, Constant):
if term.type is None:
return self.constant_factory.construct(term.name)
return self.constant_factory.construct(term.name, term.type)

if isinstance(term, str):
if term[0].islower() or term.isnumeric():
return self.constant_factory.construct(term)
Expand Down
17 changes: 12 additions & 5 deletions neuralogic/core/constructs/relation.py
Expand Up @@ -19,13 +19,20 @@ def __init__(
):
self.predicate = predicate
self.function = function
self.terms = terms
self.negated = negated
self.terms = []

if self.terms is None:
self.terms = []
elif not isinstance(self.terms, Iterable):
self.terms = [self.terms]
if not isinstance(terms, Iterable) or isinstance(terms, str):
terms = [terms]

for term in terms:
if term is None:
continue

if isinstance(term, list):
self.terms.extend(term)
else:
self.terms.append(term)

def __neg__(self) -> "BaseRelation":
return self.attach_activation_function(Transformation.REVERSE)
Expand Down
64 changes: 64 additions & 0 deletions neuralogic/core/constructs/term.py
@@ -0,0 +1,64 @@
from typing import Optional, Union, List


class Variable:
__slots__ = "name", "type"

def __init__(self, name: str, type: Optional[str] = None):
self.name = name
self.type = type

def __str__(self) -> str:
if self.type is not None:
return f"{self.type}:{self.name}"
return f"{self.name}"

def __getitem__(self, item) -> List["Variable"]:
if not isinstance(item, slice):
raise ValueError("Variable range can be only defined by a slice")

if item.step is not None:
return [Variable(f"{self.name}{i}", self.type) for i in range(item.start, item.stop, item.step)]

return [Variable(f"{self.name}{i}", self.type) for i in range(item.start, item.stop)]

def __call__(self, item: str) -> "Variable":
if isinstance(item, str):
return Variable(self.name, item)
raise ValueError("Type can be only of type str")

def __eq__(self, other: Union["Variable", str]) -> bool:
return str(other) == str(self)

def __hash__(self):
return str(self).__hash__()

def __lt__(self, other):
return str(self).__lt__(str(other))


class Constant:
__slots__ = "name", "type"

def __init__(self, name: str, type: Optional[str] = None):
self.name = name
self.type = type

def __str__(self) -> str:
if self.type is not None:
return f"{self.type}:{self.name}"
return f"{self.name}"

def __call__(self, item: str) -> "Constant":
if isinstance(item, str):
return Constant(self.name, item)
raise ValueError("Type can be only of type str")

def __eq__(self, other: Union["Constant", str]) -> bool:
return str(other) == str(self)

def __hash__(self):
return str(self).__hash__()

def __lt__(self, other):
return str(self).__lt__(str(other))
1 change: 0 additions & 1 deletion neuralogic/core/template.py
Expand Up @@ -114,7 +114,6 @@ def get_parsed_template(self, settings: SettingsProxy, java_factory: JavaFactory
metadata_processor = metadata_processor(settings.settings)

metadata_processor.processMetadata(template)
template.inferTemplateFacts()

return template

Expand Down
2 changes: 0 additions & 2 deletions neuralogic/inference/inference_engine.py
Expand Up @@ -18,8 +18,6 @@ def __init__(self, template: Template, settings: Settings = None):
self.settings = Settings().create_disconnected_proxy() if settings is None else settings.create_proxy()
self.java_factory = JavaFactory()

self.settings.settings.inferTemplateFacts = False

self.parsed_template = template.get_parsed_template(self.settings, self.java_factory)
self.dataset_builder = DatasetBuilder(self.parsed_template, self.java_factory)

Expand Down
17 changes: 14 additions & 3 deletions tests/test_constructs.py
@@ -1,7 +1,5 @@
import copy

from neuralogic.core.constructs.relation import BaseRelation, WeightedRelation
from neuralogic.core import R, Transformation, Aggregation, Metadata, Combination, V
from neuralogic.core import R, Transformation, Aggregation, Metadata, Combination, V, C
from neuralogic.core.constructs.rule import Rule


Expand Down Expand Up @@ -189,3 +187,16 @@ def test_rules_and_with_metadata():
my_rule: Rule = R.a(V.X) <= R.b(V.Y) & R.c(V.Z) & R.d | [Transformation.SIGMOID]

assert str(my_rule) == "a(X) :- b(Y), c(Z), d. [transformation=sigmoid]"


def test_var_and_const():
assert V.get("abc") == "Abc"
assert V.get("abc", "type") == "type:Abc"

assert C.get("Abc") == "abc"
assert C.get("Abc", "type") == "type:abc"

assert str(R.head(V.get("abc", "type")[1:3], V.X)) == "head(type:Abc1, type:Abc2, X)."

# With step
assert str(R.head(V.get("abc", "type")[1:6:2], V.X)) == "head(type:Abc1, type:Abc3, type:Abc5, X)."
4 changes: 2 additions & 2 deletions tests/test_inference_engine.py
Expand Up @@ -74,8 +74,8 @@ def test_inference_engine_london() -> None:
# Should yield two substitutions for x (green_park and bond_street)
substitutions = list(engine.q(R.nearby(V.X, C.oxford_circus)))

assert substitutions[0]["X"] == "green_park"
assert substitutions[1]["X"] == "bond_street"
assert substitutions[0]["X"] == "bond_street"
assert substitutions[1]["X"] == "green_park"
assert len(substitutions) == 2 and len(substitutions[0]) == 1 and len(substitutions[1]) == 1

# Run query for nearby(X, tottenham_court_road)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_java_evaluator.py
Expand Up @@ -368,7 +368,7 @@ def test_evaluator_run_on_rules(template: Template, dataset: BaseDataset, expect
assert len(results) == len(expected_results)

for result, expected_result in zip(results, expected_results):
assert expected_result == result
assert result == expected_result


@pytest.mark.parametrize(
Expand Down

0 comments on commit a102d47

Please sign in to comment.