Skip to content

Commit

Permalink
Merge pull request #92 from bowen-xu/update_task_and_link_budget
Browse files Browse the repository at this point in the history
Update Task and Link Budgets
  • Loading branch information
bowen-xu authored Mar 8, 2024
2 parents 5cab9f4 + 5698837 commit 4e379ad
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 53 deletions.
2 changes: 1 addition & 1 deletion pynars/NAL/Inference/LocalRules.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def revision(task: Task, belief: Task, budget_tasklink: Budget=None, budget_term
raise "Invalid case."
return task

def solution_question(task: Task, belief: Belief, budget_tasklink: Budget=None, budget_termlink: Budget=None):
def solution_question(task: Task, belief: Task, budget_tasklink: Budget=None, budget_termlink: Budget=None):
question: Union[Question, Quest] = task.sentence
answer: Union[Judgement, Goal] = belief.sentence
answer_best = question.best_answer
Expand Down
16 changes: 9 additions & 7 deletions pynars/NARS/DataStructures/_py/Link.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,6 @@ def get_index(cls, main_term: Union[Term, Statement, Compound], sub_term: Union[

return indices

@classmethod
def update_budget(cls, budget: Budget, q: float, p_belief: float):
budget.priority = min(1.0, Or(budget.priority, Or(q, p_belief)))
budget.durability = min(1.0-Config.budget_epsilon, Or(budget.durability, q))



@property
def is_valid(self):
Expand All @@ -211,6 +205,11 @@ def set_type(self, source_is_component=True, type: LinkType=None):
Link.set_type(self, source_is_component, type)
if not self.is_valid: self.type = None


def reward_budget(self, reward: float):
self.budget.quality = Or(self.budget.quality, reward)


@property
def is_valid(self):
return self.type in (
Expand Down Expand Up @@ -240,12 +239,15 @@ def __init__(self, source: 'Concept', target: 'Concept', budget: Budget, copy_bu
def set_type(self, source_is_component=True, type: LinkType=None):
Link.set_type(self, source_is_component, type, enable_transform=True)
if not self.is_valid: self.type = None

def reward_budget(self, reward: float):
self.budget.priority = Or(self.budget.priority, reward)

@property
def is_valid(self) -> bool:
return self.type in (
LinkType.SELF,
LinkType.COMPOUND,
LinkType.COMPOUND,
LinkType.COMPOUND_STATEMENT,
LinkType.COMPOUND_CONDITION,
LinkType.TRANSFORM,
Expand Down
90 changes: 50 additions & 40 deletions pynars/NARS/DataStructures/_py/Memory.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
from pynars.NAL.Functions import BudgetFunctions

from pynars import Global
from pynars.Config import Enable, Config
from pynars.NAL.Inference.LocalRules import solve_query, solution_query, solution_question
from pynars.NAL.Functions.BudgetFunctions import Budget_evaluate_goal_solution
from pynars.NAL.Functions.Tools import calculate_solution_quality
from pynars.NAL.Functions.Tools import project, project_truth
from pynars.NAL.Functions.Tools import revisible
from pynars.NAL.Inference import local__revision
from pynars.NAL.Inference.LocalRules import solution_query, solution_question
from pynars.NAL.MetaLevelInference.VariableSubstitution import get_elimination__var_const

from pynars.NARS.DataStructures._py.Link import TaskLink
from pynars.Narsese._py.Sentence import Goal, Judgement, Question
from pynars.Narsese import Statement, Term, Sentence, Budget, Task, Truth
from pynars.NARS.GlobalEval import GlobalEval
from pynars.Narsese import Statement, Budget, Task
from pynars.Narsese._py.Sentence import Goal, Question
from pynars.Narsese._py.Task import Belief, Desire
from .Concept import Concept
from .Bag import Bag
from pynars.NAL.Functions.Tools import revisible
from pynars.NAL.Inference import local__revision
# from pynars.NARS import Operation
from pynars.NAL.Functions.Tools import project, project_truth
from pynars import Global
from pynars.NAL.Functions.BudgetFunctions import Budget_evaluate_goal_solution
from pynars.NAL.Functions.Tools import calculate_solution_quality
from typing import Callable, Any
from pynars.NARS.GlobalEval import GlobalEval
from .Concept import Concept


class Memory:
def __init__(self, capacity: int, n_buckets: int = None, take_in_order: bool = False, output_buffer = None, global_eval: GlobalEval=None) -> None:
Expand Down Expand Up @@ -299,7 +295,7 @@ def _accept_quest(self, task: Task, concept: Concept):

return answers

def _solve_judgement(self, belief: Task, concept: Concept):
def _solve_judgement(self, belief_task: Task, concept: Concept):
'''
It should be ensured that the task has no query-variables.
Expand All @@ -309,11 +305,20 @@ def _solve_judgement(self, belief: Task, concept: Concept):
'''
answers = []
# 1. try to solve yn-questions
for question in concept.question_table:
answer = solution_question(question, belief)
for question_task in concept.question_table:
question: Question = question_task.sentence
old_answer = question.best_answer
answer = solution_question(question_task, belief_task)
new_answer = question.best_answer
if old_answer != new_answer:
# the belief is a better answer to the question, so reward the Task and tasklinks
reward = question_task.achieving_level()
belief_task.reward_budget(reward)
for task_link in concept.task_links:
task_link.reward_budget(reward)
if answer is not None: answers.append(answer)
# 2. try to solve wh-questions
sub_terms = belief.term.sub_terms
sub_terms = belief_task.term.sub_terms
for sub_term in sub_terms:
concept_term: Concept = self.concepts.take_by_key(sub_term, remove=False)
if concept_term is None: continue
Expand All @@ -322,8 +327,8 @@ def _solve_judgement(self, belief: Task, concept: Concept):
query = task_link.target
if query is None: continue
if not query.is_query: continue
if not query.term.equal(belief.term): continue
answer = solution_query(query, belief)
if not query.term.equal(belief_task.term): continue
answer = solution_query(query, belief_task)
if answer is not None: answers.append(answer)

return answers
Expand Down Expand Up @@ -374,42 +379,47 @@ def _solve_query(self, query: Task, concept: Concept):
raise "Invalid case."
return answers

def _solve_goal(self, task: Task, concept: Concept, task_link: TaskLink=None, belief=None):
def _solve_goal(self, goal_task: Task, concept: Concept, task_link: TaskLink=None, belief_task: Task =None):
'''
Args:
task (Task): Its sentence should be a goal.
goal_task (Task): Its sentence should be a goal.
concept (Concept): The concept corresponding to the task.
'''
tasks = []
belief = belief or concept.match_belief(task.sentence)
if belief is None:
self.global_eval.update_satisfaction(task.achieving_level(), task.budget.priority)
belief_task = belief_task or concept.match_belief(goal_task.sentence)
if belief_task is None:
self.global_eval.update_satisfaction(goal_task.achieving_level(), goal_task.budget.priority)
return tasks, None
old_best = task.best_solution
old_best = goal_task.best_solution

belief = belief or concept.match_belief(task.sentence)
if belief is None or belief == old_best:
belief_task = belief_task or concept.match_belief(goal_task.sentence)
if belief_task is None or belief_task == old_best:
return tasks, None
elif belief_task != old_best:
reward = goal_task.achieving_level()
belief_task.reward_budget(reward)
for task_link in concept.task_links:
task_link.reward_budget(reward)

if old_best is not None:
quality_new = calculate_solution_quality(task.sentence, belief.sentence, True)
quality_old = calculate_solution_quality(task.sentence, old_best.sentence, True)
quality_new = calculate_solution_quality(goal_task.sentence, belief_task.sentence, True)
quality_old = calculate_solution_quality(goal_task.sentence, old_best.sentence, True)
if (quality_new <= quality_old):
return tasks, belief
return tasks, belief_task

task.best_solution = belief
tasks.append(belief) # the task as the new best solution should be added into the internal buffer, so that it would be paid attention
budget = Budget_evaluate_goal_solution(task.sentence, belief.sentence, task.budget, (task_link.budget if task_link is not None else None))
goal_task.best_solution = belief_task
tasks.append(belief_task) # the task as the new best solution should be added into the internal buffer, so that it would be paid attention
budget = Budget_evaluate_goal_solution(goal_task.sentence, belief_task.sentence, goal_task.budget, (task_link.budget if task_link is not None else None))
if budget.is_above_thresh:
task.budget = budget
tasks.append(task)
goal_task.budget = budget
tasks.append(goal_task)

''' Here, belief is not None, and it is the best solution for the task
Thus, do global evaluation to update satisfaction of the system.
'''
self.global_eval.update_satisfaction(task.achieving_level(belief.truth), task.budget.priority)
self.global_eval.update_satisfaction(goal_task.achieving_level(belief_task.truth), goal_task.budget.priority)

return tasks, belief
return tasks, belief_task

def _solve_quest(self, task: Task, concept: Concept):
'''
Expand Down
13 changes: 8 additions & 5 deletions pynars/NARS/InferenceEngine/GeneralEngine/GeneralEngine.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,11 +391,14 @@ def step(self, concept: Concept):
if is_valid:
Global.States.record_premises(task, belief)
Global.States.record_rules(rules)
tasks = self.inference(task, belief, term_belief, task_link_valid, term_link_valid, rules)
if term_link_valid is not None: # TODO: Check here whether the budget updating is the same as OpenNARS 3.0.4.
for task in tasks: TermLink.update_budget(term_link_valid.budget, task.budget.quality, belief.budget.priority if belief is not None else concept_target.budget.priority)

tasks_derived.extend(tasks)
new_tasks = self.inference(task, belief, term_belief, task_link_valid, term_link_valid, rules)
if term_link_valid is not None:
# reward the termlink
for new_task in new_tasks:
reward: float = max(new_task.budget.priority, task.achieving_level())
term_link_valid.reward_budget(reward)

tasks_derived.extend(new_tasks)

for term_link in term_links: concept.term_links.put_back(term_link)

Expand Down
8 changes: 8 additions & 0 deletions pynars/Narsese/_py/Task.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from copy import copy
from typing import Type, Union

from pynars import NAL

from .Sentence import Sentence, Judgement, Goal, Quest, Question, Stamp
from .Item import Item
from .Budget import Budget
from .Term import Term
from .Truth import Truth



class Task(Item):
input_id = -1
best_solution: 'Task' = None
Expand Down Expand Up @@ -35,6 +40,9 @@ def achieving_level(self, previous_belief: Truth=None):
else:
raise f'Invalid type! {type(self.sentence)}'

def reward_budget(self, reward: float):
self.budget.priority = NAL.Functions.Or(self.budget.priority, reward)

def reduce_budget_by_achieving_level(self, belief_selected: Union[Type['Belief'], None]):
truth = belief_selected.truth if belief_selected is not None else None
self.budget.reduce_by_achieving_level(self.achieving_level(truth))
Expand Down

0 comments on commit 4e379ad

Please sign in to comment.