Added is_lesser and is_greatest in SheerkaComparison

This commit is contained in:
2020-08-30 20:31:06 +02:00
parent 37cd3ed757
commit 8a866880bc
11 changed files with 393 additions and 51 deletions
+9 -7
View File
@@ -84,10 +84,10 @@ def concept plus from a plus b as a + b
def concept minus from a minus b as a - b def concept minus from a minus b as a - b
def concept multiplied from a multiplied by b as a * b def concept multiplied from a multiplied by b as a * b
def concept divided from a divided by b as a * b def concept divided from a divided by b as a * b
set_is_greater_than(BuiltinConcepts.PRECEDENCE, multiplied, plus) set_is_greater_than(__PRECEDENCE, multiplied, plus)
set_is_greater_than(BuiltinConcepts.PRECEDENCE, divided, plus) set_is_greater_than(__PRECEDENCE, divided, plus)
set_is_greater_than(BuiltinConcepts.PRECEDENCE, multiplied, minus) set_is_greater_than(__PRECEDENCE, multiplied, minus)
set_is_greater_than(BuiltinConcepts.PRECEDENCE, divided, minus) set_is_greater_than(__PRECEDENCE, divided, minus)
def concept explain as get_results() | filter("id == 0") | recurse(2) def concept explain as get_results() | filter("id == 0") | recurse(2)
def concept explain last as get_last_results() | filter("id == 0") | recurse(2) def concept explain last as get_last_results() | filter("id == 0") | recurse(2)
def concept explain x as get_results() | filter(f"id == {x}") | recurse(3) where x def concept explain x as get_results() | filter(f"id == {x}") | recurse(3) where x
@@ -95,9 +95,11 @@ def concept explain x '--recurse' y as get_results() | filter(f"id == {x}") | re
set_isa(c:explain:, __COMMAND) set_isa(c:explain:, __COMMAND)
set_isa(c:explain last:, __COMMAND) set_isa(c:explain last:, __COMMAND)
set_isa(c:explain x:, __COMMAND) set_isa(c:explain x:, __COMMAND)
def concept precedence a > precedence b as set_is_greater_than(BuiltinConcepts.PRECEDENCE, a, b) def concept precedence a > precedence b as set_is_greater_than(__PRECEDENCE, a, b)
set_isa(c:precedence a > precedence b:, __COMMAND) set_isa(c:precedence a > precedence b:, __COMMAND)
def concept x is a command as set_isa(x, __COMMAND) def concept x is a command as set_isa(x, __COMMAND)
set_isa(c:x is a command:, __COMMAND) set_isa(c:x is a command:, __COMMAND)
def concept q from q ? as question(q) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED) def concept q from q ? as question(q) pre is_question()
def concept x is a 'concept' as isinstance(x, Concept) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED) set_is_lesser(__PRECEDENCE, q)
def concept x is a 'concept' as isinstance(x, Concept) pre is_question()
def concept x is a y as isa(x,y) pre is_question()
+10 -3
View File
@@ -72,7 +72,7 @@ class BuiltinConcepts(Enum):
IS_EMPTY = "is empty" # when a set is empty IS_EMPTY = "is empty" # when a set is empty
NO_RESULT = "no result" # no return value returned NO_RESULT = "no result" # no return value returned
INVALID_RETURN_VALUE = "invalid return value" # the return value of an evaluator is not correct INVALID_RETURN_VALUE = "invalid return value" # the return value of an evaluator is not correct
CONCEPT_ALREADY_DEFINED = "concept already defined" # when you try to add the same concept twice ALREADY_DEFINED = "already defined" # when you try to add the same object twice (a concept or whatever)
NOP = "no operation" # no operation concept. Does nothing NOP = "no operation" # no operation concept. Does nothing
CONCEPT_EVAL_ERROR = "concept evaluation error" # cannot evaluate a property or metadata of a concept CONCEPT_EVAL_ERROR = "concept evaluation error" # cannot evaluate a property or metadata of a concept
ENUMERATION = "enum" # represents a list or a set ENUMERATION = "enum" # represents a list or a set
@@ -91,6 +91,8 @@ class BuiltinConcepts(Enum):
FORMAT_INSTRUCTIONS = "format instructions" # to express how to print the concept FORMAT_INSTRUCTIONS = "format instructions" # to express how to print the concept
NOT_IMPLEMENTED = "not implemented" # instead of raise an error NOT_IMPLEMENTED = "not implemented" # instead of raise an error
PYTHON_SECURITY_ERROR = "security error" # when trying to execute statement when only expression is allowed PYTHON_SECURITY_ERROR = "security error" # when trying to execute statement when only expression is allowed
INVALID_LESSER_OPERATION = "Invalid lesser operation"
INVALID_GREATEST_OPERATION = "Invalid greatest operation"
NODE = "node" NODE = "node"
GENERIC_NODE = "generic node" GENERIC_NODE = "generic node"
@@ -152,6 +154,9 @@ BuiltinUnique = [
BuiltinConcepts.ISA, BuiltinConcepts.ISA,
BuiltinConcepts.COMMAND, BuiltinConcepts.COMMAND,
BuiltinConcepts.INVALID_LESSER_OPERATION,
BuiltinConcepts.INVALID_GREATEST_OPERATION,
] ]
BuiltinErrors = [str(e) for e in { BuiltinErrors = [str(e) for e in {
@@ -164,14 +169,16 @@ BuiltinErrors = [str(e) for e in {
BuiltinConcepts.TOO_MANY_ERRORS, BuiltinConcepts.TOO_MANY_ERRORS,
BuiltinConcepts.MULTIPLE_ERRORS, BuiltinConcepts.MULTIPLE_ERRORS,
BuiltinConcepts.INVALID_RETURN_VALUE, BuiltinConcepts.INVALID_RETURN_VALUE,
BuiltinConcepts.CONCEPT_ALREADY_DEFINED, BuiltinConcepts.ALREADY_DEFINED,
BuiltinConcepts.CONCEPT_EVAL_ERROR, BuiltinConcepts.CONCEPT_EVAL_ERROR,
BuiltinConcepts.CONCEPT_ALREADY_IN_SET, BuiltinConcepts.CONCEPT_ALREADY_IN_SET,
BuiltinConcepts.NOT_A_SET, BuiltinConcepts.NOT_A_SET,
BuiltinConcepts.CONDITION_FAILED, BuiltinConcepts.CONDITION_FAILED,
BuiltinConcepts.CHICKEN_AND_EGG, BuiltinConcepts.CHICKEN_AND_EGG,
BuiltinConcepts.NOT_INITIALIZED, BuiltinConcepts.NOT_INITIALIZED,
BuiltinConcepts.NOT_FOUND BuiltinConcepts.NOT_FOUND,
BuiltinConcepts.INVALID_LESSER_OPERATION,
BuiltinConcepts.INVALID_GREATEST_OPERATION,
}] }]
""" """
@@ -3,7 +3,7 @@ from dataclasses import dataclass
from cache.Cache import Cache from cache.Cache import Cache
from cache.ListCache import ListCache from cache.ListCache import ListCache
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import ensure_concept from core.concept import ensure_concept, Concept
from core.sheerka.services.sheerka_service import ServiceObj, BaseService from core.sheerka.services.sheerka_service import ServiceObj, BaseService
@@ -27,15 +27,30 @@ class SheerkaComparisonManager(BaseService):
COMPARISON_ENTRY = "ComparisonManager:Comparison" COMPARISON_ENTRY = "ComparisonManager:Comparison"
RESOLVED_COMPARISON_ENTRY = "ComparisonManager:Resolved_Comparison" RESOLVED_COMPARISON_ENTRY = "ComparisonManager:Resolved_Comparison"
# to use an initialisation value for attributes that will make use of computed weights
# the lesser and the greatest weight will be given relatively to this value
DEFAULT_COMPARISON_VALUE = 1
def __init__(self, sheerka): def __init__(self, sheerka):
super().__init__(sheerka) super().__init__(sheerka)
@staticmethod @staticmethod
def _compute_key(prop_name, comparison_context): def _compute_key(prop_name, comparison_context):
return f"{prop_name}|{comparison_context}" """
Key to use to store the comparisons
:param prop_name:
:param comparison_context:
:return:
"""
if isinstance(prop_name, Concept):
prefix = prop_name.key if prop_name.metadata.is_builtin else prop_name.id
else:
prefix = prop_name
return f"{prefix}|{comparison_context}"
@staticmethod @staticmethod
def _compute_weights(comparison_objs): def _get_weights(comparison_objs):
""" """
For every element in greater_than_s, give it a weight For every element in greater_than_s, give it a weight
if weight(a) > weight(b) it means that a > b if weight(a) > weight(b) it means that a > b
@@ -45,8 +60,8 @@ class SheerkaComparisonManager(BaseService):
values = {} values = {}
for comparison_obj in comparison_objs: for comparison_obj in comparison_objs:
values[comparison_obj.a] = 1 values[comparison_obj.a] = SheerkaComparisonManager.DEFAULT_COMPARISON_VALUE
values[comparison_obj.b] = 1 values[comparison_obj.b] = SheerkaComparisonManager.DEFAULT_COMPARISON_VALUE
for _ in range(len(comparison_objs)): for _ in range(len(comparison_objs)):
for comparison_obj in comparison_objs: for comparison_obj in comparison_objs:
@@ -57,6 +72,54 @@ class SheerkaComparisonManager(BaseService):
return values return values
def _compute_weights(self, comparison_objs, lesser_objs_ids=None, greatest_objs_ids=None):
"""
:param comparison_objs:
:return:
"""
def is_not_in_objs(obj, objs_ids):
return obj.op in ("<", ">") and obj.a not in objs_ids and obj.b not in objs_ids
def is_in_objs(obj, objs_ids):
return obj.op in ("<", ">") and (obj.a in objs_ids or obj.b in objs_ids)
lesser_objs_ids = lesser_objs_ids or {co.a for co in comparison_objs if co.op == "<<"}
greatest_objs_ids = greatest_objs_ids or {co.a for co in comparison_objs if co.op == ">>"}
default_weight = SheerkaComparisonManager.DEFAULT_COMPARISON_VALUE
# get the weights for all the lesser
lesser_objs = [co for co in comparison_objs if is_in_objs(co, lesser_objs_ids)]
lesser_objs_weights = self._get_weights(lesser_objs)
# rearrange the weight to have the highest equals to DEFAULT_COMPARISON_VALUE - 1
highest_weight = len(lesser_objs_weights)
for co_id in lesser_objs_weights:
lesser_objs_weights[co_id] = lesser_objs_weights[co_id] - highest_weight + default_weight - 1
for concept_id in lesser_objs_ids:
if concept_id not in lesser_objs_weights:
lesser_objs_weights[concept_id] = default_weight - 1
# get the weights for concepts that are not lesser or greatest
in_between_objs = [o for o in comparison_objs if is_not_in_objs(o, lesser_objs_ids | greatest_objs_ids)]
in_between_weights = self._get_weights(in_between_objs)
# get the weights for all the greatest
greatest_objs = [co for co in comparison_objs if is_in_objs(co, greatest_objs_ids)]
greatest_objs_weights = self._get_weights(greatest_objs)
# rearrange the weight to have the lowest equals to DEFAULT_COMPARISON_VALUE + 1
highest_weight = max(default_weight, len(in_between_weights))
for co_id in greatest_objs_weights:
greatest_objs_weights[co_id] = greatest_objs_weights[co_id] + highest_weight
for concept_id in greatest_objs_ids:
if concept_id not in greatest_objs_weights:
greatest_objs_weights[concept_id] = highest_weight + 1
return {**lesser_objs_weights, **in_between_weights, **greatest_objs_weights}
@staticmethod @staticmethod
def _get_partition(weighted_concepts): def _get_partition(weighted_concepts):
@@ -65,21 +128,52 @@ class SheerkaComparisonManager(BaseService):
res.setdefault(v, []).append(k) res.setdefault(v, []).append(k)
return res return res
def _inner_add_comparison(self, comparison_obj): def _add_comparison(self, comparison_obj):
key = self._compute_key(comparison_obj.property, comparison_obj.context) key = self._compute_key(comparison_obj.property, comparison_obj.context)
previous = self.sheerka.cache_manager.get(self.COMPARISON_ENTRY, key) previous = self.sheerka.cache_manager.get(self.COMPARISON_ENTRY, key)
new = previous.copy() if previous else [] new = previous.copy() if previous else []
for co in new:
if co.property == comparison_obj.property and \
co.a == comparison_obj.a and \
co.b == comparison_obj.b and \
co.op == comparison_obj.op and \
co.context == comparison_obj.context:
return self.sheerka.ret(self.NAME, False, self.sheerka.new(BuiltinConcepts.ALREADY_DEFINED))
new.append(comparison_obj) new.append(comparison_obj)
lesser_objs_ids = {co.a for co in new if co.op == "<<"}
greatest_objs_ids = {co.a for co in new if co.op == ">>"}
# check if it is a valid operation regarding other lesser and greatest concepts
if comparison_obj.op in ("<", ">"):
a_is_lesser = comparison_obj.a in lesser_objs_ids
b_is_lesser = comparison_obj.b in lesser_objs_ids
if a_is_lesser != b_is_lesser: # XOR operation
return self.sheerka.ret(self.NAME, False, self.sheerka.new(BuiltinConcepts.INVALID_LESSER_OPERATION))
a_is_greatest = comparison_obj.a in greatest_objs_ids
b_is_greatest = comparison_obj.b in greatest_objs_ids
if a_is_greatest != b_is_greatest: # XOR operation
return self.sheerka.ret(self.NAME, False, self.sheerka.new(BuiltinConcepts.INVALID_GREATEST_OPERATION))
if comparison_obj.op == "<<" and comparison_obj.a in greatest_objs_ids:
return self.sheerka.ret(self.NAME, False, self.sheerka.new(BuiltinConcepts.INVALID_GREATEST_OPERATION))
if comparison_obj.op == ">>" and comparison_obj.a in lesser_objs_ids:
return self.sheerka.ret(self.NAME, False, self.sheerka.new(BuiltinConcepts.INVALID_LESSER_OPERATION))
cycles = self.detect_cycles(new) cycles = self.detect_cycles(new)
if cycles: if cycles:
concepts_in_cycle = [self.sheerka.get_by_id(c) for c in cycles] concepts_in_cycle = [self.sheerka.get_by_id(c) for c in cycles]
chicken_an_egg = self.sheerka.new(BuiltinConcepts.CHICKEN_AND_EGG, body=concepts_in_cycle) chicken_an_egg = self.sheerka.new(BuiltinConcepts.CHICKEN_AND_EGG, body=concepts_in_cycle)
return self.sheerka.ret(self.NAME, False, chicken_an_egg) return self.sheerka.ret(self.NAME, False, chicken_an_egg)
self.sheerka.cache_manager.put(self.RESOLVED_COMPARISON_ENTRY, key, self._compute_weights(new))
self.sheerka.cache_manager.put(self.COMPARISON_ENTRY, key, comparison_obj) self.sheerka.cache_manager.put(self.COMPARISON_ENTRY, key, comparison_obj)
self.sheerka.cache_manager.put(self.RESOLVED_COMPARISON_ENTRY, key, self._compute_weights(new,
lesser_objs_ids,
greatest_objs_ids))
return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS)) return self.sheerka.ret(self.NAME, True, self.sheerka.new(BuiltinConcepts.SUCCESS))
@@ -92,6 +186,8 @@ class SheerkaComparisonManager(BaseService):
self.sheerka.bind_service_method(self.set_is_greater_than, True) self.sheerka.bind_service_method(self.set_is_greater_than, True)
self.sheerka.bind_service_method(self.set_is_less_than, True) self.sheerka.bind_service_method(self.set_is_less_than, True)
self.sheerka.bind_service_method(self.set_is_lesser, True)
self.sheerka.bind_service_method(self.set_is_greatest, True)
self.sheerka.bind_service_method(self.get_partition, False) self.sheerka.bind_service_method(self.get_partition, False)
self.sheerka.bind_service_method(self.get_concepts_weights, False) self.sheerka.bind_service_method(self.get_concepts_weights, False)
@@ -110,7 +206,7 @@ class SheerkaComparisonManager(BaseService):
event_digest = context.event.get_digest() event_digest = context.event.get_digest()
comparison_obj = ComparisonObj(event_digest, prop_name, concept_a.id, concept_b.id, ">", comparison_context) comparison_obj = ComparisonObj(event_digest, prop_name, concept_a.id, concept_b.id, ">", comparison_context)
return self._inner_add_comparison(comparison_obj) return self._add_comparison(comparison_obj)
def set_is_less_than(self, context, prop_name, concept_a, concept_b, comparison_context="#"): def set_is_less_than(self, context, prop_name, concept_a, concept_b, comparison_context="#"):
""" """
@@ -127,7 +223,66 @@ class SheerkaComparisonManager(BaseService):
event_digest = context.event.get_digest() event_digest = context.event.get_digest()
comparison_obj = ComparisonObj(event_digest, prop_name, concept_a.id, concept_b.id, "<", comparison_context) comparison_obj = ComparisonObj(event_digest, prop_name, concept_a.id, concept_b.id, "<", comparison_context)
return self._inner_add_comparison(comparison_obj) return self._add_comparison(comparison_obj)
def set_is_lesser(self, context, prop_name, concept, comparison_context="#"):
"""
Records that the concept is less than any other concept if no direct comparison is given
* A lesser concept has a weight smaller than any other concept that is not a lesser
* When two concepts are lesser, you can compare (using set_is_less_than or set_is_greater_than)
* If a concept is lesser, you cannot compare it with a non lesser concept
* All lesser concepts that have no comparison directive are greater than the others (and share the same weight)
:param context:
:param prop_name:
:param concept:
:param comparison_context:
:return:
"""
context.log(f"Setting concept {concept} is lesser", who=self.NAME)
ensure_concept(concept)
event_digest = context.event.get_digest()
comparison_obj = ComparisonObj(event_digest, prop_name, concept.id, None, "<<", comparison_context)
return self._add_comparison(comparison_obj)
def set_is_greatest(self, context, prop_name, concept, comparison_context="#"):
"""
Records that the concept is greater than any other concept if no direct comparison is given
* A greatest concept has a weight bigger than any other concept that is not a greatest
* When two concepts are greatest, you can compare them (using set_is_less_than or set_is_greater_than)
* If a concept is greatest, you cannot compare it with a non greatest concept
* All greatest concepts that have no comparison directive are less than the others (and share the same weight)
:param context:
:param prop_name:
:param concept:
:param comparison_context:
:return:
"""
context.log(f"Setting concept {concept} is greatest", who=self.NAME)
ensure_concept(concept)
event_digest = context.event.get_digest()
comparison_obj = ComparisonObj(event_digest, prop_name, concept.id, None, ">>", comparison_context)
return self._add_comparison(comparison_obj)
def set_are_equivalent(self, context, prop_name, concept_a, concept_b, comparison_context="#"):
"""
Records that two concepts have the same weight
* You cannot set the weight
:param context:
:param prop_name:
:param concept_a:
:param concept_b:
:param comparison_context:
:return:
"""
pass
def set_are_equiv(self, context, prop_name, concept_a, concept_b, comparison_context="#"):
pass
def get_partition(self, prop_name, comparison_context="#"): def get_partition(self, prop_name, comparison_context="#"):
""" """
@@ -141,21 +296,21 @@ class SheerkaComparisonManager(BaseService):
return self._get_partition(weighted_concept) return self._get_partition(weighted_concept)
def get_concepts_weights(self, prop_name, comparison_context="#"): def get_concepts_weights(self, prop_name, comparison_context="#"):
weighted_concept = self.sheerka.cache_manager.get( weighted_concepts = self.sheerka.cache_manager.get(
self.RESOLVED_COMPARISON_ENTRY, self.RESOLVED_COMPARISON_ENTRY,
self._compute_key(prop_name, comparison_context)) self._compute_key(prop_name, comparison_context))
if weighted_concept is None: if weighted_concepts is None:
key = self._compute_key(prop_name, comparison_context) key = self._compute_key(prop_name, comparison_context)
entries = self.sheerka.cache_manager.get(self.COMPARISON_ENTRY, key) entries = self.sheerka.cache_manager.get(self.COMPARISON_ENTRY, key)
if entries is None: if entries is None:
return {} return {}
else: else:
weighted_concept = self._compute_weights(entries) weighted_concepts = self._compute_weights(entries)
self.sheerka.cache_manager.put(self.RESOLVED_COMPARISON_ENTRY, key, weighted_concept) self.sheerka.cache_manager.put(self.RESOLVED_COMPARISON_ENTRY, key, weighted_concepts)
return weighted_concept return weighted_concepts
@staticmethod @staticmethod
def detect_cycles(comparison_objs): def detect_cycles(comparison_objs):
@@ -45,7 +45,7 @@ class SheerkaCreateNewConcept(BaseService):
return sheerka.ret( return sheerka.ret(
self.NAME, self.NAME,
False, False,
sheerka.new(BuiltinConcepts.CONCEPT_ALREADY_DEFINED, body=concept), sheerka.new(BuiltinConcepts.ALREADY_DEFINED, body=concept),
error.args[0]) error.args[0])
# set id before saving in db # set id before saving in db
@@ -34,7 +34,7 @@ class SheerkaModifyConcept(BaseService):
return self.sheerka.ret( return self.sheerka.ret(
self.NAME, False, self.NAME, False,
self.sheerka.new( self.sheerka.new(
BuiltinConcepts.CONCEPT_ALREADY_DEFINED, BuiltinConcepts.ALREADY_DEFINED,
body=concept)) body=concept))
old_references = self.sheerka.cache_manager.get(self.sheerka.CONCEPTS_REFERENCES_ENTRY, concept.id) old_references = self.sheerka.cache_manager.get(self.sheerka.CONCEPTS_REFERENCES_ENTRY, concept.id)
+2
View File
@@ -37,6 +37,8 @@ class Expando:
for k, v in bag.items(): for k, v in bag.items():
setattr(self, k, v) setattr(self, k, v)
def __repr__(self):
return f"{dir(self)}"
@dataclass @dataclass
class PythonEvalError: class PythonEvalError:
+3 -6
View File
@@ -6,6 +6,7 @@ from typing import List
from core import builtin_helpers from core import builtin_helpers
from core.builtin_concepts import BuiltinConcepts from core.builtin_concepts import BuiltinConcepts
from core.concept import Concept, DEFINITION_TYPE_BNF from core.concept import Concept, DEFINITION_TYPE_BNF
from core.sheerka.services.SheerkaComparisonManager import SheerkaComparisonManager
from core.sheerka.services.SheerkaExecute import ParserInput from core.sheerka.services.SheerkaExecute import ParserInput
from core.tokenizer import Token, TokenKind, Tokenizer from core.tokenizer import Token, TokenKind, Tokenizer
from parsers.BaseNodeParser import UnrecognizedTokensNode, ConceptNode, SourceCodeNode, SyaAssociativity, \ from parsers.BaseNodeParser import UnrecognizedTokensNode, ConceptNode, SourceCodeNode, SyaAssociativity, \
@@ -77,7 +78,7 @@ class SyaConceptDef:
It gives the precedence and the associativity for the concept It gives the precedence and the associativity for the concept
""" """
concept: Concept concept: Concept
precedence: int = 0 precedence: int = SheerkaComparisonManager.DEFAULT_COMPARISON_VALUE
associativity: SyaAssociativity = SyaAssociativity.Right associativity: SyaAssociativity = SyaAssociativity.Right
@@ -541,11 +542,6 @@ class InFixToPostFix:
if stack.associativity == SyaAssociativity.No and current.associativity == SyaAssociativity.No: if stack.associativity == SyaAssociativity.No and current.associativity == SyaAssociativity.No:
self._add_error(NoneAssociativeSequenceErrorNode(current.concept, stack_head.start, concept_node.start)) self._add_error(NoneAssociativeSequenceErrorNode(current.concept, stack_head.start, concept_node.start))
if not current.precedence:
# precedence is not set (None or zero)
# Do not apply any rule
return False
if current.associativity == SyaAssociativity.Left and current.precedence <= stack.precedence: if current.associativity == SyaAssociativity.Left and current.precedence <= stack.precedence:
return True return True
@@ -947,6 +943,7 @@ class SyaNodeParser(BaseNodeParser):
def _get_sya_concept_def(parser, concept): def _get_sya_concept_def(parser, concept):
sya_concept_def = SyaConceptDef(concept) sya_concept_def = SyaConceptDef(concept)
if concept.id in parser.sya_definitions: if concept.id in parser.sya_definitions:
# Manage when precedence and associativity are given in the unit tests
sya_def = parser.sya_definitions.get(concept.id) sya_def = parser.sya_definitions.get(concept.id)
if sya_def[0] is not None: if sya_def[0] is not None:
sya_concept_def.precedence = sya_def[0] sya_concept_def.precedence = sya_def[0]
+188 -10
View File
@@ -6,6 +6,22 @@ from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka): class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
@staticmethod
def execution_definition(context, service, concepts_map, definition):
if ">>" in definition:
a = concepts_map[definition.split(">>")[0].strip()]
return service.set_is_greatest(context, "prop_name", a)
if "<<" in definition:
a = concepts_map[definition.split("<<")[0].strip()]
return service.set_is_lesser(context, "prop_name", a)
if ">" in definition:
a, b = [concepts_map[e.strip()] for e in definition.split(">")]
return service.set_is_greater_than(context, "prop_name", a, b)
if "<" in definition:
a, b = [concepts_map[e.strip()] for e in definition.split("<")]
return service.set_is_less_than(context, "prop_name", a, b)
def test_i_can_add_a_is_greater_than(self): def test_i_can_add_a_is_greater_than(self):
sheerka, context, one, two = self.init_concepts("one", "two", cache_only=False) sheerka, context, one, two = self.init_concepts("one", "two", cache_only=False)
service = sheerka.services[SheerkaComparisonManager.NAME] service = sheerka.services[SheerkaComparisonManager.NAME]
@@ -83,22 +99,34 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
(["one < two"], {'1001': 1, '1002': 2}), (["one < two"], {'1001': 1, '1002': 2}),
(["three > two", "one < two"], {'1001': 1, '1002': 2, '1003': 3}), (["three > two", "one < two"], {'1001': 1, '1002': 2, '1003': 3}),
(["three > one", "one < two"], {'1001': 1, '1002': 2, '1003': 2}), (["three > one", "one < two"], {'1001': 1, '1002': 2, '1003': 2}),
(["three >>"], {'1003': 2}),
(["one <<"], {'1001': 0}),
]) ])
def test_i_can_get_concept_weight(self, entries, expected): def test_i_can_get_concept_weight(self, entries, expected):
sheerka, context, *concepts = self.init_concepts("one", "two", "three") sheerka, context, *concepts = self.init_concepts("one", "two", "three")
service = sheerka.services[SheerkaComparisonManager.NAME] service = sheerka.services[SheerkaComparisonManager.NAME]
concepts_map = dict(zip(["one", "two", "three", "four", "five", "six"], concepts)) concepts_map = dict(zip(["one", "two", "three"], concepts))
for entry in entries: for entry in entries:
if ">" in entry: self.execution_definition(context, service, concepts_map, entry)
a, b = [concepts_map[e.strip()] for e in entry.split(">")]
service.set_is_greater_than(context, "prop_name", a, b)
else:
a, b = [concepts_map[e.strip()] for e in entry.split("<")]
service.set_is_less_than(context, "prop_name", a, b)
assert service.get_concepts_weights("prop_name") == expected assert service.get_concepts_weights("prop_name") == expected
def test_i_can_get_concept_weight_when_no_comparison_is_defined(self):
sheerka, context = self.init_concepts()
service = sheerka.services[SheerkaComparisonManager.NAME]
assert service.get_concepts_weights("prop_name") == {}
def test_i_can_recover_from_deleted_weight(self):
sheerka, context, one = self.init_concepts("one")
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_lesser(context, "prop_name", one)
sheerka.cache_manager.clear(service.RESOLVED_COMPARISON_ENTRY)
assert service.get_concepts_weights("prop_name") == {"1001": 0}
def test_i_can_get_partition(self): def test_i_can_get_partition(self):
sheerka, context, one, two, three = self.init_concepts("one", "two", "three") sheerka, context, one, two, three = self.init_concepts("one", "two", "three")
service = sheerka.services[SheerkaComparisonManager.NAME] service = sheerka.services[SheerkaComparisonManager.NAME]
@@ -134,9 +162,6 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
service.set_is_greater_than(context, "prop_name", four, three) service.set_is_greater_than(context, "prop_name", four, three)
service.set_is_greater_than(context, "prop_name", five, two) service.set_is_greater_than(context, "prop_name", five, two)
res = service.set_is_greater_than(context, "prop_name", two, one)
assert res.status
res = service.set_is_greater_than(context, "prop_name", one, five) res = service.set_is_greater_than(context, "prop_name", one, five)
assert not res.status assert not res.status
@@ -157,3 +182,156 @@ class TestSheerkaGreaterThanManager(TestUsingMemoryBasedSheerka):
sheerka, context, one, two = self.init_concepts("one", "two") sheerka, context, one, two = self.init_concepts("one", "two")
res = sheerka.set_is_greater_than(context, "prop_name", two, one) res = sheerka.set_is_greater_than(context, "prop_name", two, one)
assert res.status assert res.status
def test_a_lesser_concept_has_the_lowest_weight(self):
sheerka, context, one, two, three = self.init_concepts("one", "two", "three", cache_only=False)
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_lesser(context, "prop_name", one)
assert service.get_concepts_weights("prop_name") == {"1001": 0} # DEFAULT_COMPARISON_VALUE - 1
sheerka.set_is_greater_than(context, "prop_name", three, two)
assert service.get_concepts_weights("prop_name") == {"1001": 0, "1002": 1, "1003": 2}
# I can commit
sheerka.cache_manager.commit(context)
in_db = sheerka.sdp.get(SheerkaComparisonManager.COMPARISON_ENTRY, "prop_name|#")
assert in_db == [
ComparisonObj(context.event.get_digest(), "prop_name", one.id, None, "<<", "#"),
ComparisonObj(context.event.get_digest(), "prop_name", three.id, two.id, ">", "#")
]
def test_i_can_define_an_order_for_lesser_concepts(self):
sheerka, context, lesser, less_l, even_more_l = self.init_concepts("lesser", "less_l", "even_less_l")
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_lesser(context, "prop_name", lesser)
service.set_is_lesser(context, "prop_name", less_l)
service.set_is_lesser(context, "prop_name", even_more_l)
sheerka.set_is_less_than(context, "prop_name", less_l, lesser)
sheerka.set_is_greater_than(context, "prop_name", less_l, even_more_l)
assert service.get_concepts_weights("prop_name") == {"1001": 0, "1002": -1, "1003": -2}
def test_i_cannot_define_less_than_a_lesser_if_not_a_lesser_itself(self):
"""
minus_one cannot be defined as less that one is one is defined as lesser
unless minus_one is defined as lesser itself
:return:
"""
sheerka, context, lesser, foo = self.init_concepts("lesser", "foo")
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_lesser(context, "prop_name", lesser)
res = sheerka.set_is_less_than(context, "prop_name", foo, lesser)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.INVALID_LESSER_OPERATION)
res = sheerka.set_is_greater_than(context, "prop_name", foo, lesser)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.INVALID_LESSER_OPERATION)
def test_a_greatest_concept_has_the_highest_weight(self):
sheerka, context, one, two, three = self.init_concepts("one", "two", "three")
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_greatest(context, "prop_name", three)
assert service.get_concepts_weights("prop_name") == {"1003": 2} # DEFAULT_COMPARISON_VALUE + 1
sheerka.set_is_greater_than(context, "prop_name", two, one)
assert service.get_concepts_weights("prop_name") == {"1001": 1, "1002": 2, "1003": 3}
def test_i_cannot_define_greater_than_a_greatest_if_not_a_greater_itself(self):
sheerka, context, greatest, foo = self.init_concepts("greatest", "foo")
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_greatest(context, "prop_name", greatest)
res = sheerka.set_is_less_than(context, "prop_name", foo, greatest)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.INVALID_GREATEST_OPERATION)
res = sheerka.set_is_greater_than(context, "prop_name", foo, greatest)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.INVALID_GREATEST_OPERATION)
@pytest.mark.parametrize("definitions, expected", [
(["foo >>", "foo <<"], BuiltinConcepts.INVALID_GREATEST_OPERATION),
(["foo <<", "foo >>"], BuiltinConcepts.INVALID_LESSER_OPERATION),
])
def test_i_cannot_define_a_concept_as_lesser_and_greatest_at_the_same_time(self, definitions, expected):
sheerka, context, foo = self.init_concepts("foo")
service = sheerka.services[SheerkaComparisonManager.NAME]
concepts_map = {"foo": foo}
self.execution_definition(context, service, concepts_map, definitions[0])
res = self.execution_definition(context, service, concepts_map, definitions[1])
assert not res.status
assert sheerka.isinstance(res.body, expected)
def test_i_can_define_an_order_for_greatest_concepts(self):
sheerka, context, greatest, more_g, even_more_g = self.init_concepts("greatest", "more_g", "even_more_g")
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_greatest(context, "prop_name", greatest)
service.set_is_greatest(context, "prop_name", more_g)
service.set_is_greatest(context, "prop_name", even_more_g)
sheerka.set_is_less_than(context, "prop_name", greatest, more_g)
sheerka.set_is_greater_than(context, "prop_name", even_more_g, more_g)
assert service.get_concepts_weights("prop_name") == {"1001": 2, "1002": 3, "1003": 4}
def test_i_can_mix_all_comparisons(self):
sheerka, context, one, two, three, four, five, six, three_and_half = self.init_concepts(
"one", "two", "three", "four", "five", "six", "two_and_half")
service = sheerka.services[SheerkaComparisonManager.NAME]
service.set_is_lesser(context, "prop_name", one)
service.set_is_lesser(context, "prop_name", two)
sheerka.set_is_less_than(context, "prop_name", one, two)
service.set_is_greatest(context, "prop_name", five)
service.set_is_greatest(context, "prop_name", six)
sheerka.set_is_greater_than(context, "prop_name", six, five)
sheerka.set_is_less_than(context, "prop_name", three, four)
assert service.get_concepts_weights("prop_name") == {
"1001": -1,
"1002": 0,
"1003": 1,
"1004": 2,
"1005": 3,
"1006": 4
}
sheerka.set_is_less_than(context, "prop_name", three_and_half, four)
sheerka.set_is_greater_than(context, "prop_name", three_and_half, three)
assert service.get_concepts_weights("prop_name") == {
"1001": -1,
"1002": 0,
"1003": 1,
"1007": 2,
"1004": 3,
"1005": 4,
"1006": 5
}
@pytest.mark.parametrize("definition", [
"one >>",
"one <<",
"one > two",
"one < two",
])
def test_i_cannot_add_the_same_definition_twice(self, definition):
sheerka, context, *concepts = self.init_concepts("one", "two")
service = sheerka.services[SheerkaComparisonManager.NAME]
concepts_map = dict(zip(["one", "two"], concepts))
self.execution_definition(context, service, concepts_map, definition)
res = self.execution_definition(context, service, concepts_map, definition)
assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.ALREADY_DEFINED)
+2 -2
View File
@@ -99,7 +99,7 @@ class TestSheerkaCreateNewConcept(TestUsingMemoryBasedSheerka):
res = sheerka.create_new_concept(self.get_context(sheerka), concept) res = sheerka.create_new_concept(self.get_context(sheerka), concept)
assert not res.status assert not res.status
assert sheerka.isinstance(res.value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED) assert sheerka.isinstance(res.value, BuiltinConcepts.ALREADY_DEFINED)
assert res.value.body == concept assert res.value.body == concept
def test_i_can_get_a_newly_created_concept(self): def test_i_can_get_a_newly_created_concept(self):
@@ -244,7 +244,7 @@ class TestSheerkaCreateNewConceptFileBased(TestUsingFileBasedSheerka):
res = sheerka.create_new_concept(context, concept) res = sheerka.create_new_concept(context, concept)
assert not res.status assert not res.status
assert sheerka.isinstance(res.value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED) assert sheerka.isinstance(res.value, BuiltinConcepts.ALREADY_DEFINED)
assert res.value.body == concept assert res.value.body == concept
def test_new_entry_does_not_override_the_previous_ones(self): def test_new_entry_does_not_override_the_previous_ones(self):
+1 -1
View File
@@ -73,7 +73,7 @@ class TestSheerkaModifyConcept(TestUsingMemoryBasedSheerka):
res = sheerka.modify_concept(context, foo) res = sheerka.modify_concept(context, foo)
assert not res.status assert not res.status
assert sheerka.isinstance(res.body, BuiltinConcepts.CONCEPT_ALREADY_DEFINED) assert sheerka.isinstance(res.body, BuiltinConcepts.ALREADY_DEFINED)
def test_i_can_modify_a_concept_that_is_in_a_list(self): def test_i_can_modify_a_concept_that_is_in_a_list(self):
sheerka, context, foo1, foo2 = self.init_concepts( sheerka, context, foo1, foo2 = self.init_concepts(
+6 -5
View File
@@ -167,7 +167,7 @@ as:
assert len(res) == 1 assert len(res) == 1
assert not res[0].status assert not res[0].status
assert sheerka.isinstance(res[0].value, BuiltinConcepts.CONCEPT_ALREADY_DEFINED) assert sheerka.isinstance(res[0].value, BuiltinConcepts.ALREADY_DEFINED)
@pytest.mark.parametrize("text", [ @pytest.mark.parametrize("text", [
"", "",
@@ -891,16 +891,17 @@ as:
assert sheerka.get_concepts_weights("some_prop") == {'1001': 1, '1002': 2, '1003': 3, '1004': 4} assert sheerka.get_concepts_weights("some_prop") == {'1001': 1, '1002': 2, '1003': 3, '1004': 4}
def test_i_can_evaluate_expression_when_using_token_concept(self): def test_i_can_evaluate_expression_when_using_token_concept(self):
sheerka, context, one, two, plus = self.init_concepts( sheerka, context, one, two, three, is_less_than = self.init_concepts(
Concept("one", body="1"), Concept("one", body="1"),
Concept("two", body="2"), Concept("two", body="2"),
Concept("three", body="3"),
self.from_def_concept("<", "a < b", ["a", "b"], body="set_is_less_than('some_prop', a, b)") self.from_def_concept("<", "a < b", ["a", "b"], body="set_is_less_than('some_prop', a, b)")
) )
expression = "c:one: < c:two:" expression = "c:one: < c:two:"
res = sheerka.evaluate_user_input(expression) res = sheerka.evaluate_user_input(expression)
assert res[0].status assert res[0].status
assert res[0].body == CMV(plus, a="c:one:", b="c:two:") assert res[0].body == CMV(is_less_than, a="c:one:", b="c:two:")
assert res[0].body.a == NotInit # concept is not evaluated assert res[0].body.a == NotInit # concept is not evaluated
assert res[0].body.b == NotInit # concept is not evaluated assert res[0].body.b == NotInit # concept is not evaluated
@@ -911,11 +912,11 @@ as:
assert sheerka.get_concepts_weights("some_prop") == {'1001': 1, '1002': 2} assert sheerka.get_concepts_weights("some_prop") == {'1001': 1, '1002': 2}
# it now also works using the concepts names # it now also works using the concepts names
expression = "eval one < two" expression = "eval two < three"
res = sheerka.evaluate_user_input(expression) res = sheerka.evaluate_user_input(expression)
assert res[0].status assert res[0].status
assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS) assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS)
assert sheerka.get_concepts_weights("some_prop") == {'1001': 1, '1002': 2} assert sheerka.get_concepts_weights("some_prop") == {'1001': 1, '1002': 2, '1003': 3}
def test_i_can_detect_multiple_errors_when_evaluating_a_concept(self): def test_i_can_detect_multiple_errors_when_evaluating_a_concept(self):
sheerka, context, foo, plus_one = self.init_concepts( sheerka, context, foo, plus_one = self.init_concepts(