Skip to content

Commit

Permalink
added new PyReason Rule object
Browse files Browse the repository at this point in the history
  • Loading branch information
dyumanaditya committed Jan 25, 2024
1 parent 5d02ac5 commit 4704d76
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 68 deletions.
2 changes: 1 addition & 1 deletion pyreason/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

settings.verbose = False
load_graphml(graph_path)
add_rule('popular(x) <-1 popular(y), Friends(x,y), owns(y,z), owns(x,z)', 'popular_rule')
add_rule(Rule('popular(x) <-1 popular(y), Friends(x,y), owns(y,z), owns(x,z)', 'popular_rule'))
add_fact(Fact('popular-fact', 'Mary', 'popular', [1, 1], 0, 2))
reason(timesteps=2)

Expand Down
23 changes: 5 additions & 18 deletions pyreason/pyreason.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import pyreason.scripts.numba_wrapper.numba_types.label_type as label
import pyreason.scripts.numba_wrapper.numba_types.rule_type as rule
from pyreason.scripts.facts.fact import Fact
from pyreason.scripts.rules.rule import Rule
import pyreason.scripts.numba_wrapper.numba_types.fact_node_type as fact_node
import pyreason.scripts.numba_wrapper.numba_types.fact_edge_type as fact_edge
import pyreason.scripts.numba_wrapper.numba_types.interval_type as interval
Expand Down Expand Up @@ -449,29 +450,15 @@ def load_inconsistent_predicate_list(path: str) -> None:
__ipl = yaml_parser.parse_ipl(path)


def add_rule(rule_text: str, name: str, infer_edges: bool = False, set_static: bool = False, immediate_rule: bool = False) -> None:
def add_rule(pr_rule: Rule) -> None:
"""Add a rule to pyreason from text format. This format is not as modular as the YAML format.
1. It is not possible to specify thresholds. Threshold is greater than or equal to 1 by default
2. It is not possible to have weights for different clauses. Weights are 1 by default with bias 0
TODO: Add threshold class where we can pass this as a parameter
TODO: Add weights as a parameter
Example:
`'pred1(x,y) : [0.2, 1] <- pred2(a, b) : [1,1], pred3(b, c)'`
:param rule_text: The rule in text format
:param name: The name of the rule. This will appear in the rule trace
:param infer_edges: Whether to infer new edges after edge rule fires
:param set_static: Whether to set the atom in the head as static if the rule fires. The bounds will no longer change
:param immediate_rule: Whether the rule is immediate. Immediate rules check for more applicable rules immediately after being applied
"""
global __rules

r = rule_parser.parse_rule(rule_text, name, infer_edges, set_static, immediate_rule)
# Add to collection of rules
if __rules is None:
__rules = numba.typed.List.empty_list(rule.rule_type)
__rules.append(r)
__rules.append(pr_rule.rule)


def add_rules_from_file(file_path: str, infer_edges: bool = False) -> None:
Expand All @@ -488,7 +475,7 @@ def add_rules_from_file(file_path: str, infer_edges: bool = False) -> None:

rule_offset = 0 if __rules is None else len(__rules)
for i, r in enumerate(rules):
add_rule(r, f'rule_{i+rule_offset}', infer_edges)
add_rule(Rule(r, f'rule_{i+rule_offset}', infer_edges))


def add_fact(pyreason_fact: Fact) -> None:
Expand Down Expand Up @@ -578,7 +565,7 @@ def _reason(timesteps, convergence_threshold, convergence_bound_threshold):
if __graph is None:
raise Exception('Graph not loaded. Use `load_graph` to load the graphml file')
if __rules is None:
raise Exception('Rules not loaded. Use `load_rules` to load the rules yaml file')
raise Exception('There are no rules, use `add_rule` or `add_rules_from_file`')

# Check variables that are highly recommended. Warnings
if __node_labels is None and __edge_labels is None:
Expand Down
2 changes: 1 addition & 1 deletion pyreason/scripts/numba_wrapper/numba_types/rule_type.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pyreason.scripts.numba_wrapper.numba_types.label_type as label
import pyreason.scripts.numba_wrapper.numba_types.interval_type as interval
from pyreason.scripts.rules.rule import Rule
from pyreason.scripts.rules.rule_internal import Rule

from numba import types
from numba.extending import typeof_impl
Expand Down
66 changes: 20 additions & 46 deletions pyreason/scripts/rules/rule.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,22 @@
class Rule:

def __init__(self, rule_name, rule_type, target, delta, clauses, bnd, thresholds, ann_fn, weights, edges, static, immediate_rule):
self._rule_name = rule_name
self._type = rule_type
self._target = target
self._delta = delta
self._clauses = clauses
self._bnd = bnd
self._thresholds = thresholds
self._ann_fn = ann_fn
self._weights = weights
self._edges = edges
self._static = static
self._immediate_rule = immediate_rule

def get_rule_name(self):
return self._rule_name

def get_rule_type(self):
return self._type

def get_target(self):
return self._target
import pyreason.scripts.utils.rule_parser as rule_parser

def get_delta(self):
return self._delta

def get_neigh_criteria(self):
return self._clauses

def get_bnd(self):
return self._bnd

def get_thresholds(self):
return self._thresholds

def get_annotation_function(self):
return self._ann_fn

def get_edges(self):
return self._edges

def is_static(self):
return self._static

def is_immediate_rule(self):
return self._immediate_rule
class Rule:
"""
Example text:
`'pred1(x,y) : [0.2, 1] <- pred2(a, b) : [1,1], pred3(b, c)'`
1. It is not possible to specify thresholds. Threshold is greater than or equal to 1 by default
2. It is not possible to have weights for different clauses. Weights are 1 by default with bias 0
TODO: Add threshold class where we can pass this as a parameter
TODO: Add weights as a parameter
"""
def __init__(self, rule_text: str, name: str, infer_edges: bool = False, set_static: bool = False, immediate_rule: bool = False):
"""
:param rule_text: The rule in text format
:param name: The name of the rule. This will appear in the rule trace
:param infer_edges: Whether to infer new edges after edge rule fires
:param set_static: Whether to set the atom in the head as static if the rule fires. The bounds will no longer change
:param immediate_rule: Whether the rule is immediate. Immediate rules check for more applicable rules immediately after being applied
"""
self.rule = rule_parser.parse_rule(rule_text, name, infer_edges, set_static, immediate_rule)
48 changes: 48 additions & 0 deletions pyreason/scripts/rules/rule_internal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
class Rule:

def __init__(self, rule_name, rule_type, target, delta, clauses, bnd, thresholds, ann_fn, weights, edges, static, immediate_rule):
self._rule_name = rule_name
self._type = rule_type
self._target = target
self._delta = delta
self._clauses = clauses
self._bnd = bnd
self._thresholds = thresholds
self._ann_fn = ann_fn
self._weights = weights
self._edges = edges
self._static = static
self._immediate_rule = immediate_rule

def get_rule_name(self):
return self._rule_name

def get_rule_type(self):
return self._type

def get_target(self):
return self._target

def get_delta(self):
return self._delta

def get_neigh_criteria(self):
return self._clauses

def get_bnd(self):
return self._bnd

def get_thresholds(self):
return self._thresholds

def get_annotation_function(self):
return self._ann_fn

def get_edges(self):
return self._edges

def is_static(self):
return self._static

def is_immediate_rule(self):
return self._immediate_rule
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

setup(
name='pyreason',
version='2.0.4',
version='2.1.0',
author='Dyuman Aditya',
author_email='[email protected]',
description='An explainable inference software supporting annotated, real valued, graph based and temporal logic',
Expand Down
2 changes: 1 addition & 1 deletion tests/test_hello_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def test_hello_world():

# Load all the files into pyreason
pr.load_graphml(graph_path)
pr.add_rule('popular(x) <-1 popular(y), Friends(x,y), owns(y,z), owns(x,z)', 'popular_rule')
pr.add_rule(pr.Rule('popular(x) <-1 popular(y), Friends(x,y), owns(y,z), owns(x,z)', 'popular_rule'))
pr.add_fact(pr.Fact('popular-fact', 'Mary', 'popular', [1, 1], 0, 2))

# Run the program for two timesteps to see the diffusion take place
Expand Down

0 comments on commit 4704d76

Please sign in to comment.