Skip to content

Commit

Permalink
hooking up eventbuffer for temporal inference
Browse files Browse the repository at this point in the history
  • Loading branch information
maxeeem committed Mar 15, 2024
1 parent 69b73c5 commit 17e81ef
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 50 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/python-app-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Set up Python 3.7.x
- name: Set up Python 3.9.x
uses: actions/setup-python@v5
with:
python-version: "3.7"
python-version: "3.9"

- name: Install dependencies
run: |
Expand Down
45 changes: 28 additions & 17 deletions Tests/test_NAL/test_NAL7.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

class TEST_NAL7(unittest.TestCase):
def setUp(self):
Global.time = 0
nars.reset()

''''''
Expand Down Expand Up @@ -85,7 +86,7 @@ def test_induction_0(self):
tasks_derived = process_two_premises(
'<<(*, $x, door_101) --> open> =/> <(*, $x, room_101) --> enter>>. %0.90;0.90%',
'<<(*, $y, door_101) --> open> =\> <(*, $y, key_101) --> hold>>. %0.80;0.90%',
100
10
)

self.assertTrue(
Expand Down Expand Up @@ -248,7 +249,7 @@ def test_abduction(self):
tasks_derived = process_two_premises(
'<A =/> B>. %0.80;0.90%',
'<C =\> B>. %0.90;0.90%',
10
100
)

self.assertTrue(
Expand Down Expand Up @@ -278,8 +279,9 @@ def test_inference_on_tense_0(self):
tasks_derived = process_two_premises(
'<<(*,John,key_101) --> hold> =/> <(*,John,room_101) --> enter>>. %1.00;0.90%',
'<(*,John,key_101) --> hold>. :|: %1.00;0.90%',
10
100
)
Global.time = 0
self.assertTrue(
output_contains(tasks_derived, '<(*,John,room_101) --> enter>. :!5: %1.00;0.81%')
)
Expand All @@ -303,9 +305,9 @@ def test_inference_on_tense_1(self):
tasks_derived = process_two_premises(
'<<(*,John,key_101) --> hold> =/> <(*,John,room_101) --> enter>>. %1.00;0.90%',
'<(*,John,room_101) --> enter>. :\: %1.00;0.90%',
10
100
)

Global.time = 0
self.assertTrue(
output_contains(tasks_derived, '<(*,John,key_101) --> hold>. :!-10: %1.00;0.45%')
)
Expand All @@ -329,7 +331,7 @@ def test_inference_on_tense_2(self):
tasks_derived = process_two_premises(
'<<(*,John,key_101) --> hold> =/> <(*,John,room_101) --> enter>>. %1.00;0.90%',
'<(*,John,room_101) --> enter>. :\: %1.00;0.90%',
10
100
)

self.assertTrue(
Expand Down Expand Up @@ -370,13 +372,12 @@ def test_induction_on_tense_0_0(self):
None,
6
)
Global.time = 6
tasks_derived.extend(process_two_premises(
'<John --> (/,enter,_,room_101)>. :|:',
None,
20
100
))

Global.time = 0
self.assertTrue(
output_contains(tasks_derived, '<<John --> (/,enter,_,room_101)> =\> (&/,<John --> (/,open,_,door_101)>,+6)>. :!6: %1.00;0.45%')
)
Expand Down Expand Up @@ -411,12 +412,17 @@ def test_induction_on_tense_0_1(self):
10
'''
rules, task, belief, concept, task_link, term_link, result1, result2 = rule_map_two_premises(
tasks_derived = process_two_premises(
'<John --> (/,open,_,door_101)>. :|: ',
'<John --> (/,enter,_,room_101)>. :|: ',
'John.'
None,
6
)
tasks_derived = [rule(task, belief, task_link, term_link) for rule in rules]
tasks_derived.extend(process_two_premises(
'<John --> (/,enter,_,room_101)>. :|: ',
None,
100
))
Global.time = 0
self.assertTrue(
output_contains(tasks_derived, '<<$1 --> (/,enter,_,room_101)> =\> (&/,<$1 --> (/,open,_,door_101)>,+6)>. :!6: %1.00;0.45%')
)
Expand All @@ -443,12 +449,17 @@ def test_induction_on_tense_1(self):
'changed fomr +2 to +4 due to changes in interval calculations
'this one is working, just throwing exception
'''
rules, task, belief, concept, task_link, term_link, result1, result2 = rule_map_two_premises(
tasks_derived = process_two_premises(
'<(*,John,key_101) --> hold>. :|: %1.00;0.90% ',
'<<(*,John,door_101) --> open> =/> <(*,John,room_101) --> enter>>. :|: %1.00;0.90%',
'John.'
None,
6
)
tasks_derived = [rule(task, belief, task_link, term_link) for rule in rules]
tasks_derived.extend(process_two_premises(
'<<(*,John,door_101) --> open> =/> <(*,John,room_101) --> enter>>. :|: %1.00;0.90%',
None,
100
))
Global.time = 0
self.assertTrue(
output_contains(tasks_derived, '<(&/,<(*,John,key_101) --> hold>,+6,<(*,John,door_101) --> open>) =/> <(*,John,room_101) --> enter>>. :!6: %1.00;0.45%')
)
Expand Down
6 changes: 4 additions & 2 deletions Tests/utils_for_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
NUM_CYCLES_MULTIPLIER = 10
def process_two_premises(premise1: str, premise2: str, n_cycle: int = 0) -> List[Task]:
''''''
time_before = Global.time

tasks_all_cycles = []

success, task, task_overflow = nars.input_narsese(premise1)
Expand All @@ -43,8 +45,8 @@ def process_two_premises(premise1: str, premise2: str, n_cycle: int = 0) -> List
tasks_all_cycles.extend(answers_quest)

# reset time to correctly reflect tense
# ignoring cycle times
Global.time = 0
# ignoring NUM_CYCLES_MULTIPLIER
Global.time = time_before + n_cycle

return [t for t in tasks_all_cycles if t is not None]

Expand Down
24 changes: 14 additions & 10 deletions pynars/NARS/Control/Reasoner.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from pynars.Narsese._py.Sentence import Judgement, Stamp, Tense
from pynars.Narsese._py.Statement import Statement
from pynars.Narsese._py.Task import Belief
from pynars.Narsese import Copula
from pynars.Narsese import Copula, Item
from ..DataStructures import Bag, Memory, NarseseChannel, Buffer, Task, Concept, EventBuffer
from ..InferenceEngine import GeneralEngine, TemporalEngine, VariableEngine, KanrenEngine
from pynars import Config
Expand All @@ -30,6 +30,12 @@ class Reasoner:
num_runs = 0

all_theorems = Bag(100, 100, take_in_order=False)
theorems_per_cycle = 10

class TheoremItem(Item):
def __init__(self, theorem, budget: Budget) -> None:
super().__init__(hash(theorem), budget)
self._theorem = theorem

def __init__(self, n_memory, capacity, config='./config.json', nal_rules={1, 2, 3, 4, 5, 6, 7, 8, 9}) -> None:
# print('''Init...''')
Expand All @@ -46,7 +52,7 @@ def __init__(self, n_memory, capacity, config='./config.json', nal_rules={1, 2,

for theorem in self.inference.theorems:
priority = random.randint(0,9) * 0.01
item = Concept.TheoremItem(theorem, Budget(0.5 + priority, 0.8, 0.5))
item = self.TheoremItem(theorem, Budget(0.5 + priority, 0.8, 0.5))
self.all_theorems.put(item)

# self.inference = GeneralEngine(add_rules=nal_rules)
Expand Down Expand Up @@ -86,7 +92,7 @@ def reset(self):
self.all_theorems.reset()
for theorem in self.inference.theorems:
priority = random.randint(0,9) * 0.01
item = Concept.TheoremItem(theorem, Budget(0.5 + priority, 0.8, 0.5))
item = self.TheoremItem(theorem, Budget(0.5 + priority, 0.8, 0.5))
self.all_theorems.put(item)

# reset metrics
Expand Down Expand Up @@ -384,11 +390,9 @@ def inference_step(self, concept: Concept):

results = []

theorems_per_cycle = 10

# t0 = time()
theorems = []
for _ in range(min(theorems_per_cycle, len(self.all_theorems))):
for _ in range(min(self.theorems_per_cycle, len(self.all_theorems))):
theorem = self.all_theorems.take(remove=True)
theorems.append(theorem)

Expand Down Expand Up @@ -491,11 +495,11 @@ def inference_step(self, concept: Concept):

results = []

# COMPOSITIONAL
res, cached = self.inference.inference_compositional(task.sentence, belief.sentence)
# # COMPOSITIONAL
# res, cached = self.inference.inference_compositional(task.sentence, belief.sentence)

if not cached:
results.extend(res)
# if not cached:
# results.extend(res)

# Temporal Projection and Eternalization
if belief is not None:
Expand Down
4 changes: 2 additions & 2 deletions pynars/NARS/DataStructures/_py/Buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,5 @@ def put(self, event_task_to_insert: Task):

def can_task_enter(self, task: Task):
return task.is_event \
and task.term.type == TermType.STATEMENT \
and not task.term.is_higher_order
and task.term.type == TermType.STATEMENT
# and not task.term.is_higher_order
9 changes: 0 additions & 9 deletions pynars/NARS/DataStructures/_py/Concept.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@ class Concept(Item):
task_links: Bag
term_links: Bag

all_theorems = Bag(100, 100, take_in_order=False)

class TheoremItem(Item):
def __init__(self, theorem, budget: Budget) -> None:
super().__init__(hash(theorem), budget)
self._theorem = theorem

# *Note*: since this is iterated frequently, an array should be used. To avoid iterator allocation, use .get(n) in a for-loop
question_table: Table # Pending Question directly asked about the term
quest_table: Table # Pending Question directly asked about the term
Expand Down Expand Up @@ -64,8 +57,6 @@ def __init__(self, term: Term, budget: Budget, capacity_table: int=None) -> None
self.task_links = Bag(Config.capacity_task_link, Config.nlevels_task_link)
self.term_links = Bag(Config.capacity_term_link, Config.nlevels_term_link)

self.theorems = deepcopy(Concept.all_theorems)

# self._cache_subterms()
# self.accept(task)

Expand Down
21 changes: 21 additions & 0 deletions pynars/NARS/InferenceEngine/KanrenEngine/KanrenEngine.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,17 @@ def inference_structural(self, t: Sentence, theorems = None):
truth = truth_functions[r](tr1, tr2)
results.append((res, truth))

# variable introduction
if type(res[0]) is Statement \
and res[0].copula == Copula.RetrospectiveImplication \
or res[0].copula == Copula.PredictiveImplication:
common_terms = self.common_terms(res[0].subject, res[0].predicate)
if len(common_terms):
intro = self.variable_introduction(res[0], common_terms)
print(intro == res[0])
if intro != res[0]:
results.append(((intro, res[1]), truth))

return results

#################
Expand Down Expand Up @@ -256,6 +267,16 @@ def inference_compositional(self, t1: Sentence, t2: Sentence):
results.append(((conclusion, r), truth))

return results

def common_terms(self, t1: Term, t2: Term):
return set(t1.sub_terms).intersection(t2.sub_terms) - set([place_holder])

def variable_introduction(self, conclusion: Term, common: set):
prefix = '$' if conclusion.is_statement else '#'
substitution = {logic(c, True, var_intro=True): var(prefix=prefix) for c in common}
reified = reify(logic(conclusion, True, var_intro=True), substitution)
conclusion = term(reified)
return conclusion

def determine_order(self, t1: Sentence, t2: Sentence, conclusion: Term):
# TODO: add .temporal() functions to Compound
Expand Down
10 changes: 4 additions & 6 deletions pynars/NARS/InferenceEngine/KanrenEngine/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
engine = KanrenEngine()
print('--')

x = parse('<A-->B>. %0.90;0.90%')
y = parse('<B-->A>. %0.90;0.90%')
rule = convert("{<S --> P>. <P --> S>} |- <S <-> P> .int")
conclusion = engine.apply(rule, logic(x.term), logic(y.term))[0]
print(truth_functions['int'](x.truth, y.truth))
print('')
x = parse('(&/, <(*, John, key_101)-->hold>, +6, <<(*, John, door_101)-->open>=/><(*, John, room_101)-->enter>>).')
# x = parse('(&/, A, +6, <B==>C>).')
r = engine.inference_structural(x, tuple(engine.theorems))
print(r)

exit()

Expand Down
4 changes: 4 additions & 0 deletions pynars/NARS/InferenceEngine/KanrenEngine/nal-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,7 @@ theorems: |
# 'not in the NAL book but a nice to have
<<T1 --> (/, R, _, T2)> <=> <T2 --> (/, R, T1, _)>>
<<T2 --> (/, R, T1, _)> <=> <T1 --> (/, R, _, T2)>>
<(&/, S1, N1, S2) <=> <S2 =\> (&/, S1, N1)>>
<(&/, S1, N1, S2) <=> <S1 =/> S2>>
<(&/, S1, N1, <S2 ==> S3>) <=> <(&/, S1, N1, S2) =/> S3>>
3 changes: 2 additions & 1 deletion pynars/NARS/InferenceEngine/KanrenEngine/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ def logic(term: Term, rule=False, substitution=False, var_intro=False, structura
vars.add(var(name))
return var(name) if rule else term
if term.is_statement:
return cons(term.copula.get_atemporal, *[logic(t, rule, substitution, var_intro, structural, prefix) for t in term.terms])
copula = term.copula if rule else term.copula.get_atemporal
return cons(copula, *[logic(t, rule, substitution, var_intro, structural, prefix) for t in term.terms])
if term.is_compound:
# when used in variable introduction, treat single component compounds as atoms
if rule and var_intro and len(term.terms) == 1 \
Expand Down
2 changes: 1 addition & 1 deletion pynars/Narsese/_py/Statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def repr(self, *args):
word_subject = str(self.subject) if not self.subject.has_var else self.subject.repr()
word_predicate = str(self.predicate) if not self.predicate.has_var else self.predicate.repr()

return f'<{word_subject+str(self.copula.value)+word_predicate}>'
return f'<{word_subject+" "+str(self.copula.value)+" "+word_predicate}>'

@classmethod
def Inheritance(cls, subject: Term, predicate: Term, is_input: bool=False, is_subterm=True):
Expand Down

0 comments on commit 17e81ef

Please sign in to comment.