|
import Python_sml_ClientInterface as sml |
|
|
|
|
|
|
|
class WMNode: |
|
""" Represents a node in the working memory graph wrapping an Identifier and containing links to child wmes |
|
|
|
node.id = root_id (Identifier) |
|
node.symbol = string (The root_id symbol e.g. O34) |
|
node['attr'] = WMNode # for identifiers |
|
node['attr'] = constant # for string, double, or int value |
|
node['attr'] = [ val1, val2, ... ] # for multi-valued attributes (values can be constants or WMNodes) |
|
""" |
|
|
|
def __init__(self, soar_id): |
|
self.id = soar_id |
|
self.symbol = soar_id.GetValueAsString() |
|
self.children = {} |
|
|
|
def attributes(self): |
|
""" Returns a list of all child wme attribute strings """ |
|
return list(self.children.keys()) |
|
|
|
|
|
def __getitem__(self, attr): |
|
""" Returns the value of the wme (node, attr, val) |
|
where a value can be a int, double, string, WMNode, |
|
or a list of such values for a multi-valued attribute """ |
|
return self.children.get(attr, None) |
|
|
|
def __str__(self): |
|
""" Returns a nicely formatted string representation of the node and all its children |
|
(Warning: will be a lot of text for large graphs) """ |
|
return self.__str_helper__("", set()) |
|
|
|
def __str_helper__(self, indent, ignore_ids): |
|
var = "<" + self.symbol + ">" |
|
if self.symbol in ignore_ids or len(self.children) == 0: |
|
return var |
|
|
|
ignore_ids.add(self.symbol) |
|
|
|
s = var + " {\n" |
|
for a, v in self.children.items(): |
|
s += indent + " " + a + ": " + _wm_value_to_str(v, indent + " ", ignore_ids) + "\n" |
|
s += indent + "}" |
|
return s |
|
|
|
def _extract_children(self, max_depth, node_map): |
|
""" Internal helper method to recursively extract graph structure for a node's children """ |
|
if max_depth == 0: |
|
return |
|
|
|
for index in range(self.id.GetNumberChildren()): |
|
wme = self.id.GetChild(index) |
|
attr = wme.GetAttribute() |
|
if wme.IsIdentifier(): |
|
child_id = wme.ConvertToIdentifier() |
|
child_sym = child_id.GetValueAsString() |
|
|
|
if child_sym in node_map: |
|
wme_val = node_map[child_sym] |
|
else: |
|
|
|
wme_val = WMNode(child_id) |
|
node_map[wme_val.symbol] = wme_val |
|
wme_val._extract_children(max_depth-1, node_map) |
|
|
|
elif wme.GetValueType() == "int": |
|
wme_val = wme.ConvertToIntElement().GetValue() |
|
elif wme.GetValueType() == "double": |
|
wme_val = wme.ConvertToFloatElement().GetValue() |
|
else: |
|
wme_val = wme.GetValueAsString() |
|
|
|
self._add_child_wme(attr, wme_val) |
|
|
|
def _add_child_wme(self, attr, value): |
|
""" Adds the child wme to the children dictionary |
|
If there are multiple values for a given attr, move them into a list instead of replacing """ |
|
if attr in self.children: |
|
cur_val = self.children[attr] |
|
if isinstance(cur_val, list): |
|
|
|
cur_val.append(value) |
|
else: |
|
|
|
self.children[attr] = [ cur_val, value ] |
|
else: |
|
|
|
self.children[attr] = value |
|
|
|
def _wm_value_to_str(val, indent, ignore_ids): |
|
""" |
|
recursive helper function which returns a string representation of any given value type |
|
|
|
:param val: The value to convert to a string (can be str, int, float, list, WMNode) |
|
:param indent: a string of spaces to indent the current level |
|
:param ignore_ids: A set of Identifier symbols to not print |
|
""" |
|
if isinstance(val, str): |
|
return val |
|
if isinstance(val, int): |
|
return str(val) |
|
if isinstance(val, float): |
|
return str(val) |
|
if isinstance(val, list): |
|
return "[ " + ", ".join(_wm_value_to_str(i, indent, ignore_ids) for i in val) + " ]" |
|
if isinstance(val, WMNode): |
|
return val.__str_helper__(indent, ignore_ids) |
|
return "" |
|
|
|
|
|
|