Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
3 changes: 3 additions & 0 deletions pynars/Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class Config:

maximum_evidental_base_length = 20000

# cycle metrics
cycle_durations_window_length = 100

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to keep a fixed window instead of continuously calculated average?

# calculate average
self.cycles_count += 1
self.avg_cycle_duration += (self.last_cycle_duration - self.avg_cycle_duration) / self.cycles_count

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking was the variables could overflow if we don't set an upper limit to the sum/ cycles count. For example in this code the cycles_count is never capped. But I guess in practice NARS would never run for enough cycles to overflow, and it seems Python is also special in that it will infinitely extend integers so they never overflow

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python is also special in that it will infinitely extend integers so they never overflow

Wow, really? That's cool, do you have a link? just for my own education ;)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


@classmethod
def check(cls):
'''Check if each parameter is valid'''
Expand Down
6 changes: 6 additions & 0 deletions pynars/ConsolePlus.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@ def toggle_silent() -> None:
else "closed"
}.''')

@cmd_register('cycles')
def cycles(*args: List[str]) -> None:
'''Prints the "average cycles per second" metric'''
if(len(current_NARS_interface.reasoner.cycles_durations_window) == 0): current_NARS_interface.print_output(type=PrintType.INFO, content="No cycles have been run yet.")
else: current_NARS_interface.print_output(
type=PrintType.INFO, content=f'''The average cycles per second is {1 / current_NARS_interface.reasoner.avg_cycle_duration} based on the last {len(current_NARS_interface.reasoner.cycles_durations_window)} cycles. Last cycle took {current_NARS_interface.reasoner.last_cycle_duration:.32f} seconds.''')

@cmd_register(('volume'), (int, 100))
def volume(vol:int) -> None:
Expand Down
30 changes: 29 additions & 1 deletion pynars/NARS/Control/Reasoner.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from ..GlobalEval import GlobalEval



class Reasoner:

def __init__(self, n_memory, capacity, config='./config.json', nal_rules={1, 2, 3, 4, 5, 6, 7, 8, 9}) -> None:
Expand Down Expand Up @@ -50,6 +49,12 @@ def __init__(self, n_memory, capacity, config='./config.json', nal_rules={1, 2,

self.u_top_level_attention = 0.5

# metrics
self.last_cycle_duration = 0
self.cycles_durations_window = []
self.cycles_duration_window_sum = 0
self.avg_cycle_duration = 0

def reset(self):
self.memory.reset()
self.overall_experience.reset()
Expand All @@ -76,6 +81,7 @@ def input_narsese(self, text, go_cycle: bool = False) -> Tuple[bool, Union[Task,
return success, task, task_overflow

def cycle(self):
start_cycle_time_in_seconds = time()
"""Everything to do by NARS in a single working cycle"""
Global.States.reset()
tasks_derived: List[Task] = []
Expand Down Expand Up @@ -107,9 +113,14 @@ def cycle(self):
thresh_complexity = 20
tasks_derived = [
task for task in tasks_derived if task.term.complexity <= thresh_complexity]

"""done with cycle"""
self.do_cycle_metrics(start_cycle_time_in_seconds)

return tasks_derived, judgement_revised, goal_revised, answers_question, answers_quest, (
task_operation_return, task_executed)


def consider(self, tasks_derived: List[Task]):
"""
Consider a Concept in the Memory
Expand Down Expand Up @@ -272,3 +283,20 @@ def register_operator(self, name_operator: str, callback: Callable):
Operation.register(op, callback)
return op
return None

def do_cycle_metrics(self, start_cycle_time_in_seconds: float):
# record some metrics
total_cycle_duration_in_seconds = time() - start_cycle_time_in_seconds
self.last_cycle_duration = total_cycle_duration_in_seconds # store the cycle duration
# put it in with the others to find the avg duration
self.cycles_durations_window.append(total_cycle_duration_in_seconds)
self.cycles_duration_window_sum += total_cycle_duration_in_seconds

# we only want to keep track of a certain number of cycles, so remove old cycles
if len(self.cycles_durations_window) > Config.Config.cycle_durations_window_length:

self.cycles_duration_window_sum -= self.cycles_durations_window[0]
self.cycles_durations_window.pop(0)

self.avg_cycle_duration = self.cycles_duration_window_sum / len(self.cycles_durations_window) # avg seconds per 1 cycle