Skip to content

Commit

Permalink
feat: add Belief and BeliefSet (#21)
Browse files Browse the repository at this point in the history
* feat: add Belief, IBelief and Beliefset

* docs: add documentation

* test: add tests for Belief

* test: add tests for Beliefset

* fix: fix Reflection bug in Beliefset

* fix: make Beliefset constructor protected

* docs: change summaries to remarks

* fix: adhere to naming conventions for unit tests

* chore: change name Beliefset to BeliefSet

* chore: change name Beliefset to BeliefSet

* fix: change name TResource to TObservation and add more tests

* fix: improve documentation and namings

* fix: improve IBelief and Belief summaries

* fix: more improvements to docs and tests

* chore: correct test comments

* chore: rename Beliefset.cs to BeliefSet.cs

* chore: rename BeliefsetTests.cs to BeliefSetTests.cs

* chore: remove Believe folder

* fix: use actual BeliefSet in Goals

* feat: add IBeliefSet

* chore: rename believe to belief in comments
  • Loading branch information
JensSteenmetz authored Mar 26, 2024
1 parent 56f23ae commit b2d544c
Show file tree
Hide file tree
Showing 10 changed files with 433 additions and 24 deletions.
81 changes: 81 additions & 0 deletions Aplib.Core/Belief/Belief.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;

namespace Aplib.Core.Belief
{
/// <summary>
/// The <see cref="Belief{TReference, TObservation}"/> class represents the agent's belief of a single object.
/// Some <i>object reference</i> is used to generate/update an <i>observation</i>
/// (i.e., some piece of information of the game state as perceived by an agent).
/// </summary>
/// <remarks>
/// It implements the <see cref="IBelief"/> interface.
/// It supports implicit conversion to <typeparamref name="TObservation"/>.
/// </remarks>
/// <typeparam name="TReference">The type of the object reference used to generate/update the observation.</typeparam>
/// <typeparam name="TObservation">The type of the observation that the belief represents.</typeparam>
public class Belief<TReference, TObservation> : IBelief
{
/// <summary>
/// The object reference used to generate/update the observation.
/// </summary>
private readonly TReference _reference;

/// <summary>
/// A function that takes an object reference and generates/updates an observation.
/// </summary>
private readonly Func<TReference, TObservation> _getObservationFromReference;

/// <summary>
/// A condition on when the observation should be updated.
/// </summary>
private readonly Func<bool> _shouldUpdate = () => true;

/// <summary>
/// The observation represented by the belief (i.e., some piece of information of the game state as perceived by an agent).
/// </summary>
private TObservation _observation;

/// <summary>
/// Initializes a new instance of the <see cref="Belief{TReference, TObservation}"/> class with an object reference,
/// and a function to generate/update the observation using the object reference.
/// </summary>
/// <param name="reference">A function that takes an object reference and generates/updates an observation.</param>
/// <param name="getObservationFromReference">A function that takes an object reference and generates/updates an observation.</param>
public Belief(TReference reference, Func<TReference, TObservation> getObservationFromReference)
{
_reference = reference;
_getObservationFromReference = getObservationFromReference;
_observation = _getObservationFromReference(_reference);
}

/// <summary>
/// Initializes a new instance of the <see cref="Belief{TReference, TObservation}"/> class with an object reference,
/// a function to generate/update the observation using the object reference,
/// and a condition on when the observation should be updated.
/// </summary>
/// <param name="reference">The object reference used to generate/update the observation.</param>
/// <param name="getObservationFromReference">A function that takes an object reference and generates/updates an observation.</param>
/// <param name="shouldUpdate">A condition on when the observation should be updated.</param>
public Belief(TReference reference, Func<TReference, TObservation> getObservationFromReference, Func<bool> shouldUpdate)
: this(reference, getObservationFromReference)
{
_shouldUpdate = shouldUpdate;
}

/// <summary>
/// Implicit conversion operator to allow a <see cref="Belief{TReference, TObservation}"/> object
/// to be used where a <typeparamref name="TObservation"/> is expected.
/// </summary>
/// <param name="belief">The <see cref="Belief{TReference, TObservation}"/> object to convert.</param>
public static implicit operator TObservation(Belief<TReference, TObservation> belief) => belief._observation;

/// <summary>
/// Generates/updates the observation if the shouldUpdate condition is satisfied.
/// The observation is then updated by calling the getObservationFromReference function.
/// </summary>
public void UpdateBelief()
{
if (_shouldUpdate()) _observation = _getObservationFromReference(_reference);
}
}
}
39 changes: 39 additions & 0 deletions Aplib.Core/Belief/BeliefSet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Linq;

namespace Aplib.Core.Belief
{
/// <summary>
/// The <see cref="BeliefSet"/> class can be inherited to define a set of beliefs for an agent.
/// All <i>public fields</i> of type <see cref="IBelief"/> that are defined in the inheriting class
/// are automatically updated when calling <see cref="UpdateBeliefs"/>.
/// </summary>
public abstract class BeliefSet : IBeliefSet
{
/// <summary>
/// An array storing all <i>public fields</i> of type <see cref="IBelief"/> that are defined in the inheriting class.
/// </summary>
private readonly IBelief[] _beliefs;

/// <summary>
/// Initializes a new instance of the <see cref="BeliefSet"/> class,
/// and stores all <i>public fields</i> of type <see cref="IBelief"/> (that have been defined in the inheriting class) in an array.
/// All public <see cref="IBelief"/> fields are then automatically updated when calling <see cref="UpdateBeliefs"/>.
/// </summary>
protected BeliefSet()
{
_beliefs = GetType()
.GetFields()
.Where(field => typeof(IBelief).IsAssignableFrom(field.FieldType))
.Select(field => (IBelief)field.GetValue(this))
.ToArray();
}

/// <summary>
/// Updates all objects of type <see cref="IBelief"/> that are defined as <i>public fields</i> in the inheriting class.
/// </summary>
public void UpdateBeliefs()
{
foreach (IBelief belief in _beliefs) belief.UpdateBelief();
}
}
}
13 changes: 13 additions & 0 deletions Aplib.Core/Belief/IBelief.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Aplib.Core.Belief
{
/// <summary>
/// A belief represents/encapsulates an observation (i.e., piece of information of the game state as perceived by an agent).
/// </summary>
public interface IBelief
{
/// <summary>
/// Updates the belief based on information of the game state.
/// </summary>
void UpdateBelief();
}
}
13 changes: 13 additions & 0 deletions Aplib.Core/Belief/IBeliefSet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Aplib.Core.Belief
{
/// <summary>
/// A belief set defines beliefs for an agent.
/// </summary>
public interface IBeliefSet
{
/// <summary>
/// Updates all beliefs in the belief set.
/// </summary>
void UpdateBeliefs();
}
}
13 changes: 0 additions & 13 deletions Aplib.Core/Believe/BeliefSet.cs

This file was deleted.

2 changes: 1 addition & 1 deletion Aplib.Core/Desire/Goals/CommonHeuristicFunctions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Aplib.Core.Believe;
using Aplib.Core.Belief;
using System;

namespace Aplib.Core.Desire.Goals
Expand Down
2 changes: 1 addition & 1 deletion Aplib.Core/Desire/Goals/Goal.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Aplib.Core.Believe;
using Aplib.Core.Belief;
using Aplib.Core.Intent.Tactics;
using System;

Expand Down
146 changes: 146 additions & 0 deletions Aplib.Tests/Core/Belief/BeliefSetTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
using Aplib.Core.Belief;

namespace Aplib.Tests.Core.Belief;

/// <summary>
/// Describes a set of tests for the <see cref="BeliefSet"/> class.
/// </summary>
public class BeliefSetTests
{
/// <summary>
/// Given a BeliefSet instance with multiple <i>public field</i> beliefs,
/// When UpdateBeliefs is called,
/// Then all beliefs are updated.
/// </summary>
[Fact]
public void UpdateBeliefs_PublicBeliefFields_UpdatesAllBeliefs()
{
// Arrange
TestBeliefSetPublic beliefSet = new();

// Act
// UpdateBeliefs should set Updated to true for all beliefs.
beliefSet.UpdateBeliefs();

// Assert
Assert.True(beliefSet.Belief1.Updated);
Assert.True(beliefSet.Belief2.Updated);
}

/// <summary>
/// Given a BeliefSet instance with multiple <i>public property</i> beliefs,
/// When UpdateBeliefs is called,
/// Then no beliefs are updated.
/// </summary>
[Fact]
public void UpdateBeliefs_PublicBeliefProperties_DoesNotUpdateAnyBeliefs()
{
// Arrange
TestBeliefSetProperties beliefSet = new();

// Act
// UpdateBeliefs should *not* set Updated to true for any belief.
beliefSet.UpdateBeliefs();

// Assert
Assert.False(beliefSet.Belief1.Updated);
Assert.False(beliefSet.Belief2.Updated);
}

/// <summary>
/// Given a BeliefSet instance with multiple <i>private field</i> beliefs,
/// When UpdateBeliefs is called,
/// Then no beliefs are updated.
/// </summary>
[Fact]
public void UpdateBeliefs_PrivateBeliefFields_DoesNotUpdateAnyBeliefs()
{
// Arrange
TestBeliefSetPrivate beliefSet = new();

// Act
// UpdateBeliefs should *not* set Updated to true for any belief.
beliefSet.UpdateBeliefs();

// Assert
Assert.False(beliefSet.Belief1.Updated);
Assert.False(beliefSet.Belief2.Updated);
}

/// <summary>
/// A test belief set that contains two public simple beliefs.
/// </summary>
private class TestBeliefSetPublic : BeliefSet
{
/// <summary>
/// Belief that sets Updated to true when UpdateBelief is called.
/// </summary>
public SimpleBelief Belief1 = new();

/// <summary>
/// Belief that sets Updated to true when UpdateBelief is called.
/// </summary>
public SimpleBelief Belief2 = new();
}


/// <summary>
/// A test belief set that contains two simple public property beliefs.
/// </summary>
private class TestBeliefSetProperties : BeliefSet
{
/// <summary>
/// Belief that sets Updated to true when UpdateBelief is called.
/// </summary>
public SimpleBelief Belief1 { get; } = new();

/// <summary>
/// Belief that sets Updated to true when UpdateBelief is called.
/// </summary>
public SimpleBelief Belief2 { get; } = new();

}


/// <summary>
/// A test belief set that contains two private simple beliefs.
/// </summary>
private class TestBeliefSetPrivate : BeliefSet
{
/// <summary>
/// Belief that sets Updated to true when UpdateBelief is called.
/// </summary>
private SimpleBelief _belief1 = new();

/// <summary>
/// Belief that sets Updated to true when UpdateBelief is called.
/// </summary>
private SimpleBelief _belief2 = new();

/// <inheritdoc cref="_belief1"/>
public SimpleBelief Belief1 => _belief1;

/// <inheritdoc cref="_belief2"/>
public SimpleBelief Belief2 => _belief2;

}

/// <summary>
/// A simple belief that can be used to test whether <see cref="UpdateBelief"/> has been called.
/// </summary>
private class SimpleBelief : IBelief
{
/// <summary>
/// Stores whether <see cref="UpdateBelief"/> has been called.
/// </summary>
public bool Updated { get; private set; } = false;

/// <summary>
/// Sets <see cref="Updated"/> to true.
/// </summary>
public void UpdateBelief()
{
Updated = true;
}
}
}
Loading

0 comments on commit b2d544c

Please sign in to comment.