|
from collections import defaultdict |
|
from enum import Enum |
|
|
|
class SMEM_Obj(): |
|
def __init__(self): |
|
self.processed = False |
|
self.obj_type = None |
|
self.id_var = None |
|
self.class_str = None |
|
self.wme_list = [] |
|
self.description = None |
|
|
|
def set_id_var(self, var): |
|
self.id_var = var |
|
|
|
def add_wme(self, attr, val): |
|
self.wme_list.append((attr,val)) |
|
|
|
def get_class(self): |
|
if self.class_str != None: |
|
return self.class_str |
|
for (attr,val) in self.wme_list: |
|
if attr == "^class": |
|
self.class_str = val |
|
break |
|
return self.class_str |
|
|
|
def get_description(self): |
|
if self.description != None: |
|
return self.description |
|
|
|
for (attr,val) in self.wme_list: |
|
if attr == "^description": |
|
self.description = val |
|
break |
|
return self.description |
|
|
|
def get_referenced_features(self, dict_of_values=None): |
|
|
|
if not dict_of_values: |
|
dict_of_values = defaultdict(set) |
|
children = self.get_child_objects(compact=False) |
|
for child in children: |
|
_, short_label, desc = child.to_string() |
|
|
|
if child.get_class() == "prim": |
|
if desc and desc != "()": |
|
str_to_use = desc |
|
try: |
|
ind = str_to_use.index(" is ") |
|
feature, value = str_to_use.replace("(","").replace(")","").split(" is ",maxsplit=1) |
|
dict_of_values[feature].add(value) |
|
except: |
|
print("ERROR: str_to_use missing 'is'. Value was: '"+str(str_to_use)+"'") |
|
else: |
|
str_to_use = short_label |
|
try: |
|
ind = str_to_use.index(" = ") |
|
feature, value = str_to_use.replace("(","").replace(")","").split(" = ",maxsplit=1) |
|
dict_of_values[feature].add(value) |
|
except: |
|
print("ERROR: str_to_use missing '='. Value was: '"+str(str_to_use)+"'") |
|
|
|
|
|
child_dict = child.get_referenced_features(dict_of_values) |
|
for key, val in child_dict.items(): |
|
if key in dict_of_values: |
|
dict_of_values[key].update(val) |
|
else: |
|
dict_of_values[key] = val |
|
return dict_of_values |
|
|
|
def get_compact_printable_object(self): |
|
""" Return this object if printable in compact mode, else return the set of next printable descendants. |
|
""" |
|
if self.obj_type == None: |
|
print("Warning: No obj_type for obj '"+self.id_var+"' in get_compact_printable_object().") |
|
return None |
|
retval = set() |
|
returnSelf = False |
|
|
|
if self.obj_type == ObjType.COND_PRIM: |
|
for (attr,val) in self.wme_list: |
|
if attr == "^supplies-condition": |
|
val.obj_type = ObjType.COND_CONJ |
|
retval.update(val.get_compact_printable_object()) |
|
elif self.obj_type == ObjType.COND_CONJ: |
|
for (attr,val) in self.wme_list: |
|
if attr == "^satisfies-op": |
|
val.obj_type = ObjType.OP |
|
returnSelf = True |
|
break |
|
elif attr == "^activates-context": |
|
val.obj_type = ObjType.CONTEXT |
|
returnSelf = True |
|
break |
|
elif attr == "^supplies-condition": |
|
val.obj_type = ObjType.COND_CONJ |
|
retval.update(val.get_compact_printable_object()) |
|
elif self.obj_type == ObjType.CONTEXT: |
|
for (attr,val) in self.wme_list: |
|
if attr == "^primes-condition": |
|
val.obj_type = ObjType.COND_PRIM |
|
retval.update(val.get_compact_printable_object()) |
|
else: |
|
returnSelf = True |
|
|
|
if returnSelf: |
|
retval = set() |
|
retval.add(self) |
|
|
|
return retval |
|
|
|
def get_child_objects(self, compact=True): |
|
""" If compact=True, skip condition prims and contexts, only get conjunctions and action groups |
|
""" |
|
if self.obj_type == None: |
|
print("Warning: No obj_type for obj '"+self.id_var+"'") |
|
return None |
|
retval = set() |
|
for (attr,val) in self.wme_list: |
|
if self.obj_type == ObjType.CONTEXT: |
|
if attr == "^primes-condition": |
|
val.obj_type = ObjType.COND_PRIM |
|
if compact: |
|
retval.update(val.get_compact_printable_object()) |
|
else: |
|
retval.add(val) |
|
elif self.obj_type == ObjType.COND_PRIM: |
|
if attr == "^supplies-condition": |
|
val.obj_type = ObjType.COND_CONJ |
|
if compact: |
|
retval.update(val.get_compact_printable_object()) |
|
else: |
|
retval.add(val) |
|
elif self.obj_type == ObjType.COND_CONJ: |
|
if attr == "^satisfies-op": |
|
val.obj_type = ObjType.OP |
|
retval.add(val) |
|
elif attr == "^activates-context": |
|
val.obj_type = ObjType.CONTEXT |
|
if compact: |
|
retval.update(val.get_compact_printable_object()) |
|
else: |
|
retval.add(val) |
|
elif attr == "^supplies-condition": |
|
val.obj_type = ObjType.COND_CONJ |
|
if compact: |
|
retval.update(val.get_compact_printable_object()) |
|
else: |
|
retval.add(val) |
|
elif self.obj_type == ObjType.OP: |
|
if attr == "^activates-action": |
|
val.obj_type = ObjType.ACT_GROUP |
|
retval.add(val) |
|
elif self.obj_type == ObjType.ACT_GROUP: |
|
if attr == "^action": |
|
val.obj_type = ObjType.ACT_PRIM |
|
retval.add(val) |
|
return retval |
|
|
|
def get_prim_cond_string(self, negate=False): |
|
if len(self.wme_list) == 0: |
|
return "", "" |
|
if negate: |
|
if self.class_str == "prim-exists": |
|
op_join_str = " not provided" |
|
else: |
|
op_join_str = " is not " |
|
else: |
|
if self.class_str == "prim-exists": |
|
op_join_str = " provided" |
|
else: |
|
op_join_str = " is " |
|
if self.class_str == None: |
|
self.get_class() |
|
|
|
retval_long, retval_short, retval_desc = ["(", "(", None] |
|
if self.class_str == "prim" or self.class_str == "prim-exists": |
|
group_str, attr_str, val_str = ["","",""] |
|
for (attr,val) in self.wme_list: |
|
if attr == "^group": |
|
group_str = val |
|
elif attr == "^attribute": |
|
attr_str = val |
|
elif attr == "^value": |
|
val_str = val |
|
elif attr == "^description": |
|
self.description = val |
|
retval_desc = val |
|
retval_long += group_str+"."+attr_str+op_join_str+val_str |
|
retval_short += attr_str+op_join_str+val_str |
|
return retval_long+")", retval_short+")", retval_desc |
|
|
|
def get_cond_string(self): |
|
retval_long, retval_short, retval_desc = ["","",None] |
|
|
|
parent_conds = [] |
|
|
|
is_negation = (self.get_class() == "negation") |
|
for (attr,val) in self.wme_list: |
|
if attr == "^receives-condition": |
|
parent_conds.append(val) |
|
if attr == "^description": |
|
self.description = val |
|
retval_desc = val |
|
|
|
|
|
compile_component_descs = (retval_desc == None) |
|
if compile_component_descs: |
|
retval_desc = "" |
|
|
|
for i,cond in enumerate(parent_conds): |
|
if i > 0: |
|
retval_long += " \nAND " |
|
retval_short += " AND " |
|
if compile_component_descs: |
|
retval_desc += " AND " |
|
if cond.obj_type == ObjType.COND_CONJ: |
|
long, short, desc = cond.get_cond_string() |
|
else: |
|
long, short, desc = cond.get_prim_cond_string(negate=is_negation) |
|
retval_long += long |
|
retval_short += short |
|
if compile_component_descs: |
|
if desc: |
|
retval_desc += "("+desc+")" |
|
else: |
|
retval_desc = None |
|
compile_component_descs = False |
|
return retval_long, retval_short, retval_desc |
|
|
|
def get_op_string(self): |
|
retval_long, retval_short, retval_desc = ["", "", None] |
|
numeric_pref = None |
|
for (attr,val) in self.wme_list: |
|
if attr == "^name": |
|
retval_long = val |
|
retval_short = val |
|
elif attr == "^numeric-preference": |
|
try: |
|
numeric_pref = str(float(val)*100)+"%" |
|
except Exception as e: |
|
print("ERROR in get_op_string() converting numeric_pref to string: "+str(e)) |
|
numeric_pref = None |
|
elif attr == "^description": |
|
self.description = val |
|
retval_desc = val |
|
if numeric_pref: |
|
retval_long += "\nPercentage: "+numeric_pref |
|
|
|
return retval_long, retval_short, retval_desc |
|
|
|
def get_prim_act_string(self): |
|
if len(self.wme_list) == 0: |
|
return "" |
|
if self.class_str == None: |
|
self.get_class() |
|
retval_long = "(" |
|
retval_short = "(" |
|
if self.class_str == "prim": |
|
type_str, attr_str, val_str = ["","",""] |
|
for (attr,val) in self.wme_list: |
|
if attr == "^type": |
|
type_str = val |
|
elif attr == "^attribute": |
|
attr_str = val |
|
elif attr == "^value": |
|
val_str = val |
|
retval_long += type_str+"."+attr_str+" = "+val_str |
|
retval_short += attr_str+" = "+val_str |
|
elif self.class_str == "prim-message": |
|
type_str, flag_str, msg_str = ["","",""] |
|
for (attr,val) in self.wme_list: |
|
if attr == "^type": |
|
type_str = val |
|
elif attr == "^flag": |
|
flag_str = val |
|
elif attr == "^message": |
|
msg_str = val |
|
retval_long += type_str+".flag = "+flag_str+" AND "+type_str+'.message = "'+msg_str+'"' |
|
retval_short += 'message: "'+msg_str+'"' |
|
return retval_long+")", retval_short+")" |
|
|
|
def get_act_group_string(self): |
|
retval_long, retval_short, retval_desc = ["", "", None] |
|
|
|
child_prims = [] |
|
for (attr,val) in self.wme_list: |
|
if attr == "^action": |
|
child_prims.append(val) |
|
elif attr == "^description": |
|
self.description = val |
|
retval_desc = val |
|
for i,prim in enumerate(child_prims): |
|
if i > 0: |
|
retval_long += " AND " |
|
retval_short += " AND " |
|
long, short = prim.get_prim_act_string() |
|
retval_long += long |
|
retval_short += short |
|
return retval_long, retval_short, retval_desc |
|
|
|
def to_string(self): |
|
long = self.id_var |
|
short = self.id_var |
|
description = None |
|
|
|
if self.obj_type == ObjType.CONTEXT: |
|
return "", "", self.get_description() |
|
if self.obj_type == ObjType.COND_PRIM: |
|
long, short, description = self.get_prim_cond_string() |
|
|
|
|
|
if self.obj_type == ObjType.COND_CONJ: |
|
long, short, description = self.get_cond_string() |
|
if self.obj_type == ObjType.OP: |
|
long, short, description = self.get_op_string() |
|
if self.obj_type == ObjType.ACT_GROUP: |
|
long, short, description = self.get_act_group_string() |
|
if self.obj_type == ObjType.ACT_PRIM: |
|
long, short = self.get_prim_act_string() |
|
return long, short, description |
|
|
|
class ObjType(Enum): |
|
CONTEXT = 0 |
|
COND_PRIM = 1 |
|
COND_CONJ = 2 |
|
OP = 3 |
|
ACT_GROUP = 4 |
|
ACT_PRIM = 5 |
|
|