using System; using System.Collections.Generic; using System.Collections.ObjectModel; using UnityEngine; namespace Unity.MLAgents.Sensors { /// /// A sensor implementation for vector observations. /// public class VectorSensor : ISensor, IBuiltInSensor { // TODO use float[] instead // TODO allow setting float[] List m_Observations; ObservationSpec m_ObservationSpec; string m_Name; /// /// Initializes the sensor. /// /// Number of vector observations. /// Name of the sensor. public VectorSensor(int observationSize, string name = null, ObservationType observationType = ObservationType.Default) { if (string.IsNullOrEmpty(name)) { name = $"VectorSensor_size{observationSize}"; if (observationType != ObservationType.Default) { name += $"_{observationType.ToString()}"; } } m_Observations = new List(observationSize); m_Name = name; m_ObservationSpec = ObservationSpec.Vector(observationSize, observationType); } /// public int Write(ObservationWriter writer) { var expectedObservations = m_ObservationSpec.Shape[0]; if (m_Observations.Count > expectedObservations) { // Too many observations, truncate Debug.LogWarningFormat( "More observations ({0}) made than vector observation size ({1}). The observations will be truncated.", m_Observations.Count, expectedObservations ); m_Observations.RemoveRange(expectedObservations, m_Observations.Count - expectedObservations); } else if (m_Observations.Count < expectedObservations) { // Not enough observations; pad with zeros. Debug.LogWarningFormat( "Fewer observations ({0}) made than vector observation size ({1}). The observations will be padded.", m_Observations.Count, expectedObservations ); for (int i = m_Observations.Count; i < expectedObservations; i++) { m_Observations.Add(0); } } writer.AddList(m_Observations); return expectedObservations; } /// /// Returns a read-only view of the observations that added. /// /// A read-only view of the observations list. internal ReadOnlyCollection GetObservations() { return m_Observations.AsReadOnly(); } /// public void Update() { Clear(); } /// public void Reset() { Clear(); } /// public ObservationSpec GetObservationSpec() { return m_ObservationSpec; } /// public string GetName() { return m_Name; } /// public virtual byte[] GetCompressedObservation() { return null; } /// public CompressionSpec GetCompressionSpec() { return CompressionSpec.Default(); } /// public BuiltInSensorType GetBuiltInSensorType() { return BuiltInSensorType.VectorSensor; } void Clear() { m_Observations.Clear(); } void AddFloatObs(float obs) { Utilities.DebugCheckNanAndInfinity(obs, nameof(obs), nameof(AddFloatObs)); m_Observations.Add(obs); } // Compatibility methods with Agent observation. These should be removed eventually. /// /// Adds a float observation to the vector observations of the agent. /// /// Observation. public void AddObservation(float observation) { AddFloatObs(observation); } /// /// Adds an integer observation to the vector observations of the agent. /// /// Observation. public void AddObservation(int observation) { AddFloatObs(observation); } /// /// Adds an Vector3 observation to the vector observations of the agent. /// /// Observation. public void AddObservation(Vector3 observation) { AddFloatObs(observation.x); AddFloatObs(observation.y); AddFloatObs(observation.z); } /// /// Adds an Vector2 observation to the vector observations of the agent. /// /// Observation. public void AddObservation(Vector2 observation) { AddFloatObs(observation.x); AddFloatObs(observation.y); } /// /// Adds a list or array of float observations to the vector observations of the agent. /// /// Observation. public void AddObservation(IList observation) { for (var i = 0; i < observation.Count; i++) { AddFloatObs(observation[i]); } } /// /// Adds a quaternion observation to the vector observations of the agent. /// /// Observation. public void AddObservation(Quaternion observation) { AddFloatObs(observation.x); AddFloatObs(observation.y); AddFloatObs(observation.z); AddFloatObs(observation.w); } /// /// Adds a boolean observation to the vector observation of the agent. /// /// Observation. public void AddObservation(bool observation) { AddFloatObs(observation ? 1f : 0f); } /// /// Adds a one-hot encoding observation. /// /// The index of this observation. /// The max index for any observation. public void AddOneHotObservation(int observation, int range) { for (var i = 0; i < range; i++) { AddFloatObs(i == observation ? 1.0f : 0.0f); } } } }