Commit 6654bdd2 authored by Joni Salmela's avatar Joni Salmela
Browse files

Merge branch 'revert-630f7ebd' into 'master'

Revert "Merge branch 'django' into 'master'"

See merge request mitale/quantumwheel!4
parents 630f7ebd 610b35aa
......@@ -12,7 +12,7 @@ public class Mover : MonoBehaviour
private Vector3 m_startPos;
// Start is called before the first frame update
private void Start()
void Start()
{
if (relativeToStartPosition)
......
......@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Python.Runtime;
public class QuantumDemoManager : MonoBehaviour
{
......@@ -143,6 +144,15 @@ public class QuantumDemoManager : MonoBehaviour
FinalScoreObject.SetActive(false);
StartTextObject.SetActive(false);
Double noise = m_noise;
if (m_randomizeNoise)
{
noise = UnityEngine.Random.value * m_noise;
}
InitEnv(noise);
StartCoroutine(GameCoroutine());
SetRagdollsKinematic(true);
m_left.enabled = true;
......@@ -158,15 +168,15 @@ public class QuantumDemoManager : MonoBehaviour
m_rightRagdollHanger.GetComponent<Rigidbody>().isKinematic = kinematic;
}
IEnumerator InitEnv(double displacement)
private void InitEnv(double displacement)
{
// To be safe, add a using (Py.Gil()) block every time you interact with any python wrapper class like StirapEnv
using (Python.Runtime.Py.GIL())
{
m_env = new StirapEnv(TimeSteps, displacement);
yield return m_env.WaitForInit();
Debug.Log("Noise: "+m_env.Noise);
m_env = new StirapEnv(TimeSteps, displacement);
Debug.Log("Noise: "+m_env.Noise);
}
}
/// <summary>
......@@ -174,20 +184,11 @@ public class QuantumDemoManager : MonoBehaviour
/// </summary>
/// <returns></returns>
private IEnumerator GameCoroutine()
{
Double noise = m_noise;
if (m_randomizeNoise)
{
noise = UnityEngine.Random.value * m_noise;
}
yield return InitEnv(noise);
{
float time, delta;
int step = 0;
bool done = false;
ResetGrowthMeasures();
// Run the stirap env step at intervals determined by UpdateFrequency, until the result states Done.
yield return new WaitForSeconds(1f);
......@@ -204,13 +205,7 @@ public class QuantumDemoManager : MonoBehaviour
m_timeStepText.text = (TimeSteps - step).ToString();
step++;
WebCallWithValue<StirapEnv.StepResult> stepResult = RunStep(delta);
yield return stepResult;
RenderStep(stepResult,step);
done = stepResult.Value.Done;
} while (!done);
} while (!RunStep(step, delta));
EndGame();
}
......@@ -238,28 +233,32 @@ public class QuantumDemoManager : MonoBehaviour
/// </summary>
/// <param name="deltaTime"></param>
/// <returns></returns>
private WebCallWithValue<StirapEnv.StepResult> RunStep(float deltaTime)
private bool RunStep(int step, float deltaTime)
{
float left = m_left.CurrentInputPosition * deltaTime;
float right = m_right.CurrentInputPosition * deltaTime;
return m_env.Step(left, right);
}
StirapEnv.StepResult result;
// Add a using Py.GIL() block whenever interacting with Python wrapper classes such as StirapEnv
using (Py.GIL())
{
float left = m_left.CurrentInputPosition * deltaTime;
float right = m_right.CurrentInputPosition * deltaTime;
result = m_env.Step(left, right);
}
private void RenderStep(StirapEnv.StepResult stepResult, int step)
{
float leftPop = stepResult.LeftPopulation;
float rightPop = stepResult.RightPopulation;
float midPop = 1f - (leftPop + rightPop);
UpdateWell(m_rightRagdollHanger, rightPop, stepResult.RightWellPosition, m_growthRight);
UpdateWell(m_leftRagdollHanger, leftPop, stepResult.LeftWellPosition, m_growthLeft);
float leftPop = result.LeftPopulation;
float rightPop = result.RightPopulation;
float midPop = 1f - (leftPop + rightPop);
UpdateWell(m_rightRagdollHanger, rightPop, result.RightWellPosition, m_growthRight);
UpdateWell(m_leftRagdollHanger, leftPop, result.LeftWellPosition, m_growthLeft);
UpdateWell(m_midRagdollHanger, midPop, 0, m_growthMid);
m_left.UpdateTextObject(stepResult.LeftWellPosition, stepResult.LeftPopulation);
m_right.UpdateTextObject(stepResult.RightWellPosition, stepResult.RightPopulation);
RenderPlot(stepResult);
SetScore(stepResult.RightPopulation, step);
m_left.UpdateTextObject(result.LeftWellPosition, result.LeftPopulation);
m_right.UpdateTextObject(result.RightWellPosition, result.RightPopulation);
RenderPlot(result);
SetScore(result.RightPopulation, step);
return result.Done;
}
private void UpdateWell(Mover t, float height, float pos, RingBuffer growthMeasure)
......
using UnityEngine;
using System.Collections;
public class ExampleStirap : MonoBehaviour
{
// Start is called before the first frame update
IEnumerator Start()
void Start()
{
StirapEnv stirapEnv = new StirapEnv(10,0.15);
yield return stirapEnv.WaitForInit();
for (int i = 0;i < stirapEnv.TimeSteps ; i++)
UnityEngine.Random.InitState(9989);
using (Python.Runtime.Py.GIL())
{
float left = Random.Range(-.5f, .5f);
float right = Random.Range(-.5f, .5f);
WebCallWithValue<StirapEnv.StepResult> result = stirapEnv.Step(left, right);
yield return result;
StirapEnv stirapEnv = new StirapEnv();
if (result.Value.Done)
for (int i = 0; i < stirapEnv.TimeSteps; i++)
{
Debug.Log($"Episode finished after {i + 1} timesteps");
break;
float left = Random.Range(-.5f, .5f);
float right = Random.Range(-.5f, .5f);
StirapEnv.StepResult result = stirapEnv.Step(left, right);
if (result.Done)
{
Debug.Log($"Episode finished after {i + 1} timesteps");
break;
}
}
}
}
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Python.Runtime;
public class Numpy
{
public static dynamic Array(ICollection<float> collection)
{
PyList acList = new PyList();
foreach (float d in collection)
{
acList.Append(new PyFloat(d));
}
return PythonManager.Instance.Numpy.array(acList);
}
public static dynamic Sum(ICollection<float> collection)
{
return PythonManager.Instance.Numpy.sum(Array(collection));
}
}
fileFormatVersion: 2
guid: 49d45e83fd731ba488ee111b19712e72
guid: ab2bed3a4219cb847a6b6b0c0983810b
MonoImporter:
externalObjects: {}
serializedVersion: 2
......
using System.Collections.Generic;
using System.Numerics;
using Python.Runtime;
public class PythonManager/* : MonoBehaviour*/
{
private static PythonManager m_instance = new PythonManager();
public static PythonManager Instance
{
get
{
return m_instance;
}
}
public dynamic StirapEnv { get; } = Py.Import("gym_stirap.envs.stirap_env");
public dynamic Numpy { get; } = Py.Import("numpy");
public float[] SingleArray(dynamic array)
{
List<float> values = new List<float>();
foreach(float f in array)
{
values.Add(f);
}
return values.ToArray();
}
public Complex[] ComplexArray(dynamic array)
{
List<Complex> values = new List<Complex>();
foreach (dynamic complexNum in array)
{
Complex c = new Complex((double) complexNum.real, (double) complexNum.imag);
values.Add(c);
}
return values.ToArray();
}
}
fileFormatVersion: 2
guid: 32a5335ea7db2604e997955fbc9a2c47
guid: 18a44454128b5bc43ae9a5cd90576712
MonoImporter:
externalObjects: {}
serializedVersion: 2
......
using System;
using System.Collections.Generic;
using System.Numerics;
//using Python.Runtime;
using System.Collections;
using UnityEngine.Networking;
[System.Serializable]
public struct JsonComplex
{
public double Real;
public double Imag;
public Complex ToComplex()
{
return new Complex(Real,Imag);
}
}
using Python.Runtime;
/*
From stirap_env.py
......@@ -34,7 +20,7 @@ public struct JsonComplex
*/
public class StirapEnv
{
[System.Serializable]
public struct StepResult
{
/// <summary>
......@@ -48,37 +34,31 @@ public class StirapEnv
public float[] Observation;
//public float Reward;
public bool Done;
public JsonComplex[] InternalWavePoints;
public Complex[] WavePoints;
public float LeftPopulation => Observation[0];
public float RightPopulation => Observation[1];
public float LeftWellPosition => Observation[2];
public float RightWellPosition => Observation[3];
//TODO: change json library.
public static StepResult FromJson(String json)
public StepResult(dynamic result)
{
StepResult stepResult = UnityEngine.JsonUtility.FromJson<StepResult>(json);
stepResult.WavePoints = new Complex[stepResult.InternalWavePoints.Length];
for(int i = 0; i < stepResult.WavePoints.Length; i++)
{
stepResult.WavePoints[i] = stepResult.InternalWavePoints[i].ToComplex();
}
return stepResult;
Observation = PythonManager.Instance.SingleArray(result[0]);
//Reward = result[1];
Done = result[2];
WavePoints = PythonManager.Instance.ComplexArray(result[3]);
}
}
private WebStirapEnv m_webEnv = new WebStirapEnv();
private WebCall m_initCall;
private dynamic m_stirap;
/// <summary>
/// Constructor for StirapEnv. Timesteps is used to figure out for how long the simulation will run. Use -1 for infinity.
/// </summary>
/// <param name="timeSteps">timesteps for simulation. Use -1 for infinite simulation</param>
public StirapEnv(int timeSteps = 400)
{
m_initCall = m_webEnv.Init(timeSteps).Send();
m_stirap = PythonManager.Instance.StirapEnv.StirapEnv(false, new PyInt(timeSteps));
}
/// <summary>
......@@ -88,13 +68,9 @@ public class StirapEnv
/// <param name="noise">displacement (noise) for the function. between -0.25 and 0.25</param>
public StirapEnv(int timeSteps, double noise)
{
m_initCall = m_webEnv.Init(timeSteps,noise).Send();
}
public IEnumerator WaitForInit()
{
return new UnityEngine.WaitUntil(() => m_initCall.IsDone);
m_stirap = PythonManager.Instance.StirapEnv.StirapEnv(false, new PyInt(timeSteps), new PyFloat(noise));
}
/// <summary>
/// Run a single simulation step. movements for the left and right wells between -1 and 1
......@@ -102,44 +78,34 @@ public class StirapEnv
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
public WebCallWithValue<StepResult> Step(float left, float right)
public StepResult Step(float left, float right)
{
left = Math.Min(1, Math.Max(left, -1));
right = Math.Min(1, Math.Max(right, -1));
ICollection<float> action = new float[] {left, right};
WebCall webCall = m_webEnv.Step(left,right);
WebCallWithValue<StepResult> result = new WebCallWithValue<StepResult>(webCall);
webCall.InvokeWhenDone((String data) =>
{
result.Value = StepResult.FromJson(data);
});
webCall.Send();
return result;
return new StepResult(m_stirap.step(Numpy.Array(action)));
}
/// <summary>
/// Reset the simulation
/// </summary>
public IEnumerator Reset()
public void Reset()
{
WebCall webCall = m_webEnv.Reset().Send();
return new UnityEngine.WaitUntil(()=> webCall.IsDone);
m_stirap.reset();
}
/// <summary>
/// </summary>
public int TimeSteps
{
get { return m_webEnv.TimeSteps; }
get { return (int) m_stirap.timesteps; }
}
/// <summary>
/// </summary>
public double Noise
{
get { return m_webEnv.Noise; }
get { return (double) m_stirap.initial_displacement; }
}
}
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
public class WebCallDownloadHandler : DownloadHandlerScript
{
private Action<String> m_action;
private String m_data = null;
private MemoryStream m_buffer = new MemoryStream();
public WebCallDownloadHandler(Action<String> action)
{
m_action = action;
}
protected override string GetText()
{
return m_data == null ? m_data = Encoding.UTF8.GetString(m_buffer.ToArray()) : m_data;
}
protected override bool ReceiveData(byte[] data, int dataLength)
{
m_buffer.Write(data, 0, dataLength);
return base.ReceiveData(data, dataLength);
}
protected override void CompleteContent()
{
base.CompleteContent();
m_action(GetText());
}
}
public class WebCall
{
private String m_url;
private WWWForm m_form;
private String m_data;
private volatile Action<String> m_done;
private UnityWebRequest m_webRequest = null;
public WebCall(String url)
{
m_url = url;
m_form = new WWWForm();
}
public bool IsDone
{
get
{
return m_data != null;
}
}
public String Data
{
get
{
return m_data;
}
}
public WWWForm PostForm
{
get
{
return m_form;
}
}
public void InvokeWhenDone(Action<String> action)
{
if (IsDone)
{
action(Data);
}
else
{
m_done += action;
}
}
public WebCall Send()
{
m_webRequest = UnityWebRequest.Post(m_url, m_form);
m_webRequest.downloadHandler = new WebCallDownloadHandler((String data)=>
{
//UnityEngine.Debug.Log("Data: " + data);
m_data = data;
m_done?.Invoke(data);
});
m_webRequest.SendWebRequest();
return this;
}
}
using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//Wrapper so we can return values from coroutine functions.
public class WebCallWithValue<T> : UnityEngine.CustomYieldInstruction
{
private T m_value = default(T);
private WebCall m_webCall;
public WebCallWithValue(WebCall webCall)
{
m_webCall = webCall;
}
private void checkAndThrow()
{
if (!m_webCall.IsDone)
{
throw new WebStirapCallNotYetReturned();
}
}
public event Action<T> OnValueAssignedEvent;
public T Value
{
get
{
checkAndThrow();
return m_value;
}
set
{
m_value = value;
OnValueAssignedEvent?.Invoke(value);
}
}
public override bool keepWaiting => !m_webCall.IsDone;
public static implicit operator T(WebCallWithValue<T> value)
{
return value.Value;
}
}