Fixed #41 : Implement concept 'and'

This commit is contained in:
2021-03-06 19:12:22 +01:00
parent 05577012f3
commit bd8e027827
6 changed files with 153 additions and 98 deletions
+9
View File
@@ -27,6 +27,15 @@ def concept x has a y as hasa(x,y) pre is_question()
def concept x has an y as hasa(x,y) pre is_question() def concept x has an y as hasa(x,y) pre is_question()
# no need to auto eval as it's a question # no need to auto eval as it's a question
def concept x and y as x and y pre is_question()
set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya')
set_is_less_than(__PRECEDENCE, c:q:, c:x and y:, 'Sya')
def concept x or y as x or y pre is_question()
set_is_lesser(__PRECEDENCE, c:x or y:, 'Sya')
set_is_greater_than(__PRECEDENCE, c:x and y:, c:x or y:, 'Sya')
set_is_less_than(__PRECEDENCE, c:q:, c:x or y:, 'Sya')
# default # default
def concept male def concept male
def concept female def concept female
+29
View File
@@ -18,6 +18,22 @@ EVAL_STEPS = PARSE_STEPS + [BuiltinConcepts.BEFORE_EVALUATION, BuiltinConcepts.E
PARSERS = ["EmptyString", "ShortTermMemory", "Sequence", "Bnf", "Sya", "Python"] PARSERS = ["EmptyString", "ShortTermMemory", "Sequence", "Bnf", "Sya", "Python"]
def remove_python_nodes(context, return_values):
"""
Try to reduce the number of return_values by removing return values with python node
:param context:
:param return_values:
:return:
"""
res = []
for ret_val in return_values:
value = context.sheerka.objvalue(ret_val)
if not hasattr(value, "get_python_node"):
res.append(ret_val)
return res
def is_same_success(context, return_values): def is_same_success(context, return_values):
""" """
Returns True if all returns values are successful and have the same value Returns True if all returns values are successful and have the same value
@@ -89,12 +105,25 @@ def expect_one(context, return_values):
# too many winners, which one to choose ? # too many winners, which one to choose ?
if number_of_successful > 1: if number_of_successful > 1:
# first, try to remove python node results.
# In case of conflict, the concept take precedence over the natural Python result
# as it is considered as an override (overload ?)
successful_results = remove_python_nodes(context, successful_results)
if len(successful_results) == 1:
return sheerka.ret(
context.who,
True,
successful_results[0].body,
parents=return_values)
if is_same_success(context, successful_results): if is_same_success(context, successful_results):
return sheerka.ret( return sheerka.ret(
context.who, context.who,
True, True,
successful_results[0].value, successful_results[0].value,
parents=return_values) parents=return_values)
else: else:
if context.logger and context.logger.isEnabledFor(logging.DEBUG): if context.logger and context.logger.isEnabledFor(logging.DEBUG):
context.log(f"Too many successful results found by expect_one()", context.who) context.log(f"Too many successful results found by expect_one()", context.who)
+3 -3
View File
@@ -1,12 +1,12 @@
To make Jupyter notebook recognize Sheerka, To make Jupyter notebook recognize Sheerka,
the file kernel.json must be copied where the kernels are declared the file kernel.json must be copied where the kernels are declared
* First, open the kernel.json file and make sure that the path to SheerkaKernel is correct. * First, open the kernel.json file and make sure that the path to SheerkaKernel.py is correct.
* The copy it to the correct location * The copy it to the correct location
* You can use the command 'jupyter kernelspec install </path/to/kernel>' * You can use the command 'jupyter kernelspec install </path/to/kernel>'
* or simply copy it using cp ;-) * or simply copy 'Sheerka/kernel.json' into the folder 'kernels' (You may have to create it!)
Valid locations for kernel.json are Valid locations for 'Sheerka/kernel.json' are
| | Unix | Windows | | | Unix | Windows |
|----|------| ---------------| |----|------| ---------------|
+1 -1
View File
@@ -57,7 +57,7 @@ class Event(object):
return self._digest return self._digest
if not isinstance(self.message, str): if not isinstance(self.message, str):
raise NotImplementedError raise NotImplementedError(f"message={self.message}")
to_hash = f"Event:{self.user_id}{self.date}{self.message}{self.parents}".encode("utf-8") to_hash = f"Event:{self.user_id}{self.date}{self.message}{self.parents}".encode("utf-8")
self._digest = hashlib.sha256(to_hash).hexdigest() self._digest = hashlib.sha256(to_hash).hexdigest()
+7 -94
View File
@@ -1299,102 +1299,15 @@ as:
assert sheerka.objvalue(res[0].body.get_value("qty")) == 2 assert sheerka.objvalue(res[0].body.get_value("qty")) == 2
def test_i_can_implement_implement_the_concept_and(self):
init = [
"def concept x and y as x and y",
"set_is_lesser(__PRECEDENCE, c:x and y:, 'Sya')",
]
sheerka = self.init_scenario(init)
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka): res = sheerka.evaluate_user_input("def concept foo x y where x > 1 and y > 2")
def test_i_can_def_several_concepts(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept foo")
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input("def concept bar")
assert len(res) == 1 assert len(res) == 1
assert res[0].status assert res[0].status
assert res[0].body.body.id == "1002"
def test_i_can_create_concept_with_bnf_definition(self):
sheerka = self.get_sheerka()
concept_a = self.bnf_concept("a", expression=OrderedChoice(StrMatch("one"), StrMatch("two")))
sheerka.create_new_concept(self.get_context(sheerka), concept_a)
res = sheerka.evaluate_user_input("def concept plus from bnf a ('plus' plus)?")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
saved_concept = sheerka.om.current_sdp().get(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, "plus")
assert saved_concept.key == "plus"
assert saved_concept.get_metadata().definition == "a ('plus' plus)?"
assert "a" in saved_concept.values()
assert "plus" in saved_concept.values()
expected_bnf = Sequence(
ConceptExpression(concept_a, rule_name="a"),
Optional(Sequence(StrMatch("plus"), ConceptExpression("plus"))))
new_concept = res[0].value.body
assert new_concept.get_metadata().name == "plus"
assert new_concept.get_metadata().definition == "a ('plus' plus)?"
assert new_concept.get_bnf() == expected_bnf
assert "a" in new_concept.values()
assert "plus" in new_concept.values()
def test_i_can_recognize_bnf_definitions_from_separate_instances(self):
sheerka = self.get_sheerka()
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' 'two'")[0].body.body
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input("one two")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
# add another bnf definition
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input("one two") # previous one still works
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
res = self.get_sheerka().evaluate_user_input("one two three") # new one works
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_b)
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
assert evaluated.body == "one two three"
assert evaluated.get_value("a") == sheerka.new(concept_a.key, body="one two").init_key()
def test_i_can_eval_sophisticated_bnf_concepts_after_restart(self):
self.init_scenario([
"def concept one as 1",
"def concept number",
"set_isa(one, number)",
"def concept twenty as 20",
"set_isa(twenty, number)",
"def concept twenties from bnf twenty number where number < 10 as twenty + number",
"set_isa(twenties, number)",
"def concept thirty as 30",
"set_isa(thirty, number)",
"def concept thirties from bnf thirty number where number < 10 as thirty + number",
"set_isa(thirties, number)",
])
sheerka = self.get_sheerka() # another instance
assert sheerka.evaluate_user_input("eval twenty one")[0].body == 21
assert sheerka.evaluate_user_input("eval thirty one")[0].body == 31
def test_i_can_pop_ontology_after_restart(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("push_ontology('test')")
sheerka = self.new_sheerka_instance(False)
res = sheerka.evaluate_user_input("pop_ontology()")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.ONTOLOGY_REMOVED)
@@ -0,0 +1,104 @@
from core.builtin_concepts_ids import BuiltinConcepts
from core.sheerka.services.SheerkaConceptManager import SheerkaConceptManager
from parsers.BnfNodeParser import OrderedChoice, StrMatch, Sequence, ConceptExpression, Optional
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
def test_i_can_def_several_concepts(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("def concept foo")
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input("def concept bar")
assert len(res) == 1
assert res[0].status
assert res[0].body.body.id == "1002"
def test_i_can_create_concept_with_bnf_definition(self):
sheerka = self.get_sheerka()
concept_a = self.bnf_concept("a", expression=OrderedChoice(StrMatch("one"), StrMatch("two")))
sheerka.create_new_concept(self.get_context(sheerka), concept_a)
res = sheerka.evaluate_user_input("def concept plus from bnf a ('plus' plus)?")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
saved_concept = sheerka.om.current_sdp().get(SheerkaConceptManager.CONCEPTS_BY_KEY_ENTRY, "plus")
assert saved_concept.key == "plus"
assert saved_concept.get_metadata().definition == "a ('plus' plus)?"
assert "a" in saved_concept.values()
assert "plus" in saved_concept.values()
expected_bnf = Sequence(
ConceptExpression(concept_a, rule_name="a"),
Optional(Sequence(StrMatch("plus"), ConceptExpression("plus"))))
new_concept = res[0].value.body
assert new_concept.get_metadata().name == "plus"
assert new_concept.get_metadata().definition == "a ('plus' plus)?"
assert new_concept.get_bnf() == expected_bnf
assert "a" in new_concept.values()
assert "plus" in new_concept.values()
def test_i_can_recognize_bnf_definitions_from_separate_instances(self):
sheerka = self.get_sheerka()
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' 'two'")[0].body.body
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input("one two")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
# add another bnf definition
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
sheerka = self.get_sheerka()
res = sheerka.evaluate_user_input("one two") # previous one still works
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_a)
res = self.get_sheerka().evaluate_user_input("one two three") # new one works
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].value, concept_b)
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
assert evaluated.body == "one two three"
assert evaluated.get_value("a") == sheerka.new(concept_a.key, body="one two").init_key()
def test_i_can_eval_sophisticated_bnf_concepts_after_restart(self):
self.init_scenario([
"def concept one as 1",
"def concept number",
"set_isa(one, number)",
"def concept twenty as 20",
"set_isa(twenty, number)",
"def concept twenties from bnf twenty number where number < 10 as twenty + number",
"set_isa(twenties, number)",
"def concept thirty as 30",
"set_isa(thirty, number)",
"def concept thirties from bnf thirty number where number < 10 as thirty + number",
"set_isa(thirties, number)",
])
sheerka = self.get_sheerka() # another instance
assert sheerka.evaluate_user_input("eval twenty one")[0].body == 21
assert sheerka.evaluate_user_input("eval thirty one")[0].body == 31
def test_i_can_pop_ontology_after_restart(self):
sheerka = self.get_sheerka()
sheerka.evaluate_user_input("push_ontology('test')")
sheerka = self.new_sheerka_instance(False)
res = sheerka.evaluate_user_input("pop_ontology()")
assert len(res) == 1
assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.ONTOLOGY_REMOVED)