def forward(self, x_in: PLModuleInput):
        """
        x_in
            comes as tuple `(x, x_future, x_static)` where `x` is the past target, past covariates and
            historic future covariate chunk and `x_future` is the (non-historic) future chunk.
            Input dimensions are `(n_samples, n_time_steps, n_variables)`
        """
        x, x_future, x_static = x_in  # x: (batch, in_len, in_dim)
        # we clone `x`, to avoid value mutation from normalization when performing auto-regression
        x = x.clone()
        batch, _, _ = x.shape
        seq_last = None

        if self.shared_weights:
            # discard covariates, to ensure that in_dim == out_dim
            x = x[:, :, : self.output_dim]
            x = x.permute(0, 2, 1)  # (batch, out_dim, in_len)

            if self.normalize:
                seq_last = x[:, :, -1:].detach().clone()  # (batch, out_dim, 1)
                x = x - seq_last

            x = self.layer(x)  # (batch, out_dim, out_len * nr_params)

            if self.normalize:
                x = x + seq_last

            # extract nr_params
            x = x.view(batch, self.output_dim, self.output_chunk_length, self.nr_params)

            # permute back to (batch, out_len, out_dim, nr_params)
            x = x.permute(0, 2, 1, 3)
        else:
            if self.normalize:
                # get last values for all x but not future covariates
                past_dim = self.input_dim - self.future_cov_dim
                seq_last = x[:, -1:, :past_dim].detach().clone()
                # normalize the input
                x[:, :, :past_dim] -= seq_last

            x = self.layer(x.view(batch, -1))  # (batch, out_len * out_dim * nr_params)
            x = x.view(
                batch, self.output_chunk_length, self.output_dim * self.nr_params
            )

            if self.future_cov_dim != 0:
                # x_future might be shorter than output_chunk_length when n < output_chunk_length
                # so we need to pad it with zeros at the end to match the output_chunk_length
                x_future = torch.nn.functional.pad(
                    input=x_future,
                    pad=(0, 0, 0, self.output_chunk_length - x_future.shape[1]),
                    mode="constant",
                    value=0,
                )

                fut_cov_output = self.linear_fut_cov(x_future)
                x = x + fut_cov_output.view(
                    batch, self.output_chunk_length, self.output_dim * self.nr_params
                )

            if self.static_cov_dim != 0:
                static_cov_output = self.linear_static_cov(x_static.reshape(batch, -1))
                x = x + static_cov_output.view(
                    batch, self.output_chunk_length, self.output_dim * self.nr_params
                )

            if self.normalize:
                # Reverse the normalization for the target
                x = x + seq_last[:, :, : self.output_dim]

            x = x.view(batch, self.output_chunk_length, self.output_dim, self.nr_params)

        return x

        x_in
            comes as tuple `(x, x_future, x_static)` where `x` is the past target, past covariates and
            historic future covariate chunk and `x_future` is the (non-historic) future chunk.
            Input dimensions are `(n_samples, n_time_steps, n_variables)`
        
darts/models/forecasting/nlinear.py