这是indexloc提供的服务,不要输入任何密码
Skip to content

Select Ghost rules based on the rule specificity #3236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions opencog/ghost/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ Additionally, when a rule in a sequence is triggered, it will have a lower STI w
Updated May 2018:
Looks like the above methods of biasing the rules to be triggered in the defined order are not enough to give the behavior that one would expect, so an extra condition has been added to the context of the rules to make sure the rule will be triggered only if the previous rules has been triggered.

Updated Jun 2018:
Another experimantal feature has been added -- to select rules based on the pattern specificity, i.e. the more specific rule will always be preferred to less specific one. For example, if there are two rules that can potentially be selected, `(how are you)` and `(how are *)`, then `(how are you)` will be selected.

2) Rule level goal(s)

```
Expand Down
2 changes: 2 additions & 0 deletions opencog/ghost/ghost.scm
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
(define ghost-next-responder (Predicate (ghost-prefix "Next Responder")))
(define ghost-next-rejoinder (Predicate (ghost-prefix "Next Rejoinder")))
(define ghost-rej-seq-num (Predicate (ghost-prefix "Rejoinder Sequence Number")))
(define ghost-context-specificity (Predicate (ghost-prefix "Context Specificity")))
(define strval-rejoinder (StringValue "rejoinder"))
(define strval-responder (StringValue "responder"))
(define strval-random-gambit (StringValue "random gambit"))
Expand Down Expand Up @@ -165,6 +166,7 @@
(define responder-sti-boost 1)
(define rejoinder-sti-boost 10)
(define refractory-period 1)
(define specificity-based-action-selection #t)

;; --------------------
;; For monitoring the status
Expand Down
71 changes: 49 additions & 22 deletions opencog/ghost/matcher.scm
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,25 @@
(* (/ 1 (assoc-ref action-cnt-alist A))
(assoc-ref sum-weight-alist A)))

; Check if a rule should be skipped or not, based on
; its current STI, strength, and the last executed time
(define (skip-rule? r)
(or SKIP-STI
(and (or (= sti-weight 0) (> (cog-av-sti r) 0))
(or (= strength-weight 0) (> (cog-stv-strength r) 0))
(or (null? (cog-value r ghost-time-last-executed))
(> (- (current-time)
(car (cog-value->list
(cog-value r ghost-time-last-executed))))
refractory-period)))))

; ----------
(for-each
(lambda (r)
; Skip the rule if its STI or strength is zero,
; unless we choose to ignore their weights,
; or if it's still with the refractory period
(if (or SKIP-STI
(and (or (= sti-weight 0) (> (cog-av-sti r) 0))
(or (= strength-weight 0) (> (cog-stv-strength r) 0))
(or (null? (cog-value r ghost-time-last-executed))
(> (- (current-time)
(car (cog-value->list
(cog-value r ghost-time-last-executed))))
refractory-period))))
(if (skip-rule? r)
(let ((rc (psi-get-context r))
(ra (psi-get-action r)))
; Though an action may be in multiple psi-rule, but it doesn't
Expand Down Expand Up @@ -129,9 +134,10 @@
(set! sum-weight-alist (assoc-set! sum-weight-alist ra
(+ (assoc-ref sum-weight-alist ra) w)))))
(cog-logger-debug ghost-logger
"Skipping action with zero weight: ~a" ra))))
(cog-logger-debug ghost-logger
"Skipping rule with zero STI/strength: ~a" r)))
"Skipping action with zero weight: ~a" ra))
))
(cog-logger-debug ghost-logger
"Skipping rule with zero STI/strength: ~a" r)))
RULES)

; Update the status
Expand Down Expand Up @@ -171,19 +177,40 @@
(list)
(map (lambda (a) (assoc-ref action-rule-alist (car a))) action-weight-alist))))
(if (null? rejoinder)
; If there is no rejoinder that safisfy the current context, try the responders
(begin
; If there is no rejoinder that safisfy the current context, try the responders
(let* ((accum-weight 0)
(cutoff (* total-weight (random:uniform (random-state-from-platform))))
(action-rtn
(find
(lambda (a)
(set! accum-weight (+ accum-weight (cdr a)))
(<= cutoff accum-weight))
action-weight-alist)))
(if (equal? #f action-rtn)
(if specificity-based-action-selection
; Specificity-based action selection (experimental)
; It will select the one with the most specific context, always,
; and randomly pick one if there are more than one rules with
; the same specificity
(fold
(lambda (a rtn)
(cond
((null? rtn) (assoc-ref action-rule-alist (car a)))
((> (cog-value-ref (cog-value
(assoc-ref action-rule-alist (car a)) ghost-context-specificity) 0)
(cog-value-ref (cog-value rtn ghost-context-specificity) 0))
(assoc-ref action-rule-alist (car a)))
(else rtn)))
(list)
(assoc-ref action-rule-alist (car action-rtn)))))
action-weight-alist
)
(let* ((accum-weight 0)
(cutoff (* total-weight (random:uniform (random-state-from-platform))))
(action-rtn
(find
(lambda (a)
(set! accum-weight (+ accum-weight (cdr a)))
(<= cutoff accum-weight))
action-weight-alist)))
(if (equal? #f action-rtn)
(list)
(assoc-ref action-rule-alist (car action-rtn))
)
)
)
)
rejoinder))))

; ----------
Expand Down
9 changes: 9 additions & 0 deletions opencog/ghost/test.scm
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,12 @@
(cog-logger-warn ghost-logger
"The refractory period has to be a numberic value!"))
)

(define-public (ghost-set-specificity-based-as VAL)
"
ghost-set-specificity-based-as VAL

Set whether or not to do specificity-based action selection.
"
(set! specificity-based-action-selection VAL)
)
94 changes: 93 additions & 1 deletion opencog/ghost/translator.scm
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,22 @@
"
(define is-unordered? #f)
(define has-words? #f)
(define specificity 0)

; A word has at least the following conditions to be satisfied
; - one and only one word -> i.e. lower & upper bound
; - in a particular form of a particular lemma
(define spec-word 4)

; A lemma has at least the following conditions to be satisfied
; - one and only one word -> i.e. lower & upper bound
; - a particular lemma (in any form)
(define spec-lemma 3)

; A concept has at least the following conditions to be satisfied
; - be grounded to one or more words -> i.e. lower bound
; - be related to a particular "concept"
(define spec-concept 2)

(define (process terms)
(define v '())
Expand All @@ -137,44 +153,115 @@
(for-each (lambda (t)
(cond ((equal? 'unordered-matching (car t))
(update-lists (process (cdr t)))
; TODO: The specificity of ordered vs unordered should be
; considered as well
(set! is-unordered? #t))
((equal? 'word (car t))
(update-lists (word (cdr t)))
(set! specificity (+ specificity spec-word))
(set! has-words? #t))
((equal? 'word-apos (car t))
(update-lists (word-apos (cdr t)))
; Its specificity should be the same as a word
(set! specificity (+ specificity spec-word))
(set! has-words? #t))
((equal? 'lemma (car t))
(update-lists (lemma (cdr t)))
(set! specificity (+ specificity spec-lemma))
(set! has-words? #t))
((equal? 'phrase (car t))
(update-lists (phrase (cdr t)))
; The specificity of a phrase depends on the number of
; words it has and each of those words is considered
; as a "word-term"
(set! specificity (+ specificity
(* (length (string-split (cdr t) #\sp)) spec-word)))
(set! has-words? #t))
((equal? 'concept (car t))
(update-lists (concept (cdr t)))
(set! specificity (+ specificity spec-concept))
(set! has-words? #t))
((equal? 'choices (car t))
(update-lists (choices (cdr t)))
; The specificity of choices should be the term in
; the list (of choices) with the least specificity
; Potentially "concept" could have done this way too,
; though concept may change dynamically at runtime
; but this will not
(set! specificity (+ specificity
(fold
(lambda (tc min-spec)
(cond
; Only included the terms that are less specific
; than a phrase
((equal? 'concept (car tc)) spec-concept)
((and (equal? 'lemma (car tc))
(< spec-lemma min-spec))
spec-lemma)
((and (equal? 'word (car tc))
(< spec-word min-spec))
spec-word)
(else min-spec)))
; The most specific term possibility exist in choices
; is a phrase, so check and see if there is any phrase
; and get its specificity, or just take the specificity
; of a word if not
(fold
(lambda (ph max-spec)
(cond
((and (equal? 'phrase (car ph))
(> (* (length (string-split (cdr ph) #\sp)) spec-word)
max-spec))
(* (length (string-split (cdr ph) #\sp)) spec-word))
(else max-spec)))
spec-word
(cdr t)
)
(cdr t))))
(set! has-words? #t))
((equal? 'optionals (car t))
(update-lists (optionals (cdr t)))
; The specificity of optionals is almost identical to concept,
; except that it's not requied to be presence (viz optional)
(set! specificity (+ specificity (- spec-concept 1)))
(set! has-words? #t))
((equal? 'negation (car t))
(update-lists (negation (cdr t)))
; Negation has a condition of not having a particular
; term or a list of terms to be presented in the pattern
(set! specificity (+ specificity 1))
(set! has-words? #t))
((equal? 'wildcard (car t))
(update-lists (wildcard (cadr t) (cddr t)))
; The specificity of a wildcard depands on the interval
; For a pure wildcard, specificity = 0
; For a range-restricted wildcard (zero to n),
; upper bound is given so specificity = 1
; For a precise wildcard (n and only n), both lower and
; upper bound is given so specificity = 2
(if (> (cadr t) 0) (set! specificity (1+ specificity)))
(if (> (cddr t) -1) (set! specificity (1+ specificity)))
(set! has-words? #t))
((equal? 'variable (car t))
(update-lists (process (cdr t)))
(set! pat-vars (append pat-vars (last-pair ws))))
((equal? 'uvar_exist (car t))
(set! c (append c (list (uvar-exist? (cdr t)))))
; User variable has a condition of checking if a particular
; user variable has been defined
(set! specificity (+ specificity 1))
(set! has-words? #t))
((equal? 'uvar_equal (car t))
(set! c (append c (list (uvar-equal? (cadr t) (caddr t)))))
; uvar_equal should have a specificity of a word as they
; have the same set of conditions to be satisfied
(set! specificity (+ specificity spec-word))
(set! has-words? #t))
((equal? 'function (car t))
; The specificity of a function / predicate depends really
; on what that function is doing (and it could be anything)
; For now, just assume the specificity of a function is 1.
(set! specificity (+ specificity 1))
(set! c (append c
(list (context-function (cadr t)
(map (lambda (a)
Expand Down Expand Up @@ -263,7 +350,8 @@
lemma-seq))))
(MemberLink (List lemma-seq) ghost-no-constant))

(list vars conds has-words?))
(list vars conds has-words? specificity)
)

; ----------
(define (process-action ACTION RULENAME)
Expand Down Expand Up @@ -617,6 +705,7 @@
(list-ref proc-type 0)))
(conds (append (list-ref proc-terms 1)
(list-ref proc-type 1)))
(specificity (list-ref proc-terms 3))
(type (assoc-ref rule-type-alist NAME))
(action (process-action ACTION NAME))
(is-rejoinder? (equal? type strval-rejoinder))
Expand Down Expand Up @@ -683,6 +772,9 @@
; Set the type
(cog-set-value! a-rule ghost-rule-type type)

; Set how specific the context of the rule is
(cog-set-value! a-rule ghost-context-specificity (FloatValue specificity))

; Associate it with its topic
(if (not ghost-with-ecan)
(Inheritance a-rule rule-topic))
Expand Down