Skip to content

Commit 1ccd879

Browse files
authored
Add internal API for Actuators along with their tests. (#4297)
1 parent 22defae commit 1ccd879

31 files changed

+1744
-1
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
m_EditorVersion: 2018.4.17f1
1+
m_EditorVersion: 2018.4.24f1

com.unity.ml-agents/Runtime/Actuators.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
5+
6+
namespace Unity.MLAgents.Actuators
7+
{
8+
/// <summary>
9+
/// ActionSegment{T} is a data structure that allows access to a segment of an underlying array
10+
/// in order to avoid the copying and allocation of sub-arrays. The segment is defined by
11+
/// the offset into the original array, and an length.
12+
/// </summary>
13+
/// <typeparam name="T">The type of object stored in the underlying <see cref="Array"/></typeparam>
14+
internal readonly struct ActionSegment<T> : IEnumerable<T>, IEquatable<ActionSegment<T>>
15+
where T : struct
16+
{
17+
/// <summary>
18+
/// The zero-based offset into the original array at which this segment starts.
19+
/// </summary>
20+
public readonly int Offset;
21+
22+
/// <summary>
23+
/// The number of items this segment can access in the underlying array.
24+
/// </summary>
25+
public readonly int Length;
26+
27+
/// <summary>
28+
/// An Empty segment which has an offset of 0, a Length of 0, and it's underlying array
29+
/// is also empty.
30+
/// </summary>
31+
public static ActionSegment<T> Empty = new ActionSegment<T>(System.Array.Empty<T>(), 0, 0);
32+
33+
static void CheckParameters(T[] actionArray, int offset, int length)
34+
{
35+
#if DEBUG
36+
if (offset + length > actionArray.Length)
37+
{
38+
throw new ArgumentOutOfRangeException(nameof(offset),
39+
$"Arguments offset: {offset} and length: {length} " +
40+
$"are out of bounds of actionArray: {actionArray.Length}.");
41+
}
42+
#endif
43+
}
44+
45+
/// <summary>
46+
/// Construct an <see cref="ActionSegment{T}"/> with an underlying array
47+
/// and offset, and a length.
48+
/// </summary>
49+
/// <param name="actionArray">The underlying array which this segment has a view into</param>
50+
/// <param name="offset">The zero-based offset into the underlying array.</param>
51+
/// <param name="length">The length of the segment.</param>
52+
public ActionSegment(T[] actionArray, int offset, int length)
53+
{
54+
CheckParameters(actionArray, offset, length);
55+
Array = actionArray;
56+
Offset = offset;
57+
Length = length;
58+
}
59+
60+
/// <summary>
61+
/// Get the underlying <see cref="Array"/> of this segment.
62+
/// </summary>
63+
public T[] Array { get; }
64+
65+
/// <summary>
66+
/// Allows access to the underlying array using array syntax.
67+
/// </summary>
68+
/// <param name="index">The zero-based index of the segment.</param>
69+
/// <exception cref="IndexOutOfRangeException">Thrown when the index is less than 0 or
70+
/// greater than or equal to <see cref="Length"/></exception>
71+
public T this[int index]
72+
{
73+
get
74+
{
75+
if (index < 0 || index > Length)
76+
{
77+
throw new IndexOutOfRangeException($"Index out of bounds, expected a number between 0 and {Length}");
78+
}
79+
return Array[Offset + index];
80+
}
81+
}
82+
83+
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
84+
IEnumerator<T> IEnumerable<T>.GetEnumerator()
85+
{
86+
return new Enumerator(this);
87+
}
88+
89+
/// <inheritdoc cref="IEnumerable{T}"/>
90+
public IEnumerator GetEnumerator()
91+
{
92+
return new Enumerator(this);
93+
}
94+
95+
/// <inheritdoc cref="ValueType.Equals(object)"/>
96+
public override bool Equals(object obj)
97+
{
98+
if (!(obj is ActionSegment<T>))
99+
{
100+
return false;
101+
}
102+
return Equals((ActionSegment<T>)obj);
103+
}
104+
105+
/// <inheritdoc cref="IEquatable{T}.Equals(T)"/>
106+
public bool Equals(ActionSegment<T> other)
107+
{
108+
return Offset == other.Offset && Length == other.Length && Equals(Array, other.Array);
109+
}
110+
111+
/// <inheritdoc cref="ValueType.GetHashCode"/>
112+
public override int GetHashCode()
113+
{
114+
unchecked
115+
{
116+
var hashCode = Offset;
117+
hashCode = (hashCode * 397) ^ Length;
118+
hashCode = (hashCode * 397) ^ (Array != null ? Array.GetHashCode() : 0);
119+
return hashCode;
120+
}
121+
}
122+
123+
/// <summary>
124+
/// A private <see cref="IEnumerator{T}"/> for the <see cref="ActionSegment{T}"/> value type which follows its
125+
/// rules of being a view into an underlying <see cref="Array"/>.
126+
/// </summary>
127+
struct Enumerator : IEnumerator<T>
128+
{
129+
readonly T[] m_Array;
130+
readonly int m_Start;
131+
readonly int m_End; // cache Offset + Count, since it's a little slow
132+
int m_Current;
133+
134+
internal Enumerator(ActionSegment<T> arraySegment)
135+
{
136+
Debug.Assert(arraySegment.Array != null);
137+
Debug.Assert(arraySegment.Offset >= 0);
138+
Debug.Assert(arraySegment.Length >= 0);
139+
Debug.Assert(arraySegment.Offset + arraySegment.Length <= arraySegment.Array.Length);
140+
141+
m_Array = arraySegment.Array;
142+
m_Start = arraySegment.Offset;
143+
m_End = arraySegment.Offset + arraySegment.Length;
144+
m_Current = arraySegment.Offset - 1;
145+
}
146+
147+
public bool MoveNext()
148+
{
149+
if (m_Current < m_End)
150+
{
151+
m_Current++;
152+
return m_Current < m_End;
153+
}
154+
return false;
155+
}
156+
157+
public T Current
158+
{
159+
get
160+
{
161+
if (m_Current < m_Start)
162+
throw new InvalidOperationException("Enumerator not started.");
163+
if (m_Current >= m_End)
164+
throw new InvalidOperationException("Enumerator has reached the end already.");
165+
return m_Array[m_Current];
166+
}
167+
}
168+
169+
object IEnumerator.Current => Current;
170+
171+
void IEnumerator.Reset()
172+
{
173+
m_Current = m_Start - 1;
174+
}
175+
176+
public void Dispose()
177+
{
178+
}
179+
}
180+
}
181+
}

com.unity.ml-agents/Runtime/Actuators/ActionSegment.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Unity.MLAgents.Policies;
5+
6+
namespace Unity.MLAgents.Actuators
7+
{
8+
/// <summary>
9+
/// Defines the structure of an Action Space to be used by the Actuator system.
10+
/// </summary>
11+
internal readonly struct ActionSpec
12+
{
13+
14+
/// <summary>
15+
/// An array of branch sizes for our action space.
16+
///
17+
/// For an IActuator that uses a Discrete <see cref="SpaceType"/>, the number of
18+
/// branches is the Length of the Array and each index contains the branch size.
19+
/// The cumulative sum of the total number of discrete actions can be retrieved
20+
/// by the <see cref="SumOfDiscreteBranchSizes"/> property.
21+
///
22+
/// For an IActuator with a Continuous it will be null.
23+
/// </summary>
24+
public readonly int[] BranchSizes;
25+
26+
/// <summary>
27+
/// The number of actions for a Continuous <see cref="SpaceType"/>.
28+
/// </summary>
29+
public int NumContinuousActions { get; }
30+
31+
/// <summary>
32+
/// The number of branches for a Discrete <see cref="SpaceType"/>.
33+
/// </summary>
34+
public int NumDiscreteActions { get; }
35+
36+
/// <summary>
37+
/// Get the total number of Discrete Actions that can be taken by calculating the Sum
38+
/// of all of the Discrete Action branch sizes.
39+
/// </summary>
40+
public int SumOfDiscreteBranchSizes { get; }
41+
42+
/// <summary>
43+
/// Creates a Continuous <see cref="ActionSpec"/> with the number of actions available.
44+
/// </summary>
45+
/// <param name="numActions">The number of actions available.</param>
46+
/// <returns>An Continuous ActionSpec initialized with the number of actions available.</returns>
47+
public static ActionSpec MakeContinuous(int numActions)
48+
{
49+
var actuatorSpace = new ActionSpec(numActions, 0);
50+
return actuatorSpace;
51+
}
52+
53+
/// <summary>
54+
/// Creates a Discrete <see cref="ActionSpec"/> with the array of branch sizes that
55+
/// represents the action space.
56+
/// </summary>
57+
/// <param name="branchSizes">The array of branch sizes for the discrete action space. Each index
58+
/// contains the number of actions available for that branch.</param>
59+
/// <returns>An Discrete ActionSpec initialized with the array of branch sizes.</returns>
60+
public static ActionSpec MakeDiscrete(int[] branchSizes)
61+
{
62+
var numActions = branchSizes.Length;
63+
var actuatorSpace = new ActionSpec(0, numActions, branchSizes);
64+
return actuatorSpace;
65+
}
66+
67+
ActionSpec(int numContinuousActions, int numDiscreteActions, int[] branchSizes = null)
68+
{
69+
NumContinuousActions = numContinuousActions;
70+
NumDiscreteActions = numDiscreteActions;
71+
BranchSizes = branchSizes;
72+
SumOfDiscreteBranchSizes = branchSizes?.Sum() ?? 0;
73+
}
74+
}
75+
}

com.unity.ml-agents/Runtime/Actuators/ActionSpec.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using UnityEngine;
2+
3+
namespace Unity.MLAgents.Actuators
4+
{
5+
/// <summary>
6+
/// Editor components for creating Actuators. Generally an IActuator component should
7+
/// have a corresponding ActuatorComponent.
8+
/// </summary>
9+
internal abstract class ActuatorComponent : MonoBehaviour
10+
{
11+
/// <summary>
12+
/// Create the IActuator. This is called by the Agent when it is initialized.
13+
/// </summary>
14+
/// <returns>Created IActuator object.</returns>
15+
public abstract IActuator CreateActuator();
16+
}
17+
}

com.unity.ml-agents/Runtime/Actuators/ActuatorComponent.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)