diff --git a/pynars/Config.py b/pynars/Config.py index 93ac5a4..b5fd104 100644 --- a/pynars/Config.py +++ b/pynars/Config.py @@ -81,7 +81,6 @@ class Config: n_sequence_attempts = 10 n_op_condition_attempts = 10 - projection_decay = 0.99 Td_decision_threshold = 0.51 # what this value represents was originally equal to the termlink record length (10), but we may want to adjust it or make it scaled according to duration since it has more to do with time than # of records. it can probably be increased several times larger since each item should remain in the recording queue for longer than 1 cycle diff --git a/pynars/ConsolePlus.py b/pynars/ConsolePlus.py index 9f5b4ff..67bea90 100644 --- a/pynars/ConsolePlus.py +++ b/pynars/ConsolePlus.py @@ -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(current_NARS_interface.reasoner.cycles_count == 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 {int(1 // current_NARS_interface.reasoner.avg_cycle_duration)} based on the last {current_NARS_interface.reasoner.cycles_count} cycles. Last cycle took {current_NARS_interface.reasoner.last_cycle_duration:.6f} seconds.''') @cmd_register(('volume'), (int, 100)) def volume(vol:int) -> None: diff --git a/pynars/NAL/Functions/TemporalFunctions.py b/pynars/NAL/Functions/TemporalFunctions.py index 1ce7229..d31b94f 100644 --- a/pynars/NAL/Functions/TemporalFunctions.py +++ b/pynars/NAL/Functions/TemporalFunctions.py @@ -6,22 +6,23 @@ def project(truth: Truth, t_source: int, t_current: int, t_target: int): ''' Reference: - [1] OpenNARS 3.1.0 TruthFunctions.java line 492~495: - ``` - public static final float temporalProjection(final long sourceTime, final long targetTime, final long currentTime, Parameters param) { - final double a = 100000.0 * param.PROJECTION_DECAY; //projection less strict as we changed in v2.0.0 10000.0 slower decay than 100000.0 - return 1.0f - abs(sourceTime - targetTime) / (float) (abs(sourceTime - currentTime) + abs(targetTime - currentTime) + a); - } - ``` - [2] Hammer, Patrick, Tony Lofthouse, and Pei Wang. "The OpenNARS implementation of the non-axiomatic reasoning system." International conference on artificial general intelligence. Springer, Cham, 2016. + p.172 Non-Axiomatic Logic + — A Model of Intelligent Reasoning + (Second Edition) + ''' + v = abs(t_source - t_target) - Section 5. Projection and Eternalization + t_current_is_in_interval = False + if t_source < t_target: + if t_current >= t_source and t_current <= t_target: t_current_is_in_interval = True + else: + if t_current <= t_source and t_current >= t_target: t_current_is_in_interval = True - $$k_c = \frac{|tB - tT|}{|tB - tC| + |tT - tC|}$$ + if t_current_is_in_interval: s = 0.5 + else: s = min(abs(t_source - t_current),abs(t_target-t_current)) - $$c_{new} = (1 - k_c) * c_{old}$$ - ''' - c_new = truth.c * (Config.projection_decay ** (t_current - t_source)) + confidence_discount = 1 - v/(2*s + v) + c_new = truth.c * confidence_discount return Truth(truth.f, c_new, truth.k) diff --git a/pynars/NARS/Control/Reasoner.py b/pynars/NARS/Control/Reasoner.py index f5f9583..1a9174c 100644 --- a/pynars/NARS/Control/Reasoner.py +++ b/pynars/NARS/Control/Reasoner.py @@ -28,6 +28,7 @@ from ..GlobalEval import GlobalEval from ..InferenceEngine.KanrenEngine import util + class Reasoner: avg_inference = 0 num_runs = 0 @@ -82,6 +83,11 @@ def __init__(self, n_memory, capacity, config='./config.json', self.u_top_level_attention = 0.5 + # metrics + self.cycles_count = 0 + self.last_cycle_duration = 0 + self.avg_cycle_duration = 0 + def reset(self): self.memory.reset() self.overall_experience.reset() @@ -121,6 +127,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] = [] @@ -152,9 +159,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 @@ -614,4 +626,13 @@ def add_task(term): concept.term_links.put_back(term_link) return list(filter(lambda t: t.is_question or t.truth.c > 0, tasks_derived)) - \ No newline at end of file + + # METRICS + + 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 + # calculate average + self.cycles_count += 1 + self.avg_cycle_duration += (self.last_cycle_duration - self.avg_cycle_duration) / self.cycles_count diff --git a/pynars/NARS/InferenceEngine/KanrenEngine/KanrenEngine.py b/pynars/NARS/InferenceEngine/KanrenEngine/KanrenEngine.py index 2ca0913..ed8a6ef 100644 --- a/pynars/NARS/InferenceEngine/KanrenEngine/KanrenEngine.py +++ b/pynars/NARS/InferenceEngine/KanrenEngine/KanrenEngine.py @@ -78,6 +78,7 @@ def backward(self, q: Sentence, t: Sentence) -> list: continue (p1, p2, c) = rule[0] sub_terms = term(p1).sub_terms | term(p2).sub_terms | term(c).sub_terms + # conclusion should not have terms from the rule like S, P, or M if sub_terms.isdisjoint(res[0].sub_terms): r, _ = rule[1] inverse = True if r[-1] == "'" else False