From 3cdacf1a26df5c62e5f480f07c4ccd37b3410695 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tobias=20L=C3=B6w?= <tobi.loew@protonmail.ch>
Date: Fri, 29 Nov 2024 12:23:15 +0100
Subject: [PATCH] added probabilistic LQR

---
 python/LQR_probabilistic.py | 66 +++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 python/LQR_probabilistic.py

diff --git a/python/LQR_probabilistic.py b/python/LQR_probabilistic.py
new file mode 100644
index 0000000..2d06ed0
--- /dev/null
+++ b/python/LQR_probabilistic.py
@@ -0,0 +1,66 @@
+import numpy as np
+from math import factorial
+import matplotlib.pyplot as plt
+from scipy.linalg import solve_continuous_are
+from scipy.stats import multivariate_normal
+
+# Parameters
+# ===============================
+param = lambda: None # Lazy way to define an empty class in python
+param.dt = 1e-2  # Time step length
+param.nbDeriv = 2 # Order of the dynamical system
+param.nbVarPos = 2 # Number of position variable
+param.nbVar = param.nbVarPos * param.nbDeriv # Dimension of state vector
+param.nbData = 100  # Number of datapoints
+param.rfactor = 1e-7  # Control weight term
+
+R = np.eye((param.nbData-1) * param.nbVarPos) * param.rfactor  # Control cost matrix
+Q = np.zeros((param.nbVar * param.nbData, param.nbVar * param.nbData)) # Task precision for augmented state
+
+xd = np.zeros([param.nbVar, param.nbData])
+target = np.random.uniform(size=param.nbVarPos)
+xd[:, param.nbData-1] = np.concatenate((target, np.zeros(param.nbVarPos)))
+xd = xd.T.flatten()
+
+Q[param.nbVar*(param.nbData-1):param.nbVar*param.nbData,param.nbVar*(param.nbData-1):param.nbVar*param.nbData] = 10.0 * np.eye(param.nbVar)
+
+A1d = np.zeros((param.nbDeriv,param.nbDeriv))
+B1d = np.zeros((param.nbDeriv,1))
+
+for i in range(param.nbDeriv):
+    A1d += np.diag( np.ones(param.nbDeriv-i), i ) * param.dt**i * 1/factorial(i)
+    B1d[param.nbDeriv-i-1] = param.dt**(i+1) * 1/factorial(i+1)
+
+A = np.eye(param.nbVar)
+A[:param.nbVar, :param.nbVar] = np.kron(A1d, np.identity(param.nbVarPos))
+B = np.zeros((param.nbVar, param.nbVarPos))
+B[:param.nbVar] = np.kron(B1d, np.identity(param.nbVarPos))
+
+Su = np.zeros((param.nbVar*param.nbData, param.nbVarPos * (param.nbData-1))) 
+Sx = np.kron(np.ones((param.nbData,1)), np.eye(param.nbVar,param.nbVar))
+
+M = B
+for i in range(1,param.nbData):
+    Sx[i*param.nbVar:param.nbData*param.nbVar,:] = np.dot(Sx[i*param.nbVar:param.nbData*param.nbVar,:], A)
+    Su[param.nbVar*i:param.nbVar*i+M.shape[0],0:M.shape[1]] = M
+    M = np.hstack((np.dot(A,M),B)) # [0,nb_state_var-1]
+
+
+x0 = np.random.uniform(size=param.nbVar)
+mean = Sx @ x0 + Su @ np.linalg.inv(Su.T @ Q @ Su + R) @ Su.T @ Q @ (xd - Sx @ x0)
+cov = Su @ (Su.T @ Q @ Su + R) @ Su.T
+
+
+trajectories = multivariate_normal.rvs(mean=mean, cov=cov, size=100)
+
+plt.figure()
+for k in range(100):
+    trajectory = trajectories[k, :]
+    trajectory = trajectory.reshape((param.nbData, param.nbVar))
+    plt.plot(trajectory[:, 0], trajectory[:, 1], alpha=0.5)
+
+plt.scatter(x0[0], x0[1], color='green', label='Initial State')
+plt.scatter(target[0], target[1], color='red', label='Target State')
+plt.legend()
+plt.grid()
+plt.show()
-- 
GitLab