Fixed #41 : Implement concept 'and'
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 |
|
||||||
|----|------| ---------------|
|
|----|------| ---------------|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
||||||
Reference in New Issue
Block a user