function to train the model on the observed data

            Parameters:
            -----------

            times: list
                list of numpy arrays of the timesteps for each curve
            losses: list
                list of numpy arrays of the loss (the actual learning curve)
            configs: list or None
                list of the configurations for each sample. Each element
                has to be a numpy array. Set to None, if no configuration
                information is available.

def fit(self, times, losses, configs=None):
        """
            function to train the model on the observed data

            Parameters:
            -----------

            times: list
                list of numpy arrays of the timesteps for each curve
            losses: list
                list of numpy arrays of the loss (the actual learning curve)
            configs: list or None
                list of the configurations for each sample. Each element
                has to be a numpy array. Set to None, if no configuration
                information is available.
        """

        assert np.all(times > 0) and np.all(times <= self.max_num_epochs)

        train = None
        targets = None

        for i in range(len(configs)):

            t_idx = times[i] / self.max_num_epochs

            x = np.repeat(np.array(configs[i])[None, :], t_idx.shape[0], axis=0)
            x = np.concatenate((x, t_idx[:, None]), axis=1)

            # LCNet assumes increasing curves, if we feed in losses here we have to flip the curves
            lc = [1 - l for l in losses[i]]

            if train is None:
                train = x
                targets = lc
            else:
                train = np.concatenate((train, x), 0)
                targets = np.concatenate((targets, lc), 0)

        self.model.train(train, targets)