浏览代码

Merge pull request #4786 from Unity-Technologies/merge-release11-master

Merge release11 master
/MLA-1734-demo-provider
GitHub 4 年前
当前提交
5645b401
共有 92 个文件被更改,包括 254 次插入296 次删除
  1. 1
      Project/Assets/ML-Agents/Examples/3DBall/Scripts/Ball3DAgent.cs
  2. 1
      Project/Assets/ML-Agents/Examples/Basic/Scripts/BasicController.cs
  3. 7
      Project/Assets/ML-Agents/Examples/Crawler/Scripts/CrawlerAgent.cs
  4. 1
      Project/Assets/ML-Agents/Examples/FoodCollector/Scripts/FoodCollectorAgent.cs
  5. 4
      Project/Assets/ML-Agents/Examples/Match3/Scripts/Match3Agent.cs
  6. 1
      Project/Assets/ML-Agents/Examples/Match3/Scripts/Match3Drawer.cs
  7. 2
      Project/Assets/ML-Agents/Examples/Match3/Scripts/Match3TileSelector.cs
  8. 1
      Project/Assets/ML-Agents/Examples/Soccer/Scripts/AgentSoccer.cs
  9. 1
      Project/Assets/ML-Agents/Examples/Template/Scripts/TemplateAgent.cs
  10. 10
      Project/Assets/ML-Agents/Examples/Walker/Scripts/WalkerAgent.cs
  11. 1
      Project/Assets/ML-Agents/TestScenes/TestCompressedTexture/TestTextureSensor.cs
  12. 1
      Project/Assets/ML-Agents/TestScenes/TestCompressedTexture/TestTextureSensorComponent.cs
  13. 10
      README.md
  14. 2
      com.unity.ml-agents.extensions/Documentation~/Grid-Sensor.md
  15. 2
      com.unity.ml-agents.extensions/Documentation~/Match3.md
  16. 8
      com.unity.ml-agents.extensions/Documentation~/com.unity.ml-agents.extensions.md
  17. 2
      com.unity.ml-agents.extensions/Editor/EditorExample.cs
  18. 1
      com.unity.ml-agents.extensions/Editor/RigidBodySensorComponentEditor.cs
  19. 2
      com.unity.ml-agents.extensions/Runtime/Match3/Match3ActuatorComponent.cs
  20. 1
      com.unity.ml-agents.extensions/Runtime/Sensors/CountingGridSensor.cs
  21. 2
      com.unity.ml-agents.extensions/Runtime/Sensors/PhysicsBodySensor.cs
  22. 1
      com.unity.ml-agents.extensions/Runtime/Sensors/RigidBodyJointExtractor.cs
  23. 4
      com.unity.ml-agents.extensions/Tests/Editor/Match3/AbstractBoardTests.cs
  24. 2
      com.unity.ml-agents.extensions/Tests/Editor/Match3/Match3SensorTests.cs
  25. 48
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelHotPerceiveTests.cs
  26. 3
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelHotShapeTests.cs
  27. 47
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelPerceiveTests.cs
  28. 1
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelShapeTests.cs
  29. 10
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/CountingGridSensorPerceiveTests.cs
  30. 1
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/CountingGridSensorShapeTests.cs
  31. 5
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/GridObservationPerceiveTests.cs
  32. 9
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/GridSensorTestUtils.cs
  33. 2
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/PoseExtractorTests.cs
  34. 5
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/RigidBodyPoseExtractorTests.cs
  35. 8
      com.unity.ml-agents.extensions/Tests/Editor/Sensors/RigidBodySensorTests.cs
  36. 4
      com.unity.ml-agents.extensions/Tests/Runtime/RuntimeExampleTest.cs
  37. 2
      com.unity.ml-agents/Documentation~/com.unity.ml-agents.md
  38. 3
      com.unity.ml-agents/Editor/BehaviorParametersEditor.cs
  39. 1
      com.unity.ml-agents/Editor/CameraSensorComponentEditor.cs
  40. 1
      com.unity.ml-agents/Editor/RenderTextureSensorComponentEditor.cs
  41. 8
      com.unity.ml-agents/Runtime/Academy.cs
  42. 13
      com.unity.ml-agents/Runtime/Actuators/ActionSpec.cs
  43. 2
      com.unity.ml-agents/Runtime/Actuators/ActuatorComponent.cs
  44. 1
      com.unity.ml-agents/Runtime/Actuators/ActuatorDiscreteActionMask.cs
  45. 7
      com.unity.ml-agents/Runtime/Actuators/ActuatorManager.cs
  46. 5
      com.unity.ml-agents/Runtime/Actuators/IActionReceiver.cs
  47. 2
      com.unity.ml-agents/Runtime/Actuators/IActuator.cs
  48. 2
      com.unity.ml-agents/Runtime/Actuators/IDiscreteActionMask.cs
  49. 4
      com.unity.ml-agents/Runtime/Actuators/VectorActuator.cs
  50. 90
      com.unity.ml-agents/Runtime/Agent.cs
  51. 13
      com.unity.ml-agents/Runtime/Agent.deprecated.cs
  52. 14
      com.unity.ml-agents/Runtime/Communicator/GrpcExtensions.cs
  53. 3
      com.unity.ml-agents/Runtime/Communicator/ICommunicator.cs
  54. 3
      com.unity.ml-agents/Runtime/Communicator/RpcCommunicator.cs
  55. 1
      com.unity.ml-agents/Runtime/Demonstrations/DemonstrationMetaData.cs
  56. 4
      com.unity.ml-agents/Runtime/Demonstrations/DemonstrationRecorder.cs
  57. 3
      com.unity.ml-agents/Runtime/DiscreteActionMasker.cs
  58. 6
      com.unity.ml-agents/Runtime/Inference/BarracudaModelExtensions.cs
  59. 21
      com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs
  60. 2
      com.unity.ml-agents/Runtime/Inference/GeneratorImpl.cs
  61. 2
      com.unity.ml-agents/Runtime/Inference/ModelRunner.cs
  62. 3
      com.unity.ml-agents/Runtime/Inference/TensorApplier.cs
  63. 1
      com.unity.ml-agents/Runtime/Policies/BarracudaPolicy.cs
  64. 13
      com.unity.ml-agents/Runtime/Policies/BrainParameters.cs
  65. 2
      com.unity.ml-agents/Runtime/Policies/RemotePolicy.cs
  66. 3
      com.unity.ml-agents/Runtime/Sampler.cs
  67. 1
      com.unity.ml-agents/Runtime/SensorHelper.cs
  68. 2
      com.unity.ml-agents/Runtime/Sensors/ObservationWriter.cs
  69. 1
      com.unity.ml-agents/Runtime/Sensors/Reflection/EnumReflectionSensor.cs
  70. 2
      com.unity.ml-agents/Runtime/Sensors/Reflection/IntReflectionSensor.cs
  71. 2
      com.unity.ml-agents/Runtime/Sensors/StackingSensor.cs
  72. 2
      com.unity.ml-agents/Runtime/Utilities.cs
  73. 1
      com.unity.ml-agents/Tests/Editor/Actuators/ActuatorDiscreteActionMaskTests.cs
  74. 15
      com.unity.ml-agents/Tests/Editor/Actuators/ActuatorManagerTests.cs
  75. 1
      com.unity.ml-agents/Tests/Editor/Actuators/VectorActuatorTests.cs
  76. 9
      com.unity.ml-agents/Tests/Editor/Communicator/GrpcExtensionsTests.cs
  77. 3
      com.unity.ml-agents/Tests/Editor/Communicator/RpcCommunicatorTests.cs
  78. 2
      com.unity.ml-agents/Tests/Editor/DemonstrationTests.cs
  79. 2
      com.unity.ml-agents/Tests/Editor/EditModeTestInternalBrainTensorApplier.cs
  80. 4
      com.unity.ml-agents/Tests/Editor/EditModeTestInternalBrainTensorGenerator.cs
  81. 2
      com.unity.ml-agents/Tests/Editor/ModelRunnerTest.cs
  82. 4
      com.unity.ml-agents/Tests/Editor/ParameterLoaderTest.cs
  83. 2
      com.unity.ml-agents/Tests/Editor/RecursionCheckerTests.cs
  84. 3
      com.unity.ml-agents/Tests/Editor/SamplerTests.cs
  85. 1
      com.unity.ml-agents/Tests/Editor/Sensor/SensorTestHelper.cs
  86. 12
      com.unity.ml-agents/Tests/Editor/Sensor/StackingSensorTests.cs
  87. 4
      docs/Installation-Anaconda-Windows.md
  88. 6
      docs/Installation.md
  89. 16
      docs/Migrating.md
  90. 2
      docs/Training-on-Amazon-Web-Service.md
  91. 4
      docs/Unity-Inference-Engine.md
  92. 1
      utils/make_readme_table.py

1
Project/Assets/ML-Agents/Examples/3DBall/Scripts/Ball3DAgent.cs


using System;
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;

1
Project/Assets/ML-Agents/Examples/Basic/Scripts/BasicController.cs


using UnityEngine;
using UnityEngine.SceneManagement;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using UnityEngine.Serialization;
/// <summary>

7
Project/Assets/ML-Agents/Examples/Crawler/Scripts/CrawlerAgent.cs


using System;
using UnityEngine;
using Unity.MLAgents;
using Unity.Barracuda;

Vector3 avgVel = Vector3.zero;
//ALL RBS
int numOfRB = 0;
int numOfRb = 0;
numOfRB++;
numOfRb++;
avgVel = velSum / numOfRB;
avgVel = velSum / numOfRb;
return avgVel;
}

1
Project/Assets/ML-Agents/Examples/FoodCollector/Scripts/FoodCollectorAgent.cs


using System;
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;

4
Project/Assets/ML-Agents/Examples/Match3/Scripts/Match3Agent.cs


m_TimeUntilMove = MoveTime;
var nextState = State.Invalid;
State nextState;
switch (m_CurrentState)
{
case State.FindMatches:

bool HasValidMoves()
{
foreach (var move in Board.ValidMoves())
foreach (var unused in Board.ValidMoves())
{
return true;
}

1
Project/Assets/ML-Agents/Examples/Match3/Scripts/Match3Drawer.cs


using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents.Extensions.Match3;
namespace Unity.MLAgentsExamples
{

2
Project/Assets/ML-Agents/Examples/Match3/Scripts/Match3TileSelector.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

{
AllTilesOff();
emptyTile.SetActive(true);
return;
}
else
{

1
Project/Assets/ML-Agents/Examples/Soccer/Scripts/AgentSoccer.cs


using System;
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;

1
Project/Assets/ML-Agents/Examples/Template/Scripts/TemplateAgent.cs


using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;

10
Project/Assets/ML-Agents/Examples/Walker/Scripts/WalkerAgent.cs


const float m_maxWalkingSpeed = 10; //The max walking speed
//Should the agent sample a new goal velocity each episode?
//If true, walkSpeed will be randomly set between zero and m_maxWalkingSpeed in OnEpisodeBegin()
//If true, walkSpeed will be randomly set between zero and m_maxWalkingSpeed in OnEpisodeBegin()
//If false, the goal velocity will be walkingSpeed
public bool randomizeWalkSpeedEachEpisode;

//ragdoll's avg vel
var avgVel = GetAvgVelocity();
//current ragdoll velocity. normalized
//current ragdoll velocity. normalized
sensor.AddObservation(Vector3.Distance(velGoal, avgVel));
//avg body vel relative to cube
sensor.AddObservation(m_OrientationCube.transform.InverseTransformDirection(avgVel));

Vector3 avgVel = Vector3.zero;
//ALL RBS
int numOfRB = 0;
int numOfRb = 0;
numOfRB++;
numOfRb++;
avgVel = velSum / numOfRB;
avgVel = velSum / numOfRb;
return avgVel;
}

1
Project/Assets/ML-Agents/TestScenes/TestCompressedTexture/TestTextureSensor.cs


using UnityEngine;
using Unity.MLAgents.Sensors;
using Unity.MLAgents;
public class TestTextureSensor : ISensor
{

1
Project/Assets/ML-Agents/TestScenes/TestCompressedTexture/TestTextureSensorComponent.cs


using UnityEngine;
using UnityEngine.Serialization;
using Unity.MLAgents.Sensors;

10
README.md


# Unity ML-Agents Toolkit
[![docs badge](https://img.shields.io/badge/docs-reference-blue.svg)](https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/docs/)
[![docs badge](https://img.shields.io/badge/docs-reference-blue.svg)](https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/docs/)
[![license badge](https://img.shields.io/badge/license-Apache--2.0-green.svg)](LICENSE)

## Releases & Documentation
**Our latest, stable release is `Release 10`. Click
[here](https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/docs/Readme.md)
**Our latest, stable release is `Release 11`. Click
[here](https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/docs/Readme.md)
to get started with the latest release of ML-Agents.**
The table below lists all our releases, including our `master` branch which is

| **Version** | **Release Date** | **Source** | **Documentation** | **Download** |
|:-------:|:------:|:-------------:|:-------:|:------------:|
| **master (unstable)** | -- | [source](https://github.com/Unity-Technologies/ml-agents/tree/master) | [docs](https://github.com/Unity-Technologies/ml-agents/tree/master/docs/Readme.md) | [download](https://github.com/Unity-Technologies/ml-agents/archive/master.zip) |
| **Release 10** | **November 18, 2020** | **[source](https://github.com/Unity-Technologies/ml-agents/tree/release_10)** | **[docs](https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/docs/Readme.md)** | **[download](https://github.com/Unity-Technologies/ml-agents/archive/release_10.zip)** |
| **Release 11** | **December 21, 2020** | **[source](https://github.com/Unity-Technologies/ml-agents/tree/release_11)** | **[docs](https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/docs/Readme.md)** | **[download](https://github.com/Unity-Technologies/ml-agents/archive/release_11.zip)** |
| **Release 10** | November 18, 2020 | [source](https://github.com/Unity-Technologies/ml-agents/tree/release_10) | [docs](https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/docs/Readme.md) | [download](https://github.com/Unity-Technologies/ml-agents/archive/release_10.zip) |
| **Release 4** | July 15, 2020 | [source](https://github.com/Unity-Technologies/ml-agents/tree/release_4) | [docs](https://github.com/Unity-Technologies/ml-agents/tree/release_4_docs/docs/Readme.md) | [download](https://github.com/Unity-Technologies/ml-agents/archive/release_4.zip) |
## Citation

2
com.unity.ml-agents.extensions/Documentation~/Grid-Sensor.md


An image can be thought of as a matrix of a predefined width (W) and a height (H) and each pixel can be thought of as simply an array of length 3 (in the case of RGB), `[Red, Green, Blue]` holding the different channel information of the color (channel) intensities at that pixel location. Thus an image is just a 3 dimensional matrix of size WxHx3. A Grid Observation can be thought of as a generalization of this setup where in place of a pixel there is a "cell" which is an array of length N representing different channel intensities at that cell position. From a Convolutional Neural Network point of view, the introduction of multiple channels in an "image" isn't a new concept. One such example is using an RGB-Depth image which is used in several robotics applications. The distinction of Grid Observations is what the data within the channels represents. Instead of limiting the channels to color intensities, the channels within a cell of a Grid Observation generalize to any data that can be represented by a single number (float or int).
Before jumping into the details of the Grid Sensor, an important thing to note is the agent performance and qualitatively different behavior over raycasts. Unity MLAgent's comes with a suite of example environments. One in particular, the [Food Collector](https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/docs/Learning-Environment-Examples.md#food-collector), has been the focus of the Grid Sensor development.
Before jumping into the details of the Grid Sensor, an important thing to note is the agent performance and qualitatively different behavior over raycasts. Unity MLAgent's comes with a suite of example environments. One in particular, the [Food Collector](https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/docs/Learning-Environment-Examples.md#food-collector), has been the focus of the Grid Sensor development.
The Food Collector environment can be described as:
* Set-up: A multi-agent environment where agents compete to collect food.

2
com.unity.ml-agents.extensions/Documentation~/Match3.md


This implementation includes:
* C# implementation catered toward a Match-3 setup including concepts around encoding for moves based on [Human Like Playtesting with Deep Learning](https://www.researchgate.net/publication/328307928_Human-Like_Playtesting_with_Deep_Learning)
* An example Match-3 scene with ML-Agents implemented (located under /Project/Assets/ML-Agents/Examples/Match3). More information, on Match-3 example [here](https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/docs/docs/Learning-Environment-Examples.md#match-3).
* An example Match-3 scene with ML-Agents implemented (located under /Project/Assets/ML-Agents/Examples/Match3). More information, on Match-3 example [here](https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/docs/docs/Learning-Environment-Examples.md#match-3).
### Feedback
If you are a Match-3 developer and are trying to leverage ML-Agents for this scenario, [we want to hear from you](https://forms.gle/TBsB9jc8WshgzViU9). Additionally, we are also looking for interested Match-3 teams to speak with us for 45 minutes. If you are interested, please indicate that in the [form](https://forms.gle/TBsB9jc8WshgzViU9). If selected, we will provide gift cards as a token of appreciation.

8
com.unity.ml-agents.extensions/Documentation~/com.unity.ml-agents.extensions.md


recommended ways to install the package:
### Local Installation
[Clone the repository](https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/docs/Installation.md#clone-the-ml-agents-toolkit-repository-optional) and follow the
[Local Installation for Development](https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/docs/Installation.md#advanced-local-installation-for-development-1)
[Clone the repository](https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/docs/Installation.md#clone-the-ml-agents-toolkit-repository-optional) and follow the
[Local Installation for Development](https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/docs/Installation.md#advanced-local-installation-for-development-1)
![Package Manager git URL](https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/docs/images/unity_package_manager_git_url.png)
![Package Manager git URL](https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/docs/images/unity_package_manager_git_url.png)
In the dialog that appears, enter
```
git+https://github.com/Unity-Technologies/ml-agents.git?path=com.unity.ml-agents.extensions

none
## Need Help?
The main [README](https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/README.md) contains links for contacting the team or getting support.
The main [README](https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/README.md) contains links for contacting the team or getting support.

2
com.unity.ml-agents.extensions/Editor/EditorExample.cs


using Unity.MLAgents;
namespace Unity.MLAgents.Extensions.Editor
{

1
com.unity.ml-agents.extensions/Editor/RigidBodySensorComponentEditor.cs


using UnityEngine;
using UnityEditor;
using Unity.MLAgents.Editor;
using Unity.MLAgents.Extensions.Sensors;

2
com.unity.ml-agents.extensions/Runtime/Match3/Match3ActuatorComponent.cs


/// </summary>
[FormerlySerializedAs("ForceRandom")]
[Tooltip("Force using the Agent's Heuristic() method to decide the action. This should only be used in testing.")]
public bool ForceHeuristic = false;
public bool ForceHeuristic;
/// <inheritdoc/>
public override IActuator CreateActuator()

1
com.unity.ml-agents.extensions/Runtime/Sensors/CountingGridSensor.cs


using System;
using UnityEngine;
using UnityEngine.Assertions;
namespace Unity.MLAgents.Extensions.Sensors
{

2
com.unity.ml-agents.extensions/Runtime/Sensors/PhysicsBodySensor.cs


using System.Collections.Generic;
#if UNITY_2020_1_OR_NEWER
#endif
using Unity.MLAgents.Sensors;
namespace Unity.MLAgents.Extensions.Sensors

1
com.unity.ml-agents.extensions/Runtime/Sensors/RigidBodyJointExtractor.cs


using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents.Sensors;

4
com.unity.ml-agents.extensions/Tests/Editor/Match3/AbstractBoardTests.cs


public override int GetCellType(int row, int col)
{
var character = m_Board[m_Board.Length - 1 - row][col];
return (int)(character - '0');
return (character - '0');
return (int)(character - '0');
return (character - '0');
}
}

2
com.unity.ml-agents.extensions/Tests/Editor/Match3/Match3SensorTests.cs


using System;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Extensions.Match3;
using UnityEngine;
using Unity.MLAgents.Extensions.Tests.Sensors;

48
com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelHotPerceiveTests.cs


{
string[] tags = { k_Tag1 };
int[] depths = { 1 };
dummyData.Data = new float[] { -0.1f };
dummyData.Data = new[] { -0.1f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 1 };
dummyData.Data = new float[] { 1.1f };
dummyData.Data = new[] { 1.1f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 1 };
dummyData.Data = new float[] { .2f };
dummyData.Data = new[] { .2f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 1, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { .2f }, 4);
float[] expectedDefault = new float[] { 0 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { .2f }, 4);
float[] expectedDefault = new[] { 0.0f };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

string[] tags = { k_Tag1 };
int[] depths = { 3 };
dummyData.Data = new float[] { -1f };
dummyData.Data = new[] { -1f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 3 };
dummyData.Data = new float[] { 4f };
dummyData.Data = new[] { 4f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 3 };
dummyData.Data = new float[] { 2f };
dummyData.Data = new[] { 2f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 3, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
int[] subarrayIndicies = new[] { 77, 78, 87, 88 };
float[] expectedDefault = new float[] { 1, 0, 0 };
float[] expectedDefault = new[] { 1.0f, 0.0f, 0.0f };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

string[] tags = { k_Tag1 };
int[] depths = { 3 };
dummyData.Data = new float[] { 2.4f };
dummyData.Data = new[] { 2.4f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 1, 1 };
dummyData.Data = new float[] { .4f, .3f };
dummyData.Data = new[] { .4f, .3f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 2, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { .4f, .3f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { .4f, .3f }, 4);
float[] expectedDefault = new float[] { 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 1, 3 };
dummyData.Data = new float[] { .4f, 4f };
dummyData.Data = new[] { .4f, 4f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 1, 3 };
dummyData.Data = new float[] { .4f, 1f };
dummyData.Data = new[] { .4f, 1f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 4, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { .4f, 0, 1, 0 }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { .4f, 0, 1, 0 }, 4);
float[] expectedDefault = new float[] { 0, 1, 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 3, 1 };
dummyData.Data = new float[] { 1f, .4f };
dummyData.Data = new[] { 1f, .4f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 4, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 0, 1, 0, .4f }, 4);
int[] subarrayIndicies = new[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 0, 1, 0, .4f }, 4);
float[] expectedDefault = new float[] { 1, 0, 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 3, 3 };
dummyData.Data = new float[] { 1f, 2.2f };
dummyData.Data = new[] { 1f, 2.2f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 5, 1, 3 };
dummyData.Data = new float[] { 3f, .6f, 2.2f };
dummyData.Data = new[] { 3f, .6f, 2.2f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 9, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 0, 0, 0, 1, 0, .6f, 0, 0, 1 }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 0, 0, 0, 1, 0, .6f, 0, 0, 1 }, 4);
float[] expectedDefault = new float[] { 1, 0, 0, 0, 0, 0, 1, 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 5, 1, 3 };
dummyData.Data = new float[] { 3f, .6f, 2.2f };
dummyData.Data = new[] { 3f, .6f, 2.2f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.ChannelHot,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 9, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 0, 0, 0, 1, 0, .6f, 0, 0, 1 }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 0, 0, 0, 1, 0, .6f, 0, 0, 1 }, 4);
float[] expectedDefault = new float[] { 1, 0, 0, 0, 0, 0, 1, 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);

3
com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelHotShapeTests.cs


using NUnit.Framework;
using UnityEngine;
using Unity.MLAgents.Extensions.Sensors;
using NUnit.Framework.Internal;
using UnityEngine.TestTools;
using System.Collections;
namespace Unity.MLAgents.Extensions.Tests.Sensors
{

47
com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelPerceiveTests.cs


using UnityEngine.TestTools;
using Unity.MLAgents.Extensions.Sensors;
using Unity.MLAgents.Extensions.TestUtils.Sensors;
using System.Linq;
namespace Unity.MLAgents.Extensions.Tests.Sensors
{

{
string[] tags = { k_Tag1 };
int[] depths = { 1 };
dummyData.Data = new float[] { -0.1f };
dummyData.Data = new[] { -0.1f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 1 };
dummyData.Data = new float[] { 1.1f };
dummyData.Data = new[] { 1.1f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 1 };
dummyData.Data = new float[] { .2f };
dummyData.Data = new[] { .2f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 1, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { .2f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { .2f }, 4);
float[] expectedDefault = new float[] { 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 3 };
dummyData.Data = new float[] { -1f };
dummyData.Data = new[] { -1f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 3 };
dummyData.Data = new float[] { 4f };
dummyData.Data = new[] { 4f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 3 };
dummyData.Data = new float[] { 2f };
dummyData.Data = new[] { 2f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 1, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 2f / 3f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 2f / 3f }, 4);
float[] expectedDefault = new float[] { 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 3 };
dummyData.Data = new float[] { 2.4f };
dummyData.Data = new[] { 2.4f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 1, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 2.4f / 3f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 2.4f / 3f }, 4);
float[] expectedDefault = new float[] { 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 1, 1 };
dummyData.Data = new float[] { .4f, .3f };
dummyData.Data = new[] { .4f, .3f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 2, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { .4f, .3f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { .4f, .3f }, 4);
float[] expectedDefault = new float[] { 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 1, 3 };
dummyData.Data = new float[] { .4f, 4f };
dummyData.Data = new[] { .4f, 4f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

{
string[] tags = { k_Tag1 };
int[] depths = { 1, 3 };
dummyData.Data = new float[] { .4f, 1f };
dummyData.Data = new[] { .4f, 1f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 2, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { .4f, 1f / 3f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { .4f, 1f / 3f }, 4);
float[] expectedDefault = new float[] { 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 3, 1 };
dummyData.Data = new float[] { 1f, .4f };
dummyData.Data = new[] { 1f, .4f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 2, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 1f / 3f, .4f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 1f / 3f, .4f }, 4);
float[] expectedDefault = new float[] { 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 3, 3 };
dummyData.Data = new float[] { 1f, 2.2f };
dummyData.Data = new[] { 1f, 2.2f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 2, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 1f / 3f, 2.2f / 3 }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 1f / 3f, 2.2f / 3 }, 4);
float[] expectedDefault = new float[] { 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 5, 1, 3 };
dummyData.Data = new float[] { 3f, .6f, 2.2f };
dummyData.Data = new[] { 3f, .6f, 2.2f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 3, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 3f / 5f, .6f, 2.2f / 3f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 3f / 5f, .6f, 2.2f / 3f }, 4);
float[] expectedDefault = new float[] { 0, 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

{
string[] tags = { k_Tag1 };
int[] depths = { 5, 1, 3 };
dummyData.Data = new float[] { 3f, .6f, 2.2f };
dummyData.Data = new[] { 3f, .6f, 2.2f };
Color[] colors = { Color.red, Color.magenta };
gridSensor.SetParameters(tags, depths, GridSensor.GridDepthType.Channel,
1f, 1f, 10, 10, LayerMask.GetMask("Default"), false, colors);

Assert.AreEqual(10 * 10 * 3, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 3f / 5f, .6f, 2.2f / 3f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 3f / 5f, .6f, 2.2f / 3f }, 4);
float[] expectedDefault = new float[] { 0, 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);

1
com.unity.ml-agents.extensions/Tests/Editor/Sensors/ChannelShapeTests.cs


using NUnit.Framework;
using UnityEngine;
using Unity.MLAgents.Extensions.Sensors;
using NUnit.Framework.Internal;
namespace Unity.MLAgents.Extensions.Tests.Sensors
{

10
com.unity.ml-agents.extensions/Tests/Editor/Sensors/CountingGridSensorPerceiveTests.cs


Assert.AreEqual(10 * 10 * 1, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 1f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 1f }, 4);
float[] expectedDefault = new float[] { 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

Assert.AreEqual(10 * 10 * 1, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 1f }, 4);
float[] expectedDefault = new float[] { 0 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 1f }, 4);
float[] expectedDefault = new float[] { 0f };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

Assert.AreEqual(10 * 10 * 1, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { .5f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { .5f }, 4);
float[] expectedDefault = new float[] { 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

Assert.AreEqual(10 * 10 * 2, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { .5f, 1 }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { .5f, 1 }, 4);
float[] expectedDefault = new float[] { 0, 0 };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

1
com.unity.ml-agents.extensions/Tests/Editor/Sensors/CountingGridSensorShapeTests.cs


using UnityEngine;
using NUnit.Framework;
using Unity.MLAgents.Extensions.Sensors;
using NUnit.Framework.Internal;
namespace Unity.MLAgents.Extensions.Tests.Sensors
{

5
com.unity.ml-agents.extensions/Tests/Editor/Sensors/GridObservationPerceiveTests.cs


using UnityEngine;
using UnityEngine.TestTools;
using Unity.MLAgents.Extensions.Sensors;
using System.Linq;
namespace Unity.MLAgents.Extensions.Tests.Sensors
{

Assert.AreEqual(10 * 10 * 1, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 2f / 3f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 2f / 3f }, 4);
float[] expectedDefault = new float[] { 0f };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

Assert.AreEqual(10 * 10 * 1, output.Length);
int[] subarrayIndicies = new int[] { 77, 78, 87, 88 };
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new float[] { 1f / 3f }, 4);
float[][] expectedSubarrays = GridObsTestUtils.DuplicateArray(new[] { 1f / 3f }, 4);
float[] expectedDefault = new float[] { 0f };
GridObsTestUtils.AssertSubarraysAtIndex(output, subarrayIndicies, expectedSubarrays, expectedDefault);
}

9
com.unity.ml-agents.extensions/Tests/Editor/Sensors/GridSensorTestUtils.cs


using NUnit.Framework;
using System;
using System.Diagnostics;
using System.Linq;
namespace Unity.MLAgents.Extensions.Tests.Sensors

/// </summary>
/// <param name="arr">The array to convert to string</param>
/// <param name="initialIndex">The initial index. Default 0</param>
/// <param name="numOfElements">The number of elements to print</param>
/// <param name="maxNumberOfElements">The number of elements to print</param>
/// <returns>Human readable string</returns>
public static string Array2Str<T>(T[] arr, int initialIndex = 0, int maxNumberOfElements = int.MaxValue)
{

/// If the total array is data from a 4x4x2 grid observation, total will be an array of size 32 and each sub array will have a size of 2.
/// Let 3 cells at indicies (0, 1), (2, 2), and (3, 0) with values ([.1, .5]), ([.9, .7]), ([0, .2]), respectively.
/// If the default values of cells are ([0, 0]) then the grid observation will be as follows:
/// [ [0, 0], [.1, .5], [ 0, 0 ], [0, 0],
/// [ [0, 0], [.1, .5], [ 0, 0 ], [0, 0],
///
///
///
///
/// The indicies of the activated cells in the flattened array will be 1, 10, and 12
///
/// So to verify that the total array is as expected, AssertSubarraysAtIndex should be called as

2
com.unity.ml-agents.extensions/Tests/Editor/Sensors/PoseExtractorTests.cs


{
Assert.Throws<UnityAgentsException>(() =>
{
var bad = new BadPoseExtractor();
var unused = new BadPoseExtractor();
});
}

5
com.unity.ml-agents.extensions/Tests/Editor/Sensors/RigidBodyPoseExtractorTests.cs


using UnityEngine;
using NUnit.Framework;
using Unity.MLAgents.Extensions.Sensors;
using UnityEditor;
namespace Unity.MLAgents.Extensions.Tests.Sensors
{

Assert.AreEqual(0, poseExtractor.NumPoses);
// Add an RB under the other GameObject. Constructor will find a rigid body, but not the root.
var otherRb = otherGameObj.AddComponent<Rigidbody>();
otherGameObj.AddComponent<Rigidbody>();
poseExtractor = new RigidBodyPoseExtractor(rootRb, otherGameObj);
Assert.AreEqual(0, poseExtractor.NumPoses);
}

var rb1 = rootObj.AddComponent<Rigidbody>();
var go2 = new GameObject();
var rb2 = go2.AddComponent<Rigidbody>();
go2.AddComponent<Rigidbody>();
go2.transform.SetParent(rootObj.transform);
var joint = go2.AddComponent<ConfigurableJoint>();

8
com.unity.ml-agents.extensions/Tests/Editor/Sensors/RigidBodySensorTests.cs


public static void CompareObservation(ISensor sensor, float[] expected)
{
string errorMessage;
bool isOK = SensorHelper.CompareObservation(sensor, expected, out errorMessage);
Assert.IsTrue(isOK, errorMessage);
bool isOk = SensorHelper.CompareObservation(sensor, expected, out errorMessage);
Assert.IsTrue(isOk, errorMessage);
bool isOK = SensorHelper.CompareObservation(sensor, expected, out errorMessage);
Assert.IsTrue(isOK, errorMessage);
bool isOk = SensorHelper.CompareObservation(sensor, expected, out errorMessage);
Assert.IsTrue(isOk, errorMessage);
}
}

4
com.unity.ml-agents.extensions/Tests/Runtime/RuntimeExampleTest.cs


using UnityEngine;
using UnityEditor;
using UnityEngine.TestTools;
using System.Collections;
namespace Unity.MLAgents.Extensions.Tests
{

2
com.unity.ml-agents/Documentation~/com.unity.ml-agents.md


[unity ML-Agents Toolkit]: https://github.com/Unity-Technologies/ml-agents
[unity inference engine]: https://docs.unity3d.com/Packages/com.unity.barracuda@latest/index.html
[package manager documentation]: https://docs.unity3d.com/Manual/upm-ui-install.html
[installation instructions]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Installation.md
[installation instructions]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Installation.md
[github repository]: https://github.com/Unity-Technologies/ml-agents
[python package]: https://github.com/Unity-Technologies/ml-agents
[execution order of event functions]: https://docs.unity3d.com/Manual/ExecutionOrder.html

3
com.unity.ml-agents/Editor/BehaviorParametersEditor.cs


using Unity.MLAgents.Policies;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Sensors.Reflection;
using UnityEngine;
namespace Unity.MLAgents.Editor
{

var so = serializedObject;
so.Update();
bool needPolicyUpdate; // Whether the name, model, inference device, or BehaviorType changed.
bool needBrainParametersUpdate; // Whether the brain parameters changed
// Drawing the Behavior Parameters
EditorGUI.indentLevel++;

EditorGUILayout.PropertyField(so.FindProperty(k_BrainParametersName), true);
}
EditorGUI.EndDisabledGroup();
needBrainParametersUpdate = EditorGUI.EndChangeCheck();
EditorGUI.BeginChangeCheck();
{

1
com.unity.ml-agents/Editor/CameraSensorComponentEditor.cs


using UnityEngine;
using UnityEditor;
using Unity.MLAgents.Sensors;

1
com.unity.ml-agents/Editor/RenderTextureSensorComponentEditor.cs


using UnityEngine;
using UnityEditor;
using Unity.MLAgents.Sensors;
namespace Unity.MLAgents.Editor

8
com.unity.ml-agents/Runtime/Academy.cs


* API. For more information on each of these entities, in addition to how to
* set-up a learning environment and train the behavior of characters in a
* Unity scene, please browse our documentation pages on GitHub:
* https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/docs/
* https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/docs/
*/
namespace Unity.MLAgents

/// fall back to inference or heuristic decisions. (You can also set agents to always use
/// inference or heuristics.)
/// </remarks>
[HelpURL("https://github.com/Unity-Technologies/ml-agents/tree/release_10_docs/" +
[HelpURL("https://github.com/Unity-Technologies/ml-agents/tree/release_11_docs/" +
"docs/Learning-Environment-Design.md")]
public class Academy : IDisposable
{

/// </item>
/// <item>
/// <term>1.3.0</term>
/// <description>Support action spaces with both continuous and discrete actions.</description>
/// <description>Support both continuous and discrete actions.</description>
/// </item>
/// </list>
/// </remarks>

/// NNModel and the InferenceDevice as provided.
/// </summary>
/// <param name="model">The NNModel the ModelRunner must use.</param>
/// <param name="actionSpec"> Description of the action spaces for the Agent.</param>
/// <param name="actionSpec"> Description of the actions for the Agent.</param>
/// <param name="inferenceDevice">
/// The inference device (CPU or GPU) the ModelRunner will use.
/// </param>

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


namespace Unity.MLAgents.Actuators
{
/// <summary>
/// Defines the structure of an Action Space to be used by the Actuator system.
/// Defines the structure of the actions to be used by the Actuator system.
/// </summary>
[Serializable]
public struct ActionSpec

/// <summary>
/// An array of branch sizes for our action space.
/// An array of branch sizes for discrete actions.
/// For an IActuator that uses a Discrete <see cref="SpaceType"/>, the number of
/// For an IActuator that uses discrete actions, the number of
/// branches is the Length of the Array and each index contains the branch size.
/// The cumulative sum of the total number of discrete actions can be retrieved
/// by the <see cref="SumOfDiscreteBranchSizes"/> property.

public int[] BranchSizes;
/// <summary>
/// The number of actions for a Continuous <see cref="SpaceType"/>.
/// The number of continuous actions that an Agent can take.
/// The number of branches for a Discrete <see cref="SpaceType"/>.
/// The number of branches for discrete actions that an Agent can take.
/// </summary>
public int NumDiscreteActions { get { return BranchSizes == null ? 0 : BranchSizes.Length; } }

/// Creates a Discrete <see cref="ActionSpec"/> with the array of branch sizes that
/// represents the action space.
/// </summary>
/// <param name="branchSizes">The array of branch sizes for the discrete action space. Each index
/// <param name="branchSizes">The array of branch sizes for the discrete actions. Each index
var numActions = branchSizes.Length;
var actuatorSpace = new ActionSpec(0, branchSizes);
return actuatorSpace;
}

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


public abstract IActuator CreateActuator();
/// <summary>
/// The specification of the Action space for this ActuatorComponent.
/// The specification of the possible actions for this ActuatorComponent.
/// This must produce the same results as the corresponding IActuator's ActionSpec.
/// </summary>
/// <seealso cref="ActionSpec"/>

1
com.unity.ml-agents/Runtime/Actuators/ActuatorDiscreteActionMask.cs


using System;
using System.Collections.Generic;
using System.Linq;
namespace Unity.MLAgents.Actuators
{

7
com.unity.ml-agents/Runtime/Actuators/ActuatorManager.cs


}
/// <summary>
/// This method validates that all <see cref="IActuator"/>s have unique names and equivalent action space types
/// This method validates that all <see cref="IActuator"/>s have unique names
/// if the `DEBUG` preprocessor macro is defined, and allocates the appropriate buffers to manage the actions for
/// all of the <see cref="IActuator"/>s that may live on a particular object.
/// </summary>

}
#if DEBUG
// Make sure the names are actually unique
// Make sure all Actuators have the same SpaceType
ValidateActuators();
#endif

/// <summary>
/// Iterates through all of the IActuators in this list and calls their
/// <see cref="IActionReceiver.OnActionReceived"/> method on them with the appropriate
/// <see cref="ActionSegment{T}"/>s depending on their <see cref="IActionReceiver.ActionSpec"/>.
/// <see cref="ActionSegment{T}"/>s depending on their <see cref="ActionSpec"/>.
/// </summary>
public void ExecuteActions()
{

}
/// <summary>
/// Validates that the IActuators managed by this object have unique names and equivalent action space types.
/// Validates that the IActuators managed by this object have unique names.
/// Each Actuator needs to have a unique name in order for this object to ensure that the storage of action
/// buffers, and execution of Actuators remains deterministic across different sessions of running.
/// </summary>

5
com.unity.ml-agents/Runtime/Actuators/IActionReceiver.cs


/// </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>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)

/// <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();

///
/// See [Agents - Actions] for more information on masking actions.
///
/// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md#actions
/// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md#actions
/// </remarks>
/// <seealso cref="IActionReceiver.OnActionReceived"/>
void WriteDiscreteActionMask(IDiscreteActionMask actionMask);

2
com.unity.ml-agents/Runtime/Actuators/IActuator.cs


public interface IActuator : IActionReceiver
{
/// <summary>
/// The specification of the Action space for this IActuator.
/// The specification of the actions for this IActuator.
/// </summary>
/// <seealso cref="ActionSpec"/>
ActionSpec ActionSpec { get; }

2
com.unity.ml-agents/Runtime/Actuators/IDiscreteActionMask.cs


///
/// See [Agents - Actions] for more information on masking actions.
///
/// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md#actions
/// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md#actions
/// </remarks>
/// <param name="branch">The branch for which the actions will be masked.</param>
/// <param name="actionIndices">The indices of the masked actions.</param>

4
com.unity.ml-agents/Runtime/Actuators/VectorActuator.cs


using System;
using Unity.MLAgents.Policies;
namespace Unity.MLAgents.Actuators
{
/// <summary>

90
com.unity.ml-agents/Runtime/Agent.cs


internal struct AgentInfo
{
/// <summary>
/// Keeps track of the last vector action taken by the Brain.
/// Keeps track of the last actions taken by the Brain.
public ActionBuffers storedVectorActions;
public ActionBuffers storedActions;
/// <summary>
/// For discrete control, specifies the actions that the agent cannot take.

public void ClearActions()
{
storedVectorActions.Clear();
storedActions.Clear();
var continuousActions = storedVectorActions.ContinuousActions;
var continuousActions = storedActions.ContinuousActions;
var discreteActions = storedVectorActions.DiscreteActions;
var discreteActions = storedActions.DiscreteActions;
for (var i = 0; i < actionBuffers.DiscreteActions.Length; i++)
{
discreteActions[i] = actionBuffers.DiscreteActions[i];

/// [OnDisable()]: https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnDisable.html]
/// [OnBeforeSerialize()]: https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnBeforeSerialize.html
/// [OnAfterSerialize()]: https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnAfterSerialize.html
/// [Agents]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md
/// [Reinforcement Learning in Unity]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design.md
/// [Agents]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md
/// [Reinforcement Learning in Unity]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design.md
/// [Unity ML-Agents Toolkit manual]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Readme.md
/// [Unity ML-Agents Toolkit manual]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Readme.md
[HelpURL("https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/" +
[HelpURL("https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/" +
"docs/Learning-Environment-Design-Agents.md")]
[Serializable]
[RequireComponent(typeof(BehaviorParameters))]

InitializeSensors();
}
m_Info.storedVectorActions = new ActionBuffers(
m_Info.storedActions = new ActionBuffers(
new float[m_ActuatorManager.NumContinuousActions],
new int[m_ActuatorManager.NumDiscreteActions]
);

m_CumulativeReward = 0f;
m_RequestAction = false;
m_RequestDecision = false;
m_Info.storedVectorActions.Clear();
m_Info.storedActions.Clear();
}
/// <summary>

/// for information about mixing reward signals from curiosity and Generative Adversarial
/// Imitation Learning (GAIL) with rewards supplied through this method.
///
/// [Agents - Rewards]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md#rewards
/// [Reward Signals]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/ML-Agents-Overview.md#a-quick-note-on-reward-signals
/// [Agents - Rewards]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md#rewards
/// [Reward Signals]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/ML-Agents-Overview.md#a-quick-note-on-reward-signals
/// </remarks>
/// <param name="reward">The new value of the reward.</param>
public void SetReward(float reward)

/// for information about mixing reward signals from curiosity and Generative Adversarial
/// Imitation Learning (GAIL) with rewards supplied through this method.
///
/// [Agents - Rewards]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md#rewards
/// [Reward Signals]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/ML-Agents-Overview.md#a-quick-note-on-reward-signals
/// [Agents - Rewards]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md#rewards
/// [Reward Signals]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/ML-Agents-Overview.md#a-quick-note-on-reward-signals
///</remarks>
/// <param name="increment">Incremental reward value.</param>
public void AddReward(float increment)

/// implementing a simple heuristic function can aid in debugging agent actions and interactions
/// with its environment.
///
/// [Demonstration Recorder]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md#recording-demonstrations
/// [Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md#actions
/// [Demonstration Recorder]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md#recording-demonstrations
/// [Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md#actions
/// [GameObject]: https://docs.unity3d.com/Manual/GameObjects.html
/// </remarks>
/// <example>

CollectObservations(collectObservationsSensor);
}
}
using (TimerStack.Instance.Scoped("CollectDiscreteActionMasks"))
using (TimerStack.Instance.Scoped("WriteActionMask"))
{
m_ActuatorManager.WriteActionMask();
}

/// For more information about observations, see [Observations and Sensors].
///
/// [GameObject]: https://docs.unity3d.com/Manual/GameObjects.html
/// [Observations and Sensors]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md#observations-and-sensors
/// [Observations and Sensors]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md#observations-and-sensors
/// </remarks>
public virtual void CollectObservations(VectorSensor sensor)
{

}
/// <summary>
/// Implement `CollectDiscreteActionMasks()` to collects the masks for discrete
/// Implement `WriteDiscreteActionMask()` to collects the masks for discrete
/// actions. When using discrete actions, the agent will not perform the masked
/// action.
/// </summary>

/// <remarks>
/// When using Discrete Control, you can prevent the Agent from using a certain
/// action by masking it with <see cref="DiscreteActionMasker.SetMask(int, IEnumerable{int})"/>.
/// action by masking it with <see cref="IDiscreteActionMask.WriteMask(int, IEnumerable{int})"/>.
/// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md#actions
/// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md#actions
/// </remarks>
/// <seealso cref="IActionReceiver.OnActionReceived"/>
public virtual void WriteDiscreteActionMask(IDiscreteActionMask actionMask)

/// on the provided action.
/// </summary>
/// <remarks>
/// An action is passed to this function in the form of an array vector. Your
/// implementation must use the array to direct the agent's behavior for the
/// An action is passed to this function in the form of an <seealso cref="ActionBuffers"/>.
/// Your implementation must use the array to direct the agent's behavior for the
/// You decide how many elements you need in the action array to control your
/// You decide how many elements you need in the ActionBuffers to control your
/// three values in the action array to use as the force components. During
/// training, the agent's policy learns to set those particular elements of
/// three values in ActionBuffers.ContinuousActions array to use as the force components.
/// During training, the agent's policy learns to set those particular elements of
/// Actions for an agent can be either *Continuous* or *Discrete*. Specify which
/// type of action space an agent uses, along with the size of the action array,
/// in the <see cref="BrainParameters"/> of the agent's associated
/// An Agent can use continuous and/or discrete actions. Configure this along with the size
/// of the action array, in the <see cref="BrainParameters"/> of the agent's associated
/// When an agent uses the continuous action space, the values in the action
/// When an agent uses continuous actions, the values in the ActionBuffers.ContinuousActions
/// When an agent uses the discrete action space, the values in the action array
/// When an agent uses discrete actions, the values in the ActionBuffers.DiscreteActions array
/// are integers that each represent a specific, discrete action. For example,
/// you could define a set of discrete actions such as:
///

/// </code>
///
/// When making a decision, the agent picks one of the five actions and puts the
/// corresponding integer value in the action vector. For example, if the agent
/// decided to move left, the action vector parameter would contain an array with
/// corresponding integer value in the ActionBuffers.DiscreteActions array. For example, if the agent
/// decided to move left, the ActionBuffers.DiscreteActions parameter would be an array with
/// a single element with the value 1.
///
/// You can define multiple sets, or branches, of discrete actions to allow an

///
/// The action vector of a discrete action space contains one element for each
/// branch. The value of each element is the integer representing the chosen
/// action for that branch. The agent always chooses one action for each
/// branch.
/// The ActionBuffers.DiscreteActions array of an agent with discrete actions contains one
/// element for each branch. The value of each element is the integer representing the
/// chosen action for that branch. The agent always chooses one action for each branch.
/// When you use the discrete action space, you can prevent the training process
/// When you use the discrete actions, you can prevent the training process
/// implementing the <see cref="CollectDiscreteActionMasks(DiscreteActionMasker)"/>
/// function. For example, if your agent is next to a wall, you could mask out any
/// implementing the <see cref="WriteDiscreteActionMask(IDiscreteActionMask)"/>
/// method. For example, if your agent is next to a wall, you could mask out any
/// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md#actions
/// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md#actions
/// </remarks>
/// <param name="actions">
/// Struct containing the buffers of actions to be executed at this step.

var actionSpec = m_PolicyFactory.BrainParameters.ActionSpec;
// For continuous and discrete actions together, we don't need to fall back to the legacy method
if (actionSpec.NumContinuousActions > 0 && actionSpec.NumDiscreteActions > 0)
{
// Nothing implemented.
return;
}
if (!actions.ContinuousActions.IsEmpty())
{
m_LegacyActionCache = actions.ContinuousActions.Array;

13
com.unity.ml-agents/Runtime/Agent.deprecated.cs


}
/// <summary>
/// Deprecated, use <see cref="Heuristic(in ActionBuffers)"/> instead.
/// Deprecated, use <see cref="Heuristic(in Actuators.ActionBuffers)"/> instead.
/// </summary>
/// <param name="actionsOut"></param>
[Obsolete("The float[] version of Heuristic has been deprecated, please use the ActionBuffers version instead.")]

}
/// <summary>
/// Deprecated, use <see cref="OnActionReceived(ActionBuffers)"/> instead.
/// Deprecated, use <see cref="OnActionReceived(Actuators.ActionBuffers)"/> instead.
/// </summary>
/// <param name="vectorAction"></param>
[Obsolete("The float[] version of OnActionReceived has been deprecated, please use the ActionBuffers version instead.")]

[Obsolete("GetAction has been deprecated, please use GetStoredActionBuffers instead.")]
public float[] GetAction()
{
var storedAction = m_Info.storedVectorActions;
var actionSpec = m_PolicyFactory.BrainParameters.ActionSpec;
// For continuous and discrete actions together, this shouldn't be called because we can only return one.
if (actionSpec.NumContinuousActions > 0 && actionSpec.NumDiscreteActions > 0)
{
Debug.LogWarning("Agent.GetAction() when both continuous and discrete actions are in use. Use Agent.GetStoredActionBuffers() instead.");
}
var storedAction = m_Info.storedActions;
if (!storedAction.ContinuousActions.IsEmpty())
{
return storedAction.ContinuousActions.Array;

14
com.unity.ml-agents/Runtime/Communicator/GrpcExtensions.cs


var agentActionProto = new AgentActionProto();
if (!ai.storedVectorActions.IsEmpty())
if (!ai.storedActions.IsEmpty())
if (!ai.storedVectorActions.ContinuousActions.IsEmpty())
if (!ai.storedActions.ContinuousActions.IsEmpty())
agentActionProto.ContinuousActions.AddRange(ai.storedVectorActions.ContinuousActions.Array);
agentActionProto.ContinuousActions.AddRange(ai.storedActions.ContinuousActions.Array);
if (!ai.storedVectorActions.DiscreteActions.IsEmpty())
if (!ai.storedActions.DiscreteActions.IsEmpty())
agentActionProto.DiscreteActions.AddRange(ai.storedVectorActions.DiscreteActions.Array);
agentActionProto.DiscreteActions.AddRange(ai.storedActions.DiscreteActions.Array);
}
}

/// Converts an ActionSpec into to a Protobuf BrainInfoProto so it can be sent.
/// </summary>
/// <returns>The BrainInfoProto generated.</returns>
/// <param name="actionSpec"> Description of the action spaces for the Agent.</param>
/// <param name="actionSpec"> Description of the actions for the Agent.</param>
/// <param name="name">The name of the brain.</param>
/// <param name="isTraining">Whether or not the Brain is training.</param>
public static BrainParametersProto ToBrainParametersProto(this ActionSpec actionSpec, string name, bool isTraining)

/// <summary>
/// Convert a ActionSpec struct to a ActionSpecProto.
/// </summary>
/// <param name="actionSpecProto">An instance of an action spec struct.</param>
/// <param name="actionSpec">An instance of an action spec struct.</param>
/// <returns>An ActionSpecProto.</returns>
public static ActionSpecProto ToActionSpecProto(this ActionSpec actionSpec)
{

3
com.unity.ml-agents/Runtime/Communicator/ICommunicator.cs


using System;
using System.Collections.Generic;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Policies;
using Unity.MLAgents.Sensors;
namespace Unity.MLAgents

/// Registers a new Brain to the Communicator.
/// </summary>
/// <param name="name">The name or key uniquely identifying the Brain.</param>
/// <param name="actionSpec"> Description of the action spaces for the Agent.</param>
/// <param name="actionSpec"> Description of the actions for the Agent.</param>
void SubscribeBrain(string name, ActionSpec actionSpec);
/// <summary>

3
com.unity.ml-agents/Runtime/Communicator/RpcCommunicator.cs


using Unity.MLAgents.Actuators;
using Unity.MLAgents.CommunicatorObjects;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Policies;
using Unity.MLAgents.SideChannels;
using Google.Protobuf;

/// Adds the brain to the list of brains which will be sending information to External.
/// </summary>
/// <param name="brainKey">Brain key.</param>
/// <param name="actionSpec"> Description of the action spaces for the Agent.</param>
/// <param name="actionSpec"> Description of the actions for the Agent.</param>
public void SubscribeBrain(string brainKey, ActionSpec actionSpec)
{
if (m_BehaviorNames.Contains(brainKey))

1
com.unity.ml-agents/Runtime/Demonstrations/DemonstrationMetaData.cs


using System;
using UnityEngine;
using UnityEngine.Serialization;
namespace Unity.MLAgents.Demonstrations

4
com.unity.ml-agents/Runtime/Demonstrations/DemonstrationRecorder.cs


/// See [Imitation Learning - Recording Demonstrations] for more information.
///
/// [GameObject]: https://docs.unity3d.com/Manual/GameObjects.html
/// [Imitation Learning - Recording Demonstrations]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs//Learning-Environment-Design-Agents.md#recording-demonstrations
/// [Imitation Learning - Recording Demonstrations]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs//Learning-Environment-Design-Agents.md#recording-demonstrations
/// </remarks>
[RequireComponent(typeof(Agent))]
[AddComponentMenu("ML Agents/Demonstration Recorder", (int)MenuGroup.Default)]

/// </summary>
[Tooltip("Number of steps to record. The editor will stop playing when it reaches this threshold. " +
"Set to zero to record indefinitely.")]
public int NumStepsToRecord = 0;
public int NumStepsToRecord;
/// <summary>
/// Base demonstration file name. If multiple files are saved, the additional filenames

3
com.unity.ml-agents/Runtime/DiscreteActionMasker.cs


using System;
using System.Collections.Generic;
using Unity.MLAgents.Actuators;

///
/// See [Agents - Actions] for more information on masking actions.
///
/// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/docs/Learning-Environment-Design-Agents.md#actions
/// [Agents - Actions]: https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/docs/Learning-Environment-Design-Agents.md#actions
/// </remarks>
/// <param name="branch">The branch for which the actions will be masked.</param>
/// <param name="actionIndices">The indices of the masked actions.</param>

6
com.unity.ml-agents/Runtime/Inference/BarracudaModelExtensions.cs


}
/// <summary>
/// Check if the model supports hybrid action spaces.
/// Check if the model supports both continuous and discrete actions.
/// <returns>True if the model supports hybrid action spaces.</returns>
/// <returns>True if the model supports both continuous and discrete actions.</returns>
public static bool SupportsContinuousAndDiscrete(this Model model)
{
return model == null ||

/// <param name="model">
/// The Barracuda engine model for loading static parameters.
/// </param>
/// <param name="failedModelChecks">Output list of failure messages</param>
///
/// <returns>True if the model contains all the expected tensors.</returns>
public static bool CheckExpectedTensors(this Model model, List<string> failedModelChecks)
{

21
com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs


/// <param name="memory">
/// The memory size that the model is expecting.
/// </param>
/// <param name="isContinuous">
/// Whether the model is expecting continuous or discrete control.
/// </param>
/// <param name="observableAttributeTotalSize">Total size of ObservableAttributes</param>
/// <returns>
/// A IEnumerable of string corresponding to the failed input presence checks.
/// </returns>

/// The BrainParameters that are used verify the compatibility with the InferenceEngine
/// </param>
/// <param name="actuatorComponents">Array of attached actuator components.</param>
/// <param name="isContinuous">
/// Whether the model is expecting continuous or discrete control.
/// </param>
/// <param name="modelContinuousActionSize">
/// The size of the continuous action output that is expected by the model.
/// </param>
/// <param name="modelSumDiscreteBranchSizes">
/// The size of the discrete action output that is expected by the model.
/// </param>
/// <returns>
/// A IEnumerable of string corresponding to the incompatible shapes between model
/// and BrainParameters.

/// The BrainParameters that are used verify the compatibility with the InferenceEngine
/// </param>
/// <param name="actuatorComponents">Array of attached actuator components.</param>
/// <param name="shape"> The tensor shape that is expected by the model</param>
/// <param name="modelContinuousActionSize">
/// The size of the continuous action output that is expected by the model.
/// </param>
/// <param name="modelSumDiscreteBranchSizes">
/// The size of the discrete action output that is expected by the model.
/// </param>

/// The BrainParameters that are used verify the compatibility with the InferenceEngine
/// </param>
/// <param name="actuatorComponents">Array of attached actuator components.</param>
/// <param name="shape"> The tensor shape that is expected by the model</param>
/// </param>
/// <param name="modelSumDiscreteBranchSizes">
/// The size of the discrete action output that is expected by the model.
/// </param>
/// <returns>If the Check failed, returns a string containing information about why the
/// check failed. If the check passed, returns null.</returns>

2
com.unity.ml-agents/Runtime/Inference/GeneratorImpl.cs


foreach (var infoSensorPair in infos)
{
var info = infoSensorPair.agentInfo;
var pastAction = info.storedVectorActions.DiscreteActions;
var pastAction = info.storedActions.DiscreteActions;
if (!pastAction.IsEmpty())
{
for (var j = 0; j < actionSize; j++)

2
com.unity.ml-agents/Runtime/Inference/ModelRunner.cs


/// the agents
/// </summary>
/// <param name="model"> The Barracuda model to load </param>
/// <param name="actionSpec"> Description of the action spaces for the Agent.</param>
/// <param name="actionSpec"> Description of the actions for the Agent.</param>
/// <param name="inferenceDevice"> Inference execution device. CPU is the fastest
/// option for most of ML Agents models. </param>
/// <param name="seed"> The seed that will be used to initialize the RandomNormal

3
com.unity.ml-agents/Runtime/Inference/TensorApplier.cs


using System.Collections.Generic;
using Unity.Barracuda;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Policies;
namespace Unity.MLAgents.Inference

/// <summary>
/// Returns a new TensorAppliers object.
/// </summary>
/// <param name="actionSpec"> Description of the action spaces for the Agent.</param>
/// <param name="actionSpec"> Description of the actions for the Agent.</param>
/// <param name="seed"> The seed the Appliers will be initialized with.</param>
/// <param name="allocator"> Tensor allocator</param>
/// <param name="memories">Dictionary of AgentInfo.id to memory used to pass to the inference model.</param>

1
com.unity.ml-agents/Runtime/Policies/BarracudaPolicy.cs


using System;
using Unity.Barracuda;
using System.Collections.Generic;
using Unity.MLAgents.Actuators;

13
com.unity.ml-agents/Runtime/Policies/BrainParameters.cs


namespace Unity.MLAgents.Policies
{
/// <summary>
/// Whether the action space is discrete or continuous.
/// This is deprecated. Agents can now use both continuous and discrete actions together.
[Obsolete("Continuous and discrete actions on the same Agent are now supported; see ActionSpec.")]
public enum SpaceType
{
/// <summary>

internal ActionSpec m_ActionSpec = new ActionSpec(0, null);
/// <summary>
/// The specification of the Action space for the BrainParameters.
/// The specification of the Actions for the BrainParameters.
/// </summary>
public ActionSpec ActionSpec
{

}
/// <summary>
/// (Deprecated) The size of the action space.
/// (Deprecated) The number of possible actions.
/// the agent uses the continuous or the discrete action space.</remarks>
/// the agent uses the continuous or the discrete actions.</remarks>
/// For the continuous action space: the length of the float vector that represents
/// For the continuous actions: the length of the float vector that represents
/// For the discrete action space: the number of branches in the action space.
/// For the discrete actions: the number of branches.
/// </value>
[Obsolete("VectorActionSize has been deprecated, please use ActionSpec instead.")]
[FormerlySerializedAs("vectorActionSize")]

2
com.unity.ml-agents/Runtime/Policies/RemotePolicy.cs


using UnityEngine;
using System;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;

3
com.unity.ml-agents/Runtime/Sampler.cs


using System;
using System.Collections.Generic;
using Unity.MLAgents.Inference.Utils;
using UnityEngine;
using Random = System.Random;
namespace Unity.MLAgents

// Will be used to normalize intervalFuncs
float sumIntervalSizes = 0;
//The number of intervals
int numIntervals = (int)(intervals.Count / 2);
int numIntervals = (intervals.Count / 2);
// List that will store interval lengths
float[] intervalSizes = new float[numIntervals];
// List that will store uniform distributions

1
com.unity.ml-agents/Runtime/SensorHelper.cs


using UnityEngine;
using Unity.Barracuda;
namespace Unity.MLAgents.Sensors

2
com.unity.ml-agents/Runtime/Sensors/ObservationWriter.cs


}
else if (shape.Length == 2)
{
m_TensorShape = new TensorShape(new int[] { m_Batch, 1, shape[0], shape[1] });
m_TensorShape = new TensorShape(new[] { m_Batch, 1, shape[0], shape[1] });
}
else
{

1
com.unity.ml-agents/Runtime/Sensors/Reflection/EnumReflectionSensor.cs


using System;
using UnityEngine;
namespace Unity.MLAgents.Sensors.Reflection
{

2
com.unity.ml-agents/Runtime/Sensors/Reflection/IntReflectionSensor.cs


internal override void WriteReflectedField(ObservationWriter writer)
{
var intVal = (System.Int32)GetReflectedValue();
writer[0] = (float)intVal;
writer[0] = intVal;
}
}
}

2
com.unity.ml-agents/Runtime/Sensors/StackingSensor.cs


{
if (wrappedNumChannel == 1)
{
wrappedMapping = new int[] { 0, 0, 0 };
wrappedMapping = new[] { 0, 0, 0 };
}
else
{

2
com.unity.ml-agents/Runtime/Utilities.cs


using System;
using UnityEngine;
using Unity.MLAgents.Sensors;
namespace Unity.MLAgents
{

1
com.unity.ml-agents/Tests/Editor/Actuators/ActuatorDiscreteActionMaskTests.cs


using System;
using System.Collections.Generic;
using NUnit.Framework;
using Unity.MLAgents.Actuators;

15
com.unity.ml-agents/Tests/Editor/Actuators/ActuatorManagerTests.cs


using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Unity.MLAgents.Policies;
using UnityEngine;
using UnityEngine.TestTools;
using Assert = UnityEngine.Assertions.Assert;

Assert.IsTrue(13 == manager.SumOfDiscreteBranchSizes);
Assert.IsTrue(0 == manager.StoredActions.ContinuousActions.Length);
Assert.IsTrue(7 == manager.StoredActions.DiscreteActions.Length);
}
[Test]
public void TestAllowMixedActions()
{
// Make sure discrete + continuous actuators are allowed.
var manager = new ActuatorManager();
var actuator1 = new TestActuator(ActionSpec.MakeDiscrete(new[] { 1, 2, 3, 4 }), "actuator1");
var actuator2 = new TestActuator(ActionSpec.MakeContinuous(3), "actuator2");
manager.Add(actuator1);
manager.Add(actuator2);
manager.ReadyActuatorsForExecution(new[] { actuator1, actuator2 }, 3, 10, 4);
}
[Test]

1
com.unity.ml-agents/Tests/Editor/Actuators/VectorActuatorTests.cs


using System.Linq;
using NUnit.Framework;
using Unity.MLAgents.Actuators;
using Unity.MLAgents.Policies;
using Assert = UnityEngine.Assertions.Assert;
namespace Unity.MLAgents.Tests.Actuators

9
com.unity.ml-agents/Tests/Editor/Communicator/GrpcExtensionsTests.cs


using NUnit.Framework;
using UnityEngine;
using Unity.MLAgents.Policies;
using Unity.MLAgents.Demonstrations;
using Unity.MLAgents.Actuators;

var sparseChannelSensor = new DummySparseChannelSensor();
sparseChannelSensor.Mapping = null;
Assert.AreEqual(GrpcExtensions.IsTrivialMapping(sparseChannelSensor), true);
sparseChannelSensor.Mapping = new int[] { 0, 0, 0 };
sparseChannelSensor.Mapping = new[] { 0, 0, 0 };
sparseChannelSensor.Mapping = new int[] { 0, 1, 2, 3, 4 };
sparseChannelSensor.Mapping = new[] { 0, 1, 2, 3, 4 };
sparseChannelSensor.Mapping = new int[] { 1, 2, 3, 4, -1, -1 };
sparseChannelSensor.Mapping = new[] { 1, 2, 3, 4, -1, -1 };
sparseChannelSensor.Mapping = new int[] { 0, 0, 0, 1, 1, 1 };
sparseChannelSensor.Mapping = new[] { 0, 0, 0, 1, 1, 1 };
Assert.AreEqual(GrpcExtensions.IsTrivialMapping(sparseChannelSensor), false);
}
}

3
com.unity.ml-agents/Tests/Editor/Communicator/RpcCommunicatorTests.cs


using System;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.TestTools;
namespace Unity.MLAgents.Tests.Communicator

2
com.unity.ml-agents/Tests/Editor/DemonstrationTests.cs


done = true,
episodeId = 5,
maxStepReached = true,
storedVectorActions = new ActionBuffers(null, new int[] { 0, 1 }),
storedActions = new ActionBuffers(null, new[] { 0, 1 }),
};

2
com.unity.ml-agents/Tests/Editor/EditModeTestInternalBrainTensorApplier.cs


[Test]
public void ApplyHybridActionOutput()
{
var actionSpec = new ActionSpec(3, new int[] { 2, 3 });
var actionSpec = new ActionSpec(3, new[] { 2, 3 });
var continuousInputTensor = new TensorProxy()
{
shape = new long[] { 2, 3 },

4
com.unity.ml-agents/Tests/Editor/EditModeTestInternalBrainTensorGenerator.cs


var infoA = new AgentInfo
{
storedVectorActions = new ActionBuffers(null, new[] { 1, 2 }),
storedActions = new ActionBuffers(null, new[] { 1, 2 }),
storedVectorActions = new ActionBuffers(null, new[] { 3, 4 }),
storedActions = new ActionBuffers(null, new[] { 3, 4 }),
discreteActionMasks = new[] { true, false, false, false, false },
};

2
com.unity.ml-agents/Tests/Editor/ModelRunnerTest.cs


ActionSpec GetHybrid0vis53vec_3c_2dActionSpec()
{
return new ActionSpec(3, new int[] { 2 });
return new ActionSpec(3, new[] { 2 });
}
[SetUp]

4
com.unity.ml-agents/Tests/Editor/ParameterLoaderTest.cs


var validBrainParameters = new BrainParameters();
validBrainParameters.VectorObservationSize = 53;
validBrainParameters.NumStackedVectorObservations = 1;
validBrainParameters.ActionSpec = new ActionSpec(3, new int[] { 2 });
validBrainParameters.ActionSpec = new ActionSpec(3, new[] { 2 });
return validBrainParameters;
}

var model = ModelLoader.Load(hybridONNXModel);
var brainParameters = GetHybridBrainParameters();
brainParameters.ActionSpec = new ActionSpec(3, new int[] { 3 }); ; // Invalid discrete action size
brainParameters.ActionSpec = new ActionSpec(3, new[] { 3 }); // Invalid discrete action size
var errors = BarracudaModelParamLoader.CheckModel(model, brainParameters, new SensorComponent[] { sensor_21_20_3, sensor_20_22_3 }, new ActuatorComponent[0]);
Assert.Greater(errors.Count(), 0);

2
com.unity.ml-agents/Tests/Editor/RecursionCheckerTests.cs


class InfiniteRecurser
{
RecursionChecker m_checker = new RecursionChecker("InfiniteRecurser");
public int NumCalls = 0;
public int NumCalls;
public void Implode()
{

3
com.unity.ml-agents/Tests/Editor/SamplerTests.cs


using System;
using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents.SideChannels;
namespace Unity.MLAgents.Tests

1
com.unity.ml-agents/Tests/Editor/Sensor/SensorTestHelper.cs


using NUnit.Framework;
using UnityEngine;
using Unity.MLAgents.Sensors;
namespace Unity.MLAgents.Tests

12
com.unity.ml-agents/Tests/Editor/Sensor/StackingSensorTests.cs


// Test mapping with number of layers not being multiple of 3
var dummySensor = new Dummy3DSensor();
dummySensor.Shape = new int[] { 2, 2, 4 };
dummySensor.Mapping = new int[] { 0, 1, 2, 3 };
dummySensor.Shape = new[] { 2, 2, 4 };
dummySensor.Mapping = new[] { 0, 1, 2, 3 };
paddedDummySensor.Shape = new int[] { 2, 2, 4 };
paddedDummySensor.Mapping = new int[] { 0, 1, 2, 3, -1, -1 };
paddedDummySensor.Shape = new[] { 2, 2, 4 };
paddedDummySensor.Mapping = new[] { 0, 1, 2, 3, -1, -1 };
var stackedPaddedDummySensor = new StackingSensor(paddedDummySensor, 2);
Assert.AreEqual(stackedPaddedDummySensor.GetCompressedChannelMapping(), new[] { 0, 1, 2, 3, -1, -1, 4, 5, 6, 7, -1, -1 });
}

{
var wrapped = new Dummy3DSensor();
wrapped.Shape = new int[] { 2, 1, 2 };
wrapped.Shape = new[] { 2, 1, 2 };
var sensor = new StackingSensor(wrapped, 2);
// Check the stacking is on the last dimension

public void TestStackedGetCompressedObservation()
{
var wrapped = new Dummy3DSensor();
wrapped.Shape = new int[] { 1, 1, 3 };
wrapped.Shape = new[] { 1, 1, 3 };
var sensor = new StackingSensor(wrapped, 2);
wrapped.CurrentObservation = new[, ,] { { { 1f, 2f, 3f } } };

4
docs/Installation-Anaconda-Windows.md


the ml-agents Conda environment by typing `activate ml-agents`)_:
```sh
git clone --branch release_10 https://github.com/Unity-Technologies/ml-agents.git
git clone --branch release_11 https://github.com/Unity-Technologies/ml-agents.git
The `--branch release_10` option will switch to the tag of the latest stable
The `--branch release_11` option will switch to the tag of the latest stable
release. Omitting that will get the `master` branch which is potentially
unstable.

6
docs/Installation.md


of our tutorials / guides assume you have access to our example environments).
```sh
git clone --branch release_10 https://github.com/Unity-Technologies/ml-agents.git
git clone --branch release_11 https://github.com/Unity-Technologies/ml-agents.git
The `--branch release_10` option will switch to the tag of the latest stable
The `--branch release_11` option will switch to the tag of the latest stable
release. Omitting that will get the `master` branch which is potentially
unstable.

ML-Agents Toolkit for your purposes. If you plan to contribute those changes
back, make sure to clone the `master` branch (by omitting `--branch release_10`
back, make sure to clone the `master` branch (by omitting `--branch release_11`
from the command above). See our
[Contributions Guidelines](../com.unity.ml-agents/CONTRIBUTING.md) for more
information on contributing to the ML-Agents Toolkit.

16
docs/Migrating.md


([example](https://github.com/Unity-Technologies/ml-agents/blob/b255661084cb8f701c716b040693069a3fb9a257/ml-agents-envs/mlagents/envs/environment.py#L45))
# Migrating
## Migrating to Release 11
### Agent virtual method deprecation
- `Agent.CollectDiscreteActionMasks()` was deprecated and should be replaced with `Agent.WriteDiscreteActionMask()`
- `Agent.Heuristic(float[])` was deprecated and should be replaced with `Agent.Heuristic(ActionBuffers)`.
- `Agent.OnActionReceived(float[])` was deprecated and should be replaced with `Agent.OnActionReceived(ActionBuffers)`.
- `Agent.GetAction()` was deprecated and should be replaced with `Agent.GetStoredActionBuffers()`.
The default implementation of these will continue to call the deprecated versions where appropriate. However, the
deprecated versions may not be compatible with continuous and discrete actions on the same Agent.
### BrainParameters field and method deprecation
- `BrainParameters.VectorActionSize` was deprecated; you can now set `BrainParameters.ActionSpec.NumContinuousActions`
or `BrainParameters.ActionSpec.BranchSizes` instead.
- `BrainParameters.VectorActionSpaceType` was deprecated, since both continuous and discrete actions can now be used.
- `BrainParameters.NumActions()` was deprecated. Use `BrainParameters.ActionSpec.NumContinuousActions` and
`BrainParameters.ActionSpec.NumDiscreteActions` instead.
## Migrating from Release 7 to latest

2
docs/Training-on-Amazon-Web-Service.md


2. Clone the ML-Agents repo and install the required Python packages
```sh
git clone --branch release_10 https://github.com/Unity-Technologies/ml-agents.git
git clone --branch release_11 https://github.com/Unity-Technologies/ml-agents.git
cd ml-agents/ml-agents/
pip3 install -e .
```

4
docs/Unity-Inference-Engine.md


loading expects certain conventions for constants and tensor names. While it is
possible to construct a model that follows these conventions, we don't provide
any additional help for this. More details can be found in
[TensorNames.cs](https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/com.unity.ml-agents/Runtime/Inference/TensorNames.cs)
[TensorNames.cs](https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/com.unity.ml-agents/Runtime/Inference/TensorNames.cs)
[BarracudaModelParamLoader.cs](https://github.com/Unity-Technologies/ml-agents/blob/release_10_docs/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs).
[BarracudaModelParamLoader.cs](https://github.com/Unity-Technologies/ml-agents/blob/release_11_docs/com.unity.ml-agents/Runtime/Inference/BarracudaModelParamLoader.cs).
If you wish to run inference on an externally trained model, you should use
Barracuda directly, instead of trying to run it through ML-Agents.

1
utils/make_readme_table.py


ReleaseInfo("release_8", "1.5.0", "0.21.0", "October 14, 2020"),
ReleaseInfo("release_9", "1.5.0", "0.21.1", "November 4, 2020"),
ReleaseInfo("release_10", "1.6.0", "0.22.0", "November 18, 2020"),
ReleaseInfo("release_11", "1.7.0", "0.23.0", "December 21, 2020"),
]
MAX_DAYS = 150 # do not print releases older than this many days

正在加载...
取消
保存