ICCM 15: Online Material
Daniel Gall, Thom Frühwirth:
An Adaptable Implementation of ACT-R with Refraction in Constraint Handling Rules
Online Appendix
We revisit our example from the paper in more detail:
The semantic model from the ACT-R tutorial unit 1 [1] implements i.a. the following rules:
(P initial-retrieve
=goal>
ISA is-member
object =obj
category =cat
judgment nil
==>
=goal>
judgment pending
+retrieval>
ISA property
object =obj
attribute category
)
(P direct-verify
=goal>
ISA is-member
object =obj
category =cat
judgment pending
=retrieval>
ISA property
object =obj
attribute category
value =cat
==>
=goal>
judgment yes
)
(P chain-category
=goal>
ISA is-member
object =obj1
category =cat
judgment pending
=retrieval>
ISA property
object =obj1
attribute category
value =obj2
- value =cat
==>
=goal>
object =obj2
+retrieval>
ISA property
object =obj2
attribute category
)
The judgment slot in the goal chunk reveals the imperative thinking behind those rules: It always has a value clearly determining the current state of the model and narrowing down the rules that can be considered to fire artificially.
We would like to reformulate the rules without the artificial values of the judgment slot which reduce declarativity and do not seem cognitively plausible. This leads to the following rules that do not check the judgment slot for a value pending:
(P initial-retrieve
=goal>
ISA is-member
object =obj
category =cat
judgment nil
==>
+retrieval>
ISA property
object =obj
attribute category
)
(P direct-verify
=goal>
ISA is-member
object =obj
category =cat
=retrieval>
ISA property
object =obj
attribute category
value =cat
==>
=goal>
judgment yes
)
(P chain-category
=goal>
ISA is-member
object =obj1
category =cat
=retrieval>
ISA property
object =obj1
attribute category
value =obj2
- value =cat
==>
=goal>
object =obj2
+retrieval>
ISA property
object =obj2
attribute category
)
It can be seen that the pending slot is now either nil or an answer for the member check specified by the goal chunk (yes or no).
Since the initialization rule does not change the goal chunk now, it can fire again and again leading to an infinite loop. By refraction this can be prohibited:
0 ... conflict resolution
going to apply rule initial-retrieve
0.05 ... firing rule initial-retrieve
0.05 ... Started buffer request retrieval
clear buffer retrieval
0.05 ... conflict resolution
No rule matches -> Schedule next conflict resolution event
1.05 ... performing request: retrieval
Retrieved chunk p14
Put chunk p14 into buffer
1.05 ... going to apply rule direct-verify
1.1 ... firing rule direct-verify
1.1 ... buffer modification goal [ (judgment,yes) ]
1.1 ... conflict resolution
No rule matches -> Schedule next conflict resolution event
No more events in queue. End of computation.
This is the reduced example output of the model with refraction turned on. It is run with the initial goal chunk g1 with the following slots: isa is-member, object canary, category bird, judgment nil. Hence, it tries to check if canary is a member of the category bird. This query can be answered directly.
For the initial goal g2 which asks if a canary is an animal, the rule chain-category has to be used. However, this will now lead to two requests to the declarative model and hence to an error since a module should only be requested once. The problem lies with the definition of the initial state as the state where the judgment is nil. This is not very accurate, since the initial state is when the judgment slot is nil and no request is pending. Hence, the initial rule should be extended by a buffer query checking if the module is busy.
This is already an improvement of the model. However, the model can be simplified further: The initial rule does only request a new chunk if the retrieval buffer is empty. Hence, the chain-category rule can be simplified to only change to goal but not performing a request:
(P initial-retrieve
=goal>
ISA is-member
object =obj
category =cat
judgment nil
==>
+retrieval>
ISA property
object =obj
attribute category
)
(P chain-category
=goal>
ISA is-member
object =obj1
category =cat
=retrieval>
ISA property
object =obj1
attribute category
value =obj2
- value =cat
==>
=goal>
object =obj2
)
The direct-verify rule remains as before. This formulation seems to be much less state-aware than the initial model. It leads to the following reduced output called for goal chunk g2 isa is-member, object canary, category animal, judgment nil:
0 ... conflict resolution
going to apply rule initial-retrieve
0.05 ... firing rule initial-retrieve
0.05 ... Started buffer request retrieval
clear buffer retrieval:nil
0.05 ... conflict resolution
No rule matches -> Schedule next conflict resolution event
1.05 ... performing request: retrieval
Retrieved chunk p14
Put chunk p14 into buffer
1.05 ... conflict resolution
going to apply rule chain-category
1.1 ... firing rule chain-category
1.1 ... calling event: buffer modification goal [ (object,bird) ]
1.1 ... conflict resolution
going to apply rule initial-retrieve
1.15 ... firing rule initial-retrieve
1.15 ... Started buffer request retrieval
clear buffer retrieval:p14
1.15 ... conflict resolution
No rule matches -> Schedule next conflict resolution event
2.15 ... performing request: retrieval
Retrieved chunk p20
Put chunk p20 into buffer
2.15 ... conflict resolution
going to apply rule direct-verify
2.2 ... firing rule direct-verify
2.2 ... buffer modification goal [ (judgment,yes) ]
2.2 ... conflict resolution
No rule matches -> Schedule next conflict resolution event
No more events in queue. End of computation.
Translated Rules
We exemplify how the initialization rule is translated to CHR:
delay-initial-retrieve @
match,
buffer(goal,D,A),
chunk(A,is-member),
chunk_has_slot(A,object,B),
chunk_has_slot(A,category,C),
chunk_has_slot(A,judgment,nil)
==>
B\==nil,
C\==nil |
conflict_set(rule(initial-retrieve,
[match,
buffer(goal,D,A),
chunk(A,is-member),
chunk_has_slot(A,object,B),
chunk_has_slot(A,category,C),
chunk_has_slot(A,judgment,nil)
])).
initial-retrieve @
buffer(goal,D,A),
chunk(A,is-member),
chunk_has_slot(A,object,B),
chunk_has_slot(A,category,C),
chunk_has_slot(A,judgment,nil)
\ apply_rule(rule(initial-retrieve,
[match,
buffer(goal,D,A),
chunk(A,is-member),
chunk_has_slot(A,object,B),
chunk_has_slot(A,category,C),
chunk_has_slot(A,judgment,nil)],[]))
<=>
B\==nil,
C\==nil |
buffer_request(retrieval,
chunk(_,property,
[ (object,B), (attribute,category)])),
select.
Due to space reasons, we have omitted the detailed translation of guards of the rules in the paper. Those guards consist of tests similar to the slot modifiers in ACT-R. Since this rule does not contain modifiers, the guard only consists of tests stating that a variable appearing in the rule must not be nil. This is a requirement of the ACT-R production rule system [2] and has to be checked explicitly in CHR.
The rest of the rule consists of the buffer tests and actions as described in the paper.
References
[1] http://act-r.psy.cmu.edu/actr6/units.zip
[2] http://act-r.psy.cmu.edu/wordpress/wp-content/themes/ACT-R/actr6/reference-manual.pdfBothell, D. (n.d.). Act-r 6.0 reference manual – working draft [Computer software manual]. Pittsburgh, Pennsylvania 15213.