#!/usr/bin/python """ This isa API for bots who can read and write in the Semantic Cloud. It is based on memory structures of graphs containing nodes and labeled arrows. theory forms credits Originally written by "Seth Russell" parsePentals by "Sean B. Palmer" downloads licenseUrl version 0.040 revised 05/24/2002 9:00 PM status works for level of development lastProgress wrote quidty interperter: doit, readPentals makes graphs priorProgress inProgress write do('at(thing) mem gress sayBal!') nextToDo1 process imparatives nextToDo2 revise output stragegy ... show attn with html highlight ... thinkingAbout0 changeing Arrow -> Object thinkingAbout1 compound subjects with grammar enlosing in parenthesis (Seth Russell)' """ __license__= 'Copyright (C) 2001 Seth Russell. GNU GPL 2' import types import sys import re from bot import * global ok, fail, oh fail=0 ok=1 oh=2 class wake: def __init__(self,MyName='I',ownedBy='nobody'): # Acquire my identity from imput arguments self.MyName=MyName self.Owner=ownedBy # The Logical State Value for Trivalent Logic # Logic is set by methods: ok, fail, oh # To values: 'ok', 'fail', 'oh' # These states are tested by methods: then, else, ohthen # the third logical value, 'oh', is sometimes refered to as 'surprise' # set to surprise here because attn is not yet on an arrow self.Logic='oh' # This variable exposes the descripiton of the last error # Usually Logic is set to 'oh' whenever an error occurs # @@@ ? @@@ any method which can error, must set error='' prior to execuition # @@@ Proposed change: strategy with surprise and pushing errors on a stack ? self.error='' # Things are identified in this system by integer serial numbers # A thing's integer serial numbers is refered to as it's id # A thing's type, given by thingType(id), is coded in the high order decimal digit of an id # 99,000,000 should be enough grains of sand for the moment # The following assignments fix the thingType for various kinds of things self.graphIdFix = 100000000 # thingType='Graph' self.nodeIdFix = 200000000 # thingType='Node' self.open3IdFix = 300000000 # thingType='3unused' self.arrowIdFix = 400000000 # thingType='Arrow' self.lexIdFix = 500000000 # thingType='Lex' self.open6IdFix = 600000000 # thingType='6unused' self.numberIdFix= 700000000 # thingType='Number' self.actionIdFix= 800000000 # thingType='Program' self.open9IdFix = 900000000 # thingType='9unused' # Start the ids where they left off in the Persistent Data Storage(PDS) # @@@@@ initilized to blank here because we havent gotten to that yet self.PDS='' if self.PDS == '': # If starting a new PDS, start all Ids from their fixes self.graphId=self.graphIdFix self.nodeId=self.nodeIdFix self.arrowId=self.arrowIdFix self.lexId=self.lexIdFix self.numberId=self.numberIdFix self.actionId=self.actionIdFix # The structure of mentography in python is a python list # of graphs, of nodes, of predicates, of arrows to objects # seeUrl http://robustai.net/mentography/python_Memory_structure.gif # This list called graphs contains the actual mentograph in Memory self.graphs=[] # Initilize the attn pointers into these graphs # seeUrl http://robustai.net/mentography/python_Memory_structure.gif # red pointers in mentograph are moved when navigating attn self.attnGraph=0 self.attnNode=0 self.attnPredicate=0 self.attnArrow=0 # There are two dictionaies as seen in green in the mentograph # seeUrl http://robustai.net/mentography/python_Memory_structure.gif # The lexicon {symbal : id } which associates a symbal with an id self.lexicon={} # associations look like {id : [ symbal, (graph1,node1), (graph2,node2), ...] } # provides the symbal associated with the id and a list of which graphs in which that id exists self.associations={} # the stack for mem and remem contains tuples of attn # [(attnGraph,attnNode,attnPredicate,attnArrow) ... ] self.memStack=[] # commands that are permissable to run in the interperter # currently we are very permissable self.commands =dir(self) # Let's grow the first arrow in the first node in the first graph # so that attn from this point on is alway closed on the graph. self.groGraph('UrGraph') # from the input parameters making an instance of wake # Asserting the Pental (in default of any args) that {I ownedBy NoBody UrGraph.}. # assert first pent that {MyName ownedBy Owner UrGraph.} self.groNode(self.Owner) self.groNode(self.MyName) self.groPredicate('ownedBy') self.groArrow(self.Owner) # kludge for memo self.memo=() # ----- END INITILIZE wake instance self.Logic='ok' return None # ----------------------------------------------------- # ---------------- AN QUIDTY INTERPERTER ------------ # ----------------------------------------------------- def doit(self, toDo): # toDo is a list of lists like: [[command1, arg1], [command2, arg2] ... ] for do in toDo: if do[0] in self.commands: method = getattr(self, do[0]) if do[1]=='': method() else: method(do[1]) # ----------------------------------------------------- # ---------------- NAVIGATION METHODS ----------------- # ----------------------------------------------------- # MOVING BETWEEN GRAPHS def firstGraph(self): self.attnGraph=0 self.firstNode() return self.Attn() def nextGraph(self): if self.attnGraph+2>=len(self.graphs): self.firstGraph() self.Logic='fail' return fail else: self.attnGraph+=2 self.firstNode() self.Logic='ok' return ok def lastGraph(self): self.attnGraph=len(self.graphs)-2 self.firstNode() return self.Attn() # MOVING BETWEEN NODES IN A GRAPH def firstNode(self): self.attnNode,self.attnPredicate,self.attnArrow=0,0,0 return self.Attn() def jace(self): if self.attnNode+2>=len(self.graphs[self.attnGraph]): self.firstNode() self.Logic='fail' return fail else: self.attnNode+=2 self.attnPredicate,self.attnArrow=0,0 self.Logic='ok' return ok def lastNode(self): self.attnNode=len(self.graphs[self.attnGraph])-2 self.attnPredicate,self.attnArrow=0,0 return self.Attn() # MOVING BETWEEN PREDICATES IN A NODE def firstPredicate(self): self.attnPredicate,self.attnArrow=0,0 return self.Attn() def sym(self): if self.attnPredicate+3>=len(self.graphs[self.attnGraph][self.attnNode]): self.attnPredicate,self.attnArrow=0,0 self.Logic='fail' return fail else: self.attnPredicate+=3 self.attnArrow=0 self.Logic='ok' return ok def lastPredicate(self): self.attnPredicate=len(self.graphs[self.attnGraph][self.attnNode])-3 self.attnArrow=0 return self.Attn() def symTo(self,property): if property==None and len(self.graphs[self.attnGraph][self.attnNode])==0: self.Logic='ok' return ok if thingType(property)=='NotThing': if property==None: id=None elif self.lexicon.has_key(property): id=self.lexicon[property] else: self.Logic='fail' return fail else: id=property self.firstPredicate() self.Logic='ok' while self.Logic=='ok': if self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1]==id: break self.sym() if self.Logic=='ok': return ok return fail # MOVING BETWEEN ARROWS IN A PREDICATE def firstArrow(self): self.attnArrow=0 return self.Attn() def gress(self): if self.attnArrow+3>=len(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate]): self.attnArrow=0 self.Logic='fail' return fail else: self.attnArrow+=3 self.Logic='ok' return ok def gressTo(self,object): if object==None and self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow]==None: self.Logic='ok' return ok if thingType(object)=='NotThing': if object==None: id=None elif self.lexicon.has_key(object): id=self.lexicon[object] else: self.Logic='fail' return fail else: id=object self.firstArrow() self.Logic='ok' while self.Logic=='ok': if self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+1]==id: break self.gress() if self.Logic=='ok': return ok return fail def lastArrow(self): self.attnArrow=len(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate])-3 return self.Attn() # MANIPULATING ATTENTION ONLY def at(self,called): # find a node in any graph associated with this symbal # if not found in any grpah, make a node in attn graph # set attn to first arrow in node # Note, node may be a graph node if self.lexicon.has_key(called): id=self.lexicon[called] else: id=self.newNodeId(called) if self.associations.has_key(id): a=self.associations[id] self.attnGraph,self.attnNode = a[1][0], a[1][1] else: self.groNode(called) self.associations[id]=[called, (self.attnGraph,self.attnNode)] self.attnPredicate, self.attnArrow = 0 , 0 return self.Attn() def mem(self): # push attn on the stack for future reference self.memStack.append((self.attnGraph, self.attnNode, self.attnPredicate, self.attnArrow)) def remem(self): # pop attn off the stack # if nothing on stack report error and be surprised if len(self.memStack)>0: self.attnGraph, self.attnNode, self.attnPredicate, self.attnArrow = self.memStack.pop() else: self.error='remem but nothing on memStack' self.Logic='oh' return oh # VANCE - FOLLOW YOUR ARROW TO IT'S DESTINATION def vance(self): if type(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow]) is types.TupleType: self.attnGraph,self.attnNode=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow] self.attnPredicate,self.attnArrow=0,0 self.Logic='ok' return ok else: self.Logic='fail' return fail # ----------------------------------------------------- # ---------------- GROWTH METHODS --------------------- # ----------------------------------------------------- # ISSUE NEW IDENTITIES def newGraphId(self,called=None): if called==None: # new anonymous graph self.graphId+=1 return self.graphId elif self.lexicon.has_key(called): # we already have a graph\node called that return self.lexicon[called] else: # assign a new graphId and put it in lexicon self.graphId+=1 self.lexicon[called]=self.graphId return self.graphId def newNodeId(self,called=None): # Note: property nodes are just nodes if called==None: # new anonymous node self.nodeId+=1 return self.nodeId elif self.lexicon.has_key(called): # we already have a graph\node called that return self.lexicon[called] else: # assign a new nodeId and put it in lexicon self.nodeId+=1 self.lexicon[called]=self.nodeId return self.nodeId def newArrowId(self): # we dont give arrows identity at the moment # self.arrowId+=1 return None def newLexId(self, value, parseType='', language=''): # seeUrl http://rdfig.xmlhack.com/2002/05/01/2002-05-01.html#1020277030.932331 # seeUrl http://cvs.ilrt.org/cvsweb/~checkout~/redland/raptor/tests/test.nt if (value[0]=='"' and value[-1]=='"') or (value[0]=="'" and value[-1]=="'"): pass else: value='"'+value+'"' literal=parseType+value+language if self.lexicon.has_key(literal): # we already have such a literal return lexicon[literal] else: # assign a new lexId and put it in lexicon self.lexId+=1 self.lexicon[literal]=self.lexId return self.lexId # GROW GRAPHS, NODES, PREDICATES AND ARROWS def groGraph(self,called=None): # Grow a new graph with one empty node # The name of the graph is passed as the optional argument 'called' # fails: if graph exists, yet moves attn there # surprised: if graph name exists yet has not assoications or is not a graph # seeUrl self.error='' if called!=None: if self.lexicon.has_key(called): # can't make new graph, it already exists if self.associations.has_key(self.lexicon[called]): id=self.lexicon[called] if thingType(id)!='Graph': self.error='Attempt to groGraph called "'+called+'" but that name is already used, and is not a Graph.' self.logic='oh' return oh # set the Graph we found at Attn id=self.lexicon[called] self.attnGraph=self.associations[id][1] self.firstNode() self.Logic='fail' return fail else: # should not happen self.error='Attempt to groGraph called "'+called+'" which name is already used, yet is not associated with anything.' self.Logic='oh' return oh id=self.newGraphId(called) self.graphs.append([]) self.graphs.append(id) self.attnGraph=len(self.graphs)-2 self.associations[id]=[called] self.groNode(called) self.Logic='ok' return ok def groNode(self,called=None): # Grow a new node with one empty predicate # The name of the node is passed as the optional argument 'called' # fails: if node already exists, yet moves attn there # seeUrl id=self.newNodeId(called) # get the id for this node if self.associations.has_key(id): assn=self.associations[id] for i in assn: if type(i) is types.TupleType and i[0]==self.attnGraph: # go to that node in this graph self.attnNode=i[1] # but we failed to gro a new node # because one already existed with that id self.Logic='fail' return fail self.graphs[self.attnGraph].append([]) self.graphs[self.attnGraph].append(id) # move attn to new node self.attnNode=len(self.graphs[self.attnGraph])-2 self.attnPredicate,self.attnArrow=0,0 # add it to the associations dictionary if self.associations.has_key(id): self.associations[id].append((self.attnGraph,self.attnNode)) else: self.associations[id]=[called,(self.attnGraph,self.attnNode)] # gro a default empty predicate on it self.groPredicate() self.Logic='ok' return ok def groPredicate(self,property=None): # Grow a new predicate # The property name of the predicate is passed as the optional argument # fails: if predicate already exists on this node, yet moves attn there if property==None: self.graphs[self.attnGraph][self.attnNode].append([]) self.graphs[self.attnGraph][self.attnNode].append(None) self.graphs[self.attnGraph][self.attnNode].append(None) self.groArrow() return ok self.mem() self.at(property) id=self.graphs[self.attnGraph][self.attnNode+1] propertyLocation=self.attnGraph,self.attnNode self.remem() if self.symTo(id): # predicate already exists on this node, cannot gro a new one self.Logic='fail' return fail if self.symTo(None): self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+0]=[None,None,None] self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1]=id self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+2]=propertyLocation return ok self.graphs[self.attnGraph][self.attnNode].append([]) self.graphs[self.attnGraph][self.attnNode].append(id) self.graphs[self.attnGraph][self.attnNode].append(propertyLocation) # move attn to new predicate self.attnPredicate=len(self.graphs[self.attnGraph][self.attnNode])-3 self.attnArrow=0 # gro a empty arrow here self.groArrow() self.Logic='ok' return ok def groArrow(self,object=None, seq=None): # Gro a new arrow to the object and place attn on the arrow # fails if arrow to object already exists, yet goes there # @@@@@ support for seq missing if object==None: self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(None) self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(None) self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(None) self.attnArrow=len(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate])-3 self.Logic='ok' return ok self.mem() self.at(object) id=self.graphs[self.attnGraph][self.attnNode+1] objectLocation=self.attnGraph,self.attnNode self.remem() if self.gressTo(id): # object already exists on this node, cannot gro a new one self.Logic='fail' return fail if self.gressTo(None): self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+0]=objectLocation self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+1]=id self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+2]=None return ok self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(objectLocation) self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(id) self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(None) # move attn to new arrow self.attnArrow=len(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate])-3 self.Logic='ok' return ok def gro(self,subject,predicate,object,graph=None,seq=None): # @@@@ process graph and seq arguments if present self.groNode(subject) self.groPredicate(predicate) self.groArrow(object) # ----------------------------------------------------- # ---------------- READ IN DATA FROM OUTSIDE ---------- # ----------------------------------------------------- def readPentals(self,xstimulus): # returns a list of tuples [(subject,predicate,object,graph,seq,terminal), ...] stmts=parsePentals(xstimulus) #stmts is a list of tuples [(subject,predicate,object,graph,seq,terminal), ...] #stmts is a list of tuples [(s[0] ,s[1] ,s[2] ,s[3],s[4],s[5] ), ...] #@@@ does not process seq and terminal performatives yet for s in stmts: if s[3]!='': self.groGraph(s[3]) self.groNode(s[0]) self.groPredicate(s[1]) self.groArrow(s[2]) # __________________________________________________________________________________________ # ************* METHODS TO GERERATE OUTPUT ****************** # ------------------------------------------------------------------------------------------ def say(self): predicateId=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1] if predicateId==None: return fail self.mem() predicateToken=self.associations[predicateId][0] print predicateToken, self.sayObject() while self.gress(): print ',', self.sayObject() print self.remem() def sayObject(self): object=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow] if object==None: return fail elif type(object) is types.TupleType: self.mem() if self.vance(): self.sayTopic() self.remem() return ok else: print object, def sayTopic(self): topicId=self.graphs[self.attnGraph][self.attnNode+1] if topicId==None: return fail topicToken=self.associations[topicId][0] print topicToken, return ok def sayBal(self): if self.ifEmptyPredicate(): return ok self.mem() self.sayTopic() print self.firstPredicate() print ' ', self.say() while self.sym(): print ' ', self.say() # print '.' self.remem() def ifEmptyPredicate(self): if self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1]==None: self.Logic='ok' return ok self.Logic='fail' return fail def sayGraph(self): self.mem() self.firstNode() self.sayBal() while self.jace(): self.sayBal() self.remem() def sayGraphServer(self): saveStreams=sys.stdin, sys.stdout f=open('temp.txt', 'w') sys.stdout=f self.sayGraph() f.close() f=open('temp.txt', 'r') s='' for i in f: s=s+i f.close() l=s.replace('<','<') r=l.replace('>','>') return r def Attn(self): return self.attnGraph, self.attnNode, self.attnPredicate, self.attnArrow def dispAttnLogic(self): return (self.attnGraph, self.attnNode, self.attnPredicate, self.attnArrow),self.Logic # ----------------------------------------------------- # ---------------- DEBUGGING TOOLS -------------------- # ----------------------------------------------------- def showAssociations(self): a=self.associations.items() for i in a: print i[0],i[1] def showLexicon(self): a=self.lexicon.items() for i in a: print i[0],i[1] def showAttn(self): gId=self.graphs[self.attnGraph+1] print 'graph=',gId,self.symbalOf(gId) nId=self.graphs[self.attnGraph][self.attnNode+1] print 'node=',nId,self.symbalOf(nId) pId=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1] print 'predicate=',pId,self.symbalOf(pId) object=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow] stId=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+1] seq=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+2] print 'object=',object,' stId=',stId,' seq=',seq def symbalOf(self,id): k=self.lexicon.items() for i in k: if i[1]==id: return i[0] return '' def showGraph(self): self.mem() self.savememo() print self.symbalOf(self.graphs[self.attnGraph+1]), print self.graphs[self.attnGraph+1] self.firstNode() self.Logic='ok' while self.Logic=='ok': self.showNode() self.jace() self.remem() def showNode(self): self.mem() print ' ', print self.symbalOf(self.graphs[self.attnGraph][self.attnNode+1]), print self.graphs[self.attnGraph][self.attnNode+1], print self.Attn() self.firstPredicate() self.Logic='ok' while self.Logic=='ok': self.showPredicate() self.sym() self.remem() def showPredicate(self): print ' ', print self.symbalOf(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1]), print self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1], print self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+2] self.showObjects() def showObjects(self): self.mem() self.firstArrow() self.Logic='ok' while self.Logic=='ok': print ' ', print self.symbalOf(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+1]), print self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+1], print self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow],self.showPlace() self.gress() self.remem() return None def showPlace(self): x=self.attnGraph,self.attnPredicate,self.attnNode,self.attnArrow if x==self.memo: return '<---' else: return '' def savememo(self): self.memo=self.attnGraph,self.attnPredicate,self.attnNode,self.attnArrow # --------- END WAKE METHODS ------------ # ---------FUNCTIONS IN THE MODULE BOT FOLLOW---------------- def tokenType(called): # Tokens are elements of text read from external languages # This function classifies tokens # Symbals are tokens that refer to things but are not things in themselves # Symbals must contain at least one alphabetic character and not be enclosed in quotes # Symbals are sometimes called constants or variables in logical languages like KIF or CycL # Digits are numbers # Literals are data to be taken as is --- URI are literals # Punctuation is everything else # seeUrl http://robustai.net/mentography/types.gif if type(called)!=type('a'): return 'NotToken' elif called.isdigit(): return 'Digits' elif called.isalnum(): return 'Symbal' elif called[-1]=='"' or called[-1]=="'": return 'Literal' elif called[0]=='<' and called[-1]==">": return 'Uri' else: return 'Punctuation' def thingType(id): # This function classifies things according to # the high order digit of their id # seeUrl http://robustai.net/mentography/types.gif if type(id)!=type(100000000): return 'NotThing' if id < 100000000 or id > 999999999 : return 'NotThing' thingTypes=('NotThing','Graph','Node','3unused','Arrow','Lex','6unused','Number','Program','9unused') return thingTypes[int(str(id)[0])] def parsePentals(s, t=[]): # This lexical analizer was written by Sean Palmer # returns a list of tuples [(subject,predicate,object,graph,seq,terminal), ...] a, t = r'("[^"\\]*(?:\\.[^"\\]*)*"|\S+)', t[:] rt = r'%s[ \t]%s[ \t]%s(?:[ \t]%s)?(?:[ \t]%s)?[ \t]?([!?.])' \ % (a, a, a, a, a) for line in s.replace('\r\n', '\n').replace('\r', '\n').split('\n'): if re.compile(rt).match(line): t.append(re.compile(rt).findall(line)[0]) return t """ ___________________________________________________________________________________________ FLOATSAM ___________________________________________________________________________________________ """