| using System; | |
| using System.Linq; | |
| using UnityEngine; | |
| namespace Unity.MLAgents.Actuators | |
| { | |
| /// <summary> | |
| /// A structure that wraps the <see cref="ActionSegment{T}"/>s for a particular <see cref="IActionReceiver"/> and is | |
| /// used when <see cref="IActionReceiver.OnActionReceived"/> is called. | |
| /// </summary> | |
| public readonly struct ActionBuffers | |
| { | |
| /// <summary> | |
| /// An empty action buffer. | |
| /// </summary> | |
| public static ActionBuffers Empty = new ActionBuffers(ActionSegment<float>.Empty, ActionSegment<int>.Empty); | |
| /// <summary> | |
| /// Holds the Continuous <see cref="ActionSegment{T}"/> to be used by an <see cref="IActionReceiver"/>. | |
| /// </summary> | |
| public ActionSegment<float> ContinuousActions { get; } | |
| /// <summary> | |
| /// Holds the Discrete <see cref="ActionSegment{T}"/> to be used by an <see cref="IActionReceiver"/>. | |
| /// </summary> | |
| public ActionSegment<int> DiscreteActions { get; } | |
| /// <summary> | |
| /// Create an <see cref="ActionBuffers"/> instance with discrete actions stored as a float array. This exists | |
| /// to achieve backward compatibility with the former Agent methods which used a float array for both continuous | |
| /// and discrete actions. | |
| /// </summary> | |
| /// <param name="discreteActions">The float array of discrete actions.</param> | |
| /// <returns>An <see cref="ActionBuffers"/> instance initialized with a <see cref="DiscreteActions"/> | |
| /// <see cref="ActionSegment{T}"/> initialized from a float array.</returns> | |
| public static ActionBuffers FromDiscreteActions(float[] discreteActions) | |
| { | |
| return new ActionBuffers(ActionSegment<float>.Empty, discreteActions == null ? ActionSegment<int>.Empty | |
| : new ActionSegment<int>(Array.ConvertAll(discreteActions, | |
| x => (int)x))); | |
| } | |
| /// <summary> | |
| /// Construct an <see cref="ActionBuffers"/> instance with the continuous and discrete actions that will | |
| /// be used. | |
| /// /// </summary> | |
| /// <param name="continuousActions">The continuous actions to send to an <see cref="IActionReceiver"/>.</param> | |
| /// <param name="discreteActions">The discrete actions to send to an <see cref="IActionReceiver"/>.</param> | |
| public ActionBuffers(float[] continuousActions, int[] discreteActions) | |
| : this(new ActionSegment<float>(continuousActions), new ActionSegment<int>(discreteActions)) { } | |
| /// <summary> | |
| /// Construct an <see cref="ActionBuffers"/> instance with the continuous and discrete actions that will | |
| /// be used. | |
| /// </summary> | |
| /// <param name="continuousActions">The continuous actions to send to an <see cref="IActionReceiver"/>.</param> | |
| /// <param name="discreteActions">The discrete actions to send to an <see cref="IActionReceiver"/>.</param> | |
| public ActionBuffers(ActionSegment<float> continuousActions, ActionSegment<int> discreteActions) | |
| { | |
| ContinuousActions = continuousActions; | |
| DiscreteActions = discreteActions; | |
| } | |
| /// <summary> | |
| /// Construct an <see cref="ActionBuffers"/> instance with <see cref="ActionSpec"/>. All values are initialized to zeros. | |
| /// /// </summary> | |
| /// <param name="actionSpec">The <see cref="ActionSpec"/> to send to an <see cref="IActionReceiver"/>.</param> | |
| public ActionBuffers(ActionSpec actionSpec) | |
| : this(new ActionSegment<float>(new float[actionSpec.NumContinuousActions]), | |
| new ActionSegment<int>(new int[actionSpec.NumDiscreteActions])) | |
| { } | |
| /// <summary> | |
| /// Create an <see cref="ActionBuffers"/> instance with ActionSpec and all actions stored as a float array. | |
| /// </summary> | |
| /// <param name="actionSpec"><see cref="ActionSpec"/> of the <see cref="ActionBuffers"/></param> | |
| /// <param name="actions">The float array of all actions, including discrete and continuous actions.</param> | |
| /// <returns>An <see cref="ActionBuffers"/> instance initialized with a <see cref="ActionSpec"/> and a float array.</returns> | |
| internal static ActionBuffers FromActionSpec(ActionSpec actionSpec, float[] actions) | |
| { | |
| if (actions == null) | |
| { | |
| return ActionBuffers.Empty; | |
| } | |
| Debug.Assert(actions.Length == actionSpec.NumContinuousActions + actionSpec.NumDiscreteActions, | |
| $"The length of '{nameof(actions)}' does not match the total size of ActionSpec.\n" + | |
| $"{nameof(actions)}.Length: {actions.Length}\n" + | |
| $"{nameof(actionSpec)}: {actionSpec.NumContinuousActions + actionSpec.NumDiscreteActions}"); | |
| ActionSegment<float> continuousActionSegment = ActionSegment<float>.Empty; | |
| ActionSegment<int> discreteActionSegment = ActionSegment<int>.Empty; | |
| int offset = 0; | |
| if (actionSpec.NumContinuousActions > 0) | |
| { | |
| continuousActionSegment = new ActionSegment<float>(actions, 0, actionSpec.NumContinuousActions); | |
| offset += actionSpec.NumContinuousActions; | |
| } | |
| if (actionSpec.NumDiscreteActions > 0) | |
| { | |
| int[] discreteActions = new int[actionSpec.NumDiscreteActions]; | |
| for (var i = 0; i < actionSpec.NumDiscreteActions; i++) | |
| { | |
| discreteActions[i] = (int)actions[i + offset]; | |
| } | |
| discreteActionSegment = new ActionSegment<int>(discreteActions); | |
| } | |
| return new ActionBuffers(continuousActionSegment, discreteActionSegment); | |
| } | |
| /// <summary> | |
| /// Clear the <see cref="ContinuousActions"/> and <see cref="DiscreteActions"/> segments to be all zeros. | |
| /// </summary> | |
| public void Clear() | |
| { | |
| ContinuousActions.Clear(); | |
| DiscreteActions.Clear(); | |
| } | |
| /// <summary> | |
| /// Check if the <see cref="ActionBuffers"/> is empty. | |
| /// </summary> | |
| /// <returns>Whether the buffers are empty.</returns> | |
| public bool IsEmpty() | |
| { | |
| return ContinuousActions.IsEmpty() && DiscreteActions.IsEmpty(); | |
| } | |
| /// <summary> | |
| /// Indicates whether the current ActionBuffers is equal to another ActionBuffers. | |
| /// </summary> | |
| /// <param name="obj">An ActionBuffers to compare with this ActionBuffers.</param> | |
| /// <returns>true if the current ActionBuffers is equal to the other parameter; otherwise, false.</returns> | |
| public override bool Equals(object obj) | |
| { | |
| if (!(obj is ActionBuffers)) | |
| { | |
| return false; | |
| } | |
| var ab = (ActionBuffers)obj; | |
| return ab.ContinuousActions.SequenceEqual(ContinuousActions) && | |
| ab.DiscreteActions.SequenceEqual(DiscreteActions); | |
| } | |
| /// <summary> | |
| /// Computes the hash code of the ActionBuffers. | |
| /// </summary> | |
| /// <returns>A hash code for the current ActionBuffers.</returns> | |
| public override int GetHashCode() | |
| { | |
| unchecked | |
| { | |
| return (ContinuousActions.GetHashCode() * 397) ^ DiscreteActions.GetHashCode(); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// An interface that describes an object that can receive actions from a Reinforcement Learning network. | |
| /// </summary> | |
| public interface IActionReceiver | |
| { | |
| /// <summary> | |
| /// Method called in order too allow object to execute actions based on the | |
| /// <see cref="ActionBuffers"/> contents. The structure of the contents in the <see cref="ActionBuffers"/> | |
| /// are defined by the <see cref="ActionSpec"/>. | |
| /// </summary> | |
| /// <param name="actionBuffers">The data structure containing the action buffers for this object.</param> | |
| void OnActionReceived(ActionBuffers actionBuffers); | |
| /// <summary> | |
| /// Implement `WriteDiscreteActionMask()` to modify the masks for discrete | |
| /// actions. When using discrete actions, the agent will not perform the masked | |
| /// action. | |
| /// </summary> | |
| /// <param name="actionMask"> | |
| /// The action mask for the agent. | |
| /// </param> | |
| /// <remarks> | |
| /// When using Discrete Control, you can prevent the Agent from using a certain | |
| /// action by masking it with <see cref="IDiscreteActionMask.SetActionEnabled"/>. | |
| /// | |
| /// See [Agents - Actions] for more information on masking actions. | |
| /// | |
| /// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_20_docs/docs/Learning-Environment-Design-Agents.md#actions | |
| /// </remarks> | |
| /// <seealso cref="IActionReceiver.OnActionReceived"/> | |
| void WriteDiscreteActionMask(IDiscreteActionMask actionMask); | |
| } | |
| } | |