diff --git a/README.md b/README.md index cd9b087..d42c439 100644 --- a/README.md +++ b/README.md @@ -630,9 +630,22 @@ After applying the belief update, our agent's belief base is as follows: Note that in detail, the priorities are interpreted as follows: -* If a belief exists in the update, but not in the agent's belief base, this belief is added. -* If the belief's priority is 0 in the belief base and a belief with the same key exists in the update, the agent's belief is overridden; this behavior is desired for beliefs that are generally defeasible. -* If a belief's priority in the update is higher than the same belief's priority in the agent's belief base, the agent's belief is overridden. + * If a belief exists in the update, but not in the agent's belief base, this belief is added. + * If the belief's priority is 0 in the belief base and a belief with the same key exists in the update, the agent's belief is overridden; this behavior is desired for beliefs that are generally defeasible. + * If a belief's priority in the update is higher than the same belief's priority in the agent's belief base, the agent's belief is overridden. + +A potential issue that the belief revision function we use above does not address is that it essentially requires the *inflation* of priorities in case of regular successful revisions of beliefs with a non-zero priority. +For example, in order to update ``the belief \verb|propertyValue: { value: 500000, priority: 1 }``, a new ``propertyValue`` belief can only defeat the belief if its priority is ``2`` or higher; the subsequent defeater will then require a priority of ``3``, and so on. +We can address this issue by defining whether a particular belief (or beliefs in general) should, when defeated, adopt the priority of their defeater. + +When using ``JSson.revisionFunctions.revisePriorityStatic`` as our belief revision function, the priority of the initial beliefs are maintained. Alternatively, we can specify whether or not a belief's priority should be updated, on the level of the individual belief: + +```JavaScript +const beliefBase = { + isRaining: Belief('isRaining', true, Infinity, true), + temperature: Belief('temperature', 10, Infinity, false) + } +``` ## Messaging JS-son agents can send "private" messages to any other JS-son agent, which the environment will then relay to this agent only. diff --git a/spec/src/agent/Belief.spec.js b/spec/src/agent/Belief.spec.js index 1d4ef1d..56e5198 100644 --- a/spec/src/agent/Belief.spec.js +++ b/spec/src/agent/Belief.spec.js @@ -9,8 +9,8 @@ describe('belief()', () => { expect(Belief('test', 'test')).toEqual({ test: 'test' }) }) - it('should create a new belief with the specified key, value (explicitly managed), and priority', () => { - expect(Belief('test', 'test', 1)).toEqual({ test: 'test', value: 'test', priority: 1 }) + it('should create a new belief with the specified key, value (explicitly managed), priority, and priority update spec', () => { + expect(Belief('test', 'test', 1)).toEqual({ test: 'test', value: 'test', priority: 1, updatePriority: false }) }) it('should not throw a warning if belief is of a JSON data type', () => { diff --git a/spec/src/agent/beliefRevision/revisionFunctions.spec.js b/spec/src/agent/beliefRevision/revisionFunctions.spec.js index f344ad2..e453a09 100644 --- a/spec/src/agent/beliefRevision/revisionFunctions.spec.js +++ b/spec/src/agent/beliefRevision/revisionFunctions.spec.js @@ -3,7 +3,8 @@ const Belief = require('../../../../src/agent/Belief') const { reviseSimpleNonmonotonic, reviseMonotonic, - revisePriority } = require('../../../../src/agent/beliefRevision/revisionFunctions') + revisePriority, + revisePriorityStatic } = require('../../../../src/agent/beliefRevision/revisionFunctions') const { beliefs, @@ -98,4 +99,38 @@ describe('revisionFunctions', () => { expect(newAgent.beliefs.isRaining.value).toBe(true) expect(newAgent.beliefs.temperature.value).toEqual(10) }) + + it('should allow configuring a belief such that its initial priority is kept', () => { + const beliefBase = { isRaining: Belief('isRaining', true, 1, false) } + + const update = { isRaining: Belief('isRaining', false, 2) } + + const newAgent = new Agent({ + id: 'myAgent', + beliefs: beliefBase, + desires, + plans, + selfUpdatesPossible: false, + reviseBeliefs: revisePriority + }) + newAgent.next(update) + expect(newAgent.beliefs.isRaining.priority).toBe(1) + }) + + it('should allow configuring a priority belief revision function such that the initial priorities of it beliefs are generally kept', () => { + const beliefBase = { isRaining: Belief('isRaining', true, 1) } + + const update = { isRaining: Belief('isRaining', false, 2) } + + const newAgent = new Agent({ + id: 'myAgent', + beliefs: beliefBase, + desires, + plans, + selfUpdatesPossible: false, + reviseBeliefs: revisePriorityStatic + }) + newAgent.next(update) + expect(newAgent.beliefs.isRaining.priority).toBe(1) + }) }) diff --git a/src/agent/Belief.js b/src/agent/Belief.js index 261e774..55841bb 100644 --- a/src/agent/Belief.js +++ b/src/agent/Belief.js @@ -5,14 +5,16 @@ const warning = 'JS-son: Created belief with non-JSON object, non-JSON data type * @param {string} id the belief's unique identifier * @param {any} value the belief's value * @param {number} priority the belief's priority in case of belief revision; optional + * @param {boolean} updatePriority whether in case of a belief update, the priority of the defeating belief should be adopted; optional, defaults to true * @returns {object} JS-son agent belief */ -const Belief = (id, value, priority) => { +const Belief = (id, value, priority, updatePriority=false) => { const belief = {} belief[id] = value if (priority || priority === 0) { belief.priority = priority belief['value'] = value + belief.updatePriority = updatePriority } try { const parsedBelief = JSON.parse(JSON.stringify(belief)) diff --git a/src/agent/beliefRevision/revisionFunctions.js b/src/agent/beliefRevision/revisionFunctions.js index db12e3b..07f6566 100644 --- a/src/agent/beliefRevision/revisionFunctions.js +++ b/src/agent/beliefRevision/revisionFunctions.js @@ -26,13 +26,31 @@ const reviseMonotonic = (oldBeliefs, newBeliefs) => ({ ...newBeliefs, ...oldBeli const revisePriority = (oldBeliefs, newBeliefs) => Object.fromEntries( new Map( Object.keys(newBeliefs).map(key => - !key in oldBeliefs || oldBeliefs[key].priority == 0 || oldBeliefs[key].priority < newBeliefs[key].priority ? [key, newBeliefs[key]] : [key, oldBeliefs[key]] + !key in oldBeliefs || oldBeliefs[key].priority == 0 || oldBeliefs[key].priority < newBeliefs[key].priority ? oldBeliefs[key].updatePriority ? [key, newBeliefs[key]] : [key, { ...oldBeliefs[key], value: newBeliefs[key].value }] : [key, oldBeliefs[key]] ) ) ) +/** + * Revises beliefs by merging old and new beliefs such that an old belief overrides a new one in. Does not update belief priorities. + * case of conflict + * @param {object} oldBeliefs Old belief base (JSON object of beliefs) + * @param {object} newBeliefs New belief base (JSON object of beliefs) + * @returns Revised belief base (JSON object of beliefs) + */ + +const revisePriorityStatic = (oldBeliefs, newBeliefs) => revisePriority(Object.fromEntries( + new Map( + Object.keys(oldBeliefs).map(key => [ + key, + { ...oldBeliefs[key], updatePriority: false } + ]) + ) + ), newBeliefs) + module.exports = { reviseSimpleNonmonotonic, reviseMonotonic, - revisePriority + revisePriority, + revisePriorityStatic }