Skip to content

Commit

Permalink
Implement Intensional and Extensional Image as one-premise inference;…
Browse files Browse the repository at this point in the history
… Big efficiency boost: Fix get_semantically_related_concept to actually provide related concepts more often
  • Loading branch information
ccrock4t committed May 5, 2021
1 parent c41d3bc commit 00587ce
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 32 deletions.
2 changes: 2 additions & 0 deletions Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
MINDFULNESS = 0.90 # between 0-1, how much attention the system allocates to the present moment (overall experience buffer) [1.0] vs. pondering concepts [0.0]
MEMORY_CONCEPT_CAPACITY = 50000 # how many concepts can this NARS have?
PRIORITY_DECAY_MULTIPLIER = 0.95 # value in [0,1] multiplied w/ priority during priority decay
NUMBER_OF_ATTEMPTS_TO_SEARCH_FOR_SEMANTICALLY_RELATED_CONCEPT = 10 # The number of times to look for a semantically related concept
NUMBER_OF_ATTEMPTS_TO_SEARCH_FOR_SEMANTICALLY_RELATED_BELIEF = 10 # The number of times to look for a semantically related belief to interact with

"""
Bags
Expand Down
7 changes: 7 additions & 0 deletions Global.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"""

import NARSGUI
import NALGrammar


class Global:
"""
Expand All @@ -15,6 +17,11 @@ class Global:
SENTENCE_ID_MARKER = "SentenceID:"
ID_END_MARKER = ":ID "

"""
Terms
"""
IMAGE_PLACEHOLDER_TERM = NALGrammar.Term.from_string("_")

# thread ready boolean
thread_ready_gui = False
thread_ready_input = False
Expand Down
96 changes: 95 additions & 1 deletion NALInferenceRules.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Config
import Global
import NALGrammar
import NALSyntax

Expand Down Expand Up @@ -436,7 +437,7 @@ def Contraposition(j):
Frequency must be below one or confidence of conclusion will be zero
:param j:
:return:s
:return: ((--,P) ==> (--,S))
"""
NALGrammar.assert_sentence(j)
# Statement
Expand All @@ -459,6 +460,99 @@ def Contraposition(j):

return result

def ExtensionalImage(j: NALGrammar.Sentence):
"""
Intensional Image
Inputs:
j: ((*,S,P) --> R)
:param j:
:returns: array of
(S --> (/,R,_,P))
and
(P --> (/,R,S,_))
"""
NALGrammar.assert_sentence(j)

# Statement
S = j.statement.get_subject_term().subterms[0];
P = j.statement.get_subject_term().subterms[1];
R = j.statement.get_predicate_term()

image_term_1 = NALGrammar.CompoundTerm([R, Global.Global.IMAGE_PLACEHOLDER_TERM, P],
NALSyntax.TermConnector.ExtensionalImage)

result_statement_1 = NALGrammar.Statement(S,
image_term_1,
NALSyntax.Copula.Inheritance)

image_term_2 = NALGrammar.CompoundTerm([R, S, Global.Global.IMAGE_PLACEHOLDER_TERM],
NALSyntax.TermConnector.ExtensionalImage)

result_statement_2 = NALGrammar.Statement(P,
image_term_2,
NALSyntax.Copula.Inheritance)

if j.punctuation == NALSyntax.Punctuation.Judgment:
result_truth = NALGrammar.TruthValue(j.value.frequency, j.value.confidence)
result_1 = NALGrammar.Judgment(result_statement_1, result_truth)
result_2 = NALGrammar.Judgment(result_statement_2, result_truth)
elif j.punctuation == NALSyntax.Punctuation.Question:
result_1 = NALGrammar.Question(result_statement_1)
result_2 = NALGrammar.Question(result_statement_2)

# merge in the parent sentence's evidential base
result_1.stamp.evidential_base.merge_sentence_evidential_base_into_self(j)
result_2.stamp.evidential_base.merge_sentence_evidential_base_into_self(j)

return [result_1, result_2]

def IntensionalImage(j: NALGrammar.Sentence):
"""
Intensional Image
Inputs:
j: (R --> (*,S,P))
:param j:
:returns: array of
((/,R,_,P) --> S)
and
((/,R,S,_) --> P)
"""
NALGrammar.assert_sentence(j)

# Statement
S = j.statement.get_predicate_term().subterms[0];
P = j.statement.get_predicate_term().subterms[1];
R = j.statement.get_subject_term()

image_term_1 = NALGrammar.CompoundTerm([R, Global.Global.IMAGE_PLACEHOLDER_TERM, P],
NALSyntax.TermConnector.IntensionalImage)

result_statement_1 = NALGrammar.Statement(image_term_1,
S,
NALSyntax.Copula.Inheritance)

image_term_2 = NALGrammar.CompoundTerm([R, S, Global.Global.IMAGE_PLACEHOLDER_TERM],
NALSyntax.TermConnector.IntensionalImage)

result_statement_2 = NALGrammar.Statement(image_term_2,
P,
NALSyntax.Copula.Inheritance)

if j.punctuation == NALSyntax.Punctuation.Judgment:
result_truth = NALGrammar.TruthValue(j.value.frequency, j.value.confidence)
result_1 = NALGrammar.Judgment(result_statement_1, result_truth)
result_2 = NALGrammar.Judgment(result_statement_2, result_truth)
elif j.punctuation == NALSyntax.Punctuation.Question:
result_1 = NALGrammar.Question(result_statement_1)
result_2 = NALGrammar.Question(result_statement_2)

# merge in the parent sentence's evidential base
result_1.stamp.evidential_base.merge_sentence_evidential_base_into_self(j)
result_2.stamp.evidential_base.merge_sentence_evidential_base_into_self(j)

return [result_1, result_2]

"""
======================================
Expand Down
2 changes: 1 addition & 1 deletion NALSyntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class TermConnector(enum.Enum):
# NAL-4
Product = "*"
ExtensionalImage = "/"
IntensionalImage = r"\\"
IntensionalImage = "\\"
ImagePlaceHolder = "_"

# NAL-5
Expand Down
44 changes: 26 additions & 18 deletions NARS.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,11 @@ def Consider(self):
concept_to_consider = concept_item.object
else:
# Concept is S or P
related_concept = self.memory.get_semantically_related_concept(concept_item.object)
concept_to_consider = related_concept
concept_to_consider = self.memory.get_semantically_related_concept(concept_item.object)

if concept_to_consider is not None:
sentence = concept_to_consider.belief_table.peek() # get most confident belief
if sentence is not None:
# process the judgment
if len(concept_to_consider.belief_table) > 0:
sentence = concept_to_consider.belief_table.peek() # get most confident belief
self.process_judgment_sentence(sentence)

# decay priority
Expand All @@ -188,7 +186,8 @@ def process_task(self, task: NARSDataStructures.Task):
"""
NARSDataStructures.assert_task(task)

if task.sentence.punctuation == NALSyntax.Punctuation.Question or NALGrammar.VariableTerm.QUERY_SYM in str(task.sentence.statement.term):
if task.sentence.punctuation == NALSyntax.Punctuation.Question \
or NALGrammar.VariableTerm.QUERY_SYM in str(task.sentence.statement.term):
self.process_question(task)
elif task.sentence.punctuation == NALSyntax.Punctuation.Judgment:
self.process_judgment_task(task)
Expand Down Expand Up @@ -251,19 +250,28 @@ def process_judgment_sentence(self, j1, related_concept=None):
statement_concept = self.memory.peek_concept(statement_term)

if statement_term.contains_variable(): return

if related_concept is None: # get a related concept
related_concept = self.memory.get_semantically_related_concept(statement_concept)
if related_concept is None:
print("none!")
return # no related concepts! Should never happen, the concept is always semantically related to itself

# check for a belief we can interact with
j2 = None
for (belief, confidence) in related_concept.belief_table:
if NALGrammar.Sentence.may_interact(j1,belief):
j2 = belief # belief can interact with j1
break
if related_concept is None:
number_of_attempts = 0
while j2 is None and number_of_attempts < Config.NUMBER_OF_ATTEMPTS_TO_SEARCH_FOR_SEMANTICALLY_RELATED_BELIEF: # try searching a maximum of 3 concepts
related_concept = self.memory.get_semantically_related_concept(statement_concept)
if related_concept is None:
return # no related concepts! Should never happen, the concept is always semantically related to itself

# check for a belief we can interact with

for (belief, confidence) in related_concept.belief_table:
if NALGrammar.Sentence.may_interact(j1,belief):
j2 = belief # belief can interact with j1
break

number_of_attempts += 1
if j2 is None: print (related_concept.get_formatted_string() + ' concept was no good')
else:
for (belief, confidence) in related_concept.belief_table:
if NALGrammar.Sentence.may_interact(j1, belief):
j2 = belief # belief can interact with j1
break

if j2 is None: return # done if can't interact

Expand Down
1 change: 1 addition & 0 deletions NARSDataStructures.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ def _peek_probabilistically(self):
# bucket was not selected, try next bucket
self._move_to_next_nonempty_bucket() # try next non-empty bucket
rnd = random.random() # randomly generated number in [0.0, 1.0)
bucket_probability = self.current_bucket_number / self.number_of_buckets

# peek a random item from the bucket
item, randidx = self._peek_random_item_from_current_bucket()
Expand Down
26 changes: 17 additions & 9 deletions NARSInferenceEngine.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,12 +238,6 @@ def do_semantic_inference_two_premise(j1: NALGrammar.Sentence, j2: NALGrammar.Se
print_inference_rule(inference_rule="Resemblance")
derived_sentences.append(derived_sentence)

immediate_inference_derived_sentences = []
for derived_sentence in derived_sentences:
immediate_inference_derived_sentences.extend(do_inference_one_premise(derived_sentence))

derived_sentences.extend(immediate_inference_derived_sentences)

"""
===============================================
===============================================
Expand Down Expand Up @@ -284,26 +278,40 @@ def do_inference_one_premise(j):
"""
Immediate Inference Rules
Generates beliefs that are equivalent to j but in a different form.
"""
derived_sentences = []
if isinstance(j, NALGrammar.Judgment):
# Negation
# Negation (--,(S-->P))
derived_sentence = NALInferenceRules.Negation(j)
print_inference_rule(inference_rule="Negation")
derived_sentences.append(derived_sentence)

# Conversion
# Conversion (P --> S)
if not NALSyntax.Copula.is_symmetric(j.statement.copula) and j.value.frequency > 0:
derived_sentence = NALInferenceRules.Conversion(j)
print_inference_rule(inference_rule="Conversion")
derived_sentences.append(derived_sentence)

# Contraposition
# Contraposition ((--,P) ==> (--,S))
if j.statement.copula == NALSyntax.Copula.Implication and j.value.frequency < 1:
derived_sentence = NALInferenceRules.Contraposition(j)
print_inference_rule(inference_rule="Contraposition")
derived_sentences.append(derived_sentence)

if isinstance(j.statement.get_subject_term(), NALGrammar.CompoundTerm) \
and j.statement.get_subject_term().connector == NALSyntax.TermConnector.Product:
derived_sentence_array = NALInferenceRules.ExtensionalImage(j)
print_inference_rule(inference_rule="Extensional Image")
for derived_sentence in derived_sentence_array:
derived_sentences.append(derived_sentence)
elif isinstance(j.statement.get_predicate_term(), NALGrammar.CompoundTerm) \
and j.statement.get_predicate_term().connector == NALSyntax.TermConnector.Product:
derived_sentence_array = NALInferenceRules.IntensionalImage(j)
print_inference_rule(inference_rule="Intensional Image")
for derived_sentence in derived_sentence_array:
derived_sentences.append(derived_sentence)

return derived_sentences


Expand Down
11 changes: 10 additions & 1 deletion NARSMemory.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def peek_concept(self, term):
def get_semantically_related_concept(self, concept):
"""
Get a concept (named by a Statement Term) that is semantically related to the given concept by a term.
This can return a belief from the input concept, which can be used in Revision.
This can return the given concept in rare cases where no other semantically related concept is found
:param concept - Statement-Term Concept for which to find a semantically related Statement-Term concept
Expand All @@ -108,7 +108,16 @@ def get_semantically_related_concept(self, concept):
predicate_term = concept.term.get_predicate_term()

concept_item_related_to_subject = self.peek_concept(subject_term).term_links.peek()
number_of_attempts = 0
while concept_item_related_to_subject.object == concept and number_of_attempts < Config.NUMBER_OF_ATTEMPTS_TO_SEARCH_FOR_SEMANTICALLY_RELATED_CONCEPT:
concept_item_related_to_subject = self.peek_concept(subject_term).term_links.peek()
number_of_attempts += 1

concept_item_related_to_predicate = self.peek_concept(predicate_term).term_links.peek()
number_of_attempts = 0
while concept_item_related_to_predicate.object == concept and number_of_attempts < Config.NUMBER_OF_ATTEMPTS_TO_SEARCH_FOR_SEMANTICALLY_RELATED_CONCEPT:
concept_item_related_to_predicate = self.peek_concept(predicate_term).term_links.peek()
number_of_attempts += 1

if concept_item_related_to_subject is not None and \
concept_item_related_to_predicate is None: # none from predicate
Expand Down
27 changes: 27 additions & 0 deletions TestCases/InferenceTests.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,33 @@ def extensional_composition():

assert success,"TEST FAILURE: Extensional Composition test failed: " + failed_criterion

def extensional_image():
"""
Test Extensional Image rule:
j: ((*,S,P)-->R). %1.0;0.9%
:- j: (S-->(/,R,_,P)). %1.0;0.9%
:- j: (P-->(/,R,S,_)). %1.0;0.9%
"""
input_judgment_q, input_question_q, output_q = initialize_multiprocess_queues()

j1 = NALGrammar.Sentence.new_sentence_from_string("((*,S,P)-->R). %1.0;0.9%")
q1 = "(S-->(/,R,_,P))?"
q2 = "(P-->(/,R,S,_))?"
input_judgment_q.put(j1)
input_question_q.put(NALGrammar.Sentence.new_sentence_from_string(q1))
input_question_q.put(NALGrammar.Sentence.new_sentence_from_string(q2))

process = threading.Thread(target=run_test, args=(input_judgment_q, input_question_q, output_q))
process.start()
process.join()

success_criteria = []
success_criteria.append(NALInferenceRules.ExtensionalImage(j1).get_formatted_string_no_id())
success, failed_criterion = check_success(output_q, success_criteria)

assert success,"TEST FAILURE: Extensional Image test failed: " + failed_criterion

def main():
revision()

Expand Down
4 changes: 2 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ def main():
"""
# set globals
Global.Global.gui_use_internal_data = False # Setting this to False will prevent creation of the Internal Data GUI thread
Global.Global.gui_use_interface = False # Setting this to False uses the shell as interface
Global.Global.gui_use_internal_data = True # Setting this to False will prevent creation of the Internal Data GUI thread
Global.Global.gui_use_interface = True # Setting this to False uses the shell as interface

# First, create the NARS
Global.Global.NARS = NARS.NARS()
Expand Down

0 comments on commit 00587ce

Please sign in to comment.