{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "135c08ed-bb56-402b-8f70-6753236fb3fd", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd" ] }, { "cell_type": "code", "execution_count": 2, "id": "544a9dae-f975-4b9b-8ce8-6acb0cebe67f", "metadata": {}, "outputs": [], "source": [ "import gpflow\n", "import tensorflow as tf" ] }, { "cell_type": "code", "execution_count": 3, "id": "4e4ea353-bcaa-4f11-8482-fc4a1350e6e3", "metadata": {}, "outputs": [], "source": [ "import casadi as cs" ] }, { "cell_type": "code", "execution_count": 4, "id": "6ed9f89d-5004-46d6-bee0-912fda25edfd", "metadata": {}, "outputs": [], "source": [ "from sklearn.preprocessing import MinMaxScaler\n", "from sklearn.exceptions import NotFittedError" ] }, { "cell_type": "markdown", "id": "fdde6962-b16a-4986-b872-ecc692b3e7d9", "metadata": { "id": "0aba0df5-b0e3-4738-bb61-1dad869d1ea3" }, "source": [ "## Load previously exported data" ] }, { "cell_type": "code", "execution_count": 5, "id": "8e31e7be-e669-4c2a-a44d-79c2d61278c6", "metadata": {}, "outputs": [], "source": [ "dfs_train = []\n", "dfs_test = []" ] }, { "cell_type": "code", "execution_count": 6, "id": "2ea88fb9-7fb0-47fe-be7f-ff4401d12f14", "metadata": {}, "outputs": [], "source": [ "train_exps = ['Exp1', 'Exp3', 'Exp5', 'Exp6']\n", "test_exps = ['Exp2', 'Exp4', 'Exp7']" ] }, { "cell_type": "code", "execution_count": 7, "id": "573381ca-2162-4a90-8e68-af4f5c61a1c9", "metadata": {}, "outputs": [], "source": [ "for exp in train_exps:\n", " dfs_train.append(pd.read_csv(f\"../Data/Good_CARNOT/{exp}_table.csv\").rename(columns = {'Power': 'SimulatedHeat'}))\n", " \n", "for exp in test_exps:\n", " dfs_test.append(pd.read_csv(f\"../Data/Good_CARNOT/{exp}_table.csv\").rename(columns = {'Power': 'SimulatedHeat'}))" ] }, { "cell_type": "code", "execution_count": 8, "id": "6c6d2eb9-7052-4161-82af-812d1cdae872", "metadata": {}, "outputs": [], "source": [ "#t_cols = ['time_h', 'time_m']\n", "t_cols = []\n", "w_cols = ['SolRad', 'OutsideTemp']\n", "u_cols = ['SimulatedHeat']\n", "y_cols = ['SimulatedTemp']" ] }, { "cell_type": "code", "execution_count": 9, "id": "4f0fa4b8-3aa3-479c-b6ee-5268896cb4e5", "metadata": {}, "outputs": [], "source": [ "t_lags = 0\n", "w_lags = 1\n", "u_lags = 2\n", "y_lags = 3" ] }, { "cell_type": "code", "execution_count": 10, "id": "56c6ceb7-b448-419f-9502-1fd96f674711", "metadata": {}, "outputs": [], "source": [ "dict_cols = {\n", " 't': (t_lags, t_cols),\n", " 'w': (w_lags, w_cols),\n", " 'u': (u_lags, u_cols),\n", " 'y': (y_lags, y_cols)\n", "}" ] }, { "cell_type": "markdown", "id": "ad177bfe-dbbd-4808-9f52-8cb5118dd928", "metadata": {}, "source": [ "Create the scaler and set up input data scaling:" ] }, { "cell_type": "code", "execution_count": 11, "id": "4cd8297e-19c3-4615-a493-577a585f23d2", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "7uZWtjPo6XhD", "outputId": "e0c4a8be-881e-4adc-a344-0b7e4ee9bc75" }, "outputs": [], "source": [ "scaler = MinMaxScaler(feature_range = (-1, 1))" ] }, { "cell_type": "code", "execution_count": 12, "id": "025a3183-0cd9-45fe-98ca-d12ae5bc6307", "metadata": {}, "outputs": [], "source": [ "def get_scaled_df(df, dict_cols, scaler):\n", " \n", " t_list = dict_cols['t'][1]\n", " w_list = dict_cols['w'][1]\n", " u_list = dict_cols['u'][1]\n", " y_list = dict_cols['y'][1]\n", " \n", " df_local = df[t_list + w_list + u_list + y_list]\n", " df_scaled = df_local.to_numpy()\n", " \n", " try:\n", " df_scaled = scaler.transform(df_scaled)\n", " except NotFittedError:\n", " df_scaled = scaler.fit_transform(df_scaled)\n", " \n", " df_scaled = pd.DataFrame(df_scaled, index = df_local.index, columns = df_local.columns)\n", " \n", " return df_scaled" ] }, { "cell_type": "code", "execution_count": 13, "id": "17ccf631-9789-4787-bcb4-83f45a36dddc", "metadata": {}, "outputs": [], "source": [ "df_train = pd.concat(dfs_train)" ] }, { "cell_type": "code", "execution_count": 14, "id": "d62d612e-9b00-4d7a-9c3f-12c4d418dc9c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
SolRadOutsideTempSimulatedHeatSimulatedTemp
057.93658222.0-3150023.000000
154.91444322.0-3150020.585367
273.94470622.0-3150020.300922
376.20633422.0-3150020.034647
465.12005722.0-3150019.786064
\n", "
" ], "text/plain": [ " SolRad OutsideTemp SimulatedHeat SimulatedTemp\n", "0 57.936582 22.0 -31500 23.000000\n", "1 54.914443 22.0 -31500 20.585367\n", "2 73.944706 22.0 -31500 20.300922\n", "3 76.206334 22.0 -31500 20.034647\n", "4 65.120057 22.0 -31500 19.786064" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_train = df_train[t_cols + w_cols + u_cols + y_cols]\n", "df_train.head()" ] }, { "cell_type": "markdown", "id": "0fbc4b0d-a91a-4a00-bce5-da119fe2c271", "metadata": {}, "source": [ "Condition number of the raw input data:" ] }, { "cell_type": "code", "execution_count": 15, "id": "e9eace0f-3f1e-4746-b396-ad1af97690f0", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "16199.169760599052" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.linalg.cond(df_train.to_numpy())" ] }, { "cell_type": "markdown", "id": "3d5ccf02-919d-4781-a194-19f3599202d7", "metadata": {}, "source": [ "Fit the scaler and scale the data:" ] }, { "cell_type": "code", "execution_count": 16, "id": "913c6705-e8e7-4b40-9aed-6ec5e1d1b010", "metadata": {}, "outputs": [], "source": [ "df_train_sc = get_scaled_df(df_train, dict_cols, scaler)" ] }, { "cell_type": "markdown", "id": "5728348e-2aac-4975-b308-0de3c3347933", "metadata": {}, "source": [ "Check the condition number of the input data:" ] }, { "cell_type": "code", "execution_count": 17, "id": "847a66b9-a7b8-47b5-974e-7ca79369088a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4.946636675064373" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.linalg.cond(df_train_sc.to_numpy())" ] }, { "cell_type": "markdown", "id": "51ab5f01-60be-4ed4-9b2a-d9038b086236", "metadata": {}, "source": [ "NOTE: Condition number of scaled data is much smaller. This makes sense." ] }, { "cell_type": "markdown", "id": "d76e19ec-5c52-43f5-9043-a8e25e730bdd", "metadata": {}, "source": [ "Scale the data for each experiment individually. Used for validation graphs:" ] }, { "cell_type": "code", "execution_count": 18, "id": "fbb2019d-c5d1-463e-bca6-a57adcb3373a", "metadata": {}, "outputs": [], "source": [ "dfs_train_sc = []\n", "dfs_test_sc = []\n", "for df in dfs_train:\n", " df_sc = get_scaled_df(df, dict_cols, scaler)\n", " dfs_train_sc.append(df_sc)\n", " \n", "for df in dfs_test:\n", " df_sc = get_scaled_df(df, dict_cols, scaler)\n", " dfs_test_sc.append(df_sc)" ] }, { "cell_type": "markdown", "id": "3ce1f200-136f-4ea2-aa51-dadf4b2a0cf3", "metadata": {}, "source": [ "Set up the function which generated the GPR input matrix from the experimental data (including all autoregressive inputs, etc.):" ] }, { "cell_type": "code", "execution_count": 19, "id": "adc3cd49-b4f6-43a6-ad24-76e8fbce1746", "metadata": {}, "outputs": [], "source": [ "def data_to_gpr(df, dict_cols):\n", " \n", " t_list = dict_cols['t'][1]\n", " w_list = dict_cols['w'][1]\n", " u_list = dict_cols['u'][1]\n", " y_list = dict_cols['y'][1]\n", " \n", " df_gpr = df[t_list + w_list + u_list + y_list].copy()\n", " \n", " for lags, names in dict_cols.values():\n", " for name in names:\n", " col_idx = df_gpr.columns.get_loc(name)\n", " for lag in range(1, lags + 1):\n", " df_gpr.insert(col_idx + lag, f\"{name}_{lag}\", df_gpr.loc[:, name].shift(lag))\n", "\n", " df_gpr.dropna(inplace = True)\n", " \n", " return df_gpr" ] }, { "cell_type": "code", "execution_count": 20, "id": "ce6e9294-7a9d-440f-b017-85467719f2dd", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
SolRadSolRad_1OutsideTempOutsideTemp_1SimulatedHeatSimulatedHeat_1SimulatedHeat_2SimulatedTempSimulatedTemp_1SimulatedTemp_2SimulatedTemp_3
3-0.855164-0.8594630.0588240.058824-1.0-1.0-1.0-0.295224-0.270561-0.244215-0.020567
4-0.876235-0.8551640.0588240.058824-1.0-1.0-1.0-0.318248-0.295224-0.270561-0.244215
5-0.911207-0.8762350.0588240.058824-1.0-1.0-1.0-0.340062-0.318248-0.295224-0.270561
6-0.933425-0.9112070.0588240.0588241.0-1.0-1.0-0.361066-0.340062-0.318248-0.295224
7-0.952322-0.9334250.0588240.058824-1.01.0-1.00.051533-0.361066-0.340062-0.318248
\n", "
" ], "text/plain": [ " SolRad SolRad_1 OutsideTemp OutsideTemp_1 SimulatedHeat \\\n", "3 -0.855164 -0.859463 0.058824 0.058824 -1.0 \n", "4 -0.876235 -0.855164 0.058824 0.058824 -1.0 \n", "5 -0.911207 -0.876235 0.058824 0.058824 -1.0 \n", "6 -0.933425 -0.911207 0.058824 0.058824 1.0 \n", "7 -0.952322 -0.933425 0.058824 0.058824 -1.0 \n", "\n", " SimulatedHeat_1 SimulatedHeat_2 SimulatedTemp SimulatedTemp_1 \\\n", "3 -1.0 -1.0 -0.295224 -0.270561 \n", "4 -1.0 -1.0 -0.318248 -0.295224 \n", "5 -1.0 -1.0 -0.340062 -0.318248 \n", "6 -1.0 -1.0 -0.361066 -0.340062 \n", "7 1.0 -1.0 0.051533 -0.361066 \n", "\n", " SimulatedTemp_2 SimulatedTemp_3 \n", "3 -0.244215 -0.020567 \n", "4 -0.270561 -0.244215 \n", "5 -0.295224 -0.270561 \n", "6 -0.318248 -0.295224 \n", "7 -0.340062 -0.318248 " ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dfs_gpr_train = []\n", "for df_sc in dfs_train_sc:\n", " dfs_gpr_train.append(data_to_gpr(df_sc, dict_cols))\n", "df_gpr_train = pd.concat(dfs_gpr_train)\n", "df_gpr_train.head()" ] }, { "cell_type": "code", "execution_count": 21, "id": "395b093c-04f8-437f-a2b4-4350ce851226", "metadata": {}, "outputs": [], "source": [ "df_gpr_train = df_gpr_train.sample(n = 500)" ] }, { "cell_type": "code", "execution_count": 22, "id": "7bcc9265-9ff0-4630-abdf-321d75180da7", "metadata": {}, "outputs": [], "source": [ "dfs_gpr_test = []\n", "for df_sc in dfs_test_sc:\n", " dfs_gpr_test.append(data_to_gpr(df_sc, dict_cols))" ] }, { "cell_type": "code", "execution_count": 23, "id": "609b6a99-d122-4af9-a5e6-84005f899f2b", "metadata": { "id": "eZAetwUd6YuE" }, "outputs": [], "source": [ "df_input_train = df_gpr_train.drop(columns = dict_cols['w'][1] + dict_cols['u'][1] + dict_cols['y'][1])\n", "df_output_train = df_gpr_train[dict_cols['y'][1]]\n", "\n", "np_input_train = df_input_train.to_numpy()\n", "np_output_train = df_output_train.to_numpy().reshape(-1, 1)" ] }, { "cell_type": "code", "execution_count": 24, "id": "f884ea7d-5dde-404b-8b99-94592d1aa2b9", "metadata": {}, "outputs": [], "source": [ "data_train = (np_input_train, np_output_train)\n", "#pickle.dump(data_train, open(Path(\"data_train.pkl\"), 'wb'))" ] }, { "cell_type": "code", "execution_count": 25, "id": "c3a19716-82ba-4ef8-86bc-47da3a518d06", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
SolRad_1OutsideTemp_1SimulatedHeat_1SimulatedHeat_2SimulatedTemp_1SimulatedTemp_2SimulatedTemp_3
1760.320390-0.4117651.01.00.022707-0.000856-0.024018
491-0.2423510.0588241.01.00.3607710.3367270.312594
111-0.994599-0.6470591.0-1.0-0.674620-0.262339-0.282320
187-0.515202-0.8823531.0-1.0-0.762459-0.736413-0.322186
335-0.994964-0.6470591.01.0-0.406616-0.817147-0.794250
\n", "
" ], "text/plain": [ " SolRad_1 OutsideTemp_1 SimulatedHeat_1 SimulatedHeat_2 \\\n", "176 0.320390 -0.411765 1.0 1.0 \n", "491 -0.242351 0.058824 1.0 1.0 \n", "111 -0.994599 -0.647059 1.0 -1.0 \n", "187 -0.515202 -0.882353 1.0 -1.0 \n", "335 -0.994964 -0.647059 1.0 1.0 \n", "\n", " SimulatedTemp_1 SimulatedTemp_2 SimulatedTemp_3 \n", "176 0.022707 -0.000856 -0.024018 \n", "491 0.360771 0.336727 0.312594 \n", "111 -0.674620 -0.262339 -0.282320 \n", "187 -0.762459 -0.736413 -0.322186 \n", "335 -0.406616 -0.817147 -0.794250 " ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_input_train.head()" ] }, { "cell_type": "code", "execution_count": 26, "id": "46b1c9ca-557c-40f8-a8a9-187f1f6bbba6", "metadata": { "id": "l_VzOWL66aD3" }, "outputs": [], "source": [ "## Define Kernel" ] }, { "cell_type": "code", "execution_count": 27, "id": "8bfeac5e-22ae-408f-a928-03c66e4280ff", "metadata": { "id": "oBHgoYNf6b6t" }, "outputs": [], "source": [ "nb_dims = np_input_train.shape[1]\n", "rational_dims = np.arange(0, (dict_cols['t'][0] + 1) * len(dict_cols['t'][1]), 1)\n", "nb_rational_dims = len(rational_dims)\n", "squared_dims = np.arange(nb_rational_dims, nb_dims, 1)\n", "nb_squared_dims = len(squared_dims)" ] }, { "cell_type": "code", "execution_count": 28, "id": "0672bd9e-f2e7-48f4-9d30-7f00171b7a9b", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "_WagEJum8uUG", "outputId": "c65ec503-b964-49f6-fe3a-51c57a175f9b" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "rational: 0\n", "squared: 7\n" ] } ], "source": [ "print(f\"rational: {nb_rational_dims}\")\n", "print(f\"squared: {nb_squared_dims}\")" ] }, { "cell_type": "code", "execution_count": 29, "id": "d2e67ab9-c903-4605-9167-76fe0b811e3a", "metadata": { "id": "kTIQlLIP6dJz" }, "outputs": [], "source": [ "squared_l = np.linspace(1, 1, nb_squared_dims)\n", "rational_l = np.linspace(1, 1, nb_rational_dims)" ] }, { "cell_type": "code", "execution_count": 30, "id": "ab407ff8-aac1-48c5-94aa-ee693a451a38", "metadata": { "id": "MEGkQJvY_izQ" }, "outputs": [], "source": [ "variance = tf.math.reduce_variance(np_input_train)" ] }, { "cell_type": "code", "execution_count": 303, "id": "b28d8306-8d13-46e7-a6ec-c3e0549bf07b", "metadata": { "id": "WZfssVHG6edn" }, "outputs": [], "source": [ "k0 = gpflow.kernels.SquaredExponential(lengthscales = squared_l, active_dims = squared_dims, variance = variance)\n", "k1 = gpflow.kernels.Constant(variance = variance)\n", "k2 = gpflow.kernels.RationalQuadratic(lengthscales = rational_l, active_dims = rational_dims, variance = variance)\n", "k3 = gpflow.kernels.Periodic(k2)" ] }, { "cell_type": "code", "execution_count": 458, "id": "cb2867d9-85ff-4c4e-84ae-182cec152dd6", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 169 }, "id": "vo8rcdBm6fuc", "outputId": "75485dcd-961c-40d9-cf1f-d10516e2b80f" }, "outputs": [], "source": [ "k = (k0 + k1) * k2\n", "k = k0" ] }, { "cell_type": "markdown", "id": "bbde76b9-07ec-4292-b419-3b49663c008b", "metadata": { "id": "4af25a43-15c9-4543-af73-3c313b5fc7af" }, "source": [ "## Compile Model" ] }, { "cell_type": "code", "execution_count": 459, "id": "fd569132-6a46-4029-9eb5-8d1878f172d7", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 190 }, "id": "PC4cbp926j29", "outputId": "72c9441d-2657-4e0f-de70-11a197d07ad3" }, "outputs": [], "source": [ "m = gpflow.models.GPR(\n", " data = data_train, \n", " kernel = k, \n", " mean_function = None,\n", " )" ] }, { "cell_type": "markdown", "id": "fd24e71e-9c98-4577-82de-0aeffd966286", "metadata": { "id": "08f41235-12df-4e9c-bf63-e7a4390cf21a" }, "source": [ "## Train Model" ] }, { "cell_type": "code", "execution_count": 460, "id": "9c70c87e-22c0-456b-9a09-fc98f273cdbf", "metadata": { "id": "Pn5TwPPT6ogs" }, "outputs": [], "source": [ "opt = gpflow.optimizers.Scipy()" ] }, { "cell_type": "code", "execution_count": 461, "id": "405d1197-23df-4d00-8fef-9fa26b63e236", "metadata": { "id": "slQg9Ohv6oxR" }, "outputs": [], "source": [ "from datetime import datetime" ] }, { "cell_type": "code", "execution_count": 462, "id": "81cff1a8-dd95-4cf1-96b2-c92af0843068", "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 212 }, "id": "GhsxZhc56p43", "outputId": "778ec150-cfc3-44b7-9e21-e52bf69d494a", "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Finished fitting in 0:00:01.293315\n" ] } ], "source": [ "start_time = datetime.now()\n", "opt.minimize(m.training_loss, m.trainable_variables)\n", "print(f\"Finished fitting in {datetime.now() - start_time}\")" ] }, { "cell_type": "markdown", "id": "8bf5c4b8-1c6e-4f39-8665-c3518f54c207", "metadata": {}, "source": [ "## CasADi Optimization part" ] }, { "cell_type": "code", "execution_count": 350, "id": "cefb26f7-0c9a-4b8a-b658-ee6eb6f16ea0", "metadata": {}, "outputs": [], "source": [ "def get_tf_evaluator(model):\n", " @tf.function\n", " def tensor_model_eval(tf_input):\n", " preds = model.predict_f(tf_input)\n", " return preds\n", " return tensor_model_eval" ] }, { "cell_type": "code", "execution_count": 364, "id": "706a8865-9a1a-42b4-bcfe-7802256cad0f", "metadata": {}, "outputs": [], "source": [ "tensor_model_eval = get_tf_evaluator(m)" ] }, { "cell_type": "code", "execution_count": 399, "id": "69aa5a0d-53ff-41a3-a22f-08d74a102407", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(,\n", " )" ] }, "execution_count": 399, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.predict_f(tf_test)" ] }, { "cell_type": "code", "execution_count": 400, "id": "2493b2c2-ef9a-4370-9887-31eb43e181e6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(,\n", " )" ] }, "execution_count": 400, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tensor_model_eval(tf_test)" ] }, { "cell_type": "code", "execution_count": 401, "id": "efefc120-53e4-4ab4-9899-7d79f62ac7b7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "DM(-7.03164e-195)" ] }, "execution_count": 401, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cs_model(np_test)" ] }, { "cell_type": "code", "execution_count": 405, "id": "67c4057a-5b73-408b-be06-10828a10da4f", "metadata": {}, "outputs": [], "source": [ "cs_model.update_model(m)" ] }, { "cell_type": "code", "execution_count": 407, "id": "c40e3957-19cf-43fe-accf-aacb58f7587e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "DM(1.03053)" ] }, "execution_count": 407, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cs_model(np_test)" ] }, { "cell_type": "code", "execution_count": 516, "id": "1864beb3-7896-42cd-8553-1bacf1bf5aaf", "metadata": {}, "outputs": [], "source": [ "# Package the resulting regression model in a CasADi callback\n", "class GPR(cs.Callback):\n", " def __init__(self, name, model, opts={}):\n", " cs.Callback.__init__(self)\n", "\n", " print(\"Instance of GPR callback\")\n", " self.model = model\n", " self.tf_evaluator = get_tf_evaluator(model)\n", " self.n_in = model.data[0].shape[1]\n", " self.tf_var = tf.Variable(np.ones((1, self.n_in)), dtype = tf.float64)\n", " # Create a variable to keep all the gradient callback references\n", " self.refs = []\n", "\n", " self.construct(name, opts)\n", " \n", " # Update tf_evaluator\n", " def update_model(self, model):\n", " self.model = model\n", " self.tf_evaluator = get_tf_evaluator(model)\n", " \n", " # Number of inputs/outputs\n", " def get_n_in(self): return 1\n", " def get_n_out(self): return 1\n", " \n", "\n", " # Sparsity of the input/output\n", " def get_sparsity_in(self,i):\n", " return cs.Sparsity.dense(1,self.n_in)\n", " def get_sparsity_out(self,i):\n", " return cs.Sparsity.dense(1,1)\n", "\n", "\n", " def eval(self, arg):\n", " self.tf_var.assign(arg[0])\n", " [mean, _] = self.tf_evaluator(self.tf_var)\n", " #[mean, _] = self.model.predict_f(arg[0])\n", " return [mean.numpy()]\n", " \n", " def has_reverse(self, nadj): return nadj==1\n", " def get_reverse(self, nadj, name, inames, onames, opts):\n", " grad_callback = GPR_grad(name, self.n_in, self.tf_evaluator, self.tf_var)\n", " self.refs.append(grad_callback)\n", " \n", " nominal_in = self.mx_in()\n", " nominal_out = self.mx_out()\n", " adj_seed = self.mx_out()\n", " return cs.Function(name, nominal_in+nominal_out+adj_seed, grad_callback.call(nominal_in), inames, onames)" ] }, { "cell_type": "code", "execution_count": 517, "id": "6084bd09-4a0f-43bc-8090-fec07556556f", "metadata": {}, "outputs": [], "source": [ "class GPR_grad(cs.Callback):\n", " def __init__(self, name, n_in, tf_evaluator, tf_var, opts={}):\n", " cs.Callback.__init__(self)\n", " self.tf_evaluator = tf_evaluator\n", " self.n_in = n_in\n", " self.tf_var = tf_var\n", "\n", "\n", " self.construct(name, opts)\n", "\n", " \n", " def get_n_in(self): return 1\n", " def get_n_out(self): return 1\n", " \n", " def get_sparsity_in(self,i):\n", " return cs.Sparsity.dense(1,self.n_in)\n", " def get_sparsity_out(self,i):\n", " return cs.Sparsity.dense(1,self.n_in)\n", " \n", "\n", " def eval(self, arg):\n", " self.tf_var.assign(arg[0])\n", " with tf.GradientTape() as tape:\n", " preds = self.tf_evaluator(self.tf_var)\n", "\n", " grads = tape.gradient(preds, self.tf_var)\n", " return [grads.numpy()]" ] }, { "cell_type": "code", "execution_count": 519, "id": "eb5224ae-09b0-4cb5-92f1-8476cfa32469", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Instance of GPR callback\n" ] } ], "source": [ "cs_model = GPR(\"gpr\", m)" ] }, { "cell_type": "code", "execution_count": 419, "id": "9294cdc6-e2de-4230-9214-440712df5bb3", "metadata": {}, "outputs": [], "source": [ "np_test = np.ones((1, 7))\n", "tf_test = tf.Variable(np_test, dtype = tf.float64)" ] }, { "cell_type": "code", "execution_count": 422, "id": "4545f9d9-8488-4e75-9143-b63671395143", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5.13 ms ± 115 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], "source": [ "%%timeit\n", "tf_test.assign(2 * np_test)\n", "tensor_model_eval(tf_test)" ] }, { "cell_type": "code", "execution_count": 421, "id": "779dc6b2-b6b3-478f-ace2-edb9443233cf", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "13.9 ms ± 533 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], "source": [ "%%timeit\n", "casual_model_eval(np_test)" ] }, { "cell_type": "code", "execution_count": 273, "id": "4529796e-879c-4984-bce7-e17051546b5e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "41.8 ms ± 381 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" ] } ], "source": [ "%%timeit\n", "tf_iter = tf.Variable(np_test, dtype = tf.float64)\n", "with tf.GradientTape() as tape:\n", " preds = m.predict_f(tf_iter)\n", "grads = tape.gradient(preds, tf_iter)\n", "grads" ] }, { "cell_type": "code", "execution_count": 117, "id": "088c73cf-5512-443e-b9db-4f8ed2311414", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "22.7 ms ± 733 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" ] } ], "source": [ "%%timeit\n", "with tf.GradientTape() as tape:\n", " preds = tensor_model_eval(tf_test)\n", "grads = tape.gradient(preds, tf_test)" ] }, { "cell_type": "markdown", "id": "074b2c86-9a01-4963-8dda-57f442261a4b", "metadata": {}, "source": [ "### Multiple shooting problem formulation" ] }, { "cell_type": "code", "execution_count": 520, "id": "debd1d82-f50b-4ddf-aa34-bdd808c5e6d0", "metadata": {}, "outputs": [], "source": [ "N_horizon = 8\n", "n_states = 7" ] }, { "cell_type": "code", "execution_count": 521, "id": "259d01bf-abad-43a7-8a14-0c5725b3aef9", "metadata": {}, "outputs": [], "source": [ "X = cs.MX.sym(\"X\", N_horizon + 1, n_states)\n", "lbd = cs.MX.sym(\"lambda\")\n", "x0 = cs.MX.sym(\"x0\", 1, n_states)\n", "W = cs.MX.sym(\"W\", N_horizon, 2)" ] }, { "cell_type": "code", "execution_count": 522, "id": "fdda49b3-7751-43a5-a4ff-858631ebf73a", "metadata": {}, "outputs": [], "source": [ "g = []\n", "lbg = []\n", "ubg = []\n", "\n", "lbx = -np.inf*np.ones(X.shape)\n", "ubx = np.inf*np.ones(X.shape)\n", "\n", "T_set_sc = 2.5\n", "##\n", "# Set up the opjective function\n", "##\n", "\n", "# stage cost\n", "u_cost = cs.dot(X[:, 2], X[:, 2])\n", "\n", "# temperature constraint\n", "y_cost = 0.01 * cs.dot(X[:, 4], X[:, 4])\n", "\n", "J = u_cost + y_cost" ] }, { "cell_type": "code", "execution_count": 523, "id": "1e2ae7b4-a311-4080-8c22-cf0d10693fcc", "metadata": {}, "outputs": [], "source": [ "# Set up equality constraints for the first step\n", "for idx in range(n_states):\n", " g.append(X[0, idx] - x0[0, idx])\n", " lbg.append(0)\n", " ubg.append(0)" ] }, { "cell_type": "code", "execution_count": 524, "id": "373aee32-112d-4d55-b553-a6d360e98748", "metadata": {}, "outputs": [], "source": [ "# Set up equality constraints for the following steps\n", "for idx in range(1, N_horizon + 1):\n", " base_col = 0\n", " # w\n", " nb_cols = dict_cols['w'][0]\n", " for w_idx in range(W.shape[1]):\n", " w_base_col = w_idx * nb_cols\n", " g.append(X[idx, base_col + w_base_col] - W[idx - 1, w_idx])\n", " lbg.append(0)\n", " ubg.append(0)\n", " for w_lag_idx in range(1, nb_cols):\n", " g.append(X[idx, base_col + w_base_col + w_lag_idx] - X[idx - 1, base_col + w_base_col + w_lag_idx - 1])\n", " lbg.append(0)\n", " ubg.append(0)\n", " \n", " base_col += nb_cols * W.shape[1]\n", " # u\n", " nb_cols = dict_cols['u'][0]\n", "\n", " lbx[idx, base_col] = -1 #lower bound on input\n", " ubx[idx, base_col] = 1 #upper bound on input\n", " for u_lag_idx in range(1, nb_cols):\n", " g.append(X[idx, base_col + u_lag_idx] - X[idx - 1, base_col + u_lag_idx - 1])\n", " lbg.append(0)\n", " ubg.append(0)\n", " \n", " base_col += nb_cols\n", " # y\n", " nb_cols = dict_cols['y'][0]\n", " g.append(X[idx, base_col] - cs_model(X[idx - 1, :]))\n", " lbg.append(0)\n", " ubg.append(0)\n", " for y_lag_idx in range(1, nb_cols):\n", " g.append(X[idx, base_col + y_lag_idx] - X[idx - 1, base_col + y_lag_idx - 1])\n", " lbg.append(0)\n", " ubg.append(0)" ] }, { "cell_type": "code", "execution_count": 525, "id": "c0ba0f93-f284-41a4-b70e-61ee04c8591a", "metadata": {}, "outputs": [], "source": [ "p = cs.vertcat(cs.vec(W), cs.vec(x0))" ] }, { "cell_type": "code", "execution_count": 526, "id": "0e33b5fa-9f3e-47f5-8369-c4f62ae09bcc", "metadata": {}, "outputs": [], "source": [ "prob = {'f': J, 'x': cs.vec(X), 'g': cs.vertcat(*g), 'p': p}\n", "options = {\"ipopt\": {\"hessian_approximation\": \"limited-memory\", \"max_iter\": 100,\n", " \"acceptable_tol\": 1e-4, \"tol\": 1e-4,\n", " \"linear_solver\": \"ma27\",\n", " #\"warm_start_init_point\": \"yes\"\n", " #\"acceptable_obj_change_tol\": 1e-5, \n", " #\"mu_strategy\": \"adaptive\",\n", " }}\n", "solver = cs.nlpsol(\"solver\",\"ipopt\",prob, options)" ] }, { "cell_type": "code", "execution_count": 527, "id": "92802031-6a68-45b9-b894-f9ea44fbb2b5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0.19784954, 0.75380109, 0.20258375, 0.48384381, 0.26975897,\n", " 0.59621339, 0.89703682]])" ] }, "execution_count": 527, "metadata": {}, "output_type": "execute_result" } ], "source": [ "real_x0 = np.random.rand(*x0.shape)\n", "real_x0" ] }, { "cell_type": "code", "execution_count": 528, "id": "f7d9ee2b-7e75-4dbd-899b-1a002bcd3d3f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0.870293 , 0.08461537],\n", " [0.65722421, 0.34585863],\n", " [0.70636811, 0.12671317],\n", " [0.78048239, 0.64362432],\n", " [0.50636252, 0.66469496],\n", " [0.77969876, 0.09749162],\n", " [0.25604673, 0.25789882],\n", " [0.1594542 , 0.46832943]])" ] }, "execution_count": 528, "metadata": {}, "output_type": "execute_result" } ], "source": [ "real_W = np.random.rand(*W.shape)\n", "real_W" ] }, { "cell_type": "code", "execution_count": 529, "id": "4eccd416-9939-43aa-b81f-4ce981d7e353", "metadata": {}, "outputs": [], "source": [ "real_p = cs.vertcat(cs.vec(real_W), cs.vec(real_x0))" ] }, { "cell_type": "code", "execution_count": 530, "id": "f6e595f5-3126-445a-877e-b54168f8d7de", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "DM(1.03058)" ] }, "execution_count": 530, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cs_model(np_test)" ] }, { "cell_type": "code", "execution_count": 512, "id": "80b023cf-6563-4517-9d83-d39bba9dd6da", "metadata": {}, "outputs": [], "source": [ "cs_model.update_model(m)" ] }, { "cell_type": "code", "execution_count": 513, "id": "cf3fd768-4b47-4a69-bc3f-96e7343608ae", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "DM(1.03058)" ] }, "execution_count": 513, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cs_model(np_test)" ] }, { "cell_type": "code", "execution_count": 536, "id": "1e94b993-7e81-46be-9e20-94b964c27347", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This is Ipopt version 3.13.4, running with linear solver ma27.\n", "\n", "Number of nonzeros in equality constraint Jacobian...: 135\n", "Number of nonzeros in inequality constraint Jacobian.: 0\n", "Number of nonzeros in Lagrangian Hessian.............: 0\n", "\n", "Total number of variables............................: 63\n", " variables with only lower bounds: 0\n", " variables with lower and upper bounds: 8\n", " variables with only upper bounds: 0\n", "Total number of equality constraints.................: 55\n", "Total number of inequality constraints...............: 0\n", " inequality constraints with only lower bounds: 0\n", " inequality constraints with lower and upper bounds: 0\n", " inequality constraints with only upper bounds: 0\n", "\n", "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", " 0 0.0000000e+00 8.97e-01 0.00e+00 0.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", " 1 5.7575353e-02 2.49e-03 8.97e-01 -6.0 8.97e-01 - 9.43e-01 1.00e+00h 1\n", " 2 6.3726414e-02 9.47e-07 3.51e-01 -1.9 1.05e-01 - 9.95e-01 1.00e+00h 1\n", " 3 4.6035747e-02 6.50e-07 4.49e-03 -3.1 5.84e-02 - 1.00e+00 1.00e+00f 1\n", " 4 4.6032694e-02 1.12e-08 1.98e-05 -5.3 8.15e-04 - 1.00e+00 1.00e+00h 1\n", "\n", "Number of Iterations....: 4\n", "\n", " (scaled) (unscaled)\n", "Objective...............: 4.6032694495482543e-02 4.6032694495482543e-02\n", "Dual infeasibility......: 1.9751167684148774e-05 1.9751167684148774e-05\n", "Constraint violation....: 1.1249818632208530e-08 1.1249818632208530e-08\n", "Complementarity.........: 5.7908803598244531e-06 5.7908803598244531e-06\n", "Overall NLP error.......: 1.9751167684148774e-05 1.9751167684148774e-05\n", "\n", "\n", "Number of objective function evaluations = 5\n", "Number of objective gradient evaluations = 5\n", "Number of equality constraint evaluations = 5\n", "Number of inequality constraint evaluations = 0\n", "Number of equality constraint Jacobian evaluations = 5\n", "Number of inequality constraint Jacobian evaluations = 0\n", "Number of Lagrangian Hessian evaluations = 0\n", "Total CPU secs in IPOPT (w/o function evaluations) = 1.002\n", "Total CPU secs in NLP function evaluations = 5.199\n", "\n", "EXIT: Optimal Solution Found.\n", " solver : t_proc (avg) t_wall (avg) n_eval\n", " nlp_f | 31.00us ( 6.20us) 31.34us ( 6.27us) 5\n", " nlp_g | 376.39ms ( 75.28ms) 177.69ms ( 35.54ms) 5\n", " nlp_grad | 888.99ms (888.99ms) 217.22ms (217.22ms) 1\n", " nlp_grad_f | 65.00us ( 10.83us) 63.12us ( 10.52us) 6\n", " nlp_jac_g | 5.94 s (989.93ms) 1.60 s (266.53ms) 6\n", " total | 7.21 s ( 7.21 s) 2.00 s ( 2.00 s) 1\n" ] } ], "source": [ "res = solver(lbx = cs.vec(lbx), ubx = cs.vec(ubx), p = real_p, lbg = lbg, ubg = ubg)" ] }, { "cell_type": "code", "execution_count": 445, "id": "902f3a30-4fca-4e10-84a4-2fc380bdff81", "metadata": {}, "outputs": [], "source": [ "## Old result" ] }, { "cell_type": "code", "execution_count": 443, "id": "ca224e84-6c4a-4205-bf8d-006e67599f02", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "DM(\n", "[[0.761242, 0.36861, 0.556879, 0.104919, 0.160625, 0.774017, 0.547034], \n", " [0.480629, 0.922048, -0.000639741, 0.556879, 0.2753, 0.160625, 0.774017], \n", " [0.00685743, 0.247726, -0.000615418, -0.000639741, 0.187375, 0.2753, 0.160625], \n", " [0.447852, 0.283534, -0.000597185, -0.000615418, 0.192971, 0.187375, 0.2753], \n", " [0.624033, 0.160237, -0.000576846, -0.000597185, 0.200781, 0.192971, 0.187375], \n", " [0.771545, 0.00394968, -0.000558971, -0.000576846, 0.205897, 0.200781, 0.192971], \n", " [0.660621, 0.609428, -0.000568339, -0.000558971, 0.206814, 0.205897, 0.200781], \n", " [0.914765, 0.539141, -0.000550041, -0.000568339, 0.221992, 0.206814, 0.205897], \n", " [0.0561185, 0.209053, 0, -0.000550041, 0.236093, 0.221992, 0.206814]])" ] }, "execution_count": 443, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res['x'].reshape((N_horizon + 1, n_states))" ] }, { "cell_type": "code", "execution_count": 444, "id": "6a3dd26b-64ca-4a88-be86-248f800f2f88", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "DM(0.2753)" ] }, "execution_count": 444, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cs_model([0.761242, 0.36861, 0.556879, 0.104919, 0.160625, 0.774017, 0.547034])" ] }, { "cell_type": "code", "execution_count": 446, "id": "865b7e52-1b57-4aee-a027-89639d12d0f3", "metadata": {}, "outputs": [], "source": [ "## New result" ] }, { "cell_type": "code", "execution_count": 466, "id": "9f362d2f-5c14-40f7-989d-db691ebc3005", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "DM(\n", "[[0.761242, 0.36861, 0.556879, 0.104919, 0.160625, 0.774017, 0.547034], \n", " [0.480629, 0.922048, -0.000640366, 0.556879, 0.275295, 0.160625, 0.774017], \n", " [0.00685743, 0.247726, -0.000615877, -0.000640366, 0.187418, 0.275295, 0.160625], \n", " [0.447852, 0.283534, -0.00059751, -0.000615877, 0.193019, 0.187418, 0.275295], \n", " [0.624033, 0.160237, -0.000577033, -0.00059751, 0.200834, 0.193019, 0.187418], \n", " [0.771545, 0.00394968, -0.000558939, -0.000577033, 0.205969, 0.200834, 0.193019], \n", " [0.660621, 0.609428, -0.000568317, -0.000558939, 0.206929, 0.205969, 0.200834], \n", " [0.914765, 0.539141, -0.000550168, -0.000568317, 0.22211, 0.206929, 0.205969], \n", " [0.0561185, 0.209053, 0, -0.000550168, 0.236208, 0.22211, 0.206929]])" ] }, "execution_count": 466, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res['x'].reshape((N_horizon + 1, n_states))" ] }, { "cell_type": "code", "execution_count": 467, "id": "1c5a8976-257f-4a47-bed9-4529077a78e2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "DM(0.275295)" ] }, "execution_count": 467, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cs_model([0.761242, 0.36861, 0.556879, 0.104919, 0.160625, 0.774017, 0.547034])" ] }, { "cell_type": "code", "execution_count": null, "id": "c3dba702-e4cf-48de-b034-5485b5bfd7ac", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.4" } }, "nbformat": 4, "nbformat_minor": 5 }