## This Notebook serves as a walthrough to irt models & demonstrate following objective:
  1. Obtain Item parameters of a 4 PL (parameter logistic) IRT model by training an equivalent Deep Neural Network.

  2. Realise smaller models such as 1PL via 4PL model trained using hyper parameter search viz. NAS functionality

### Item Response Theory: Brief context
It is also known as psychometric theory or latent response theory. It measures the ability or latent trait of a person by looking at the responses for items or questions asked using statistical models. It assumes as ability increases, probability of correct response also increases. This relationship can be depicted from Item Characteristic Curve (ICC) which is S-shaped or sigmoid curve. It calculates parameters like discrimination, difficulty and guessability for each item and ability for every user.

### Model specification -- keras 4PL
    `4PL model` uses Four parameters difficulty, item discrimination, item guesssability and item slip to calculate the probability of correct response given the ability of person.
. . .

If $i$ be a $question$ and $j$ be a $user$. Then, Probability $P_{ij}$ of an $j^{th}$ $user$ responding correctly to $i^{th}$ $question$, where $a_i$ is the $discrimination$ parameter, $b_i$ is difficulty, $c_j$ is guessability and $s_j$ is probability of slip for all $questions$, is given by:

\begin{equation}\
P_{ij} =  c_i+ [(1-s_i) - c_i]Sigmoid(a_i(\theta_j-b_i))
\end{equation}
Where
\begin{equation}
\text{Sigmoid}(x) =  \frac{e^{x}}{1 + e^{x}}
\end{equation}

_________________________________________________

### 1. Load 1-Parameter logistic IRT dataset with values of item difficulties levels, user abilities & response of various users on various given items.

```python
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

def generate_train_test(train_data, size= 0.1):
    df_new = train_data[['question_code', 'user_id', 'correctness']]
    df_cols = df_new.columns
    xtrain, xtest, ytrain, ytest = train_test_split(df_new[df_cols[:-1]], df_new[df_cols[-1]], test_size=size)
    x_train_user = pd.get_dummies(xtrain['user_id']).values#contains the one-hot encoded user data
    x_train_questions = pd.get_dummies(xtrain['question_code']).values#contains the one-hot encoded questions

    y_train= ytrain.values
    print('shape of x_train_user:', x_train_user.shape,'\nshape of x_train_questions:', x_train_questions.shape,
          '\nshape of y_train:',y_train.shape)
    return train_data, xtrain, y_train, x_train_user, x_train_questions

path= "../datasets/irt_4pl_dataset.csv"
df= pd.read_csv(path)

train_data, xtrain, y_train, x_train_user, x_train_questions = generate_train_test(df, size= 0.05)
df.head(3)
```

    2021-08-05 12:17:12,406	INFO node.py:423 -- Process STDOUT and STDERR is being redirected to /tmp/ray/session_2021-08-05_12-17-12_258/logs.
    2021-08-05 12:17:12,530	INFO services.py:363 -- Waiting for redis server at 127.0.0.1:64240 to respond...
    2021-08-05 12:17:12,663	INFO services.py:363 -- Waiting for redis server at 127.0.0.1:30595 to respond...
    2021-08-05 12:17:12,667	INFO services.py:760 -- Starting Redis shard with 20.0 GB max memory.
    2021-08-05 12:17:12,706	INFO services.py:1384 -- Starting the Plasma object store with 1.0 GB memory using /dev/shm.

    shape of x_train_user: (95000, 100)
    shape of x_train_questions: (95000, 100)
    shape of y_train: (95000,)

      question_code
      user_id
      difficulty
      ability
      response
      correctness

      0
      que_99
      user_99
      1.0
      0.559055
      0.391516
      0

      1
      que_99
      user_99
      1.0
      0.559055
      0.391516
      0

      2
      que_99
      user_99
      1.0
      0.559055
      0.391516
      1

_____________________________________

### 2. Instantiate a 4-Parameter Logistic IRT model, as primal model.

```python
from mlsquare.models import fourPL

primal = fourPL()
primal
```

    fourPL(IRT_param=None, constraint='NULL', control=[], data=None, max_guessing=1,
           na_action='NULL', start_val='NULL', type_='latent_trait')

___________________________________

### 3. Define initialization values for user & item parameters, boundary constraints or search space for hyper parameters.
*Note:* Search space constraints are defined such that high regularization enforces 4PL model to imitates 1PL model, thus fitting the current 1PL dataset theoretically.

**4PL model as 1PL: Passing activity_regularizers l1 to hyperOpt search for layers (discrimination, guess, slip) corresponding to 1PL dataset, that is by pushing the guess_params & slip_params contribution in overall estimation to 0 and  disc_params's contribution to 1.**

```python
from ray.tune.schedulers import AsyncHyperBandScheduler
from ray.tune.suggest.hyperopt import HyperOptSearch
from hyperopt import hp

src_space= {
    "slip_params.group_lasso.l1": hp.uniform("slip_params.group_lasso.l1", 0, 10),
    "guess_params.group_lasso.l1": hp.uniform("guess_params.group_lasso.l1", 0, 10),
    "disc_params.group_lasso.l1": hp.uniform("disc_params.group_lasso.l1", 0, 10),

}
nas_params= {'search_algo_name':'hyperOpt', 'search_space':src_space, 'union':False}

params_= {'disc_params':{'kernel_params':{'stddev':0.2}},
    'guess_params':{'kernel_params':{'stddev':0.2}},
          'slip_params':{'kernel_params':{'stddev':0.2}
                        }
         }
```

_________________________________________

### 4. "Dope" the primal model to obtain an equivalent 4PL Deep Neural Network on 1PL data, passing initializations & search space constraints.

```python
from mlsquare import dope

model_4t1 = dope(primal)
model_4t1.fit(x_user= x_train_user, x_questions= x_train_questions, y_vals= y_train, batch_size= 128, epochs=450,
        params=params_, nas_params=nas_params)

```

    Transpiling your model to it's Deep Neural Network equivalent...
    2021-08-05 12:20:05,090	ERROR worker.py:1412 -- Calling ray.init() again after it has already been called.

    Intitializing fit for fourPL model. . .
    Batch_size: 128; epochs: 450;
    == Status ==
    Using AsyncHyperBand: num_stopped=0
    Bracket: Iter 90.000: None | Iter 30.000: None | Iter 10.000: None
    Bracket: Iter 90.000: None | Iter 30.000: None
    Bracket: Iter 90.000: None
    Resources requested: 0/4 CPUs, 0/1 GPUs
    Memory usage on this node: 1.4/13.6 GB

    2021-08-05 12:20:05,507	ERROR worker.py:1780 -- Warning: The actor WrappedFunc has size 19782331 when pickled. It will be stored in Redis, which could cause memory issues. This may mean that its definition uses a large array or other object.

    == Status ==
    Using AsyncHyperBand: num_stopped=0
    Bracket: Iter 90.000: None | Iter 30.000: None | Iter 10.000: None
    Bracket: Iter 90.000: None | Iter 30.000: None
    Bracket: Iter 90.000: None
    Resources requested: 4/4 CPUs, 0/1 GPUs
    Memory usage on this node: 1.5/13.6 GB
    Result logdir: /root/ray_results/hyperOpt_optimization
    Number of trials: 4 ({'RUNNING': 1, 'PENDING': 3})
    PENDING trials:
     - train_model_2_disc_params.group_lasso.l1=6.5627,guess_params.group_lasso.l1=2.9186,slip_params.group_lasso.l1=1.3818:	PENDING
     - train_model_3_disc_params.group_lasso.l1=6.6343,guess_params.group_lasso.l1=7.145,slip_params.group_lasso.l1=5.1955:	PENDING
     - train_model_4_disc_params.group_lasso.l1=0.8419,guess_params.group_lasso.l1=9.5492,slip_params.group_lasso.l1=4.4229:	PENDING
    RUNNING trials:
     - train_model_1_disc_params.group_lasso.l1=2.7829,guess_params.group_lasso.l1=3.9435,slip_params.group_lasso.l1=5.9648:	RUNNING

    (pid=312) 2021-08-05 12:20:06.470238: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
    (pid=312) 2021-08-05 12:20:07,839	ERROR worker.py:1412 -- Calling ray.init() again after it has already been called.
    (pid=312)
    (pid=312) config val 1:
    (pid=312)  key_list: ['disc_params', 'group_lasso'];
    (pid=312)  values: {'l1': 2.7829298208870936, 'l2': 0}
    (pid=312)
    (pid=312)
    (pid=312)
    (pid=312) config val 2:
    (pid=312)  key_list: ['guess_params', 'group_lasso'];
    (pid=312)  values: {'l1': 3.9434923495322796, 'l2': 0}
    (pid=312)
    (pid=312)
    (pid=312)
    (pid=312) config val 3:
    (pid=312)  key_list: ['slip_params', 'group_lasso'];
    (pid=312)  values: {'l1': 5.964767729148698, 'l2': 0}
    (pid=312)
    (pid=312)
    (pid=312)
    (pid=312) Intitializing fit for fourPL model. . .
    (pid=312) Batch_size: 128; epochs: 450;
    (pid=312) 2021-08-05 12:20:08.742924: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
    (pid=312) 2021-08-05 12:20:08.774150: E tensorflow/stream_executor/cuda/cuda_driver.cc:328] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected
    (pid=312) 2021-08-05 12:20:08.774212: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: d005995f49c5
    (pid=312) 2021-08-05 12:20:08.774229: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: d005995f49c5
    (pid=312) 2021-08-05 12:20:08.774332: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:200] libcuda reported version is: 460.32.3
    (pid=312) 2021-08-05 12:20:08.774364: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:204] kernel reported version is: 460.32.3
    (pid=312) 2021-08-05 12:20:08.774373: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:310] kernel version seems to match DSO: 460.32.3
    (pid=312) 2021-08-05 12:20:08.774710: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
    (pid=312) To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
    (pid=312) 2021-08-05 12:20:09.082573: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)
    (pid=312) 2021-08-05 12:20:09.082935: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2199995000 Hz
    (pid=312)
    (pid=312)    1/2969 [..............................] - ETA: 37s - loss: 0.6022 - mae: 0.3906 - accuracy: 0.6875
    (pid=312)
    (pid=312)   60/2969 [..............................] - ETA: 2s - loss: 0.5876 - mae: 0.3996 - accuracy: 0.6818
    (pid=312)
    (pid=312)  115/2969 [>.............................] - ETA: 2s - loss: 0.5841 - mae: 0.3981 - accuracy: 0.6864
    (pid=312)
    (pid=312)  178/2969 [>.............................] - ETA: 2s - loss: 0.5764 - mae: 0.3944 - accuracy: 0.6935
    (pid=312)
    (pid=312)  242/2969 [=>............................] - ETA: 2s - loss: 0.5782 - mae: 0.3954 - accuracy: 0.6896
    (pid=312)
    (pid=312)  301/2969 [==>...........................] - ETA: 2s - loss: 0.5814 - mae: 0.3969 - accuracy: 0.6885
    (pid=312)
    (pid=312)  364/2969 [==>...........................] - ETA: 2s - loss: 0.5796 - mae: 0.3962 - accuracy: 0.6892
    (pid=312)
    (pid=312)  429/2969 [===>..........................] - ETA: 2s - loss: 0.5818 - mae: 0.3970 - accuracy: 0.6890
    (pid=312)
    (pid=312)  493/2969 [===>..........................] - ETA: 2s - loss: 0.5815 - mae: 0.3970 - accuracy: 0.6904
    (pid=312)
    (pid=312)  553/2969 [====>.........................] - ETA: 1s - loss: 0.5806 - mae: 0.3965 - accuracy: 0.6909
    (pid=312)
    (pid=312)  616/2969 [=====>........................] - ETA: 1s - loss: 0.5812 - mae: 0.3968 - accuracy: 0.6903
    (pid=312)
    (pid=312)  669/2969 [=====>........................] - ETA: 1s - loss: 0.5806 - mae: 0.3965 - accuracy: 0.6916
    (pid=312)
    (pid=312)  724/2969 [======>.......................] - ETA: 1s - loss: 0.5795 - mae: 0.3960 - accuracy: 0.6919
    (pid=312)
    (pid=312)  781/2969 [======>.......................] - ETA: 1s - loss: 0.5790 - mae: 0.3957 - accuracy: 0.6931
    (pid=312)
    (pid=312)  842/2969 [=======>......................] - ETA: 1s - loss: 0.5779 - mae: 0.3952 - accuracy: 0.6943
    (pid=312)
    (pid=312)  900/2969 [========>.....................] - ETA: 1s - loss: 0.5776 - mae: 0.3950 - accuracy: 0.6947
    (pid=312)
    (pid=312)  963/2969 [========>.....................] - ETA: 1s - loss: 0.5773 - mae: 0.3949 - accuracy: 0.6947
    (pid=312)
    (pid=312) 1017/2969 [=========>....................] - ETA: 1s - loss: 0.5777 - mae: 0.3951 - accuracy: 0.6942
    (pid=312)
    (pid=312) 1077/2969 [=========>....................] - ETA: 1s - loss: 0.5780 - mae: 0.3953 - accuracy: 0.6939
    (pid=312)
    (pid=312) 1140/2969 [==========>...................] - ETA: 1s - loss: 0.5784 - mae: 0.3955 - accuracy: 0.6939
    (pid=312)
    (pid=312) 1192/2969 [===========>..................] - ETA: 1s - loss: 0.5785 - mae: 0.3955 - accuracy: 0.6937
    (pid=312)
    (pid=312) 1248/2969 [===========>..................] - ETA: 1s - loss: 0.5793 - mae: 0.3959 - accuracy: 0.6927
    (pid=312)
    (pid=312) 1304/2969 [============>.................] - ETA: 1s - loss: 0.5792 - mae: 0.3959 - accuracy: 0.6931
    (pid=312)
    (pid=312) 1359/2969 [============>.................] - ETA: 1s - loss: 0.5792 - mae: 0.3959 - accuracy: 0.6928
    (pid=312)
    (pid=312) 1418/2969 [=============>................] - ETA: 1s - loss: 0.5782 - mae: 0.3955 - accuracy: 0.6935
    (pid=312)
    (pid=312) 1480/2969 [=============>................] - ETA: 1s - loss: 0.5784 - mae: 0.3956 - accuracy: 0.6934
    (pid=312)
    (pid=312) 1540/2969 [==============>...............] - ETA: 1s - loss: 0.5785 - mae: 0.3956 - accuracy: 0.6934
    (pid=312)
    (pid=312) 1604/2969 [===============>..............] - ETA: 1s - loss: 0.5795 - mae: 0.3962 - accuracy: 0.6927
    (pid=312)
    (pid=312) 1667/2969 [===============>..............] - ETA: 1s - loss: 0.5796 - mae: 0.3961 - accuracy: 0.6928
    (pid=312)
    (pid=312) 1729/2969 [================>.............] - ETA: 1s - loss: 0.5794 - mae: 0.3960 - accuracy: 0.6932
    (pid=312)
    (pid=312) 1787/2969 [=================>............] - ETA: 1s - loss: 0.5799 - mae: 0.3961 - accuracy: 0.6929
    (pid=312)
    (pid=312) 1840/2969 [=================>............] - ETA: 0s - loss: 0.5798 - mae: 0.3961 - accuracy: 0.6931
    (pid=312)
    (pid=312) 1902/2969 [==================>...........] - ETA: 0s - loss: 0.5800 - mae: 0.3961 - accuracy: 0.6930
    (pid=312)
    (pid=312) 1966/2969 [==================>...........] - ETA: 0s - loss: 0.5796 - mae: 0.3960 - accuracy: 0.6934
    (pid=312)
    (pid=312) 2026/2969 [===================>..........] - ETA: 0s - loss: 0.5797 - mae: 0.3959 - accuracy: 0.6935
    (pid=312)
    (pid=312) 2091/2969 [====================>.........] - ETA: 0s - loss: 0.5797 - mae: 0.3959 - accuracy: 0.6937
    (pid=312)
    (pid=312) 2157/2969 [====================>.........] - ETA: 0s - loss: 0.5795 - mae: 0.3958 - accuracy: 0.6945
    (pid=312)
    (pid=312) 2222/2969 [=====================>........] - ETA: 0s - loss: 0.5795 - mae: 0.3959 - accuracy: 0.6944
    (pid=312)
    (pid=312) 2281/2969 [======================>.......] - ETA: 0s - loss: 0.5796 - mae: 0.3959 - accuracy: 0.6941
    (pid=312)
    (pid=312) 2344/2969 [======================>.......] - ETA: 0s - loss: 0.5794 - mae: 0.3958 - accuracy: 0.6943
    (pid=312)
    (pid=312) 2402/2969 [=======================>......] - ETA: 0s - loss: 0.5797 - mae: 0.3959 - accuracy: 0.6940
    (pid=312)
    (pid=312) 2462/2969 [=======================>......] - ETA: 0s - loss: 0.5797 - mae: 0.3958 - accuracy: 0.6943
    (pid=312)
    (pid=312) 2516/2969 [========================>.....] - ETA: 0s - loss: 0.5798 - mae: 0.3959 - accuracy: 0.6940
    (pid=312)
    (pid=312) 2576/2969 [=========================>....] - ETA: 0s - loss: 0.5798 - mae: 0.3959 - accuracy: 0.6942
    (pid=312)
    (pid=312) 2639/2969 [=========================>....] - ETA: 0s - loss: 0.5800 - mae: 0.3960 - accuracy: 0.6941
    (pid=312)
    (pid=312) 2699/2969 [==========================>...] - ETA: 0s - loss: 0.5802 - mae: 0.3961 - accuracy: 0.6940
    (pid=312)
    (pid=312) 2759/2969 [==========================>...] - ETA: 0s - loss: 0.5805 - mae: 0.3963 - accuracy: 0.6936
    (pid=312)
    (pid=312) 2822/2969 [===========================>..] - ETA: 0s - loss: 0.5805 - mae: 0.3963 - accuracy: 0.6936
    (pid=312)
    (pid=312) 2881/2969 [============================>.] - ETA: 0s - loss: 0.5807 - mae: 0.3964 - accuracy: 0.6932
    (pid=312)
    (pid=312) 2944/2969 [============================>.] - ETA: 0s - loss: 0.5805 - mae: 0.3963 - accuracy: 0.6934
    (pid=312) 2969/2969 [==============================] - 3s 839us/step - loss: 0.5805 - mae: 0.3963 - accuracy: 0.6934
    Result for train_model_1_disc_params.group_lasso.l1=2.7829,guess_params.group_lasso.l1=3.9435,slip_params.group_lasso.l1=5.9648:
      checkpoint: weights_tune_[(0, 'disc_params.group_lasso.l1'), (5, 'guess_params.group_lasso.l1'),
        (8, 'slip_params.group_lasso.l1')].h5
      date: 2021-08-05_12-25-35
      done: true
      experiment_id: b2b59f5124084f44adf67b0312a02ab1
      hostname: d005995f49c5
      iterations_since_restore: 1
      mean_accuracy: 0.6933789253234863
      mean_error: 0.5804693102836609
      node_ip: 172.28.0.2
      pid: 312
      time_since_restore: 327.2989342212677
      time_this_iter_s: 327.2989342212677
      time_total_s: 327.2989342212677
      timestamp: 1628166335
      timesteps_since_restore: 0
      training_iteration: 1

    2021-08-05 12:25:36,059	ERROR worker.py:1780 -- Warning: The actor WrappedFunc has size 19782331 when pickled. It will be stored in Redis, which could cause memory issues. This may mean that its definition uses a large array or other object.

    == Status ==
    Using AsyncHyperBand: num_stopped=0
    Bracket: Iter 90.000: None | Iter 30.000: None | Iter 10.000: None
    Bracket: Iter 90.000: None | Iter 30.000: None
    Bracket: Iter 90.000: None
    Resources requested: 0/4 CPUs, 0/1 GPUs
    Memory usage on this node: 1.7/13.6 GB
    Result logdir: /root/ray_results/hyperOpt_optimization
    Number of trials: 4 ({'TERMINATED': 1, 'PENDING': 3})
    PENDING trials:
     - train_model_2_disc_params.group_lasso.l1=6.5627,guess_params.group_lasso.l1=2.9186,slip_params.group_lasso.l1=1.3818:	PENDING
     - train_model_3_disc_params.group_lasso.l1=6.6343,guess_params.group_lasso.l1=7.145,slip_params.group_lasso.l1=5.1955:	PENDING
     - train_model_4_disc_params.group_lasso.l1=0.8419,guess_params.group_lasso.l1=9.5492,slip_params.group_lasso.l1=4.4229:	PENDING
    TERMINATED trials:
     - train_model_1_disc_params.group_lasso.l1=2.7829,guess_params.group_lasso.l1=3.9435,slip_params.group_lasso.l1=5.9648:	TERMINATED, [4 CPUs, 0 GPUs], [pid=312], 327 s, 1 iter, 0.693 acc

    (pid=313) 2021-08-05 12:25:37.171612: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
    (pid=313) 2021-08-05 12:25:38,480	ERROR worker.py:1412 -- Calling ray.init() again after it has already been called.
    (pid=313)
    (pid=313) config val 1:
    (pid=313)  key_list: ['disc_params', 'group_lasso'];
    (pid=313)  values: {'l1': 6.562664791374827, 'l2': 0}
    (pid=313)
    (pid=313)
    (pid=313)
    (pid=313) config val 2:
    (pid=313)  key_list: ['guess_params', 'group_lasso'];
    (pid=313)  values: {'l1': 2.9186447579369856, 'l2': 0}
    (pid=313)
    (pid=313)
    (pid=313)
    (pid=313) config val 3:
    (pid=313)  key_list: ['slip_params', 'group_lasso'];
    (pid=313)  values: {'l1': 1.3818327930197527, 'l2': 0}
    (pid=313)
    (pid=313)
    (pid=313)
    (pid=313) Intitializing fit for fourPL model. . .
    (pid=313) Batch_size: 128; epochs: 450;
    (pid=313) 2021-08-05 12:25:39.332564: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
    (pid=313) 2021-08-05 12:25:39.337904: E tensorflow/stream_executor/cuda/cuda_driver.cc:328] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected
    (pid=313) 2021-08-05 12:25:39.337954: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: d005995f49c5
    (pid=313) 2021-08-05 12:25:39.337964: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: d005995f49c5
    (pid=313) 2021-08-05 12:25:39.338049: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:200] libcuda reported version is: 460.32.3
    (pid=313) 2021-08-05 12:25:39.338076: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:204] kernel reported version is: 460.32.3
    (pid=313) 2021-08-05 12:25:39.338085: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:310] kernel version seems to match DSO: 460.32.3
    (pid=313) 2021-08-05 12:25:39.338282: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
    (pid=313) To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
    (pid=313) 2021-08-05 12:25:39.625346: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)
    (pid=313) 2021-08-05 12:25:39.625696: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2199995000 Hz
    (pid=313)
    (pid=313)    1/2969 [..............................] - ETA: 38s - loss: 0.6050 - mae: 0.3900 - accuracy: 0.6875
    (pid=313)
    (pid=313)   52/2969 [..............................] - ETA: 2s - loss: 0.5922 - mae: 0.4003 - accuracy: 0.6869
    (pid=313)
    (pid=313)  108/2969 [>.............................] - ETA: 2s - loss: 0.5905 - mae: 0.3992 - accuracy: 0.6843
    (pid=313)
    (pid=313)  162/2969 [>.............................] - ETA: 2s - loss: 0.5763 - mae: 0.3926 - accuracy: 0.6966
    (pid=313)
    (pid=313)  217/2969 [=>............................] - ETA: 2s - loss: 0.5809 - mae: 0.3948 - accuracy: 0.6910
    (pid=313)
    (pid=313)  262/2969 [=>............................] - ETA: 2s - loss: 0.5846 - mae: 0.3967 - accuracy: 0.6880
    (pid=313)
    (pid=313)  317/2969 [==>...........................] - ETA: 2s - loss: 0.5839 - mae: 0.3961 - accuracy: 0.6901
    (pid=313)
    (pid=313)  368/2969 [==>...........................] - ETA: 2s - loss: 0.5837 - mae: 0.3963 - accuracy: 0.6892
    (pid=313)
    (pid=313)  422/2969 [===>..........................] - ETA: 2s - loss: 0.5850 - mae: 0.3968 - accuracy: 0.6894
    (pid=313)
    (pid=313)  473/2969 [===>..........................] - ETA: 2s - loss: 0.5848 - mae: 0.3967 - accuracy: 0.6905
    (pid=313)
    (pid=313)  527/2969 [====>.........................] - ETA: 2s - loss: 0.5849 - mae: 0.3969 - accuracy: 0.6902
    (pid=313)
    (pid=313)  579/2969 [====>.........................] - ETA: 2s - loss: 0.5846 - mae: 0.3966 - accuracy: 0.6906
    (pid=313)
    (pid=313)  622/2969 [=====>........................] - ETA: 2s - loss: 0.5848 - mae: 0.3967 - accuracy: 0.6904
    (pid=313)
    (pid=313)  681/2969 [=====>........................] - ETA: 2s - loss: 0.5834 - mae: 0.3961 - accuracy: 0.6919
    (pid=313)
    (pid=313)  724/2969 [======>.......................] - ETA: 2s - loss: 0.5831 - mae: 0.3960 - accuracy: 0.6917
    (pid=313)
    (pid=313)  782/2969 [======>.......................] - ETA: 2s - loss: 0.5827 - mae: 0.3957 - accuracy: 0.6929
    (pid=313)
    (pid=313)  834/2969 [=======>......................] - ETA: 2s - loss: 0.5819 - mae: 0.3953 - accuracy: 0.6939
    (pid=313)
    (pid=313)  893/2969 [========>.....................] - ETA: 1s - loss: 0.5810 - mae: 0.3949 - accuracy: 0.6949
    (pid=313)
    (pid=313)  943/2969 [========>.....................] - ETA: 1s - loss: 0.5810 - mae: 0.3950 - accuracy: 0.6946
    (pid=313)
    (pid=313)  996/2969 [=========>....................] - ETA: 1s - loss: 0.5813 - mae: 0.3950 - accuracy: 0.6944
    (pid=313)
    (pid=313) 1050/2969 [=========>....................] - ETA: 1s - loss: 0.5817 - mae: 0.3953 - accuracy: 0.6938
    (pid=313)
    (pid=313) 1106/2969 [==========>...................] - ETA: 1s - loss: 0.5824 - mae: 0.3956 - accuracy: 0.6936
    (pid=313)
    (pid=313) 1160/2969 [==========>...................] - ETA: 1s - loss: 0.5821 - mae: 0.3954 - accuracy: 0.6939
    (pid=313)
    (pid=313) 1218/2969 [===========>..................] - ETA: 1s - loss: 0.5826 - mae: 0.3957 - accuracy: 0.6932
    (pid=313)
    (pid=313) 1276/2969 [===========>..................] - ETA: 1s - loss: 0.5827 - mae: 0.3958 - accuracy: 0.6932
    (pid=313)
    (pid=313) 1331/2969 [============>.................] - ETA: 1s - loss: 0.5826 - mae: 0.3957 - accuracy: 0.6932
    (pid=313)
    (pid=313) 1381/2969 [============>.................] - ETA: 1s - loss: 0.5822 - mae: 0.3956 - accuracy: 0.6934
    (pid=313)
    (pid=313) 1432/2969 [=============>................] - ETA: 1s - loss: 0.5820 - mae: 0.3956 - accuracy: 0.6933
    (pid=313)
    (pid=313) 1491/2969 [==============>...............] - ETA: 1s - loss: 0.5821 - mae: 0.3956 - accuracy: 0.6934
    (pid=313)
    (pid=313) 1542/2969 [==============>...............] - ETA: 1s - loss: 0.5822 - mae: 0.3956 - accuracy: 0.6934
    (pid=313)
    (pid=313) 1597/2969 [===============>..............] - ETA: 1s - loss: 0.5831 - mae: 0.3961 - accuracy: 0.6928
    (pid=313)
    (pid=313) 1642/2969 [===============>..............] - ETA: 1s - loss: 0.5833 - mae: 0.3961 - accuracy: 0.6931
    (pid=313)
    (pid=313) 1698/2969 [================>.............] - ETA: 1s - loss: 0.5832 - mae: 0.3960 - accuracy: 0.6932
    (pid=313)
    (pid=313) 1748/2969 [================>.............] - ETA: 1s - loss: 0.5834 - mae: 0.3961 - accuracy: 0.6931
    (pid=313)
    (pid=313) 1791/2969 [=================>............] - ETA: 1s - loss: 0.5835 - mae: 0.3961 - accuracy: 0.6930
    (pid=313)
    (pid=313) 1843/2969 [=================>............] - ETA: 1s - loss: 0.5835 - mae: 0.3960 - accuracy: 0.6931
    (pid=313)
    (pid=313) 1896/2969 [==================>...........] - ETA: 1s - loss: 0.5835 - mae: 0.3960 - accuracy: 0.6933
    (pid=313)
    (pid=313) 1949/2969 [==================>...........] - ETA: 0s - loss: 0.5836 - mae: 0.3961 - accuracy: 0.6932
    (pid=313)
    (pid=313) 2006/2969 [===================>..........] - ETA: 0s - loss: 0.5834 - mae: 0.3959 - accuracy: 0.6934
    (pid=313)
    (pid=313) 2056/2969 [===================>..........] - ETA: 0s - loss: 0.5832 - mae: 0.3958 - accuracy: 0.6940
    (pid=313)
    (pid=313) 2107/2969 [====================>.........] - ETA: 0s - loss: 0.5835 - mae: 0.3960 - accuracy: 0.6937
    (pid=313)
    (pid=313) 2162/2969 [====================>.........] - ETA: 0s - loss: 0.5832 - mae: 0.3958 - accuracy: 0.6945
    (pid=313)
    (pid=313) 2217/2969 [=====================>........] - ETA: 0s - loss: 0.5832 - mae: 0.3958 - accuracy: 0.6944
    (pid=313)
    (pid=313) 2270/2969 [=====================>........] - ETA: 0s - loss: 0.5833 - mae: 0.3959 - accuracy: 0.6942
    (pid=313)
    (pid=313) 2323/2969 [======================>.......] - ETA: 0s - loss: 0.5831 - mae: 0.3957 - accuracy: 0.6943
    (pid=313)
    (pid=313) 2379/2969 [=======================>......] - ETA: 0s - loss: 0.5834 - mae: 0.3959 - accuracy: 0.6940
    (pid=313)
    (pid=313) 2432/2969 [=======================>......] - ETA: 0s - loss: 0.5834 - mae: 0.3959 - accuracy: 0.6941
    (pid=313)
    (pid=313) 2479/2969 [========================>.....] - ETA: 0s - loss: 0.5834 - mae: 0.3959 - accuracy: 0.6943
    (pid=313)
    (pid=313) 2527/2969 [========================>.....] - ETA: 0s - loss: 0.5836 - mae: 0.3960 - accuracy: 0.6940
    (pid=313)
    (pid=313) 2585/2969 [=========================>....] - ETA: 0s - loss: 0.5836 - mae: 0.3959 - accuracy: 0.6943
    (pid=313)
    (pid=313) 2637/2969 [=========================>....] - ETA: 0s - loss: 0.5837 - mae: 0.3960 - accuracy: 0.6941
    (pid=313)
    (pid=313) 2695/2969 [==========================>...] - ETA: 0s - loss: 0.5838 - mae: 0.3961 - accuracy: 0.6941
    (pid=313)
    (pid=313) 2741/2969 [==========================>...] - ETA: 0s - loss: 0.5841 - mae: 0.3962 - accuracy: 0.6937
    (pid=313)
    (pid=313) 2799/2969 [===========================>..] - ETA: 0s - loss: 0.5840 - mae: 0.3962 - accuracy: 0.6936
    (pid=313)
    (pid=313) 2845/2969 [===========================>..] - ETA: 0s - loss: 0.5841 - mae: 0.3962 - accuracy: 0.6936

    2021-08-05 12:31:06,491	ERROR worker.py:1780 -- Warning: The actor WrappedFunc has size 19782331 when pickled. It will be stored in Redis, which could cause memory issues. This may mean that its definition uses a large array or other object.

    (pid=313)
    (pid=313) 2900/2969 [============================>.] - ETA: 0s - loss: 0.5842 - mae: 0.3963 - accuracy: 0.6933
    Result for train_model_2_disc_params.group_lasso.l1=6.5627,guess_params.group_lasso.l1=2.9186,slip_params.group_lasso.l1=1.3818:
      checkpoint: weights_tune_[(2, 'disc_params.group_lasso.l1'), (9, 'guess_params.group_lasso.l1'),
        (5, 'slip_params.group_lasso.l1')].h5
      date: 2021-08-05_12-31-06
      done: true
      experiment_id: acc4cfab0ec841ce9a8abf40a281c9f7
      hostname: d005995f49c5
      iterations_since_restore: 1
      mean_accuracy: 0.6934000253677368
      mean_error: 0.5841391086578369
      node_ip: 172.28.0.2
      pid: 313
      time_since_restore: 327.1404161453247
      time_this_iter_s: 327.1404161453247
      time_total_s: 327.1404161453247
      timestamp: 1628166666
      timesteps_since_restore: 0
      training_iteration: 1

    == Status ==
    Using AsyncHyperBand: num_stopped=0
    Bracket: Iter 90.000: None | Iter 30.000: None | Iter 10.000: None
    Bracket: Iter 90.000: None | Iter 30.000: None
    Bracket: Iter 90.000: None
    Resources requested: 0/4 CPUs, 0/1 GPUs
    Memory usage on this node: 1.7/13.6 GB
    Result logdir: /root/ray_results/hyperOpt_optimization
    Number of trials: 4 ({'TERMINATED': 2, 'PENDING': 2})
    PENDING trials:
     - train_model_3_disc_params.group_lasso.l1=6.6343,guess_params.group_lasso.l1=7.145,slip_params.group_lasso.l1=5.1955:	PENDING
     - train_model_4_disc_params.group_lasso.l1=0.8419,guess_params.group_lasso.l1=9.5492,slip_params.group_lasso.l1=4.4229:	PENDING
    TERMINATED trials:
     - train_model_1_disc_params.group_lasso.l1=2.7829,guess_params.group_lasso.l1=3.9435,slip_params.group_lasso.l1=5.9648:	TERMINATED, [4 CPUs, 0 GPUs], [pid=312], 327 s, 1 iter, 0.693 acc
     - train_model_2_disc_params.group_lasso.l1=6.5627,guess_params.group_lasso.l1=2.9186,slip_params.group_lasso.l1=1.3818:	TERMINATED, [4 CPUs, 0 GPUs], [pid=313], 327 s, 1 iter, 0.693 acc

    (pid=313)
    (pid=313) 2950/2969 [============================>.] - ETA: 0s - loss: 0.5841 - mae: 0.3963 - accuracy: 0.6934
    (pid=313) 2969/2969 [==============================] - 3s 958us/step - loss: 0.5841 - mae: 0.3963 - accuracy: 0.6934
    (pid=3225) 2021-08-05 12:31:08.370318: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
    (pid=3225) 2021-08-05 12:31:09,732	ERROR worker.py:1412 -- Calling ray.init() again after it has already been called.
    (pid=3225)
    (pid=3225) config val 1:
    (pid=3225)  key_list: ['disc_params', 'group_lasso'];
    (pid=3225)  values: {'l1': 6.634291754359234, 'l2': 0}
    (pid=3225)
    (pid=3225)
    (pid=3225)
    (pid=3225) config val 2:
    (pid=3225)  key_list: ['guess_params', 'group_lasso'];
    (pid=3225)  values: {'l1': 7.145003759304225, 'l2': 0}
    (pid=3225)
    (pid=3225)
    (pid=3225)
    (pid=3225) config val 3:
    (pid=3225)  key_list: ['slip_params', 'group_lasso'];
    (pid=3225)  values: {'l1': 5.195499108646523, 'l2': 0}
    (pid=3225)
    (pid=3225)
    (pid=3225)
    (pid=3225) Intitializing fit for fourPL model. . .
    (pid=3225) Batch_size: 128; epochs: 450;
    (pid=3225) 2021-08-05 12:31:10.623240: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
    (pid=3225) 2021-08-05 12:31:10.628720: E tensorflow/stream_executor/cuda/cuda_driver.cc:328] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected
    (pid=3225) 2021-08-05 12:31:10.628768: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: d005995f49c5
    (pid=3225) 2021-08-05 12:31:10.628778: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: d005995f49c5
    (pid=3225) 2021-08-05 12:31:10.628868: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:200] libcuda reported version is: 460.32.3
    (pid=3225) 2021-08-05 12:31:10.628903: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:204] kernel reported version is: 460.32.3
    (pid=3225) 2021-08-05 12:31:10.628912: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:310] kernel version seems to match DSO: 460.32.3
    (pid=3225) 2021-08-05 12:31:10.629113: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
    (pid=3225) To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
    (pid=3225) 2021-08-05 12:31:10.938766: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)
    (pid=3225) 2021-08-05 12:31:10.939086: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2199995000 Hz
    (pid=3225)
    (pid=3225)    1/2969 [..............................] - ETA: 40s - loss: 0.6049 - mae: 0.3903 - accuracy: 0.6875
    (pid=3225)
    (pid=3225)   54/2969 [..............................] - ETA: 2s - loss: 0.5904 - mae: 0.3998 - accuracy: 0.6863
    (pid=3225)
    (pid=3225)  114/2969 [>.............................] - ETA: 2s - loss: 0.5877 - mae: 0.3983 - accuracy: 0.6856
    (pid=3225)
    (pid=3225)  175/2969 [>.............................] - ETA: 2s - loss: 0.5794 - mae: 0.3942 - accuracy: 0.6932
    (pid=3225)
    (pid=3225)  237/2969 [=>............................] - ETA: 2s - loss: 0.5811 - mae: 0.3953 - accuracy: 0.6897
    (pid=3225)
    (pid=3225)  291/2969 [=>............................] - ETA: 2s - loss: 0.5833 - mae: 0.3965 - accuracy: 0.6891
    (pid=3225)
    (pid=3225)  352/2969 [==>...........................] - ETA: 2s - loss: 0.5829 - mae: 0.3963 - accuracy: 0.6887
    (pid=3225)
    (pid=3225)  412/2969 [===>..........................] - ETA: 2s - loss: 0.5846 - mae: 0.3970 - accuracy: 0.6885
    (pid=3225)
    (pid=3225)  473/2969 [===>..........................] - ETA: 2s - loss: 0.5839 - mae: 0.3968 - accuracy: 0.6900
    (pid=3225)
    (pid=3225)  530/2969 [====>.........................] - ETA: 2s - loss: 0.5842 - mae: 0.3970 - accuracy: 0.6893
    (pid=3225)
    (pid=3225)  591/2969 [====>.........................] - ETA: 2s - loss: 0.5836 - mae: 0.3967 - accuracy: 0.6904
    (pid=3225)
    (pid=3225)  652/2969 [=====>........................] - ETA: 1s - loss: 0.5840 - mae: 0.3968 - accuracy: 0.6903
    (pid=3225)
    (pid=3225)  705/2969 [======>.......................] - ETA: 1s - loss: 0.5822 - mae: 0.3960 - accuracy: 0.6919
    (pid=3225)
    (pid=3225)  765/2969 [======>.......................] - ETA: 1s - loss: 0.5817 - mae: 0.3957 - accuracy: 0.6921
    (pid=3225)
    (pid=3225)  822/2969 [=======>......................] - ETA: 1s - loss: 0.5814 - mae: 0.3955 - accuracy: 0.6932
    (pid=3225)
    (pid=3225)  885/2969 [=======>......................] - ETA: 1s - loss: 0.5800 - mae: 0.3948 - accuracy: 0.6945
    (pid=3225)
    (pid=3225)  946/2969 [========>.....................] - ETA: 1s - loss: 0.5801 - mae: 0.3949 - accuracy: 0.6944
    (pid=3225)
    (pid=3225) 1009/2969 [=========>....................] - ETA: 1s - loss: 0.5805 - mae: 0.3951 - accuracy: 0.6938
    (pid=3225)
    (pid=3225) 1066/2969 [=========>....................] - ETA: 1s - loss: 0.5810 - mae: 0.3954 - accuracy: 0.6935
    (pid=3225)
    (pid=3225) 1129/2969 [==========>...................] - ETA: 1s - loss: 0.5814 - mae: 0.3955 - accuracy: 0.6935
    (pid=3225)
    (pid=3225) 1192/2969 [===========>..................] - ETA: 1s - loss: 0.5814 - mae: 0.3955 - accuracy: 0.6934
    (pid=3225)
    (pid=3225) 1249/2969 [===========>..................] - ETA: 1s - loss: 0.5821 - mae: 0.3959 - accuracy: 0.6925
    (pid=3225)
    (pid=3225) 1309/2969 [============>.................] - ETA: 1s - loss: 0.5819 - mae: 0.3959 - accuracy: 0.6929
    (pid=3225)
    (pid=3225) 1367/2969 [============>.................] - ETA: 1s - loss: 0.5817 - mae: 0.3957 - accuracy: 0.6928
    (pid=3225)
    (pid=3225) 1429/2969 [=============>................] - ETA: 1s - loss: 0.5812 - mae: 0.3956 - accuracy: 0.6931
    (pid=3225)
    (pid=3225) 1492/2969 [==============>...............] - ETA: 1s - loss: 0.5813 - mae: 0.3956 - accuracy: 0.6932
    (pid=3225)
    (pid=3225) 1553/2969 [==============>...............] - ETA: 1s - loss: 0.5816 - mae: 0.3957 - accuracy: 0.6929
    (pid=3225)
    (pid=3225) 1616/2969 [===============>..............] - ETA: 1s - loss: 0.5825 - mae: 0.3962 - accuracy: 0.6925
    (pid=3225)
    (pid=3225) 1665/2969 [===============>..............] - ETA: 1s - loss: 0.5826 - mae: 0.3962 - accuracy: 0.6925
    (pid=3225)
    (pid=3225) 1727/2969 [================>.............] - ETA: 1s - loss: 0.5822 - mae: 0.3960 - accuracy: 0.6931
    (pid=3225)
    (pid=3225) 1788/2969 [=================>............] - ETA: 0s - loss: 0.5827 - mae: 0.3961 - accuracy: 0.6926
    (pid=3225)
    (pid=3225) 1847/2969 [=================>............] - ETA: 0s - loss: 0.5827 - mae: 0.3961 - accuracy: 0.6929
    (pid=3225)
    (pid=3225) 1894/2969 [==================>...........] - ETA: 0s - loss: 0.5827 - mae: 0.3961 - accuracy: 0.6930
    (pid=3225)
    (pid=3225) 1955/2969 [==================>...........] - ETA: 0s - loss: 0.5826 - mae: 0.3960 - accuracy: 0.6932
    (pid=3225)
    (pid=3225) 2017/2969 [===================>..........] - ETA: 0s - loss: 0.5826 - mae: 0.3959 - accuracy: 0.6932
    (pid=3225)
    (pid=3225) 2081/2969 [====================>.........] - ETA: 0s - loss: 0.5824 - mae: 0.3959 - accuracy: 0.6938
    (pid=3225)
    (pid=3225) 2135/2969 [====================>.........] - ETA: 0s - loss: 0.5826 - mae: 0.3960 - accuracy: 0.6939
    (pid=3225)
    (pid=3225) 2196/2969 [=====================>........] - ETA: 0s - loss: 0.5827 - mae: 0.3960 - accuracy: 0.6940
    (pid=3225)
    (pid=3225) 2257/2969 [=====================>........] - ETA: 0s - loss: 0.5823 - mae: 0.3959 - accuracy: 0.6942
    (pid=3225)
    (pid=3225) 2320/2969 [======================>.......] - ETA: 0s - loss: 0.5825 - mae: 0.3959 - accuracy: 0.6940
    (pid=3225)
    (pid=3225) 2380/2969 [=======================>......] - ETA: 0s - loss: 0.5827 - mae: 0.3960 - accuracy: 0.6938
    (pid=3225)
    (pid=3225) 2439/2969 [=======================>......] - ETA: 0s - loss: 0.5826 - mae: 0.3959 - accuracy: 0.6939
    (pid=3225) 2500/2969 [========================>.....] - ETA: 0s - loss: 0.5828 - mae: 0.3960 - accuracy: 0.6938
    (pid=3225)
    (pid=3225) 2560/2969 [========================>.....] - ETA: 0s - loss: 0.5826 - mae: 0.3959 - accuracy: 0.6941
    (pid=3225)
    (pid=3225) 2616/2969 [=========================>....] - ETA: 0s - loss: 0.5829 - mae: 0.3960 - accuracy: 0.6940
    (pid=3225)
    (pid=3225) 2671/2969 [=========================>....] - ETA: 0s - loss: 0.5829 - mae: 0.3961 - accuracy: 0.6939
    (pid=3225)
    (pid=3225) 2729/2969 [==========================>...] - ETA: 0s - loss: 0.5832 - mae: 0.3962 - accuracy: 0.6936
    (pid=3225)
    (pid=3225) 2789/2969 [===========================>..] - ETA: 0s - loss: 0.5831 - mae: 0.3962 - accuracy: 0.6935
    (pid=3225)
    (pid=3225) 2842/2969 [===========================>..] - ETA: 0s - loss: 0.5833 - mae: 0.3963 - accuracy: 0.6933
    (pid=3225)
    (pid=3225) 2893/2969 [============================>.] - ETA: 0s - loss: 0.5835 - mae: 0.3964 - accuracy: 0.6931
    (pid=3225)
    (pid=3225) 2948/2969 [============================>.] - ETA: 0s - loss: 0.5834 - mae: 0.3963 - accuracy: 0.6932
    Result for train_model_3_disc_params.group_lasso.l1=6.6343,guess_params.group_lasso.l1=7.145,slip_params.group_lasso.l1=5.1955:
      checkpoint: weights_tune_[(6, 'disc_params.group_lasso.l1'), (1, 'guess_params.group_lasso.l1'),
        (8, 'slip_params.group_lasso.l1')].h5
      date: 2021-08-05_12-36-48
      done: true
      experiment_id: b87ca9906d2e4494930ffcd41699b968
      hostname: d005995f49c5
      iterations_since_restore: 1
      mean_accuracy: 0.6931789517402649
      mean_error: 0.5833627581596375
      node_ip: 172.28.0.2
      pid: 3225
      time_since_restore: 337.9791102409363
      time_this_iter_s: 337.9791102409363
      time_total_s: 337.9791102409363
      timestamp: 1628167008
      timesteps_since_restore: 0
      training_iteration: 1

    == Status ==
    Using AsyncHyperBand: num_stopped=0
    Bracket: Iter 90.000: None | Iter 30.000: None | Iter 10.000: None
    Bracket: Iter 90.000: None | Iter 30.000: None
    Bracket: Iter 90.000: None
    Resources requested: 0/4 CPUs, 0/1 GPUs
    Memory usage on this node: 1.7/13.6 GB
    Result logdir: /root/ray_results/hyperOpt_optimization
    Number of trials: 4 ({'TERMINATED': 3, 'PENDING': 1})
    PENDING trials:
     - train_model_4_disc_params.group_lasso.l1=0.8419,guess_params.group_lasso.l1=9.5492,slip_params.group_lasso.l1=4.4229:	PENDING
    TERMINATED trials:
     - train_model_1_disc_params.group_lasso.l1=2.7829,guess_params.group_lasso.l1=3.9435,slip_params.group_lasso.l1=5.9648:	TERMINATED, [4 CPUs, 0 GPUs], [pid=312], 327 s, 1 iter, 0.693 acc
     - train_model_2_disc_params.group_lasso.l1=6.5627,guess_params.group_lasso.l1=2.9186,slip_params.group_lasso.l1=1.3818:	TERMINATED, [4 CPUs, 0 GPUs], [pid=313], 327 s, 1 iter, 0.693 acc
     - train_model_3_disc_params.group_lasso.l1=6.6343,guess_params.group_lasso.l1=7.145,slip_params.group_lasso.l1=5.1955:	TERMINATED, [4 CPUs, 0 GPUs], [pid=3225], 337 s, 1 iter, 0.693 acc

    (pid=3225)
    (pid=3225) 2969/2969 [==============================] - 3s 856us/step - loss: 0.5834 - mae: 0.3963 - accuracy: 0.6932

    2021-08-05 12:36:48,645	ERROR worker.py:1780 -- Warning: The actor WrappedFunc has size 19782331 when pickled. It will be stored in Redis, which could cause memory issues. This may mean that its definition uses a large array or other object.

    (pid=3230) 2021-08-05 12:36:49.768151: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
    (pid=3230) 2021-08-05 12:36:51,048	ERROR worker.py:1412 -- Calling ray.init() again after it has already been called.
    (pid=3230)
    (pid=3230) config val 1:
    (pid=3230)  key_list: ['disc_params', 'group_lasso'];
    (pid=3230)  values: {'l1': 0.8418982931597918, 'l2': 0}
    (pid=3230)
    (pid=3230)
    (pid=3230)
    (pid=3230) config val 2:
    (pid=3230)  key_list: ['guess_params', 'group_lasso'];
    (pid=3230)  values: {'l1': 9.54924129569551, 'l2': 0}
    (pid=3230)
    (pid=3230)
    (pid=3230)
    (pid=3230) config val 3:
    (pid=3230)  key_list: ['slip_params', 'group_lasso'];
    (pid=3230)  values: {'l1': 4.4228552146004905, 'l2': 0}
    (pid=3230)
    (pid=3230)
    (pid=3230)
    (pid=3230) Intitializing fit for fourPL model. . .
    (pid=3230) Batch_size: 128; epochs: 450;
    (pid=3230) 2021-08-05 12:36:51.897031: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
    (pid=3230) 2021-08-05 12:36:51.902552: E tensorflow/stream_executor/cuda/cuda_driver.cc:328] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected
    (pid=3230) 2021-08-05 12:36:51.902603: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: d005995f49c5
    (pid=3230) 2021-08-05 12:36:51.902613: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: d005995f49c5
    (pid=3230) 2021-08-05 12:36:51.902703: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:200] libcuda reported version is: 460.32.3
    (pid=3230) 2021-08-05 12:36:51.902731: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:204] kernel reported version is: 460.32.3
    (pid=3230) 2021-08-05 12:36:51.902739: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:310] kernel version seems to match DSO: 460.32.3
    (pid=3230) 2021-08-05 12:36:51.902960: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
    (pid=3230) To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
    (pid=3230) 2021-08-05 12:36:52.186884: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)
    (pid=3230) 2021-08-05 12:36:52.187210: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2199995000 Hz
    (pid=3230)
    (pid=3230)    1/2969 [..............................] - ETA: 40s - loss: 0.6019 - mae: 0.3906 - accuracy: 0.6875
    (pid=3230)
    (pid=3230)   59/2969 [..............................] - ETA: 2s - loss: 0.5886 - mae: 0.4008 - accuracy: 0.6801
    (pid=3230)
    (pid=3230)  118/2969 [>.............................] - ETA: 2s - loss: 0.5812 - mae: 0.3972 - accuracy: 0.6864
    (pid=3230)
    (pid=3230)  182/2969 [>.............................] - ETA: 2s - loss: 0.5754 - mae: 0.3943 - accuracy: 0.6932
    (pid=3230)
    (pid=3230)  244/2969 [=>............................] - ETA: 2s - loss: 0.5774 - mae: 0.3955 - accuracy: 0.6892
    (pid=3230)
    (pid=3230)  303/2969 [==>...........................] - ETA: 2s - loss: 0.5803 - mae: 0.3968 - accuracy: 0.6886
    (pid=3230)
    (pid=3230)  361/2969 [==>...........................] - ETA: 2s - loss: 0.5793 - mae: 0.3964 - accuracy: 0.6882
    (pid=3230)
    (pid=3230)  422/2969 [===>..........................] - ETA: 2s - loss: 0.5806 - mae: 0.3969 - accuracy: 0.6888
    (pid=3230)
    (pid=3230)  484/2969 [===>..........................] - ETA: 2s - loss: 0.5813 - mae: 0.3973 - accuracy: 0.6894
    (pid=3230)
    (pid=3230)  548/2969 [====>.........................] - ETA: 2s - loss: 0.5803 - mae: 0.3968 - accuracy: 0.6895
    (pid=3230)
    (pid=3230)  603/2969 [=====>........................] - ETA: 1s - loss: 0.5805 - mae: 0.3969 - accuracy: 0.6902
    (pid=3230)
    (pid=3230)  660/2969 [=====>........................] - ETA: 1s - loss: 0.5799 - mae: 0.3966 - accuracy: 0.6905
    (pid=3230)
    (pid=3230)  718/2969 [======>.......................] - ETA: 1s - loss: 0.5787 - mae: 0.3961 - accuracy: 0.6913
    (pid=3230)
    (pid=3230)  776/2969 [======>.......................] - ETA: 1s - loss: 0.5783 - mae: 0.3958 - accuracy: 0.6921
    (pid=3230)
    (pid=3230)  823/2969 [=======>......................] - ETA: 1s - loss: 0.5778 - mae: 0.3956 - accuracy: 0.6930
    (pid=3230)
    (pid=3230)  886/2969 [=======>......................] - ETA: 1s - loss: 0.5764 - mae: 0.3949 - accuracy: 0.6943
    (pid=3230)
    (pid=3230)  949/2969 [========>.....................] - ETA: 1s - loss: 0.5766 - mae: 0.3950 - accuracy: 0.6940
    (pid=3230) 1011/2969 [=========>....................] - ETA: 1s - loss: 0.5768 - mae: 0.3951 - accuracy: 0.6937
    (pid=3230)
    (pid=3230) 1069/2969 [=========>....................] - ETA: 1s - loss: 0.5775 - mae: 0.3955 - accuracy: 0.6932
    (pid=3230)
    (pid=3230) 1122/2969 [==========>...................] - ETA: 1s - loss: 0.5778 - mae: 0.3956 - accuracy: 0.6932
    (pid=3230)
    (pid=3230) 1182/2969 [==========>...................] - ETA: 1s - loss: 0.5779 - mae: 0.3957 - accuracy: 0.6933
    (pid=3230)
    (pid=3230) 1241/2969 [===========>..................] - ETA: 1s - loss: 0.5784 - mae: 0.3959 - accuracy: 0.6924
    (pid=3230)
    (pid=3230) 1296/2969 [============>.................] - ETA: 1s - loss: 0.5784 - mae: 0.3960 - accuracy: 0.6926
    (pid=3230)
    (pid=3230) 1359/2969 [============>.................] - ETA: 1s - loss: 0.5784 - mae: 0.3960 - accuracy: 0.6924
    (pid=3230)
    (pid=3230) 1420/2969 [=============>................] - ETA: 1s - loss: 0.5774 - mae: 0.3956 - accuracy: 0.6930
    (pid=3230)
    (pid=3230) 1480/2969 [=============>................] - ETA: 1s - loss: 0.5776 - mae: 0.3957 - accuracy: 0.6930
    (pid=3230)
    (pid=3230) 1540/2969 [==============>...............] - ETA: 1s - loss: 0.5777 - mae: 0.3957 - accuracy: 0.6930
    (pid=3230)
    (pid=3230) 1597/2969 [===============>..............] - ETA: 1s - loss: 0.5786 - mae: 0.3962 - accuracy: 0.6924
    (pid=3230)
    (pid=3230) 1657/2969 [===============>..............] - ETA: 1s - loss: 0.5790 - mae: 0.3963 - accuracy: 0.6924
    (pid=3230)
    (pid=3230) 1720/2969 [================>.............] - ETA: 1s - loss: 0.5786 - mae: 0.3961 - accuracy: 0.6928
    (pid=3230)
    (pid=3230) 1783/2969 [=================>............] - ETA: 1s - loss: 0.5790 - mae: 0.3962 - accuracy: 0.6925
    (pid=3230)
    (pid=3230) 1835/2969 [=================>............] - ETA: 0s - loss: 0.5791 - mae: 0.3962 - accuracy: 0.6925
    (pid=3230)
    (pid=3230) 1896/2969 [==================>...........] - ETA: 0s - loss: 0.5790 - mae: 0.3961 - accuracy: 0.6929
    (pid=3230)
    (pid=3230) 1959/2969 [==================>...........] - ETA: 0s - loss: 0.5788 - mae: 0.3960 - accuracy: 0.6931
    (pid=3230)
    (pid=3230) 2010/2969 [===================>..........] - ETA: 0s - loss: 0.5789 - mae: 0.3960 - accuracy: 0.6931
    (pid=3230)
    (pid=3230) 2063/2969 [===================>..........] - ETA: 0s - loss: 0.5787 - mae: 0.3959 - accuracy: 0.6937
    (pid=3230)
    (pid=3230) 2123/2969 [====================>.........] - ETA: 0s - loss: 0.5790 - mae: 0.3961 - accuracy: 0.6937
    (pid=3230)
    (pid=3230) 2184/2969 [=====================>........] - ETA: 0s - loss: 0.5788 - mae: 0.3960 - accuracy: 0.6941
    (pid=3230)
    (pid=3230) 2246/2969 [=====================>........] - ETA: 0s - loss: 0.5786 - mae: 0.3959 - accuracy: 0.6942
    (pid=3230)
    (pid=3230) 2304/2969 [======================>.......] - ETA: 0s - loss: 0.5790 - mae: 0.3960 - accuracy: 0.6937
    (pid=3230)
    (pid=3230) 2356/2969 [======================>.......] - ETA: 0s - loss: 0.5787 - mae: 0.3959 - accuracy: 0.6940
    (pid=3230)
    (pid=3230) 2414/2969 [=======================>......] - ETA: 0s - loss: 0.5790 - mae: 0.3960 - accuracy: 0.6937
    (pid=3230)
    (pid=3230) 2473/2969 [=======================>......] - ETA: 0s - loss: 0.5789 - mae: 0.3960 - accuracy: 0.6940
    (pid=3230)
    (pid=3230) 2531/2969 [========================>.....] - ETA: 0s - loss: 0.5790 - mae: 0.3960 - accuracy: 0.6939
    (pid=3230)
    (pid=3230) 2580/2969 [=========================>....] - ETA: 0s - loss: 0.5790 - mae: 0.3960 - accuracy: 0.6940
    (pid=3230)
    (pid=3230) 2636/2969 [=========================>....] - ETA: 0s - loss: 0.5792 - mae: 0.3961 - accuracy: 0.6939
    (pid=3230)
    (pid=3230) 2690/2969 [==========================>...] - ETA: 0s - loss: 0.5793 - mae: 0.3962 - accuracy: 0.6938
    (pid=3230)
    (pid=3230) 2747/2969 [==========================>...] - ETA: 0s - loss: 0.5796 - mae: 0.3963 - accuracy: 0.6934
    (pid=3230)
    (pid=3230) 2796/2969 [===========================>..] - ETA: 0s - loss: 0.5795 - mae: 0.3963 - accuracy: 0.6934
    (pid=3230)
    (pid=3230) 2847/2969 [===========================>..] - ETA: 0s - loss: 0.5796 - mae: 0.3963 - accuracy: 0.6933
    (pid=3230)
    (pid=3230) 2898/2969 [============================>.] - ETA: 0s - loss: 0.5798 - mae: 0.3964 - accuracy: 0.6931
    Result for train_model_4_disc_params.group_lasso.l1=0.8419,guess_params.group_lasso.l1=9.5492,slip_params.group_lasso.l1=4.4229:
      checkpoint: weights_tune_[(1, 'disc_params.group_lasso.l1'), (6, 'guess_params.group_lasso.l1'),
        (5, 'slip_params.group_lasso.l1')].h5
      date: 2021-08-05_12-42-24
      done: true
      experiment_id: 8877a1b470414e1680751ff7d7118d16
      hostname: d005995f49c5
      iterations_since_restore: 1
      mean_accuracy: 0.6931789517402649
      mean_error: 0.5796586275100708
      node_ip: 172.28.0.2
      pid: 3230
      time_since_restore: 333.13375973701477
      time_this_iter_s: 333.13375973701477
      time_total_s: 333.13375973701477
      timestamp: 1628167344
      timesteps_since_restore: 0
      training_iteration: 1

    (pid=3230)
    (pid=3230) 2951/2969 [============================>.] - ETA: 0s - loss: 0.5796 - mae: 0.3963 - accuracy: 0.6932
    (pid=3230) 2969/2969 [==============================] - 3s 873us/step - loss: 0.5797 - mae: 0.3963 - accuracy: 0.6932
    == Status ==
    Using AsyncHyperBand: num_stopped=0
    Bracket: Iter 90.000: None | Iter 30.000: None | Iter 10.000: None
    Bracket: Iter 90.000: None | Iter 30.000: None
    Bracket: Iter 90.000: None
    Resources requested: 0/4 CPUs, 0/1 GPUs
    Memory usage on this node: 1.7/13.6 GB
    Result logdir: /root/ray_results/hyperOpt_optimization
    Number of trials: 4 ({'TERMINATED': 4})
    TERMINATED trials:
     - train_model_1_disc_params.group_lasso.l1=2.7829,guess_params.group_lasso.l1=3.9435,slip_params.group_lasso.l1=5.9648:	TERMINATED, [4 CPUs, 0 GPUs], [pid=312], 327 s, 1 iter, 0.693 acc
     - train_model_2_disc_params.group_lasso.l1=6.5627,guess_params.group_lasso.l1=2.9186,slip_params.group_lasso.l1=1.3818:	TERMINATED, [4 CPUs, 0 GPUs], [pid=313], 327 s, 1 iter, 0.693 acc
     - train_model_3_disc_params.group_lasso.l1=6.6343,guess_params.group_lasso.l1=7.145,slip_params.group_lasso.l1=5.1955:	TERMINATED, [4 CPUs, 0 GPUs], [pid=3225], 337 s, 1 iter, 0.693 acc
     - train_model_4_disc_params.group_lasso.l1=0.8419,guess_params.group_lasso.l1=9.5492,slip_params.group_lasso.l1=4.4229:	TERMINATED, [4 CPUs, 0 GPUs], [pid=3230], 333 s, 1 iter, 0.693 acc

    == Status ==
    Using AsyncHyperBand: num_stopped=0
    Bracket: Iter 90.000: None | Iter 30.000: None | Iter 10.000: None
    Bracket: Iter 90.000: None | Iter 30.000: None
    Bracket: Iter 90.000: None
    Resources requested: 0/4 CPUs, 0/1 GPUs
    Memory usage on this node: 1.7/13.6 GB
    Result logdir: /root/ray_results/hyperOpt_optimization
    Number of trials: 4 ({'TERMINATED': 4})
    TERMINATED trials:
     - train_model_1_disc_params.group_lasso.l1=2.7829,guess_params.group_lasso.l1=3.9435,slip_params.group_lasso.l1=5.9648:	TERMINATED, [4 CPUs, 0 GPUs], [pid=312], 327 s, 1 iter, 0.693 acc
     - train_model_2_disc_params.group_lasso.l1=6.5627,guess_params.group_lasso.l1=2.9186,slip_params.group_lasso.l1=1.3818:	TERMINATED, [4 CPUs, 0 GPUs], [pid=313], 327 s, 1 iter, 0.693 acc
     - train_model_3_disc_params.group_lasso.l1=6.6343,guess_params.group_lasso.l1=7.145,slip_params.group_lasso.l1=5.1955:	TERMINATED, [4 CPUs, 0 GPUs], [pid=3225], 337 s, 1 iter, 0.693 acc
     - train_model_4_disc_params.group_lasso.l1=0.8419,guess_params.group_lasso.l1=9.5492,slip_params.group_lasso.l1=4.4229:	TERMINATED, [4 CPUs, 0 GPUs], [pid=3230], 333 s, 1 iter, 0.693 acc

    Creating model...

    config val 1:
     key_list: ['disc_params', 'group_lasso'];
     values: {'l1': 0.8418982931597918, 'l2': 0}

    config val 2:
     key_list: ['guess_params', 'group_lasso'];
     values: {'l1': 9.54924129569551, 'l2': 0}

    config val 3:
     key_list: ['slip_params', 'group_lasso'];
     values: {'l1': 4.4228552146004905, 'l2': 0}

    Loading from /root/ray_results/hyperOpt_optimization/train_model_4_disc_params.group_lasso.l1=0.8419,guess_params.group_lasso.l1=9.5492,slip_params.group_lasso.l1=4.4229_2021-08-05_12-36-48_oe4qj2r/weights_tune_[(1, 'disc_params.group_lasso.l1'), (6, 'guess_params.group_lasso.l1'), (5, 'slip_params.group_lasso.l1')].h5
    2969/2969 [==============================] - 16s 976us/step - loss: 0.5790 - mae: 0.3961 - accuracy: 0.6922

    Training on : 95000 samples for : 450 epochs has completed in : 1340.374 seconds.

    AIC value: 1005.091 and AICc value: 1010.435

    Use `object.plot()` to view train/validation loss curves;
    Use `object.history` to obtain train/validation loss across all the epochs.
    Use `object.coefficients()` to obtain model parameters--Question difficulty, discrimination, guessing & slip
    Use `object.AIC` & `object.AIC` to obtain Akaike Information Criterion(AIC & AICc) values.

    <mlsquare.adapters.sklearn.IrtKerasRegressor at 0x7fc100c44c10>

**Following lists the layer names in order from model archiecture of doped model.**

Note:
* trained weights of layer 8 named `slip_param` corresponds to  slip parameter values.
* trained weights of layer 9 named `guessing_param` corresponds to guess parameter values.
* trained weights of layer 1 named `disc_param` corresponds to discrimination parameter values.
* trained weights of layer 4 named `latent_trait/ability` corresponds to user ability values.

```python
for idx, lay in enumerate(model_4t1.model.layers):
    print('{} and layer name: {}'.format(idx, lay.name))
```

    0 and layer name: questions/items
    1 and layer name: disc_param
    2 and layer name: user_id
    3 and layer name: disc_activation
    4 and layer name: latent_trait/ability
    5 and layer name: difficulty_level
    6 and layer name: lambda_latent_inter.
    7 and layer name: alpha_param.
    8 and layer name: slip_param
    9 and layer name: guessing_param
    10 and layer name: alpha_lambda_add
    11 and layer name: slip_param_inter.
    12 and layer name: Sigmoid_func
    13 and layer name: slip/guess_interaction
    14 and layer name: disc/guess_param_inter.
    15 and layer name: guess_param_inter/add
    16 and layer name: prediction_layer

### Obtain User & Item parameters from trained 4PL IRT model
**User parameters (per user):** Ability values.

**Item parameters (per item):** Item difficulty, Item Discrimination, Item guessability, Item Slip

```python
import matplotlib.pyplot as plt
def get_keras_parameters(model, xtrain):# model is a dope object
    ability = model.coefficients()['latent_trait/ability']
    ability = [x[0] for x in ability]

    diff= model.coefficients()['difficulty_level']
    diff = [x[0] for x in diff]

    disc= model.coefficients()['disc_param']
    disc = [x[0] for x in disc]

    guess= model.coefficients()['guessing_param']
    guess = [x[0] for x in guess]

    slip= model.coefficients()['slip_param']
    slip = [x[0] for x in slip]

    question_code = pd.get_dummies(xtrain['question_code']).columns
    df_quest_related_params = pd.DataFrame({'slip_keras':slip, 'guessing_keras':guess, 'discrimination_keras': disc,'difficulty_keras': diff, 'question_code':question_code})

    user_id = pd.get_dummies(xtrain['user_id']).columns
    df_ability = pd.DataFrame({'user_id':user_id, 'ability_keras':ability})
    return df_quest_related_params, df_ability

def scatter_plot(x, y, x_label, y_label):
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    min_x = min(list(x)+list(y)) - 0.5
    max_x = max(list(x)+list(y)) + 0.5
    ax.plot([min_x, max_x], [min_x, max_x])

    ax.set_xlim([min_x, max_x])
    ax.set_ylim([min_x, max_x])

    ax.set_title('{} vs. {} correlation scatterplot'.format(x_label, y_label))
    ax.scatter(x, y, c="red")
    plt.ylabel(y_label)
    plt.xlabel(x_label)
    plt.show()

def hexbin_plot(x, y, x_label, y_label):
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    min_x = min(list(x)+list(y)) - 0.1
    max_x = max(list(x)+list(y)) + 0.1
    ax.plot([min_x, max_x], [min_x, max_x])

    ax.set_xlim([min_x, max_x])
    ax.set_ylim([min_x, max_x])

    ax.set_title('{} vs. {} correlation scatterplot'.format(x_label, y_label))
    hbin= ax.hexbin(x, y, gridsize=25, mincnt=2)
    cb = fig.colorbar(hbin, ax=ax)
    cb.set_label('occurence_density')
    plt.ylabel(y_label)
    plt.xlabel(x_label)
    plt.show()
```

```python
question_code = pd.get_dummies(xtrain['question_code']).columns
user_id = pd.get_dummies(xtrain['user_id']).columns

quest_related_params_df, ability_df = get_keras_parameters(model_4t1, xtrain)

true_difficulty = {_.question_code: _.difficulty for _ in train_data.itertuples()}
quest_related_params_df['difficulty_true'] = quest_related_params_df['question_code'].apply(lambda x: true_difficulty.get(x))

quest_related_params_df['discrimination_true']= 1#Disc 1; Since Input data was for 1 PL model

quest_related_params_df['guessing_true'] = 0 #Guess 0; Since Input data was for 1 PL model

quest_related_params_df['slip_true']=0 #Slip 0; Since Input data was for 1 PL model

quest_related_params_df.head(3)
```

      slip_keras
      guessing_keras
      discrimination_keras
      difficulty_keras
      question_code
      difficulty_true
      discrimination_true
      guessing_true
      slip_true

      0
      0.000089
      0.000052
      0.999977
      -1.041043
      que_0
      -1.000000
      1
      0
      0

      1
      0.000088
      0.000049
      0.999977
      -1.027209
      que_1
      -0.979798
      1
      0
      0

      2
      0.000079
      0.000043
      1.000103
      -0.749467
      que_10
      -0.797980
      1
      0
      0

```python
true_ability = {_.user_id: _.ability for _ in train_data.itertuples()}
ability_df['ability_true'] = ability_df['user_id'].apply(lambda x: true_ability.get(x))
ability_df.head(3)
```

      user_id
      ability_keras
      ability_true

      0
      user_0
      -0.484500
      -0.501354

      1
      user_1
      0.336772
      0.330120

      2
      user_10
      2.554405
      2.763429

_________________________________________
### Plots: Observed parameters vs. True parameters correlation

#### 1. Observed Slip vs. True Slip

```python
scatter_plot(quest_related_params_df['slip_true'], quest_related_params_df['slip_keras'], "True slip", "Observed slip")
```

#### 2. Observed Guess vs. True Guess

```python
scatter_plot(quest_related_params_df['guessing_true'], quest_related_params_df['guessing_keras'], "True guessing", "Observed guessing")
```

#### 3. Observed Discrimination vs. True Discrimination

```python
scatter_plot(quest_related_params_df['discrimination_true'], quest_related_params_df["discrimination_keras"], "True discrimination", "Observed discrimination")

```

#### 4. Observed Difficulty vs. True Difficulty

```python
scatter_plot(quest_related_params_df['difficulty_true'], quest_related_params_df['difficulty_keras'], "True Difficulty", "Observed difficulty")

```

#### 5. Observed Abilities vs. True Abilities

```python
scatter_plot(ability_df['ability_true'], ability_df['ability_keras'], "True Ability", "Observed Ability")

```

#### 6. Observed Response vs. True Response

```python
import math
def fourPL_func(ability, diff, disc, guess, slip):
    res= guess + ((1-slip) + guess)*(1 / (1 + math.exp(-disc*(ability-diff))))
    return res
def get_true_values(quest_related_params_df, ability_df, train_data):
    difficulty_keras_map = {_.question_code: _.difficulty_keras for _ in quest_related_params_df.itertuples()}
    ability_keras_map = {_.user_id: _.ability_keras for _ in ability_df.itertuples()}
    guessing_keras_map = {_.question_code: _.guessing_keras for _ in quest_related_params_df.itertuples()}
    slip_keras_map = {_.question_code: _.slip_keras for _ in quest_related_params_df.itertuples()}
    discrimination_keras_map = {_.question_code: _.discrimination_keras for _ in quest_related_params_df.itertuples()}

    train_data = train_data.drop_duplicates(['question_code', 'user_id'])
    train_data['difficulty_keras'] = train_data['question_code'].apply(lambda x: difficulty_keras_map.get(x))
    train_data['ability_keras'] = train_data['user_id'].apply(lambda x: ability_keras_map.get(x))
    train_data['guessing_keras'] = train_data['question_code'].apply(lambda x: guessing_keras_map.get(x))
    train_data['slip_keras']= train_data['question_code'].apply(lambda x: slip_keras_map.get(x))
    train_data['discrimination_keras'] = train_data['question_code'].apply(lambda x: discrimination_keras_map.get(x))
    train_data['response_keras'] = train_data.apply(lambda x: fourPL_func(x['ability_keras'], x['difficulty_keras'], x['discrimination_keras'], x['guessing_keras'], x['slip_keras']), axis=1)
    return train_data

train_data = get_true_values(quest_related_params_df, ability_df, train_data)
train_data.head(5)

```

      question_code
      user_id
      difficulty
      ability
      response
      correctness
      difficulty_keras
      ability_keras
      guessing_keras
      slip_keras
      discrimination_keras
      response_keras

      0
      que_99
      user_99
      1.0
      0.559055
      0.391516
      0
      1.011985
      0.401654
      0.000047
      0.000125
      1.000112
      0.351987

      10
      que_99
      user_98
      1.0
      0.164593
      0.302503
      0
      1.011985
      0.181314
      0.000047
      0.000125
      1.000112
      0.303506

      20
      que_99
      user_97
      1.0
      0.566402
      0.393268
      1
      1.011985
      0.517328
      0.000047
      0.000125
      1.000112
      0.378801

      30
      que_99
      user_96
      1.0
      1.186521
      0.546496
      0
      1.011985
      1.059723
      0.000047
      0.000125
      1.000112
      0.511940

      40
      que_99
      user_95
      1.0
      -0.039525
      0.261242
      0
      1.011985
      -0.229570
      0.000047
      0.000125
      1.000112
      0.224170

```python

hexbin_plot(train_data['response'], train_data['response_keras'], "True Response", "Observed Response")

```

__________________________________


# Chapter 12. Morlet Wavelets and Wavelet Convolution

```python
import numpy as np
import scipy.io
from matplotlib import pyplot as plt

from numpy import pi, sin, cos, exp, sqrt, log, random  #import basic functions from numpy that we'll need
```

```python
data=scipy.io.loadmat('../data/sampleEEGdata')
```

```python
EEGdata=data["EEG"][0,0]["data"]
srate = float(data["EEG"][0,0]["srate"][0,0])
```

### Figure 12.1
The real component of a Morlet wavelet is a cosine multiplied by a Gaussian window:
\begin{equation}
Re(\text{Morlet wavelet}) = \cos(2\pi f t) e^{-t^2/(2s^2)}
\end{equation}

```python
time = np.arange(-1,1+1/srate,1/srate)

f=4 #sinewave frequency, Hz

#create a sinewave (cosine wave)
sine_wave = cos(2*pi*f*time)

#create a Gaussian

s=4/(2*pi*f) #standard deviation

gaussian_win = exp(-time**2/(2*s**2))

#plot our first wavelet!
_=plt.plot(time,sine_wave*gaussian_win)
```

### Figure 12.2

```python
fig, ax = plt.subplots(5,1)
ax[0].plot(np.squeeze(EEGdata[46,:,0]))

sine_wave = cos(2*pi*12*time) # 12Hz cosine wave
ax[1].plot(time, sine_wave)

#boxcar envelope
boxcar = np.zeros(len(sine_wave))
midpoint = (len(time))//2
boxcar[midpoint-int(srate//12//5):midpoint+int(srate//12//2)] = 1
ax[2].plot(time, sine_wave*boxcar)

#boxcar of different length
boxcar = np.zeros(len(sine_wave))
midpoint = int(len(time))//2
boxcar[midpoint-50:midpoint+50] = 1
ax[3].plot(time, sine_wave*boxcar)

s = 1.5/(2*pi*f)
gaussian_win = exp(-time**2/(2*s**2))
ax[4].plot(time, sine_wave*gaussian_win)

fig.tight_layout()
```

### Figure 12.3

```python
srate = 500. #sample rate in Hz
f = 10
time = np.arange(-1,1,1/srate)

#complex sinusoid
sine_wave = exp(2*pi*1j*f*time)

#Gaussian window
s = 6/(2*pi*f)
gaussian_win = exp(-time**2/(2*s**2))

#together they make a complex morlet wavelet!
wavelet = sine_wave*gaussian_win

#create plots for each component
fig, ax = plt.subplots(3,1,sharex='all', sharey='all')

ax[0].plot(time,np.real(sine_wave))
ax[0].set(title="sine wave")

ax[1].plot(time,gaussian_win)
ax[1].set(title="gaussian window")

ax[2].plot(time, np.real(wavelet))
ax[2].set(title="my first wavelet", xlabel='time')

fig.tight_layout()
```

### Figure 12.4

```python
num_wavelets = 80 # number of frequency bands
lowest_frequency = 2 #in Hz
highest_frequency = 100 # in Hz

#(linear) equally spaced frequencies for our wavelet family
frequencies = np.linspace(lowest_frequency, highest_frequency, num_wavelets)

plt.figure()
plt.plot(frequencies)
plt.xlabel("Frequency order")
_=plt.ylabel("Frequency in Hz")
```

```python
#initialize our wavelet family
wavelet_family = np.zeros([num_wavelets,len(time)])*1j #1j is to create a complex array of zeros

#iterate through freqs and make a wavelet family

for fi in range(num_wavelets):

    #create a sine wave
    sinewave = exp(2*1j*pi*frequencies[fi]*time)

    #create gaussian window
    gaus_win = exp(-time**2/(2*(6/(2*pi*frequencies[fi]))**2))

    #create wavelet by multiplying our sine wave by the gaussian window
    wavelet_family[fi,:] = sinewave*gaus_win

    #this could be done in one line
#     wavelet_family[fi,:] = exp(2*1j*pi*frequencies[fi]*time) * exp(-time**2/(2*(6/(2*pi*frequencies[fi]))**2))

#plot some of our wavelet family
fig=plt.figure()
plt.subplots(2,1)
plt.subplot(211)
plt.plot(time,np.real(wavelet_family[::int(random.rand()*30),:].T))

plt.subplot(212)
plt.plot(time,np.real(wavelet_family[30,:]))
plt.plot(time,np.imag(wavelet_family[30,:]),'r:')
plt.title("real and imaginary parts of one wavelet")
plt.legend(["real","imaginary"])
plt.tight_layout()
```

```python
fig=plt.figure(figsize=(6,6))
plt.imshow(np.real(wavelet_family),
           extent=[time[0], time[-1], frequencies[0], frequencies[-1]],
           aspect="auto",
           cmap=plt.get_cmap("hot"),
           origin="lower")

plt.xlabel("time (s)")
_=plt.ylabel("frequency (Hz)")
```

### Figure 12.5

```python
from numpy.fft import fft, ifft #import fft functions for ease of use
from scipy import signal as sig
#EEG data from one trial (electrode FCz)
eegdata = np.squeeze(EEGdata[46,:,9])
EEGpnts = data["EEG"][0,0]["pnts"][0,0] #number of points in EEG data
EEGtimes = data["EEG"][0,0]["times"][0]
EEGsrate = float(data["EEG"][0,0]["srate"][0])

#create wavelet
time = np.arange(-1,1 + 1/EEGsrate,1/EEGsrate)
f = 6 #frequency in Hz
sine_wave = exp(2*1j*pi*f*time)

#compute gaussian
s=4.5/(2*pi*f)
gaussian_win = exp(-time**2/(2*s**2))
#window the sinewave by a gaussian to create complex morlet wavelet
wavelet = sine_wave * gaussian_win

#half of wavelet size, useful for chopping off edges after convolution
halfwaveletsize = len(wavelet)//2

#convolve with data
n_conv = len(wavelet) + EEGpnts - 1 #number of points in our convolution

fft_w = fft(wavelet,n_conv)
fft_e = fft(eegdata,n_conv)
#convolution theorem -- convolution = pointwise multiplication in frequency-space
ift = ifft(fft_e*fft_w,n_conv)*sqrt(s)/10 #sqrt(s)/20 is empirical scaling factor (sqrt(s)/10 in the book)
wavelet_conv_data = np.real(ift[halfwaveletsize: - halfwaveletsize]) #take middle portion of convolution
wavelet_conv_data = np.real(ift[halfwaveletsize:-halfwaveletsize]) #take middle portion of convolution

#create a filter to apply to data
nyquist = EEGsrate/2
transition_width = 0.2 #percent
filter_low = 4 #Hz
filter_high = 8 #Hz

ffrequencies = np.array([0 ,filter_low*(1-transition_width),
                         filter_low, filter_high, filter_high*(1+transition_width), nyquist])/nyquist
ideal_response = np.array([0, 0, 1, 1, 0, 0])

#there doesn't seem to be a python equivalent to MATLAB's firls function,
#so I am going to use butterworth filter as a close approximation.

b, a = sig.butter(5, np.array([filter_low*(1-transition_width),filter_high*(1+transition_width)])/nyquist,btype="bandpass")
eeg_4to8 = sig.filtfilt(b, a, eegdata, padlen=150)

plt.plot(EEGtimes,eegdata)
plt.plot(EEGtimes,wavelet_conv_data,'r')
plt.plot(EEGtimes,eeg_4to8,'g')
plt.axis([-200,1200,-40,40])
plt.xlabel("time (ms)")
plt.ylabel("voltage (mV)")
_=plt.legend(["raw","wavelet conv","band-passed"])
```

### Figure 12.6

```python
time = np.arange(-1,1+1/EEGsrate,1/EEGsrate)
n_conv = EEGpnts + len(time) -1
n2p1 = n_conv//2 + 1

f = 6 #hz
s = 6/(2*pi*f)
wavelet = exp(2*pi*1j*f*time) * exp(-time**2/(2*s**2))
halfwaveletsize = len(wavelet)//2

eegdata = np.squeeze(EEGdata[46,:,9])

plt.figure()
plt.subplot(311)
plt.plot(EEGtimes,eegdata)
plt.xlim([-500,1200])
plt.title("raw")

plt.subplot(323)
fft_w = fft(wavelet,n_conv)
hz    = np.linspace(0,EEGsrate/2.,n2p1)
plt.plot(hz,np.absolute(fft_w[:n2p1])/np.max(np.absolute(fft_w[:n2p1])),'b')

fft_e = fft(eegdata,n_conv)
plt.plot(hz,np.absolute(fft_e[:n2p1])/np.max(np.absolute(fft_e[:n2p1])),'g')
plt.axis([0,40,0,1.05])
plt.title("individual power spectra")

plt.subplot(324)
plt.plot(hz,np.absolute(fft_e[:n2p1]*np.absolute(fft_w[:n2p1])))
plt.xlim([0, 40])
plt.title("convolved power spectrum")

plt.subplot(313)
plt.plot(EEGtimes,eegdata)
ift = ifft(fft_e*fft_w,n_conv)*sqrt(s)/10 #sqrt(s)/20 is empirical scaling factor (sqrt(s)/10 in the book)
plt.plot(EEGtimes,np.real(ift[halfwaveletsize:-halfwaveletsize]),'r')
plt.title("wavelet filtered")

plt.tight_layout()
```

### Figure 12.7

```python
#create 10Hz wavelet kernel

time = np.arange(-(EEGpnts/EEGsrate/2),EEGpnts/EEGsrate/2 + 1/EEGsrate,1/EEGsrate)
f = 10. #hz
s = 4/(2*pi*f) #sd of gaussian
wavelet = cos(2*pi*f*time) * exp(-time**2/(2*s**2))

#signal is one sine cycle
timeS = np.arange(0,1/f + 1/EEGsrate,1/EEGsrate)
signal = sin(2*pi*f*timeS)

#zeropad the signal
zz = np.zeros(EEGpnts//2 - len(timeS)//2)
signal = np.concatenate([zz,signal,zz])

plt.figure(figsize=(6,6))

#plot waves
plt.subplot(321)
plt.plot(wavelet,'r')
plt.xlim(200, len(time) - 200)
plt.title("wavelet")

plt.subplot(323)
plt.plot(signal)
plt.xlim([200, len(time)-200])
plt.title("1 cycle of signal")

plt.subplot(325)
plt.plot(np.convolve(wavelet,signal,mode="same"),'purple')
plt.axis([200,len(time)-200,-12,12])
plt.title("convolved wavelet and signal")

#plot the dot products at selected phase lags
plt.subplot(322)
plt.plot(wavelet[int(100/f)-2-1:],'r')
plt.plot(signal)
plt.xlim([200,len(time)-200])
plt.title("dot product: " + str( np.fix(np.sum(wavelet[int(100/f)-2-1:]*signal[:-int(100/f)+3]))))
plt.legend(["wavelet","signal"])

plt.subplot(324)
plt.plot(wavelet[int(2.3*100/f)-2-1:],'r')
plt.plot(signal)
plt.xlim([200,len(time)-200])
plt.title("dot product: " + str( np.fix(np.sum(
                wavelet[int(2.3*100/f)-2-1:]*signal[:-int(2.3*100/f)+3]))))

plt.subplot(326)
plt.plot(wavelet,'r')
plt.plot(signal)
plt.xlim([200,len(time)-200])
plt.title("dot product: " + str( np.fix(np.sum(
                wavelet*signal))))

plt.tight_layout()
```


# Simplest model

The role of this model is to test the feasibility of the device.
It assumes that an external filter is used to give a correct orientation reading from the MARG (IMU + accelerometer + angular rate meter).

Assumptions:
* The robot moves in the 2D plane.
* An external system provides the yaw of the robot with respect to the world frame.
    This external system does not exhibit drift but has white gaussian noise.

The state of the robot is as follow:

\begin{equation}
\mathbf{x} = \begin{pmatrix}
    x\\
    y\\
    \theta\\
    \dot{x}\\
    \dot{y}
\end{pmatrix}
\end{equation}

```python
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
sp.init_printing()
```

```python
# defines a few variables
x, y, xdot, ydot, theta = sp.symbols('x y v_x v_y theta')
state = sp.Matrix([x, y, theta, xdot, ydot])
dt = sp.symbols('Delta_t')
```

## Prediction step

The prediction step uses the acceleration in body frame as control input:

\begin{equation}
\mathbf{u} = \begin{pmatrix}
    a_x\\
    a_y\\
    \omega
\end{pmatrix}
\end{equation}

Therefore, the differential equation governing the motion is given by

\begin{equation}
\mathbf{\dot{x}} = \begin{pmatrix}
\dot{x}\\
\dot{y}\\
0\\
\cos(\theta) a_x - \sin(\theta) a_y \\
\sin(\theta) a_x + \cos(\theta) a_y \\
\end{pmatrix}
\end{equation}

Using forward Euler integration we get:

\begin{equation}
\mathbf{x}_{k+1} = \mathbf{x}_{k} + \Delta_t \mathbf{\dot{x}} = \mathbf{g}\left(\mathbf{x}_{k}, \mathbf{u}_k\right)
\end{equation}

```python
a_x, a_y = sp.symbols('a_x a_y') # in body frame
u = sp.Matrix([a_x, a_y])
dx = sp.Matrix([xdot,
                ydot,
                0,
                sp.cos(theta) * a_x - sp.sin(theta) * a_y,
                sp.sin(theta) * a_x + sp.cos(theta) * a_y])
g = state + dt * dx
```

## Correction step

For this model, we define two measurement functions:

1. The first one is just giving the angle, as output by the angular position system.
2. The second one represents the distance to a beacon at position $\mathbf{b}$.

The first measurement model is simply:

\begin{equation}
h_{\theta}(\mathbf{x}) = \theta
\end{equation}

The second measurement model is given by:

\begin{equation}
h_b(\mathbf{x}, \mathbf{b}) = \sqrt{(x - b_x)^2 + (y - b_y)^2}
\end{equation}

```python
h_theta = sp.Matrix([theta])
b_x, b_y = sp.symbols('b_x b_y') # beacon position
h_b = sp.Matrix([sp.sqrt((x - b_x)**2 + (y - b_y)**2)])
```

## EKF implementation

Some parts of the model are already extracted into their own module (`simple_module.py`), so take a look there for details.

To implement the EKF, we will need the jacobians of the model. We can derivate them automatically using Sympy.

```python
g.jacobian(state)
```

```python
h_theta.jacobian(state)
```

```python
h_b.jacobian(state)
```

# Simulation

```python
# Setup the simulation
from simple_model import SimpleModel
import trajectories

BEACON_POS = [
    (-1.5, 0),
    (1.5, 1),
    (1.5, -1),
]

# Update rate
dt = 1 / 200

# Value taken from the MPU9250 datasheet (8 mg RMS)
accelerometer_noise_std = 8e-3 * 9.81

# Sample covariance for the model
Q_b = np.array([[10]])
Q_theta = np.array([[0.1]])
R = np.diag([0.1, 0.1, 0.1, 0.1, 0.1])
```

```python
angle, angle_estimated, angle_measured = [], [], []
x, xhat = [], []
y, yhat = [], []
acc = []
ts = []

estimator = SimpleModel(dt, R, Q_theta, Q_b)

for i, p in zip(range(10000), trajectories.generate_circular_traj(1, np.deg2rad(20), dt)):
    ts.append(p.timestamp)

    # control input
    u = np.array([p.acc[0], p.acc[1]]) + np.random.normal(0, accelerometer_noise_std, 2)
    acc.append(u)
    estimator.predict(u)

    # Angle measurement
    z = p.theta + np.random.normal(0, 0.1)
    estimator.correct_angle(z)
    angle_measured.append(z)

    # Beacon update
    if i % 20 == 0:
        for bx, by in BEACON_POS:
            distance = np.sqrt((p.pos[0]-bx)**2+(p.pos[1]-by)**2)
            z = distance + np.random.normal(0, 0.03)
            estimator.correct_beacon(bx, by, z)

    angle.append(p.theta)
    angle_estimated.append(estimator.theta)

    xhat.append(estimator.x)
    x.append(p.pos[0])

    yhat.append(estimator.y)
    y.append(p.pos[1])

```

## Results

```python
plt.plot(ts, [s[0] for s in acc])
plt.plot(ts, [s[1] for s in acc])
plt.xlabel('time')
plt.ylabel('acc (m/s^2)')
plt.legend(['x', 'y'])
plt.show()

plt.plot(ts, [a-b for a, b in zip(angle, angle_estimated)])
plt.xlabel('time')
plt.ylabel('angle error (rad)')
plt.show()

plt.plot(ts, x)
plt.plot(ts, xhat)
plt.plot(ts, y)
plt.plot(ts, yhat)
plt.xlabel('time')
plt.ylabel('position (m)')
plt.legend(('x', 'x estimated', 'y', 'y estimated'))
plt.show()

plt.plot(x, y)
plt.plot(xhat, yhat)
plt.plot([x for x, y in BEACON_POS],[y for x, y in BEACON_POS], 'x')
plt.legend(('Simulated trajectory', 'EKF output', 'anchors'))
plt.title('trajectory')
plt.xlabel('x [m]')
plt.ylabel('y [m]')
plt.gcf().savefig('simple_model_trajectory.pdf')
plt.show()

error = [np.sqrt((x-xh)**2+(y-yh)**2) for x,xh,y,yh in zip(x, xhat,y,yhat)]
plt.plot(ts, error)
plt.ylim(0., 0.1)
plt.xlabel('time [s]')
plt.ylabel('position error [m]')
plt.title('Position error (RMS = {:.3f} m)'.format(np.mean(error)))
plt.gcf().savefig('simple_model_error.pdf')
plt.show()
```

```python

```


# Parameter Identification Technique (PIT) on a linear VMM model

# Purpose
Show the general workflow by applying PIT regression on a very simple model

# Methodology
* Load time series from a ZigZag test
* Determine yaw rate and acceleration (compare with accelerometers from test).
* Find the best parameter values in the Nomoto model using OLS linear regression.

# Setup

```python
# %load imports.py
%matplotlib inline
%load_ext autoreload
%autoreload 2
%config Completer.use_jedi = False  ## (To fix autocomplete)

## External packages:
import pandas as pd
pd.options.display.max_rows = 999
pd.options.display.max_columns = 999
pd.set_option("display.max_columns", None)

import numpy as np
import os
import matplotlib.pyplot as plt
#if os.name == 'nt':
#    plt.style.use('presentation.mplstyle')  # Windows

import plotly.express as px
import plotly.graph_objects as go

import seaborn as sns
import sympy as sp
from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame,
                                      Particle, Point)
from sympy.physics.vector.printing import vpprint, vlatex
from IPython.display import display, Math, Latex
from src.substitute_dynamic_symbols import run, lambdify

import pyro

import sklearn
import pykalman
from statsmodels.sandbox.regression.predstd import wls_prediction_std
import statsmodels.api as sm

from scipy.integrate import solve_ivp

## Local packages:
from src.data import mdl
from src.models import linear_vmm
import src.linear_vmm_equations as eq
from src.symbols import *
import src.symbols as symbols
from src.models import regression
```

## Load test

```python
df_runs = mdl.runs()
```

```python
#id=22773
id=22616
#id=22774
#id=22770

df, units, meta_data = mdl.load(id=id, dir_path='../data/processed/kalman')
df.index = df.index.total_seconds()
df = df.iloc[0:-100].copy()
df.index-=df.index[0]
df.sort_index(inplace=True)
```

```python
meta_data['rho']=1000
meta_data['mass'] = meta_data['Volume']*meta_data['rho']
meta_data.dropna()
```

```python
df.head()
```

```python
from src.visualization.plot import track_plot
fig,ax=plt.subplots()
#fig.set_size_inches(10,10)
track_plot(df=df, lpp=meta_data.lpp, x_dataset='x0', y_dataset='y0',  psi_dataset='psi', beam=meta_data.beam, ax=ax);
```

## Yaw rate

```python
px.line(data_frame=df, y=['r'], width=1400, height=300,)
```

# Linear VMM

## N

```python
Math(vlatex(eq.N_eq))
```

```python
N_eq = eq.N_eq.copy()
N_eq = N_eq.subs([
    (x_G,0),  # Assuming or moving to CG=0
    #(I_z,1),  # Removing inertia
    #(eq.p.Nrdot,0),  # Removing added mass
    (eq.p.Nvdot,0),  # Removing added mass
    (eq.p.Nudot,0),  # Removing added mass

])

solution = sp.solve(N_eq,r1d)[0]
N_eq = sp.Eq(r1d, solution*(I_z-eq.p.Nrdot))  # Putting r1d on the LHS
```

```python
#Math(vlatex(N_eq))
```

```python
diff_eq_N = regression.DiffEqToMatrix(ode=N_eq, label=r1d, base_features=[delta,u,v,r])
```

```python
Math(vlatex(diff_eq_N.acceleration_equation))
```

$ y = X \cdot \beta + \epsilon $

```python
Math(vlatex(diff_eq_N.acceleration_equation_x))
```

```python
Math(vlatex(diff_eq_N.eq_y))
```

```python
diff_eq_N.eq_beta
```

```python
Math(vlatex(diff_eq_N.eq_X))
```

```python
diff_eq_N.X_lambda
```

```python
from statsmodels.sandbox.regression.predstd import wls_prediction_std
def show_pred(X,y,results, label):

    display(results.summary())

    X_ = X
    y_ = y
    y_pred = results.predict(X_)

    prstd, iv_l, iv_u = wls_prediction_std(results, exog=X_, alpha=0.05)
    #iv_l*=-1
    #iv_u*=-1

    fig,ax=plt.subplots()
    ax.plot(X_.index,y_, label='Numerical gradient from model test')
    ax.plot(X_.index,y_pred, '--', label='OLS')
    ax.set_ylabel(label)

    ax.fill_between(X_.index, y1=iv_l, y2=iv_u, zorder=-10, color='grey', alpha=0.5, label=r'5\% confidence')
    ax.legend();
```

```python
X = diff_eq_N.calculate_features(data=df)
y = diff_eq_N.calculate_label(y=df['r1d'])

model_N = sm.OLS(y,X)
results_N = model_N.fit()

show_pred(X=X,y=y,results=results_N, label=r'$\dot{r}$')
```

## Y

```python
Y_eq = eq.Y_eq.copy()
Y_eq = Y_eq.subs([
    #(eq.p.Yvdot,1),  # Removing added mass
    (eq.p.Yudot,0),  # Removing added mass
    (eq.p.Yrdot,0),  # Removing added mass
    (x_G,0),

])
solution = sp.solve(Y_eq,v1d)[0]
solution = solution*(-eq.p.Yvdot+m)
solution = solution + U*m*r# (adding u*m*r to the measurement fy instead)
Y_eq = sp.simplify(sp.Eq(v1d, solution))  # Putting r1d on the LHS
```

```python
Math(vlatex(Y_eq))
```

```python
diff_eq_Y = regression.DiffEqToMatrix(ode=Y_eq, label=v1d, base_features=[delta,u,v,r])
```

```python
diff_eq_Y.eq_beta
```

```python
diff_eq_Y.acceleration_equation_x
```

```python
X = diff_eq_Y.calculate_features(data=df, simplify_names=True)
y = diff_eq_Y.calculate_label(y=df['v1d'])
#y+=df['u']*df['r']  # adding centrifugal force

model_Y = sm.OLS(y,X)
results_Y = model_Y.fit()

show_pred(X=X,y=y,results=results_Y, label=r'$\dot{v}$')
```

```python
X.head()
```

## X

```python
X_eq = eq.X_eq.copy()
X_eq = X_eq.subs([
    #(eq.p.Xudot,1),  # Removing added mass
    (eq.p.Xvdot,0),  # Removing added mass
    (eq.p.Xrdot,0),  # Removing added mass

    #(m,0),  # mass

])

solution = sp.solve(X_eq,u1d)[0]
X_eq = sp.Eq(u1d, solution*(-eq.p.Xudot+m))  # Putting r1d on the LHS
```

```python
Math(vlatex(X_eq))
```

```python
diff_eq_X = regression.DiffEqToMatrix(ode=X_eq, label=u1d, base_features=[delta,u,v,r])
```

```python
X = diff_eq_X.calculate_features(data=df)
y = diff_eq_X.calculate_label(y=df['u1d'])

model_X = sm.OLS(y,X)
results_X = model_X.fit()

show_pred(X=X,y=y,results=results_X, label=r'$\dot{u}$')
```

```python
results_summary_X = regression.results_summary_to_dataframe(results_X)
results_summary_Y = regression.results_summary_to_dataframe(results_Y)
results_summary_N = regression.results_summary_to_dataframe(results_N)
```

## Simulation

```python
eqs = [diff_eq_X.acceleration_equation, diff_eq_Y.acceleration_equation, diff_eq_N.acceleration_equation]
solution = sp.solve(eqs, u1d, v1d, r1d, dict=True)

## Decouple the equations:
u1d_eq = sp.Eq(u1d, solution[0][u1d])
v1d_eq = sp.Eq(v1d, solution[0][v1d])
r1d_eq = sp.Eq(r1d, solution[0][r1d])

## Lambdify:
subs = {value:key for key,value in eq.p.items()}
u1d_lambda = lambdify(u1d_eq.subs(subs).rhs)
v1d_lambda = lambdify(v1d_eq.subs(subs).rhs)
r1d_lambda = lambdify(r1d_eq.subs(subs).rhs)
```

```python
display(Math(vlatex(u1d_eq)))
display(Math(vlatex(v1d_eq)))
display(Math(vlatex(r1d_eq)))
```

```python
from scipy.spatial.transform import Rotation as R

def step(t, states, parameters, df_control, meta_data):

    u,v,r,x0,y0,psi = states

    states_dict = {

        'u':u,
        'v':v,
        'r':r,

        'x0':x0,
        'y0':y0,
        'psi':psi,

        }

    inputs = dict(parameters)
    inputs.update(states_dict)

    index = np.argmin(np.array(np.abs(df_control.index - t)))
    control = dict(df_control.iloc[index])
    #print(f't:{t}, i:{index}')
    inputs.update(control)

    inputs['U'] = np.sqrt(u**2 + v**2)  #Instantanious velocity

    if not 'u1d' in control:
        u1d = -run(function=u1d_lambda, inputs=inputs)
    else:
        u1d = control['u1d']

    mass = meta_data['mass']
    v1d = run(function=v1d_lambda, inputs=inputs) - u*r
    #v1d = run(function=v1d_lambda, inputs=inputs)

    r1d = run(function=r1d_lambda, inputs=inputs)

    rotation = R.from_euler('z', psi, degrees=False)
    w = 0
    velocities = rotation.apply([u,v,w])
    x01d = velocities[0]
    y01d = velocities[1]
    psi1d = r

    dstates = [
        u1d,
        v1d,
        r1d,
        x01d,
        y01d,
        psi1d,
    ]

    #print(t)

    return dstates

```

```python
parameters = dict(results_summary_X['coeff'])  # Fix (-)
parameters.update(dict(results_summary_Y['coeff']))   # Fix (-)
parameters.update(dict(results_summary_N['coeff']))

states = ['u','v','r','x0','y0','psi']
states0 = [float(df[key].iloc[0]) for key in states]
#df_control = df[['delta','u1d','u']]
df_control = df[['delta']].copy()
#df_control['delta']+=np.deg2rad(0.5)
```

```python
t_ = 10
index = np.argmin(np.array(np.abs(df_control.index - t_)))
df_control.iloc[index]
```

```python
(np.diff(df_control.index) > 0).all()
```

```python
## Simulate:
df_ = df.copy()
t = np.array(df_.index)
t_span = [t[0],t[-1]]
solution = solve_ivp(fun=step, t_span=t_span, y0=states0, t_eval=t, args=(parameters, df_control, meta_data), method='RK45')
```

```python
df_result = pd.DataFrame(data=solution.y.T, columns=states)
df_result.index=t
```

```python
fig,ax=plt.subplots()
#fig.set_size_inches(15,15)
track_plot(df=df_, lpp=meta_data['lpp'], beam=meta_data['beam'], ax=ax, color='k', label='model test');
track_plot(df=df_result, lpp=meta_data['lpp'], beam=meta_data['beam'], ax=ax, color='g', label='simulation');
ax.legend()
```

```python
fig,ax=plt.subplots()
df_['-delta'] = -df_['delta']
df_.plot(y='-delta', style='--', ax=ax)
df_.plot(y='psi', ax=ax, label='model test')
df_result.plot(y='psi', ax=ax, label='simulation')
ax.legend()

for key in ['u','v','r']:

    fig,ax=plt.subplots()
    df_.plot(y=key, ax=ax, label='model test')
    df_result.plot(y=key, ax=ax, label='simulation')
    ax.set_ylabel(key)

```

```python

```