Skip to content

Commit

Permalink
feat: ✨ Spell typo fixes, improved '\op' test for NAL-8, new mental o…
Browse files Browse the repository at this point in the history
…perations from "NAL" textbook, implemented "register" mental operation, and added cmd 'register-operation'

- Fixed some spell typos
- Optimized "\op" test about NAL-8, now 'EXE' can be contained in outputs and obtained correctly
- Add a series of mental operations according to "NAL" textbook (2012), and add an implementation for the mental operation "register"
- New cmd "register-operation"/"register" to register custom operations globally without modifying source code of PyNARS
  • Loading branch information
ARCJ137442 committed Oct 19, 2023
1 parent 4b49df0 commit e44974b
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 42 deletions.
40 changes: 29 additions & 11 deletions Experiments/ExConsole/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from random import randint

# compatible type annotation
from typing import List, Dict, Tuple, Union
from typing import List, Dict, Tuple, Iterable

# information

Expand Down Expand Up @@ -207,24 +207,42 @@ def shared_memory_test() -> None:

@exp_register('op')
def operations_test() -> None:
task1: Task = NarseseParser.parse('<antecedent --> result>.') # auto parse
# term.type = TermType.STATEMENT # ! Only statements can be actions, not mandatory
statement1 = task1.term # term of the task
# register operation, the register of mental operations can be seen in pynars\NARS\InferenceEngine\GeneralEngine\Rules\NAL9.py
from pynars.NARS import Operation
def exeF(arguments: Iterable[Term], task: Task=None, memory: Memory=None) -> Union[Task,None]:
'''
The execution should accepts arguments (terms), task(current) and current memory(to deal mental operations)
@return a task(is used to represent the new task generated) or None(no task is processed)
'''
print(f'executed: arguments={arguments}, task={task}, memory={memory}. the "task" will be returned')
return task
Operation.register(Operation.Operation('f'), exeF)
# build task
# task1: Task = NarseseParser.parse('f(x).') # the same as <(*, x) --> ^f>.
# task1: Task = NarseseParser.parse('f(x).') # the same as <(*, x) --> ^f>.
# * Force the term involved in the task to be set to "action", if is_executable = True
statement1.is_operation = True
print(f'Is operation? {statement1.is_executable}')
# print(f'Is operation? {task1.is_executable}')
# placing tasks directly into perceptual channels (Narsese channels can only pass text)
# current_NARS_interface.reasoner.perception_channel.put(task1)
'''concept Concept: Concept = concept. _conceptualize( # Generate concept
current_NARS_interface.reasoner.memory,
term=statement Operation statement,
Budget=budget(0.9, 0.9, 0.5)
)
current_NARS_interface.reasoner.memory.concepts.put(concept)
# into the concept, but it does not seem to be associated with the task, the reasoner will not use it.
# '''
# placing tasks directly into perceptual channels (Narsese channels can only pass text)
current_NARS_interface.reasoner.perception_channel.put(task1)
# Automatic reasoning five steps, let NAS put "antecedent" and "result" into the memory area
'''
# into the concept, but it does not seem to be associated with the task, the reasoner will not use it.
# run other cmds
execute_input('5')
execute_input('<A ==> G>.')
execute_input('<(^f, x) ==> A>.')
execute_input('5')
current_NARS_interface.input_narsese('G!') # avoid to be <G>!
# Automatic reasoning five steps, let NAS put "antecedent" and "result" into the memory area
execute_input('/waitans ACHIEVED')
# * it should be contained with two outputs:
# * `EXE :<(*, x)-->^f> = $0.022;0.225;0.644$ <(*, x)-->^f>! %1.000;0.287% {None: 2, 1, 0}`
# * `ACHIEVED:<(*, x)-->^f>. :\: %1.000;0.900%`
# print concept list
print(show_bag(current_NARS_interface.reasoner.memory.concepts))

Expand Down
2 changes: 1 addition & 1 deletion pynars/Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
raise "please install the module by `pip install jstyleson`"

class Enable:
temporal_rasoning = False
temporal_reasoning = False
variable = True
anticipation = False
operation = False
Expand Down
56 changes: 47 additions & 9 deletions pynars/ConsolePlus.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
from typing import List, Dict, Tuple, Union
from typing import List
from typing import List, Dict, Tuple, Union, Iterable
import functools
import re
from pynars.Interface import narsese_parse_safe
from pynars.Narsese import Term,Task
from pynars.NARS.DataStructures import Memory

from pynars.Interface import NARSInterface
from pynars.Interface import NARSOutput
from pynars.Interface import PrintType
from pynars.Interface import Reasoner
from pynars.Interface import print_out_origin
from pynars.Interface import NARSInterface,NARSOutput,PrintType,Reasoner,print_out_origin
print_output = print_out_origin

# compatible type annotation
Expand Down Expand Up @@ -258,14 +255,55 @@ def print_history(*args: List[str]) -> None:
def exec_code(*args: List[str]) -> None:
'''Format: exec <Python code >
Directly invoke Python's built-in exec cmd to execute a single line of code'''
exec(' '.join(args))
code = " ".join(args)
print(f'[exec]{code}')
try:
exec(code)
except BaseException as e:
print(f'exec failed: {e}')


@cmd_register(('evaluate', 'eval'))
def eval_code(*args: List[str]) -> None:
'''Format: eval <Python code >
Directly invoke Python's built-in eval cmd to evaluate a single line of code'''
print(f'eval result: {eval(" ".join(args))}')
code = " ".join(args)
print(f'[eval]{code}')
try:
print(f'eval result: {eval(code)}')
except BaseException as e:
print(f'eval failed: {e}')


@cmd_register(('register-operation', 'register'))
def register_operation(*args: List[str]) -> None:
'''Format: register-operation <Operation(Term) Name> <"eval"/"exec"> <Python Code>
Register an operation to the whole PyNARS instance.
function signature:
execution_F(arguments: Iterable[Term], task: Task=None, memory: Memory=None) -> Union[Task,None]
! Unsupported: register mental operations
'''
name = args[0]
eType = args[1]
code = " ".join(args[2:])
if code == '':
def execution_F(arguments: Iterable[Term], task: Task=None, memory: Memory=None) -> Union[Task,None]:
print(f'executed: arguments={arguments}, task={task}, memory={memory}. the "task" will be returned')
return task
else:
if eType =='exec':
def execution_F(arguments: Iterable[Term], task: Task=None, memory: Memory=None) -> Union[Task,None]:
return exec(code)
else:
def execution_F(arguments: Iterable[Term], task: Task=None, memory: Memory=None) -> Union[Task,None]:
return eval(code)
execution_F.__doc__ = f'''
The execution is auto generated from operator {name} in {eType} mode with code={code}
'''
from pynars.NARS.Operation.Register import register
from pynars.NARS.Operation import Operation
register(Operation(name), execution_F)
print(f'Operation {name} was successfully registered in mode "{eType}" with code={code}')


@cmd_register(('simplify-parse', 'parse'))
Expand Down
2 changes: 1 addition & 1 deletion pynars/NAL/Inference/LocalRules.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def revision(task: Task, belief: Task, budget_tasklink: Budget=None, budget_term
premise2: Union[Judgement, Goal] = belief.sentence
truth1 = premise1.truth
truth2 = premise2.truth
if Enable.temporal_rasoning:
if Enable.temporal_reasoning:
# boolean useNewBeliefTerm = intervalProjection(nal, newBelief.getTerm(), oldBelief.getTerm(), beliefConcept.recent_intervals, newTruth);
raise
truth = Truth_revision(truth1, truth2)
Expand Down
15 changes: 12 additions & 3 deletions pynars/NAL/MentalOperation/_execute.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List
from typing import Callable, List
from pynars.Config import Config
from pynars.Narsese._py.Budget import Budget
from pynars.Narsese._py.Operation import *
Expand All @@ -23,7 +23,7 @@ def execute(task: Task):
return None

def anticipate(task: Task, *args: Term):
''''''
'''TODO'''

def believe(statement: Term, term_truth: Term):
''''''
Expand All @@ -37,7 +37,7 @@ def believe(statement: Term, term_truth: Term):
def doubt(beliefs: List[Belief]):
''''''
for belief in beliefs:
# discount the confidence of the beleif
# discount the confidence of the belief
belief.truth.c = belief.truth.c * Config.rate_discount_c
return None

Expand Down Expand Up @@ -74,3 +74,12 @@ def wonder(statement: Term):
sentence = Question(statement, stamp=stamp)
return Task(sentence, budget)


def register(term: Term, callable: Callable=lambda arguments, task, memory: print(f'operation "{task.term.word}" is executed with arguments {arguments}')):
'''let a term be used as an operator'''
try:
from pynars.NARS.Operation.Register import register
register(term, callable)
except BaseException as e:
print(e)
return None
13 changes: 7 additions & 6 deletions pynars/NARS/Control/Reasoner.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,14 @@ def cycle(self):
# if task.is_goal:
# goal_revised = self.process_goal(task, concept)
judgement_revised, goal_revised, answers_question, answers_quest, (task_operation_return, task_executed), _tasks_derived = self.memory.accept(task)
if task_operation_return is not None: tasks_derived.append(task_operation_return)
if task_operation_return is not None:
tasks_derived.append(task_operation_return)
# if task_executed is not None: tasks_derived.append(task_executed)
tasks_derived.extend(_tasks_derived)
# self.sequence_buffer.put_back(task) # globalBuffer.putBack(task,
# narParameters.GLOBAL_BUFFER_FORGET_DURATIONS, this)

if Enable.temporal_rasoning:
if Enable.temporal_reasoning:
# TODO: Temporal Inference
# Ref: OpenNARS 3.1.0 line 409~411
# if (!task.sentence.isEternal() && !(task.sentence.term instanceof Operation)) {
Expand Down Expand Up @@ -124,7 +125,7 @@ def cycle(self):
self.memory.put_back(concept)

# temporal induction in NAL-7
if False and task is not None and task.is_judgement and task.is_external_event:
if Enable.temporal_reasoning and task is not None and task.is_judgement and task.is_external_event:
concept_task: Concept = self.memory.take_by_key(task.term, remove=False)
t1 = time()
tasks_derived.extend(
Expand All @@ -140,7 +141,7 @@ def cycle(self):
pass # TODO: select a task from `self.sequence_buffer`?

# mental operation of NAL-9
if False:
if Enable.operation: # it should be `Enable.mental_operation`?
task_operation_return, task_executed, belief_awared = self.mental_operation(task, concept, answers_question,
answers_quest)
if task_operation_return is not None: tasks_derived.append(task_operation_return)
Expand All @@ -153,8 +154,8 @@ def cycle(self):

# handle the sense of time
Global.time += 1
thresh_compexity = 20
tasks_derived = [task for task in tasks_derived if task.term.complexity <= thresh_compexity]
thresh_complexity = 20
tasks_derived = [task for task in tasks_derived if task.term.complexity <= thresh_complexity]
return tasks_derived, judgement_revised, goal_revised, answers_question, answers_quest, (
task_operation_return, task_executed)

Expand Down
4 changes: 2 additions & 2 deletions pynars/NARS/DataStructures/_py/Concept.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def term(self) -> Term:

def get_belief(self) -> Belief:
''''''
if Enable.temporal_rasoning:
if Enable.temporal_reasoning:
# final Sentence belief = beliefT.sentence;
# nal.emit(BeliefSelect.class, belief);
# nal.setTheNewStamp(taskStamp, belief.stamp, currentTime);
Expand Down Expand Up @@ -202,7 +202,7 @@ def _conceptualize(cls, concepts: Bag, term: Term, budget: Budget):
If the concept of the task is already in the memory, then merge the concept into the existed one.
Otherwise, make up a new concept and add it into the memory.
'''
if Enable.temporal_rasoning:
if Enable.temporal_reasoning:
# if(term instanceof Interval) {
# return null;
# }
Expand Down
6 changes: 3 additions & 3 deletions pynars/NARS/DataStructures/_py/Memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def accept(self, task: Task):
# Build the concepts corresponding to the terms of those components within the task.
concept.accept(task, self.concepts, conceptualize=False)

if Enable.temporal_rasoning or Enable.operation:
if Enable.temporal_reasoning or Enable.operation:
# if (!task.sentence.isEternal() && !(task.sentence.term instanceof Operation)) {
# globalBuffer.eventInference(task, cont, false); //can be triggered by Buffer itself in the future
# }
Expand All @@ -94,7 +94,7 @@ def _accept_judgement(self, task: Task, concept: Concept):
if belief is not None:
# j2: Judgement = belief.sentence
if revisible(task, belief):
if Enable.temporal_rasoning:
if Enable.temporal_reasoning:
'''
nal.setTheNewStamp(newStamp, oldStamp, nal.time.time());
final Sentence projectedBelief = oldBelief.projection(nal.time.time(), newStamp.getOccurrenceTime(), concept.memory);
Expand Down Expand Up @@ -245,8 +245,8 @@ def _accept_goal(self, task: Task, concept: Concept, task_link: TaskLink=None):
op = stat.predicate
from pynars.NARS.Operation.Register import registered_operations
from pynars.NARS.Operation.Execution import execute
# ! if `op` isn't registered, an error "AttributeError: 'NoneType' object has no attribute 'stamp'" from "key: Callable[[Task], Any] = lambda task: (hash(task), hash(task.stamp.evidential_base))" will be raised
if op in registered_operations and not task.is_mental_operation:

# to judge whether the goal has been fulfilled
task_operation_return, task_executed = execute(task, concept, self)
concept_task = self.take_by_key(task.term, remove=False)
Expand Down
4 changes: 4 additions & 0 deletions pynars/NARS/Operation/Interface_Execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ def execute__want(arguments: Iterable[Term], task: Task=None, memory: Memory=Non
return _execute.want(statement)


def execute__register(arguments: Iterable[Term], task: Task=None, memory: Memory=None):
'''let a term be used as an operator'''
term = arguments[1]
return _execute.register(term)
70 changes: 64 additions & 6 deletions pynars/Narsese/_py/Operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,69 @@ def do_hashing(self):
self._hash_value = hash(str(self))
return self._hash_value


Anticipate = Operation('anticipate', True, is_mental_operation=True)
Believe = Operation('believe', True, is_mental_operation=True)
Doubt = Operation('doubt', True, is_mental_operation=True)
Evaluate = Operation('evaluate', True, is_mental_operation=True)
Hesitate = Operation('hesitate', True, is_mental_operation=True)
Want = Operation('want', True, is_mental_operation=True)
Wonder = Operation('wonder', True, is_mental_operation=True)

# With reference to book NAL(2012)
Observe = Operation('observe', True, is_mental_operation=True)
'''get an active task from the task buffer'''

Expect = Operation('expect', True, is_mental_operation=True)
'''check the input for a given statement'''

Know = Operation('know', True, is_mental_operation=True)
'''find the truth-value of a statement'''

Assess = Operation('assess', True, is_mental_operation=True)
'''find the desire-value of a statement'''

Believe = Operation('believe', True, is_mental_operation=True)
'''turn a statement into a task containing a judgment'''

Want = Operation('want', True, is_mental_operation=True)
'''turn a statement into a task containing a goal'''

Wonder = Operation('wonder', True, is_mental_operation=True)
'''turn a statement into a task containing a question'''

Remember = Operation('remember', True, is_mental_operation=True)
'''turn a statement into a belief'''

Consider = Operation('consider', True, is_mental_operation=True)
'''do inference on a concept'''

Remind = Operation('remind', True, is_mental_operation=True)
'''activate a concept'''

Doubt = Operation('doubt', True, is_mental_operation=True)
'''decrease the confidence of a belief'''

Hesitate = Operation('hesitate', True, is_mental_operation=True)
'''decrease the confidence of a goal'''

Assume = Operation('assume', True, is_mental_operation=True)
'''temporarily take a statement as a belief'''

Name = Operation('name', True, is_mental_operation=True)
'''create a simple internal ID to a useful compound term'''

Wait = Operation('wait', True, is_mental_operation=True)
'''pause the system’s action for a given number of working cycles'''

Repeat = Operation('repeat', True, is_mental_operation=True)
'''execute an action repeatedly under a given condition'''

Tell = Operation('tell', True, is_mental_operation=True)
'''produce an outgoing task containing a judgment'''

Demand = Operation('demand', True, is_mental_operation=True)
'''produce an outgoing task containing a goal'''

Ask = Operation('ask', True, is_mental_operation=True)
'''produce an outgoing task containing a question'''

Check = Operation('check', True, is_mental_operation=True)
'''produce an outgoing task containing a query'''

Register = Operation('register', True, is_mental_operation=True)
'''let a term be used as an operator'''

0 comments on commit e44974b

Please sign in to comment.