Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Task and Link Budgets #92

Merged
merged 4 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading