Skip to content

Commit b1cb65d

Browse files
committed
Initial commit as a python_actr package
1 parent dd73234 commit b1cb65d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+6459
-0
lines changed

python_actr/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from .model import Model, log_everything
2+
from .production import ProductionSystem
3+
from .logger import log, finished
4+
from .runner import run, run_with
5+
from .actr import *
6+
from .display import display

python_actr/actr/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from .buffer import Buffer, Chunk
2+
from .dm import *
3+
from .pm import *
4+
from .compile import PMCompile
5+
6+
from .core import ACTR
7+
from .timer import Timer
8+
from .text import TextOutput
9+
from .imaginal import ImaginalModule
10+
from .vision import Vision
11+
from .sosvision import SOSVision
12+
from .motor import Motor

python_actr/actr/buffer.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import python_actr
2+
3+
from collections import UserDict
4+
5+
class Chunk(UserDict):
6+
def __init__(self,contents,bound=None):
7+
UserDict.__init__(self)
8+
if isinstance(contents,Chunk):
9+
self.update(contents)
10+
elif isinstance(contents,str):
11+
for i,x in enumerate(contents.split()):
12+
if ':' in x:
13+
i,x=x.split(':',1)
14+
if x.startswith('?'):
15+
key=x[1:]
16+
x=bound[key]
17+
self[i]=x
18+
elif hasattr(contents,'__dict__'):
19+
for k,v in list(contents.__dict__.items()):
20+
if type(v) in [str,float,int,bool]:
21+
self[k]=v
22+
else:
23+
try:
24+
self.update(contents)
25+
except:
26+
raise Exception('Unknown contents for chunk:',contents)
27+
def __repr__(self):
28+
#
29+
r=[]
30+
keys=list(self.keys())
31+
i=0
32+
while i in keys:
33+
r.append('%s'%self[i])
34+
keys.remove(i)
35+
i+=1
36+
keys.sort()
37+
for k in keys:
38+
if k[0]!='_':
39+
r.append('%s:%s'%(k,self[k]))
40+
return ' '.join(r)
41+
42+
43+
class Buffer(python_actr.Model):
44+
def __init__(self):
45+
self.chunk=None
46+
def set(self,chunk):
47+
try:
48+
self.chunk=Chunk(chunk,self.sch.bound)
49+
except AttributeError:
50+
self.chunk=Chunk(chunk,{})
51+
def modify(self,**args):
52+
for k,v in list(args.items()):
53+
if k.startswith('_'): k=int(k[1:])
54+
if k not in self.chunk:
55+
raise Exception('No slot "%s" to modify to "%s"'%(k,v))
56+
self.chunk[k]=v
57+
self.chunk=self.chunk
58+
def __getitem__(self,key):
59+
return self.chunk[key]
60+
def clear(self):
61+
self.chunk=None
62+
def __eq__(self,other):
63+
return self.chunk==other
64+
def __hash__(self):
65+
return id(self)
66+
def __len__(self):
67+
if self.chunk is None: return 0
68+
return len(self.chunk)
69+
def isEmpty(self):
70+
return len(self)==0

python_actr/actr/compile.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
from python_actr.actr.pm import ProceduralSubModule
2+
from python_actr.production import Production
3+
from python_actr.pattern import Pattern
4+
5+
class CompiledProduction(Production):
6+
def __init__(self,pre,post,keep,retrieve,pre_bound,post_bound):
7+
self.name='%s-%s-%d'%(pre.name,post.name,id(self))
8+
self.system=pre.system
9+
self.base_utility=0
10+
self.bound=None
11+
12+
code1=[]
13+
for k,v in list(pre_bound.items()):
14+
code1.append(' %s=%s'%(k,repr(v)))
15+
code1.append(' if True: # compiled from %s'%pre.name)
16+
for line in pre.code.splitlines():
17+
for k in keep:
18+
if line.strip().startswith(k):
19+
code1.append(' '+line)
20+
break
21+
22+
code1='\n'.join(code1)
23+
for k,v in list(pre_bound.items()):
24+
code1=code1.replace('?'+k,v)
25+
26+
27+
28+
code2=[]
29+
for k,v in list(post_bound.items()):
30+
code2.append(' %s=%s'%(k,repr(v)))
31+
code2.append(' if True: # compiled from %s'%post.name)
32+
for line in post.code.splitlines():
33+
if len(line.strip())>0:
34+
code2.append(' '+line)
35+
36+
code2='\n'.join(code2)
37+
for k,v in list(post_bound.items()):
38+
code2=code2.replace('?'+k,v)
39+
40+
self.code='if True:\n%s\n%s'%(code1,code2)
41+
42+
self.func=compile(self.code,'<production-%s>'%self.name,'exec')
43+
44+
45+
keys=list(pre.keys)
46+
patterns={}
47+
for buf,pat in list(pre.pattern_specs.items()):
48+
for k,v in list(pre_bound.items()):
49+
pat=pat.replace('?'+k,v)
50+
patterns[buf]=pat
51+
52+
for m in post.keys:
53+
if m==retrieve: pass
54+
elif m not in keys:
55+
keys.append(m)
56+
pat=post.pattern_specs[m]
57+
for k,v in list(post_bound.items()):
58+
pat=pat.replace('?'+k,v)
59+
patterns[buf]=pat
60+
61+
self.keys=keys
62+
self.pattern_specs=patterns
63+
self.pattern=Pattern(patterns)
64+
65+
66+
67+
68+
69+
class PMCompile(ProceduralSubModule):
70+
def __init__(self,keep,request,retrieve):
71+
if not isinstance(keep,(list,tuple)): keep=(keep,)
72+
self.keep=keep
73+
self.request=request
74+
self.retrieve=retrieve
75+
self.log=None
76+
self.pre=[]
77+
self.post=[]
78+
self._previous=None
79+
self.compiled={}
80+
def create(self,prod,parents=None):
81+
if self.retrieve in prod.keys:
82+
for m in prod.keys:
83+
if m not in self.keep and m!=self.retrieve:
84+
break
85+
else:
86+
self.post.append(prod)
87+
88+
code=prod.code
89+
good=False
90+
for line in code.splitlines():
91+
line=line.strip()
92+
if len(line)>0:
93+
keep=False
94+
if line.startswith(self.request):
95+
good=True
96+
continue
97+
for k in self.keep:
98+
if line.startswith(k):
99+
keep=True
100+
break
101+
if keep:
102+
continue
103+
else:
104+
good=False
105+
break
106+
if good:
107+
self.pre.append(prod)
108+
def firing(self,prod):
109+
if self._previous is not None and prod in self.post:
110+
self.compile(self._previous,self._previousBound,prod,prod.bound)
111+
self._previous=None
112+
if prod in self.pre:
113+
self._previous=prod
114+
self._previousBound=dict(prod.bound)
115+
116+
def compile(self,pre,pre_bound,post,post_bound):
117+
id=(pre,post,tuple(sorted(pre_bound.items())),tuple(sorted(post_bound.items())))
118+
p=self.compiled.get(id,None)
119+
if p is None:
120+
p=CompiledProduction(pre,post,self.keep,self.retrieve,pre_bound,post_bound)
121+
self.compiled[id]=p
122+
#print p.name
123+
#print p.code
124+
125+
for a in self.parent._adaptors:
126+
a.create(p,parents=[pre,post])
127+
self.parent._productions.append(p)
128+

python_actr/actr/core.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
2+
import python_actr
3+
import collections
4+
5+
class ACTR(python_actr.ProductionSystem):
6+
production_time_sd=None
7+
production_threshold=None
8+
9+
def __init__(self,log=None):
10+
#ccm.ProductionSystem.__init__(self,log=log)
11+
#print(self,"ACTR")
12+
super(ACTR,self).__init__(log=log)
13+
self._adaptors=[]
14+
15+
def _process_productions(self):
16+
self._calc_context()
17+
for i in self._initializers:
18+
i.fire(self._context)
19+
while True:
20+
if self.production_match_delay>0: yield self.production_match_delay
21+
match=[p for p in self._productions if p.match(self._context)]
22+
if len(match)==0:
23+
yield self._top.changes
24+
else:
25+
activations=[self.get_activation(p) for p in match]
26+
a=max(activations)
27+
28+
threshold=self.production_threshold
29+
if isinstance(threshold, collections.Callable): threshold=threshold()
30+
31+
if threshold is not None and a<threshold:
32+
for a in self._adaptors: a.below_threshold()
33+
yield self._top.changes
34+
continue
35+
options=[p for (i,p) in enumerate(match) if activations[i]==a]
36+
choice=self.random.choice(options)
37+
38+
for a in self._adaptors: a.selecting(choice)
39+
#self.log.selected=choice.name
40+
self.log.production=choice.name
41+
42+
t=self.production_time
43+
if isinstance(t, collections.Callable): t=t()
44+
if self.production_time_sd is not None:
45+
t=t+self.random.gauss(0,self.production_time_sd)
46+
t-=self.production_match_delay
47+
if t<0: t=0
48+
yield t
49+
50+
if not choice.match(self._context):
51+
#self.log.change_detected='before firing '+choice.name
52+
self.log.production='(changed before firing)'
53+
else:
54+
for a in self._adaptors: a.firing(choice)
55+
self.log.production=None
56+
#self.log.firing=choice.name
57+
choice.fire(self._context)
58+
yield dict(delay=0,priority=-1000) # delay so we don't try to match again until after the result of production firing has had a chance to occur
59+
60+
def add_adaptor(self,module):
61+
self._adaptors.append(module)
62+
for p in self._productions:
63+
module.create(p)
64+
65+
def reward(self,value):
66+
for a in self._adaptors:
67+
a.reward(value)
68+
def success(self):
69+
self.reward(1)
70+
def failure(self):
71+
self.reward(-1)
72+
73+
74+
75+
def get_activation(self,production=None):
76+
if production is None:
77+
r={}
78+
for p in self._productions:
79+
r[p.name]=self.get_activation(p)
80+
return r
81+
elif isinstance(production,str):
82+
for p in self._productions:
83+
if p.name==production:
84+
return self.get_activation(p)
85+
return None
86+
else:
87+
activation=production.base_utility
88+
for a in self._adaptors:
89+
activation+=a.utility(production)
90+
return activation
91+
92+

0 commit comments

Comments
 (0)